dvmInitMutex(&gDvm.jniPinRefLock);
+ Method* meth;
+
+ /*
+ * Grab the PhantomReference constructor.
+ */
+ gDvm.classJavaLangRefPhantomReference =
+ dvmFindSystemClassNoInit("Ljava/lang/ref/PhantomReference;");
+ if (gDvm.classJavaLangRefPhantomReference == NULL) {
+ LOGE("Unable to find PhantomReference class\n");
+ return false;
+ }
+ meth= dvmFindDirectMethodByDescriptor(gDvm.classJavaLangRefPhantomReference,
+ "<init>", "(Ljava/lang/Object;Ljava/lang/ref/ReferenceQueue;)V");
+ if (meth == NULL) {
+ LOGE("Unable to find constructor for PhantomReference\n");
+ return false;
+ }
+ gDvm.methJavaLangRefPhantomReference_init = meth;
+
+
/*
* Look up and cache pointers to some direct buffer classes, fields,
* and methods.
*/
- Method* meth;
-
ClassObject* platformAddressClass =
dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddress;");
ClassObject* platformAddressFactoryClass =
break;
case kIndirectKindWeakGlobal:
{
+ // TODO: implement
LOGE("weak-global not yet supported\n");
result = NULL;
dvmAbort();
dvmUnlockMutex(&gDvm.jniGlobalRefLock);
}
+
+/*
+ * Get the "magic" JNI weak global ReferenceQueue. It's allocated on
+ * first use.
+ *
+ * Returns NULL with an exception raised if allocation fails.
+ */
+static Object* getWeakGlobalRefQueue(void)
+{
+ /* use an indirect variable to avoid "type-punned pointer" complaints */
+ Object** pGlobalQ = &gDvm.jniWeakGlobalRefQueue;
+
+ if (*pGlobalQ != NULL)
+ return *pGlobalQ;
+
+ ClassObject* clazz = dvmFindSystemClass("Ljava/lang/ref/ReferenceQueue;");
+ if (clazz == NULL) {
+ LOGE("Unable to find java.lang.ref.ReferenceQueue");
+ dvmAbort();
+ }
+
+ /*
+ * Create an instance of ReferenceQueue. The object is never actually
+ * used for anything, so we don't need to call a constructor. (We could
+ * get away with using an instance of Object, but this is cleaner.)
+ */
+ Object* queue = dvmAllocObject(clazz, ALLOC_DEFAULT);
+ if (queue == NULL) {
+ LOGW("Failed allocating weak global ref queue\n");
+ assert(dvmCheckException(dvmThreadSelf()));
+ return NULL;
+ }
+ dvmReleaseTrackedAlloc(queue, NULL);
+
+ /*
+ * Save it, using atomic ops to ensure we don't double-up. The gDvm
+ * field is known to the GC.
+ */
+ if (!ATOMIC_CMP_SWAP((int*) pGlobalQ, 0, (int) queue)) {
+ LOGD("WOW: lost race to create weak global ref queue\n");
+ queue = *pGlobalQ;
+ }
+
+ return queue;
+}
+
+
+/*
+ * We create a PhantomReference that references the object, add a
+ * global reference to it, and then flip some bits before returning it.
+ * The last step ensures that we detect it as special and that only
+ * appropriate calls will accept it.
+ *
+ * On failure, returns NULL with an exception pending.
+ */
+static jweak createWeakGlobalRef(JNIEnv* env, jobject jobj)
+{
+ if (jobj == NULL)
+ return NULL;
+
+ Thread* self = ((JNIEnvExt*)env)->self;
+ Object* obj = dvmDecodeIndirectRef(env, jobj);
+ Object* weakGlobalQueue = getWeakGlobalRefQueue();
+ Object* phantomObj;
+ jobject phantomRef;
+
+ /*
+ * Allocate a PhantomReference, then call the constructor to set
+ * the referent and the reference queue.
+ *
+ * We use a "magic" reference queue that the GC knows about; it behaves
+ * more like a queueless WeakReference, clearing the referent and
+ * not calling enqueue().
+ */
+ if (!dvmIsClassInitialized(gDvm.classJavaLangRefPhantomReference))
+ dvmInitClass(gDvm.classJavaLangRefPhantomReference);
+ phantomObj = dvmAllocObject(gDvm.classJavaLangRefPhantomReference,
+ ALLOC_DEFAULT);
+ if (phantomObj == NULL) {
+ assert(dvmCheckException(self));
+ LOGW("Failed on WeakGlobalRef alloc\n");
+ return NULL;
+ }
+
+ JValue unused;
+ dvmCallMethod(self, gDvm.methJavaLangRefPhantomReference_init, phantomObj,
+ &unused, jobj, weakGlobalQueue);
+ dvmReleaseTrackedAlloc(phantomObj, self);
+
+ if (dvmCheckException(self)) {
+ LOGW("PhantomReference init failed\n");
+ return NULL;
+ }
+
+ LOGV("+++ WGR: created phantom ref %p for object %p\n", phantomObj, obj);
+
+ /*
+ * Add it to the global reference table, and mangle the pointer.
+ */
+ phantomRef = addGlobalReference(phantomObj);
+ return dvmObfuscateWeakGlobalRef(phantomRef);
+}
+
+/*
+ * Delete the global reference that's keeping the PhantomReference around.
+ * The PhantomReference will eventually be discarded by the GC.
+ */
+static void deleteWeakGlobalRef(JNIEnv* env, jweak wref)
+{
+ if (wref == NULL)
+ return;
+
+ jobject phantomRef = dvmNormalizeWeakGlobalRef(wref);
+ deleteGlobalReference(phantomRef);
+}
+
+/*
+ * Extract the referent from a PhantomReference. Used for weak global
+ * references.
+ *
+ * "jwobj" is a "mangled" WGR pointer.
+ */
+static Object* getPhantomReferent(JNIEnv* env, jweak jwobj)
+{
+ jobject jobj = dvmNormalizeWeakGlobalRef(jwobj);
+ Object* obj = dvmDecodeIndirectRef(env, jobj);
+
+ if (obj->clazz != gDvm.classJavaLangRefPhantomReference) {
+ LOGE("%p is not a phantom reference (%s)\n",
+ jwobj, obj->clazz->descriptor);
+ return NULL;
+ }
+
+ return dvmGetFieldObject(obj, gDvm.offJavaLangRefReference_referent);
+}
+
+
/*
* Objects don't currently move, so we just need to create a reference
* that will ensure the array object isn't collected.
//Object** top;
Object** ptr;
+ if (dvmIsWeakGlobalRef(jobj)) {
+ return JNIWeakGlobalRefType;
+ }
+
/* check args */
if (findInArgList(self, jobj)) {
//LOGI("--- REF found %p on stack\n", jobj);
*/
static jobject NewGlobalRef(JNIEnv* env, jobject jobj)
{
+ Object* obj;
+
JNI_ENTER();
- Object* obj = dvmDecodeIndirectRef(env, jobj);
+ if (dvmIsWeakGlobalRef(jobj))
+ obj = getPhantomReferent(env, (jweak) jobj);
+ else
+ obj = dvmDecodeIndirectRef(env, jobj);
jobject retval = addGlobalReference(obj);
JNI_EXIT();
return retval;
/*
* Add a reference to the local list.
*/
-static jobject NewLocalRef(JNIEnv* env, jobject jref)
+static jobject NewLocalRef(JNIEnv* env, jobject jobj)
{
+ Object* obj;
+
JNI_ENTER();
- Object* obj = dvmDecodeIndirectRef(env, jref);
+ if (dvmIsWeakGlobalRef(jobj))
+ obj = getPhantomReferent(env, (jweak) jobj);
+ else
+ obj = dvmDecodeIndirectRef(env, jobj);
jobject retval = addLocalReference(env, obj);
JNI_EXIT();
return retval;
static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj)
{
JNI_ENTER();
- // TODO - implement
- jobject gref = NULL;
- LOGE("JNI ERROR: NewWeakGlobalRef not implemented\n");
- dvmAbort();
+ jweak wref = createWeakGlobalRef(env, obj);
JNI_EXIT();
- return gref;
+ return wref;
}
/*
* Delete the specified weak global reference.
*/
-static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj)
+static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref)
{
JNI_ENTER();
- // TODO - implement
- LOGE("JNI ERROR: DeleteWeakGlobalRef not implemented\n");
- dvmAbort();
+ deleteWeakGlobalRef(env, wref);
JNI_EXIT();
}
dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
dvmMarkObjectNonNull(gDvm.internalErrorObj);
dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
+ dvmMarkObject(gDvm.jniWeakGlobalRefQueue);
//TODO: scan object references sitting in gDvm; use pointer begin & end
HPROF_CLEAR_GC_SCAN_STATE();
* (The referent will be marked outside of this loop,
* after handing all references of this strength, in
* case multiple references point to the same object.)
+ *
+ * One exception: JNI "weak global" references are handled
+ * as a special case. They're identified by the queue.
*/
+ if (gDvm.jniWeakGlobalRefQueue != NULL) {
+ Object* queue = dvmGetFieldObject(reference,
+ gDvm.offJavaLangRefReference_queue);
+ if (queue == gDvm.jniWeakGlobalRefQueue) {
+ LOGV("+++ WGR: clearing + not queueing %p:%p\n",
+ reference, referent);
+ schedClear = clearReference(reference);
+ schedEnqueue = false;
+ break;
+ }
+ }
schedClear = false;
/* A PhantomReference is only useful with a
/* Walk though the reference list again, and mark any non-clear/marked
* referents. Only PhantomReferences can have non-clear referents
* at this point.
+ *
+ * (Could skip this for JNI weak globals, since we know they've been
+ * cleared.)
*/
if (refType == REF_PHANTOM) {
bool scanRequired = false;