OSDN Git Service

Merge change 22659 into eclair
authorAndroid (Google) Code Review <android-gerrit@google.com>
Wed, 26 Aug 2009 14:19:51 +0000 (07:19 -0700)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Wed, 26 Aug 2009 14:19:51 +0000 (07:19 -0700)
* changes:
  Another round of scary indirect ref changes.

31 files changed:
vm/CheckJni.c
vm/Debugger.c
vm/Dvm.mk
vm/Globals.h
vm/Jni.c
vm/JniInternal.h
vm/ReferenceTable.c
vm/ReferenceTable.h
vm/SignalCatcher.c
vm/Thread.c
vm/Thread.h
vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
vm/compiler/template/armv5te/footer.S
vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
vm/interp/Stack.c
vm/interp/Stack.h
vm/mterp/armv5te/footer.S
vm/mterp/c/gotoTargets.c
vm/mterp/common/asm-constants.h
vm/mterp/out/InterpAsm-armv4t.S
vm/mterp/out/InterpAsm-armv5te-vfp.S
vm/mterp/out/InterpAsm-armv5te.S
vm/mterp/out/InterpAsm-armv7-a.S
vm/mterp/out/InterpAsm-x86.S
vm/mterp/out/InterpC-allstubs.c
vm/mterp/out/InterpC-portdbg.c
vm/mterp/out/InterpC-portstd.c
vm/mterp/out/InterpC-x86.c
vm/mterp/x86/footer.S

index 31c35c3..a8bb113 100644 (file)
@@ -1735,6 +1735,7 @@ static const jchar* Check_GetStringChars(JNIEnv* env, jstring string,
     const jchar* result;
     result = BASE_ENV(env)->GetStringChars(env, string, isCopy);
     if (((JNIEnvExt*)env)->forceDataCopy && result != NULL) {
+        // TODO: fix for indirect
         int len = dvmStringLen(string) * 2;
         result = (const jchar*) createGuardedCopy(result, len, false);
         if (isCopy != NULL)
@@ -1790,6 +1791,7 @@ static const char* Check_GetStringUTFChars(JNIEnv* env, jstring string,
     const char* result;
     result = BASE_ENV(env)->GetStringUTFChars(env, string, isCopy);
     if (((JNIEnvExt*)env)->forceDataCopy && result != NULL) {
+        // TODO: fix for indirect
         int len = dvmStringUtf8ByteLen(string) + 1;
         result = (const char*) createGuardedCopy(result, len, false);
         if (isCopy != NULL)
@@ -2056,6 +2058,7 @@ static const jchar* Check_GetStringCritical(JNIEnv* env, jstring string,
     const jchar* result;
     result = BASE_ENV(env)->GetStringCritical(env, string, isCopy);
     if (((JNIEnvExt*)env)->forceDataCopy && result != NULL) {
+        // TODO: fix for indirect
         int len = dvmStringLen(string) * 2;
         result = (const jchar*) createGuardedCopy(result, len, false);
         if (isCopy != NULL)
@@ -2153,7 +2156,7 @@ static void* Check_GetDirectBufferAddress(JNIEnv* env, jobject buf)
          * interfaces.  Note this does not guarantee that it's a direct buffer.
          */
         if (JNI_FALSE == (*env)->IsInstanceOf(env, buf,
-                (jclass) gDvm.classOrgApacheHarmonyNioInternalDirectBuffer))
+                gDvm.jclassOrgApacheHarmonyNioInternalDirectBuffer))
         {
             goto bail;
         }
index 3affa97..4ddf25c 100644 (file)
@@ -2814,7 +2814,7 @@ void dvmDbgExecuteMethod(DebugInvokeReq* pReq)
         free(desc);
     }
 
-    dvmCallMethodA(self, meth, pReq->obj, &pReq->resultValue,
+    dvmCallMethodA(self, meth, pReq->obj, false, &pReq->resultValue,
         (jvalue*)pReq->argArray);
     pReq->exceptObj = objectToObjectId(dvmGetException(self));
     pReq->resultTag = resultTagFromSignature(meth);
index 7aab98d..66ada15 100644 (file)
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -24,6 +24,7 @@
 # Compiler defines.
 #
 LOCAL_CFLAGS += -fstrict-aliasing -Wstrict-aliasing=2 -fno-align-jumps
+#LOCAL_CFLAGS += -DUSE_INDIRECT_REF
 
 #
 # Optional features.  These may impact the size or performance of the VM.
index a1a1b83..e1a91de 100644 (file)
@@ -194,6 +194,7 @@ struct DvmGlobals {
     ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMember;
     ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMemberArray;
     ClassObject* classOrgApacheHarmonyNioInternalDirectBuffer;
+    jclass      jclassOrgApacheHarmonyNioInternalDirectBuffer;
 
     /* synthetic classes for arrays of primitives */
     ClassObject* classArrayBoolean;
@@ -409,7 +410,11 @@ struct DvmGlobals {
     /*
      * JNI global reference table.
      */
+#ifdef USE_INDIRECT_REF
+    IndirectRefTable jniGlobalRefTable;
+#else
     ReferenceTable  jniGlobalRefTable;
+#endif
     pthread_mutex_t jniGlobalRefLock;
     int         jniGlobalRefHiMark;
     int         jniGlobalRefLoMark;
index abd520a..f93a332 100644 (file)
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -51,7 +51,9 @@ General notes on local/global reference tracking
 JNI provides explicit control over natively-held references that the GC
 needs to know about.  These can be local, in which case they're released
 when the native method returns into the VM, or global, which are held
-until explicitly released.
+until explicitly released.  (There are also weak-global references,
+which have the lifespan and visibility of global references, but the
+object they refer to may be collected.)
 
 The references can be created with explicit JNI NewLocalRef / NewGlobalRef
 calls.  The former is very unusual, the latter is reasonably common
@@ -71,36 +73,52 @@ with a simple store/increment operation; to avoid infinite growth in
 pathological situations, we need to reclaim the space used by deleted
 entries.
 
-The simplest implementation is an expanding append-only array that compacts
-when objects are deleted.  In typical situations, e.g. running through
-an array of objects, we will be deleting one of the most recently added
-entries, so we can minimize the number of elements moved (or avoid having
-to move any).
+If we just want to maintain a list for the GC root set, we can use an
+expanding append-only array that compacts when objects are deleted.
+In typical situations, e.g. running through an array of objects, we will
+be deleting one of the most recently added entries, so we can minimize
+the number of elements moved (or avoid having to move any).
+
+If we want to conceal the pointer values from native code, which is
+necessary to allow the GC to move JNI-referenced objects around, then we
+have to use a more complicated indirection mechanism.
 
 The spec says, "Local references are only valid in the thread in which
 they are created.  The native code must not pass local references from
 one thread to another."
 
 
+Pinned objects
+
+For some large chunks of data, notably primitive arrays and String data,
+JNI allows the VM to choose whether it wants to pin the array object or
+make a copy.  We currently pin the memory for better execution performance.
+
+TODO: we're using simple root set references to pin primitive array data,
+because they have the property we need (i.e. the pointer we return is
+guaranteed valid until we explicitly release it).  However, if we have a
+compacting GC and don't want to pin all memory held by all global refs,
+we need to treat these differently.
+
+
 Global reference tracking
 
 There should be a small "active" set centered around the most-recently
-added items.  We can use an append-only, compacting array like we do for
-local refs.
+added items.
 
-Because it's global, access to it has to be synchronized.
+Because it's global, access to it has to be synchronized.  Additions and
+removals require grabbing a mutex.  If the table serves as an indirection
+mechanism (i.e. it's not just a list for the benefit of the garbage
+collector), reference lookups may also require grabbing a mutex.
 
 The JNI spec does not define any sort of limit, so the list must be able
-to expand.  It may be useful to log significant increases in usage to
-help identify resource leaks.
+to expand to a reasonable size.  It may be useful to log significant
+increases in usage to help identify resource leaks.
+
 
-TODO: we currently use global references on strings and primitive array
-data, because they have the property we need (i.e. the pointer we return
-is guaranteed valid until we explicitly release it).  However, if we have
-a compacting GC and don't want to pin all memory held by all global refs,
-we actually want to treat these differently.  Either we need a way to
-tell the GC that specific global references are pinned, or we have to
-make a copy of the data and return that instead (something JNI supports).
+Weak-global reference tracking
+
+[TBD]
 
 
 Local reference tracking
@@ -173,14 +191,14 @@ all references.  An exact GC will need to understand the actual layout.
 
 *** Approach #2: use a parallel stack
 
-Each Thread/JNIEnv points to a ReferenceTable struct.  The struct
-has a system-heap-allocated array of references and a pointer to the
+Each Thread/JNIEnv points to a reference table.  The struct has
+a system-heap-allocated array of references and a pointer to the
 next-available entry ("nextEntry").
 
-Each stack frame has a pointer to what it sees as the "top" element in the
-array (we can double-up the "currentPc" field).  This is set to "nextEntry"
-when the frame is pushed on.  As local references are added or removed,
-"nextEntry" is updated.
+Each stack frame has a pointer to what it sees as the "bottom" element
+in the array (we can double-up the "currentPc" field).  This is set to
+"nextEntry" when the frame is pushed on.  As local references are added
+or removed, "nextEntry" is updated.
 
 We implement Push/PopLocalFrame with actual stack frames.  Before a JNI
 frame gets popped, we set "nextEntry" to the "top" pointer of the current
@@ -218,15 +236,13 @@ Compared to #1, approach #2:
 
 /* fwd */
 static const struct JNINativeInterface gNativeInterface;
-static jobject addLocalReference(JNIEnv* env, Object* obj);
 static jobject addGlobalReference(Object* obj);
 
-
 #ifdef WITH_JNI_STACK_CHECK
 # define COMPUTE_STACK_SUM(_self)   computeStackSum(_self);
 # define CHECK_STACK_SUM(_self)     checkStackSum(_self);
-static void computeStackSum(Thread* self);
-static void checkStackSum(Thread* self);
+//static void computeStackSum(Thread* self);
+//static void checkStackSum(Thread* self);
 #else
 # define COMPUTE_STACK_SUM(_self)   ((void)0)
 # define CHECK_STACK_SUM(_self)     ((void)0)
@@ -235,217 +251,6 @@ static void checkStackSum(Thread* self);
 
 /*
  * ===========================================================================
- *      JNI call bridge
- * ===========================================================================
- */
-
-/*
- * The functions here form a bridge between interpreted code and JNI native
- * functions.  The basic task is to convert an array of primitives and
- * references into C-style function arguments.  This is architecture-specific
- * and usually requires help from assembly code.
- *
- * The bridge takes four arguments: the array of parameters, a place to
- * store the function result (if any), the method to call, and a pointer
- * to the current thread.
- *
- * These functions aren't called directly from elsewhere in the VM.
- * A pointer in the Method struct points to one of these, and when a native
- * method is invoked the interpreter jumps to it.
- *
- * (The "internal native" methods are invoked the same way, but instead
- * of calling through a bridge, the target method is called directly.)
- *
- * The "args" array should not be modified, but we do so anyway for
- * performance reasons.  We know that it points to the "outs" area on
- * the current method's interpreted stack.  This area is ignored by the
- * precise GC, because there is no register map for a native method (for
- * an interpreted method the args would be listed in the argument set).
- * We know all of the values exist elsewhere on the interpreted stack,
- * because the method call setup copies them right before making the call,
- * so we don't have to worry about concealing stuff from the GC.
- *
- * If we don't want to modify "args", we either have to create a local
- * copy and modify it before calling dvmPlatformInvoke, or we have to do
- * the local reference replacement within dvmPlatformInvoke.  The latter
- * has some performance advantages, though if we can inline the local
- * reference adds we may win when there's a lot of reference args (unless
- * we want to code up some local ref table manipulation in assembly.
- */
-
-/*
- * General form, handles all cases.
- */
-void dvmCallJNIMethod_general(const u4* args, JValue* pResult,
-    const Method* method, Thread* self)
-{
-    int oldStatus;
-    u4* modArgs = (u4*) args;
-
-    assert(method->insns != NULL);
-
-    //LOGI("JNI calling %p (%s.%s:%s):\n", method->insns,
-    //    method->clazz->descriptor, method->name, method->shorty);
-
-    /*
-     * Walk the argument list, creating local references for appropriate
-     * arguments.
-     */
-    JNIEnv* env = self->jniEnv;
-    jclass staticMethodClass;
-    int idx = 0;
-    if (dvmIsStaticMethod(method)) {
-        /* add the class object we pass in */
-        staticMethodClass = addLocalReference(env, (Object*) method->clazz);
-        if (staticMethodClass == NULL) {
-            assert(dvmCheckException(self));
-            return;
-        }
-    } else {
-        /* add "this" */
-        staticMethodClass = NULL;
-        jobject thisObj = addLocalReference(env, (Object*) modArgs[0]);
-        if (thisObj == NULL) {
-            assert(dvmCheckException(self));
-            return;
-        }
-        modArgs[idx] = (u4) thisObj;
-        idx = 1;
-    }
-
-    const char* shorty = &method->shorty[1];        /* skip return type */
-    while (*shorty != '\0') {
-        switch (*shorty++) {
-        case 'L':
-            //LOGI("  local %d: 0x%08x\n", idx, modArgs[idx]);
-            if (modArgs[idx] != 0) {
-                //if (!dvmIsValidObject((Object*) modArgs[idx]))
-                //    dvmAbort();
-                jobject argObj = addLocalReference(env, (Object*) modArgs[idx]);
-                if (argObj == NULL) {
-                    assert(dvmCheckException(self));
-                    return;
-                }
-                modArgs[idx] = (u4) argObj;
-            }
-            break;
-        case 'D':
-        case 'J':
-            idx++;
-            break;
-        default:
-            /* Z B C S I -- do nothing */
-            break;
-        }
-
-        idx++;
-    }
-
-    oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
-
-    COMPUTE_STACK_SUM(self);
-    dvmPlatformInvoke(self->jniEnv, staticMethodClass,
-        method->jniArgInfo, method->insSize, modArgs, method->shorty,
-        (void*)method->insns, pResult);
-    CHECK_STACK_SUM(self);
-
-    dvmChangeStatus(self, oldStatus);
-}
-
-/*
- * Handler for the unusual case of a synchronized native method.
- *
- * Lock the object, then call through the general function.
- */
-void dvmCallJNIMethod_synchronized(const u4* args, JValue* pResult,
-    const Method* method, Thread* self)
-{
-    Object* lockObj;
-
-    assert(dvmIsSynchronizedMethod(method));
-
-    if (dvmIsStaticMethod(method))
-        lockObj = (Object*) method->clazz;
-    else
-        lockObj = (Object*) args[0];
-
-    LOGVV("Calling %s.%s: locking %p (%s)\n",
-        method->clazz->descriptor, method->name,
-        lockObj, lockObj->clazz->descriptor);
-
-    dvmLockObject(self, lockObj);
-    dvmCallJNIMethod_general(args, pResult, method, self);
-    dvmUnlockObject(self, lockObj);
-}
-
-/*
- * Virtual method call, no reference arguments.
- *
- * We need to local-ref the "this" argument, found in args[0].
- */
-void dvmCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult,
-    const Method* method, Thread* self)
-{
-    u4* modArgs = (u4*) args;
-    int oldStatus;
-
-    jobject thisObj = addLocalReference(self->jniEnv, (Object*) args[0]);
-    if (thisObj == NULL) {
-        assert(dvmCheckException(self));
-        return;
-    }
-    modArgs[0] = (u4) thisObj;
-
-    oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
-
-    COMPUTE_STACK_SUM(self);
-    dvmPlatformInvoke(self->jniEnv, NULL,
-        method->jniArgInfo, method->insSize, modArgs, method->shorty,
-        (void*)method->insns, pResult);
-    CHECK_STACK_SUM(self);
-
-    dvmChangeStatus(self, oldStatus);
-}
-
-/*
- * Static method call, no reference arguments.
- *
- * We need to local-ref the class reference.
- */
-void dvmCallJNIMethod_staticNoRef(const u4* args, JValue* pResult,
-    const Method* method, Thread* self)
-{
-    jclass staticMethodClass;
-    int oldStatus;
-
-    staticMethodClass = addLocalReference(self->jniEnv, (Object*)method->clazz);
-    if (staticMethodClass == NULL) {
-        assert(dvmCheckException(self));
-        return;
-    }
-
-    oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
-
-    COMPUTE_STACK_SUM(self);
-    dvmPlatformInvoke(self->jniEnv, staticMethodClass,
-        method->jniArgInfo, method->insSize, args, method->shorty,
-        (void*)method->insns, pResult);
-    CHECK_STACK_SUM(self);
-
-    dvmChangeStatus(self, oldStatus);
-}
-
-/*
- * Extract the return type enum from the "jniArgInfo" field.
- */
-DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
-{
-    return (jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT;
-}
-
-
-/*
- * ===========================================================================
  *      Utility functions
  * ===========================================================================
  */
@@ -492,9 +297,16 @@ DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
  */
 bool dvmJniStartup(void)
 {
+#ifdef USE_INDIRECT_REF
+    if (!dvmInitIndirectRefTable(&gDvm.jniGlobalRefTable,
+            kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize,
+            kIndirectKindGlobal))
+        return false;
+#else
     if (!dvmInitReferenceTable(&gDvm.jniGlobalRefTable,
             kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize))
         return false;
+#endif
 
     dvmInitMutex(&gDvm.jniGlobalRefLock);
     gDvm.jniGlobalRefLoMark = 0;
@@ -530,10 +342,11 @@ bool dvmJniStartup(void)
         LOGE("Unable to find internal direct buffer classes\n");
         return false;
     }
-    /* needs to be a global ref so CheckJNI thinks we're allowed to see it */
-    gDvm.classOrgApacheHarmonyNioInternalDirectBuffer =
-        addGlobalReference((Object*) directBufferClass);
     gDvm.classJavaNioReadWriteDirectByteBuffer = readWriteBufferClass;
+    gDvm.classOrgApacheHarmonyNioInternalDirectBuffer = directBufferClass;
+    /* need a global reference for extended CheckJNI tests */
+    gDvm.jclassOrgApacheHarmonyNioInternalDirectBuffer =
+        addGlobalReference((Object*) directBufferClass);
 
     /*
      * We need a Method* here rather than a vtable offset, because
@@ -605,7 +418,11 @@ bool dvmJniStartup(void)
  */
 void dvmJniShutdown(void)
 {
+#ifdef USE_INDIRECT_REF
+    dvmClearIndirectRefTable(&gDvm.jniGlobalRefTable);
+#else
     dvmClearReferenceTable(&gDvm.jniGlobalRefTable);
+#endif
 }
 
 
@@ -714,11 +531,69 @@ void dvmDestroyJNIEnv(JNIEnv* env)
  * Going through "env" rather than dvmThreadSelf() is faster but will
  * get weird if the JNI code is passing the wrong JNIEnv around.
  */
+#ifdef USE_INDIRECT_REF
+static inline IndirectRefTable* getLocalRefTable(JNIEnv* env)
+{
+    return &((JNIEnvExt*)env)->self->jniLocalRefTable;
+}
+#else
 static inline ReferenceTable* getLocalRefTable(JNIEnv* env)
 {
     //return &dvmThreadSelf()->jniLocalRefTable;
     return &((JNIEnvExt*)env)->self->jniLocalRefTable;
 }
+#endif
+
+/*
+ * Convert an indirect reference to an Object reference.  The indirect
+ * reference may be local, global, or weak-global.
+ *
+ * If "jobj" is NULL or an invalid indirect reference, this returns NULL.
+ */
+Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj)
+{
+#ifdef USE_INDIRECT_REF
+    if (jobj == NULL)
+        return NULL;
+
+    Object* result;
+
+    switch (dvmGetIndirectRefType(jobj)) {
+    case kIndirectKindLocal:
+        {
+            IndirectRefTable* pRefTable = getLocalRefTable(env);
+            result = dvmGetFromIndirectRefTable(pRefTable, jobj);
+        }
+        break;
+    case kIndirectKindGlobal:
+        {
+            // TODO: find a way to avoid the mutex activity here
+            IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
+            dvmLockMutex(&gDvm.jniGlobalRefLock);
+            result = dvmGetFromIndirectRefTable(pRefTable, jobj);
+            dvmUnlockMutex(&gDvm.jniGlobalRefLock);
+        }
+        break;
+    case kIndirectKindWeakGlobal:
+        {
+            LOGE("weak-global not yet supported\n");
+            result = NULL;
+            dvmAbort();
+        }
+        break;
+    case kIndirectKindInvalid:
+    default:
+        LOGW("Invalid indirect reference %p in decodeIndirectRef\n", jobj);
+        dvmAbort();
+        result = NULL;
+        break;
+    }
+
+    return result;
+#else
+    return (Object*) jobj;
+#endif
+}
 
 /*
  * Add a local reference for an object to the current stack frame.  When
@@ -737,6 +612,27 @@ static jobject addLocalReference(JNIEnv* env, Object* obj)
     if (obj == NULL)
         return NULL;
 
+    jobject jobj;
+
+#ifdef USE_INDIRECT_REF
+    IndirectRefTable* pRefTable = getLocalRefTable(env);
+    void* curFrame = ((JNIEnvExt*)env)->self->curFrame;
+    u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
+
+    jobj = (jobject) dvmAddToIndirectRefTable(pRefTable, cookie, obj);
+    if (jobj == NULL) {
+        dvmDumpIndirectRefTable(pRefTable, "JNI local");
+        LOGE("Failed adding to JNI local ref table (has %d entries)\n",
+            (int) dvmIndirectRefTableEntries(pRefTable));
+        dvmDumpThread(dvmThreadSelf(), false);
+        dvmAbort();     // spec says call FatalError; this is equivalent
+    } else {
+        LOGVV("LREF add %p  (%s.%s) (ent=%d)\n", obj,
+            dvmGetCurrentJNIMethod()->clazz->descriptor,
+            dvmGetCurrentJNIMethod()->name,
+            (int) dvmReferenceTableEntries(pRefTable));
+    }
+#else
     ReferenceTable* pRefTable = getLocalRefTable(env);
 
     if (!dvmAddToReferenceTable(pRefTable, obj)) {
@@ -752,20 +648,10 @@ static jobject addLocalReference(JNIEnv* env, Object* obj)
             (int) dvmReferenceTableEntries(pRefTable));
     }
 
-    return obj;
-}
+    jobj = (jobject) obj;
+#endif
 
-/*
- * Convert an indirect reference to an Object reference.  The indirect
- * reference may be local, global, or weak-global.
- *
- * If "jobj" is NULL or an invalid indirect reference, this returns NULL.
- *
- * [ this is currently a no-op ]
- */
-Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj)
-{
-    return (Object*) jobj;
+    return jobj;
 }
 
 /*
@@ -774,9 +660,16 @@ Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj)
  */
 static bool ensureLocalCapacity(JNIEnv* env, int capacity)
 {
+#ifdef USE_INDIRECT_REF
+    IndirectRefTable* pRefTable = getLocalRefTable(env);
+    int numEntries = dvmIndirectRefTableEntries(pRefTable);
+    // TODO: this isn't quite right, since "numEntries" includes holes
+    return ((kJniLocalRefMax - numEntries) >= capacity);
+#else
     ReferenceTable* pRefTable = getLocalRefTable(env);
 
     return (kJniLocalRefMax - (pRefTable->nextEntry - pRefTable->table) >= capacity);
+#endif
 }
 
 /*
@@ -787,11 +680,27 @@ static void deleteLocalReference(JNIEnv* env, jobject jobj)
     if (jobj == NULL)
         return;
 
+#ifdef USE_INDIRECT_REF
+    IndirectRefTable* pRefTable = getLocalRefTable(env);
+    Thread* self = ((JNIEnvExt*)env)->self;
+    u4 cookie = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefCookie;
+
+    if (!dvmRemoveFromIndirectRefTable(pRefTable, cookie, jobj)) {
+        /*
+         * Attempting to delete a local reference that is not in the
+         * topmost local reference frame is a no-op.  DeleteLocalRef returns
+         * void and doesn't throw any exceptions, but we should probably
+         * complain about it so the user will notice that things aren't
+         * going quite the way they expect.
+         */
+        LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry\n", jobj);
+    }
+#else
     ReferenceTable* pRefTable = getLocalRefTable(env);
-    Thread* self = dvmThreadSelf();
-    Object** top = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefTop;
+    Thread* self = ((JNIEnvExt*)env)->self;
+    Object** bottom = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefCookie;
 
-    if (!dvmRemoveFromReferenceTable(pRefTable, top, (Object*) jobj)) {
+    if (!dvmRemoveFromReferenceTable(pRefTable, bottom, (Object*) jobj)) {
         /*
          * Attempting to delete a local reference that is not in the
          * topmost local reference frame is a no-op.  DeleteLocalRef returns
@@ -802,6 +711,7 @@ static void deleteLocalReference(JNIEnv* env, jobject jobj)
         LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry (valid=%d)\n",
             jobj, dvmIsValidObject((Object*) jobj));
     }
+#endif
 }
 
 /*
@@ -837,37 +747,73 @@ static jobject addGlobalReference(Object* obj)
     }
     if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
         ArrayObject* arrayObj = (ArrayObject*) obj;
-        if (arrayObj->length == 8192 &&
-            dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400)
+        if (arrayObj->length == 8192 /*&&
+            dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
         {
             LOGI("Adding global ref on byte array %p (len=%d)\n",
                 arrayObj, arrayObj->length);
             dvmDumpThread(dvmThreadSelf(), false);
         }
     }
-
-    dvmLockMutex(&gDvm.jniGlobalRefLock);
-
-    /*
-     * Expanding the table should happen rarely, so I'm not overly
-     * concerned about the performance impact of copying the old list
-     * over.  We shouldn't see one-time activity spikes, so freeing
-     * up storage shouldn't be required.
-     *
-     * Throwing an exception on failure is problematic, because JNI code
-     * may not be expecting an exception, and things sort of cascade.  We
-     * want to have a hard limit to catch leaks during debugging, but this
-     * otherwise needs to expand until memory is consumed.  As a practical
-     * matter, if we have many thousands of global references, chances are
-     * we're either leaking global ref table entries or we're going to
-     * run out of space in the GC heap.
-     */
-    if (!dvmAddToReferenceTable(&gDvm.jniGlobalRefTable, (Object*)obj)) {
+
+    jobject jobj;
+
+    dvmLockMutex(&gDvm.jniGlobalRefLock);
+
+    /*
+     * Throwing an exception on failure is problematic, because JNI code
+     * may not be expecting an exception, and things sort of cascade.  We
+     * want to have a hard limit to catch leaks during debugging, but this
+     * otherwise needs to expand until memory is consumed.  As a practical
+     * matter, if we have many thousands of global references, chances are
+     * we're either leaking global ref table entries or we're going to
+     * run out of space in the GC heap.
+     */
+#ifdef USE_INDIRECT_REF
+    jobj = dvmAddToIndirectRefTable(&gDvm.jniGlobalRefTable, IRT_FIRST_SEGMENT,
+            obj);
+    if (jobj == NULL) {
+        dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
+        LOGE("Failed adding to JNI global ref table (%d entries)\n",
+            (int) dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable));
+        dvmAbort();
+    }
+
+    LOGVV("GREF add %p  (%s.%s)\n", obj,
+        dvmGetCurrentJNIMethod()->clazz->descriptor,
+        dvmGetCurrentJNIMethod()->name);
+
+    /* GREF usage tracking; should probably be disabled for production env */
+    if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
+        int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
+        // TODO: adjust for "holes"
+        if (count > gDvm.jniGlobalRefHiMark) {
+            LOGD("GREF has increased to %d\n", count);
+            gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
+            gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
+
+            /* watch for "excessive" use; not generally appropriate */
+            if (count >= gDvm.jniGrefLimit) {
+                JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
+                if (vm->warnError) {
+                    dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable,
+                        "JNI global");
+                    LOGE("Excessive JNI global references (%d)\n", count);
+                    dvmAbort();
+                } else {
+                    LOGW("Excessive JNI global references (%d)\n", count);
+                }
+            }
+        }
+    }
+#else
+    if (!dvmAddToReferenceTable(&gDvm.jniGlobalRefTable, obj)) {
         dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
         LOGE("Failed adding to JNI global ref table (%d entries)\n",
             (int) dvmReferenceTableEntries(&gDvm.jniGlobalRefTable));
         dvmAbort();
     }
+    jobj = (jobject) obj;
 
     LOGVV("GREF add %p  (%s.%s)\n", obj,
         dvmGetCurrentJNIMethod()->clazz->descriptor,
@@ -894,10 +840,11 @@ static jobject addGlobalReference(Object* obj)
             }
         }
     }
+#endif
 
 bail:
     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
-    return (jobject) obj;
+    return jobj;
 }
 
 /*
@@ -914,6 +861,24 @@ static void deleteGlobalReference(jobject jobj)
 
     dvmLockMutex(&gDvm.jniGlobalRefLock);
 
+#ifdef USE_INDIRECT_REF
+    if (!dvmRemoveFromIndirectRefTable(&gDvm.jniGlobalRefTable,
+            IRT_FIRST_SEGMENT, jobj))
+    {
+        LOGW("JNI: DeleteGlobalRef(%p) failed to find entry\n", jobj);
+        goto bail;
+    }
+
+    if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
+        int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
+        // TODO: not quite right, need to subtract holes
+        if (count < gDvm.jniGlobalRefLoMark) {
+            LOGD("GREF has decreased to %d\n", count);
+            gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
+            gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
+        }
+    }
+#else
     if (!dvmRemoveFromReferenceTable(&gDvm.jniGlobalRefTable,
             gDvm.jniGlobalRefTable.table, jobj))
     {
@@ -930,6 +895,7 @@ static void deleteGlobalReference(jobject jobj)
             gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
         }
     }
+#endif
 
 bail:
     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
@@ -1010,14 +976,28 @@ bail:
  */
 void dvmGcMarkJniGlobalRefs()
 {
-    Object **op;
+    Object** op;
 
     dvmLockMutex(&gDvm.jniGlobalRefLock);
 
+#ifdef USE_INDIRECT_REF
+    IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
+    op = pRefTable->table;
+    int numEntries = dvmIndirectRefTableEntries(pRefTable);
+    int i;
+
+    for (i = 0; i < numEntries; i++) {
+        Object* obj = *op;
+        if (obj != NULL)
+            dvmMarkObjectNonNull(obj);
+        op++;
+    }
+#else
     op = gDvm.jniGlobalRefTable.table;
     while ((uintptr_t)op < (uintptr_t)gDvm.jniGlobalRefTable.nextEntry) {
         dvmMarkObjectNonNull(*(op++));
     }
+#endif
 
     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
 
@@ -1124,6 +1104,13 @@ static bool findInArgList(Thread* self, Object* obj)
  */
 jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj)
 {
+#ifdef USE_INDIRECT_REF
+    /*
+     * IndirectRefKind is currently defined as an exact match of
+     * jobjectRefType, so this is easy.
+     */
+    return (jobjectRefType) dvmIndirectRefToIndex(jobj);
+#else
     ReferenceTable* pRefTable = getLocalRefTable(env);
     Thread* self = dvmThreadSelf();
     //Object** top;
@@ -1138,7 +1125,6 @@ jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj)
 #endif
 
     /* check locals */
-    //top = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefTop;
     if (dvmFindInReferenceTable(pRefTable, pRefTable->table, jobj) != NULL) {
         //LOGI("--- REF found %p in locals\n", jobj);
         return JNILocalRefType;
@@ -1157,6 +1143,7 @@ jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj)
 
     /* not found! */
     return JNIInvalidRefType;
+#endif
 }
 
 /*
@@ -1421,6 +1408,217 @@ static void checkStackSum(Thread* self)
 
 /*
  * ===========================================================================
+ *      JNI call bridge
+ * ===========================================================================
+ */
+
+/*
+ * The functions here form a bridge between interpreted code and JNI native
+ * functions.  The basic task is to convert an array of primitives and
+ * references into C-style function arguments.  This is architecture-specific
+ * and usually requires help from assembly code.
+ *
+ * The bridge takes four arguments: the array of parameters, a place to
+ * store the function result (if any), the method to call, and a pointer
+ * to the current thread.
+ *
+ * These functions aren't called directly from elsewhere in the VM.
+ * A pointer in the Method struct points to one of these, and when a native
+ * method is invoked the interpreter jumps to it.
+ *
+ * (The "internal native" methods are invoked the same way, but instead
+ * of calling through a bridge, the target method is called directly.)
+ *
+ * The "args" array should not be modified, but we do so anyway for
+ * performance reasons.  We know that it points to the "outs" area on
+ * the current method's interpreted stack.  This area is ignored by the
+ * precise GC, because there is no register map for a native method (for
+ * an interpreted method the args would be listed in the argument set).
+ * We know all of the values exist elsewhere on the interpreted stack,
+ * because the method call setup copies them right before making the call,
+ * so we don't have to worry about concealing stuff from the GC.
+ *
+ * If we don't want to modify "args", we either have to create a local
+ * copy and modify it before calling dvmPlatformInvoke, or we have to do
+ * the local reference replacement within dvmPlatformInvoke.  The latter
+ * has some performance advantages, though if we can inline the local
+ * reference adds we may win when there's a lot of reference args (unless
+ * we want to code up some local ref table manipulation in assembly.
+ */
+
+/*
+ * General form, handles all cases.
+ */
+void dvmCallJNIMethod_general(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    int oldStatus;
+    u4* modArgs = (u4*) args;
+
+    assert(method->insns != NULL);
+
+    //LOGI("JNI calling %p (%s.%s:%s):\n", method->insns,
+    //    method->clazz->descriptor, method->name, method->shorty);
+
+    /*
+     * Walk the argument list, creating local references for appropriate
+     * arguments.
+     */
+    JNIEnv* env = self->jniEnv;
+    jclass staticMethodClass;
+    int idx = 0;
+    if (dvmIsStaticMethod(method)) {
+        /* add the class object we pass in */
+        staticMethodClass = addLocalReference(env, (Object*) method->clazz);
+        if (staticMethodClass == NULL) {
+            assert(dvmCheckException(self));
+            return;
+        }
+    } else {
+        /* add "this" */
+        staticMethodClass = NULL;
+        jobject thisObj = addLocalReference(env, (Object*) modArgs[0]);
+        if (thisObj == NULL) {
+            assert(dvmCheckException(self));
+            return;
+        }
+        modArgs[idx] = (u4) thisObj;
+        idx = 1;
+    }
+
+    const char* shorty = &method->shorty[1];        /* skip return type */
+    while (*shorty != '\0') {
+        switch (*shorty++) {
+        case 'L':
+            //LOGI("  local %d: 0x%08x\n", idx, modArgs[idx]);
+            if (modArgs[idx] != 0) {
+                //if (!dvmIsValidObject((Object*) modArgs[idx]))
+                //    dvmAbort();
+                jobject argObj = addLocalReference(env, (Object*) modArgs[idx]);
+                if (argObj == NULL) {
+                    assert(dvmCheckException(self));
+                    return;
+                }
+                modArgs[idx] = (u4) argObj;
+            }
+            break;
+        case 'D':
+        case 'J':
+            idx++;
+            break;
+        default:
+            /* Z B C S I -- do nothing */
+            break;
+        }
+
+        idx++;
+    }
+
+    oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
+
+    COMPUTE_STACK_SUM(self);
+    dvmPlatformInvoke(self->jniEnv, staticMethodClass,
+        method->jniArgInfo, method->insSize, modArgs, method->shorty,
+        (void*)method->insns, pResult);
+    CHECK_STACK_SUM(self);
+
+    dvmChangeStatus(self, oldStatus);
+}
+
+/*
+ * Handler for the unusual case of a synchronized native method.
+ *
+ * Lock the object, then call through the general function.
+ */
+void dvmCallJNIMethod_synchronized(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    Object* lockObj;
+
+    assert(dvmIsSynchronizedMethod(method));
+
+    if (dvmIsStaticMethod(method))
+        lockObj = (Object*) method->clazz;
+    else
+        lockObj = (Object*) args[0];
+
+    LOGVV("Calling %s.%s: locking %p (%s)\n",
+        method->clazz->descriptor, method->name,
+        lockObj, lockObj->clazz->descriptor);
+
+    dvmLockObject(self, lockObj);
+    dvmCallJNIMethod_general(args, pResult, method, self);
+    dvmUnlockObject(self, lockObj);
+}
+
+/*
+ * Virtual method call, no reference arguments.
+ *
+ * We need to local-ref the "this" argument, found in args[0].
+ */
+void dvmCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    u4* modArgs = (u4*) args;
+    int oldStatus;
+
+    jobject thisObj = addLocalReference(self->jniEnv, (Object*) args[0]);
+    if (thisObj == NULL) {
+        assert(dvmCheckException(self));
+        return;
+    }
+    modArgs[0] = (u4) thisObj;
+
+    oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
+
+    COMPUTE_STACK_SUM(self);
+    dvmPlatformInvoke(self->jniEnv, NULL,
+        method->jniArgInfo, method->insSize, modArgs, method->shorty,
+        (void*)method->insns, pResult);
+    CHECK_STACK_SUM(self);
+
+    dvmChangeStatus(self, oldStatus);
+}
+
+/*
+ * Static method call, no reference arguments.
+ *
+ * We need to local-ref the class reference.
+ */
+void dvmCallJNIMethod_staticNoRef(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    jclass staticMethodClass;
+    int oldStatus;
+
+    staticMethodClass = addLocalReference(self->jniEnv, (Object*)method->clazz);
+    if (staticMethodClass == NULL) {
+        assert(dvmCheckException(self));
+        return;
+    }
+
+    oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
+
+    COMPUTE_STACK_SUM(self);
+    dvmPlatformInvoke(self->jniEnv, staticMethodClass,
+        method->jniArgInfo, method->insSize, args, method->shorty,
+        (void*)method->insns, pResult);
+    CHECK_STACK_SUM(self);
+
+    dvmChangeStatus(self, oldStatus);
+}
+
+/*
+ * Extract the return type enum from the "jniArgInfo" field.
+ */
+DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
+{
+    return (jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT;
+}
+
+
+/*
+ * ===========================================================================
  *      JNI implementation
  * ===========================================================================
  */
@@ -1885,7 +2083,8 @@ static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...)
             JValue unused;
             va_list args;
             va_start(args, methodID);
-            dvmCallMethodV(_self, (Method*) methodID, newObj, &unused, args);
+            dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused,
+                args);
             va_end(args);
         }
     }
@@ -1904,7 +2103,7 @@ static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID,
     result = addLocalReference(env, newObj);
     if (newObj != NULL) {
         JValue unused;
-        dvmCallMethodV(_self, (Method*) methodID, newObj, &unused, args);
+        dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused, args);
     }
 
     JNI_EXIT();
@@ -1921,7 +2120,7 @@ static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID,
     result = addLocalReference(env, newObj);
     if (newObj != NULL) {
         JValue unused;
-        dvmCallMethodA(_self, (Method*) methodID, newObj, &unused, args);
+        dvmCallMethodA(_self, (Method*) methodID, newObj, true, &unused, args);
     }
 
     JNI_EXIT();
@@ -2256,9 +2455,9 @@ SET_TYPE_FIELD(jdouble, Double, false);
             return _retfail;                                                \
         }                                                                   \
         va_start(args, methodID);                                           \
-        dvmCallMethodV(_self, meth, obj, &result, args);                    \
+        dvmCallMethodV(_self, meth, obj, true, &result, args);              \
         va_end(args);                                                       \
-        if (_isref)                                                         \
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         JNI_EXIT();                                                         \
         return _retok;                                                      \
@@ -2275,8 +2474,8 @@ SET_TYPE_FIELD(jdouble, Double, false);
             JNI_EXIT();                                                     \
             return _retfail;                                                \
         }                                                                   \
-        dvmCallMethodV(_self, meth, obj, &result, args);                    \
-        if (_isref)                                                         \
+        dvmCallMethodV(_self, meth, obj, true, &result, args);              \
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         JNI_EXIT();                                                         \
         return _retok;                                                      \
@@ -2293,8 +2492,8 @@ SET_TYPE_FIELD(jdouble, Double, false);
             JNI_EXIT();                                                     \
             return _retfail;                                                \
         }                                                                   \
-        dvmCallMethodA(_self, meth, obj, &result, args);                    \
-        if (_isref)                                                         \
+        dvmCallMethodA(_self, meth, obj, true, &result, args);              \
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         JNI_EXIT();                                                         \
         return _retok;                                                      \
@@ -2334,8 +2533,8 @@ CALL_VIRTUAL(void, Void, , , false);
             return _retfail;                                                \
         }                                                                   \
         va_start(args, methodID);                                           \
-        dvmCallMethodV(_self, meth, obj, &result, args);                    \
-        if (_isref)                                                         \
+        dvmCallMethodV(_self, meth, obj, true, &result, args);              \
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         va_end(args);                                                       \
         JNI_EXIT();                                                         \
@@ -2355,8 +2554,8 @@ CALL_VIRTUAL(void, Void, , , false);
             JNI_EXIT();                                                     \
             return _retfail;                                                \
         }                                                                   \
-        dvmCallMethodV(_self, meth, obj, &result, args);                    \
-        if (_isref)                                                         \
+        dvmCallMethodV(_self, meth, obj, true, &result, args);              \
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         JNI_EXIT();                                                         \
         return _retok;                                                      \
@@ -2375,8 +2574,8 @@ CALL_VIRTUAL(void, Void, , , false);
             JNI_EXIT();                                                     \
             return _retfail;                                                \
         }                                                                   \
-        dvmCallMethodA(_self, meth, obj, &result, args);                    \
-        if (_isref)                                                         \
+        dvmCallMethodA(_self, meth, obj, true, &result, args);              \
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         JNI_EXIT();                                                         \
         return _retok;                                                      \
@@ -2405,9 +2604,9 @@ CALL_NONVIRTUAL(void, Void, , , false);
         JValue result;                                                      \
         va_list args;                                                       \
         va_start(args, methodID);                                           \
-        dvmCallMethodV(_self, (Method*) methodID, NULL, &result, args);     \
+        dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
         va_end(args);                                                       \
-        if (_isref)                                                         \
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         JNI_EXIT();                                                         \
         return _retok;                                                      \
@@ -2418,8 +2617,8 @@ CALL_NONVIRTUAL(void, Void, , , false);
         UNUSED_PARAMETER(jclazz);                                           \
         JNI_ENTER();                                                        \
         JValue result;                                                      \
-        dvmCallMethodV(_self, (Method*) methodID, NULL, &result, args);     \
-        if (_isref)                                                         \
+        dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         JNI_EXIT();                                                         \
         return _retok;                                                      \
@@ -2430,8 +2629,8 @@ CALL_NONVIRTUAL(void, Void, , , false);
         UNUSED_PARAMETER(jclazz);                                           \
         JNI_ENTER();                                                        \
         JValue result;                                                      \
-        dvmCallMethodA(_self, (Method*) methodID, NULL, &result, args);     \
-        if (_isref)                                                         \
+        dvmCallMethodA(_self, (Method*)methodID, NULL, true, &result, args);\
+        if (_isref && !dvmCheckException(_self))                            \
             result.l = addLocalReference(env, result.l);                    \
         JNI_EXIT();                                                         \
         return _retok;                                                      \
@@ -2496,7 +2695,7 @@ static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy)
     JNI_ENTER();
 
     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
-    ArrayObject* strChars = dvmStringCharArray(jstr);
+    ArrayObject* strChars = dvmStringCharArray(strObj);
 
     pinPrimitiveArray(strChars);
 
@@ -2515,7 +2714,7 @@ static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars)
 {
     JNI_ENTER();
     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
-    ArrayObject* strChars = dvmStringCharArray(jstr);
+    ArrayObject* strChars = dvmStringCharArray(strObj);
     unpinPrimitiveArray(strChars);
     JNI_EXIT();
 }
@@ -3220,7 +3419,7 @@ static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf)
     JValue callResult;
     const Method* meth = dvmGetVirtualizedMethod(bufObj->clazz,
         gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress);
-    dvmCallMethodA(self, meth, bufObj, &callResult, NULL);
+    dvmCallMethodA(self, meth, bufObj, false, &callResult, NULL);
     if (dvmGetException(self) != NULL) {
         dvmClearException(self);
         callResult.l = NULL;
index f39583e..4620c50 100644 (file)
@@ -98,15 +98,17 @@ typedef enum DalvikJniReturnType {
 /*
  * Pop the JNI local stack when we return from a native method.  "saveArea"
  * points to the StackSaveArea for the method we're leaving.
+ *
+ * (This may be implemented directly in assembly in mterp, so changes here
+ * may only affect the portable interpreter.)
  */
 INLINE void dvmPopJniLocals(Thread* self, StackSaveArea* saveArea)
 {
-    if (saveArea->xtra.localRefTop != self->jniLocalRefTable.nextEntry) {
-        LOGVV("LREF: popped %d entries (%d remain)\n",
-            (int)(self->jniLocalRefTable.nextEntry-saveArea->xtra.localRefTop),
-            (int)(saveArea->xtra.localRefTop - self->jniLocalRefTable.table));
-    }
-    self->jniLocalRefTable.nextEntry = saveArea->xtra.localRefTop;
+#ifdef USE_INDIRECT_REF
+    self->jniLocalRefTable.segmentState.all = saveArea->xtra.localRefCookie;
+#else
+    self->jniLocalRefTable.nextEntry = saveArea->xtra.localRefCookie;
+#endif
 }
 
 /*
index 089f2f2..a8010a2 100644 (file)
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 /*
  * Reference table management.
  */
@@ -96,13 +97,13 @@ bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj)
 /*
  * Returns NULL if not found.
  */
-Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** top,
+Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** bottom,
     Object* obj)
 {
     Object** ptr;
 
     ptr = pRef->nextEntry;
-    while (--ptr >= top) {
+    while (--ptr >= bottom) {
         if (*ptr == obj)
             return ptr;
     }
@@ -112,12 +113,12 @@ Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** top,
 /*
  * Remove "obj" from "pRef".  We start at the end of the list (where the
  * most-recently-added element is), and stop searching for a match after
- * examining the element at "top".
+ * examining the element at "bottom".
  *
  * Most of the time "obj" is at or near the end of the list.  If not, we
  * compact it down.
  */
-bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** top,
+bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** bottom,
     Object* obj)
 {
     Object** ptr;
@@ -125,10 +126,10 @@ bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** top,
     assert(pRef->table != NULL);
 
     /*
-     * Scan from the most-recently-added entry up to the top entry for
+     * Scan from the most-recently-added entry up to the bottom entry for
      * this frame.
      */
-    ptr = dvmFindInReferenceTable(pRef, top, obj);
+    ptr = dvmFindInReferenceTable(pRef, bottom, obj);
     if (ptr == NULL)
         return false;
 
index f8f2461..d6e2d70 100644 (file)
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 /*
  * Maintain a table of references.  Used for internal local references,
  * JNI locals, JNI globals, and GC heap references.
@@ -36,8 +37,8 @@
  * table/nextEntry is allowed.)
  */
 typedef struct ReferenceTable {
-    Object**        table;              /* top of the list */
-    Object**        nextEntry;          /* bottom of the list */
+    Object**        nextEntry;          /* top of the list */
+    Object**        table;              /* bottom of the list */
 
     int             allocEntries;       /* #of entries we have space for */
     int             maxEntries;         /* max #of entries allowed */
@@ -88,23 +89,24 @@ INLINE size_t dvmIsReferenceTableFull(const ReferenceTable* pRef)
 bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj);
 
 /*
- * Determine if "obj" is present in "pRef".  Stops searching when we hit "top".
- * To include the entire table, pass in "pRef->table" as the top.
+ * Determine if "obj" is present in "pRef".  Stops searching when we hit
+ * "bottom".  To include the entire table, pass in "pRef->table" as the
+ * bottom.
  *
  * Returns NULL if "obj" was not found.
  */
-Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** top,
+Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** bottom,
     Object* obj);
 
 /*
  * Remove an existing entry.
  *
- * We stop searching for a match after examining the element at "top".  This
- * is useful when entries are associated with a stack frame.
+ * We stop searching for a match after examining the element at "bottom".
+ * This is useful when entries are associated with a stack frame.
  *
  * Returns "false" if the entry was not found.
  */
-bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** top,
+bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** bottom,
     Object* obj);
 
 /*
index 309ad5d..e187aeb 100644 (file)
@@ -246,7 +246,7 @@ loop:
 
             if (false) {
                 dvmLockMutex(&gDvm.jniGlobalRefLock);
-                dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
+                //dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
                 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
             }
 
index 3f63132..6a1e9aa 100644 (file)
@@ -980,15 +980,22 @@ static bool prepareThread(Thread* thread)
     /*
      * Initialize our reference tracking tables.
      *
-     * The JNI local ref table *must* be fixed-size because we keep pointers
-     * into the table in our stack frames.
-     *
      * Most threads won't use jniMonitorRefTable, so we clear out the
      * structure but don't call the init function (which allocs storage).
      */
+#ifdef USE_INDIRECT_REF
+    if (!dvmInitIndirectRefTable(&thread->jniLocalRefTable,
+            kJniLocalRefMin, kJniLocalRefMax, kIndirectKindLocal))
+        return false;
+#else
+    /*
+     * The JNI local ref table *must* be fixed-size because we keep pointers
+     * into the table in our stack frames.
+     */
     if (!dvmInitReferenceTable(&thread->jniLocalRefTable,
             kJniLocalRefMax, kJniLocalRefMax))
         return false;
+#endif
     if (!dvmInitReferenceTable(&thread->internalLocalRefTable,
             kInternalRefDefault, kInternalRefMax))
         return false;
@@ -1042,7 +1049,11 @@ static void freeThread(Thread* thread)
 #endif
     }
 
+#ifdef USE_INDIRECT_REF
+    dvmClearIndirectRefTable(&thread->jniLocalRefTable);
+#else
     dvmClearReferenceTable(&thread->jniLocalRefTable);
+#endif
     dvmClearReferenceTable(&thread->internalLocalRefTable);
     if (&thread->jniMonitorRefTable.table != NULL)
         dvmClearReferenceTable(&thread->jniMonitorRefTable);
@@ -3742,6 +3753,20 @@ static void gcScanReferenceTable(ReferenceTable *refTable)
     }
 }
 
+static void gcScanIndirectRefTable(IndirectRefTable* pRefTable)
+{
+    Object** op = pRefTable->table;
+    int numEntries = dvmIndirectRefTableEntries(pRefTable);
+    int i;
+
+    for (i = 0; i < numEntries; i++) {
+        Object* obj = *op;
+        if (obj != NULL)
+            dvmMarkObjectNonNull(obj);
+        op++;
+    }
+}
+
 /*
  * Scan a Thread and mark any objects it references.
  */
@@ -3772,7 +3797,11 @@ static void gcScanThread(Thread *thread)
 
     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_LOCAL, thread->threadId);
 
+#ifdef USE_INDIRECT_REF
+    gcScanIndirectRefTable(&thread->jniLocalRefTable);
+#else
     gcScanReferenceTable(&thread->jniLocalRefTable);
+#endif
 
     if (thread->jniMonitorRefTable.table != NULL) {
         HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_MONITOR, thread->threadId);
index 1725b1e..50bf5a0 100644 (file)
@@ -68,6 +68,7 @@ void dvmThreadShutdown(void);
 void dvmSlayDaemons(void);
 
 
+#define kJniLocalRefMin         32
 #define kJniLocalRefMax         512     /* arbitrary; should be plenty */
 #define kInternalRefDefault     32      /* equally arbitrary */
 #define kInternalRefMax         4096    /* mainly a sanity check */
@@ -152,7 +153,11 @@ typedef struct Thread {
     ReferenceTable  internalLocalRefTable;
 
     /* JNI local reference tracking */
+#ifdef USE_INDIRECT_REF
+    IndirectRefTable jniLocalRefTable;
+#else
     ReferenceTable  jniLocalRefTable;
+#endif
 
     /* JNI native monitor reference tracking (initialized on first use) */
     ReferenceTable  jniMonitorRefTable;
index 5e59991..b20d564 100644 (file)
     bxne    lr                          @ bail to the interpreter
 
     @ go ahead and transfer control to the native code
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
-                                        @ newFp->localRefTop=refNext
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
 
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
index 29073c3..3b0b149 100644 (file)
     @ Prep for the native call
     @ r1 = newFP, r0 = methodToCall
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
-                                        @ newFp->localRefTop=refNext
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
 
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
index 2c669f8..0c433a1 100644 (file)
@@ -394,10 +394,10 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
     bxne    lr                          @ bail to the interpreter
 
     @ go ahead and transfer control to the native code
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
-                                        @ newFp->localRefTop=refNext
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
 
@@ -410,11 +410,11 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
@@ -1012,10 +1012,10 @@ dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP:
     @ Prep for the native call
     @ r1 = newFP, r0 = methodToCall
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
-                                        @ newFp->localRefTop=refNext
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
 
@@ -1028,11 +1028,11 @@ dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP:
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
index b973691..29dde74 100644 (file)
@@ -394,10 +394,10 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
     bxne    lr                          @ bail to the interpreter
 
     @ go ahead and transfer control to the native code
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
-                                        @ newFp->localRefTop=refNext
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
 
@@ -410,11 +410,11 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
@@ -746,10 +746,10 @@ dvmCompiler_TEMPLATE_USHR_LONG:
     @ Prep for the native call
     @ r1 = newFP, r0 = methodToCall
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
-                                        @ newFp->localRefTop=refNext
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
 
@@ -762,11 +762,11 @@ dvmCompiler_TEMPLATE_USHR_LONG:
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
index 1faf7f6..9e97b74 100644 (file)
@@ -394,10 +394,10 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
     bxne    lr                          @ bail to the interpreter
 
     @ go ahead and transfer control to the native code
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
-                                        @ newFp->localRefTop=refNext
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
 
@@ -410,11 +410,11 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
@@ -1012,10 +1012,10 @@ dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP:
     @ Prep for the native call
     @ r1 = newFP, r0 = methodToCall
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
-                                        @ newFp->localRefTop=refNext
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
 
@@ -1028,11 +1028,11 @@ dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP:
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
index 838147f..5920cbc 100644 (file)
@@ -105,7 +105,7 @@ static bool dvmPushInterpFrame(Thread* self, const Method* method)
 
     breakSaveBlock->prevFrame = self->curFrame;
     breakSaveBlock->savedPc = NULL;             // not required
-    breakSaveBlock->xtra.localRefTop = NULL;    // not required
+    breakSaveBlock->xtra.localRefCookie = 0;    // not required
     breakSaveBlock->method = NULL;
     saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
     saveBlock->savedPc = NULL;                  // not required
@@ -182,11 +182,15 @@ bool dvmPushJNIFrame(Thread* self, const Method* method)
 
     breakSaveBlock->prevFrame = self->curFrame;
     breakSaveBlock->savedPc = NULL;             // not required
-    breakSaveBlock->xtra.localRefTop = NULL;    // not required
+    breakSaveBlock->xtra.localRefCookie = 0;    // not required
     breakSaveBlock->method = NULL;
     saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
     saveBlock->savedPc = NULL;                  // not required
-    saveBlock->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
+#ifdef USE_INDIRECT_REF
+    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+#else
+    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
+#endif
     saveBlock->method = method;
 
     LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)\n",
@@ -245,7 +249,11 @@ bool dvmPushLocalFrame(Thread* self, const Method* method)
 
     saveBlock->prevFrame = self->curFrame;
     saveBlock->savedPc = NULL;                  // not required
-    saveBlock->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
+#ifdef USE_INDIRECT_REF
+    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+#else
+    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
+#endif
     saveBlock->method = method;
 
     LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)\n",
@@ -320,9 +328,9 @@ static bool dvmPopFrame(Thread* self)
                 saveBlock->method->name,
                 (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
                 "" : " (JNI local)");
-            assert(saveBlock->xtra.localRefTop != NULL);
-            assert(saveBlock->xtra.localRefTop >=self->jniLocalRefTable.table &&
-                saveBlock->xtra.localRefTop <=self->jniLocalRefTable.nextEntry);
+            assert(saveBlock->xtra.localRefCookie != 0);
+            //assert(saveBlock->xtra.localRefCookie >= self->jniLocalRefTable.table &&
+            //    saveBlock->xtra.localRefCookie <=self->jniLocalRefTable.nextEntry);
 
             dvmPopJniLocals(self, saveBlock);
         }
@@ -424,7 +432,7 @@ void dvmCallMethod(Thread* self, const Method* method, Object* obj,
 
     va_list args;
     va_start(args, pResult);
-    dvmCallMethodV(self, method, obj, pResult, args);
+    dvmCallMethodV(self, method, obj, false, pResult, args);
     va_end(args);
 }
 
@@ -438,7 +446,7 @@ void dvmCallMethod(Thread* self, const Method* method, Object* obj,
  * we don't need to worry about static synchronized methods.
  */
 void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
-    JValue* pResult, va_list args)
+    bool fromJni, JValue* pResult, va_list args)
 {
     const char* desc = &(method->shorty[1]); // [0] is the return type.
     int verifyCount = 0;
@@ -483,7 +491,10 @@ void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
             case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
                 void* argObj = va_arg(args, void*);
                 assert(obj == NULL || dvmIsValidObject(obj));
-                *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
+                if (fromJni)
+                    *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
+                else
+                    *ins++ = (u4) argObj;
                 verifyCount++;
                 break;
             }
@@ -541,7 +552,7 @@ bail:
  * "args" may be NULL if the method has no arguments.
  */
 void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
-    JValue* pResult, const jvalue* args)
+    bool fromJni, JValue* pResult, const jvalue* args)
 {
     const char* desc = &(method->shorty[1]); // [0] is the return type.
     int verifyCount = 0;
@@ -572,7 +583,10 @@ void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
             verifyCount++;              /* this needs an extra push */
             break;
         case 'L':                       /* includes array refs */
-            *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
+            if (fromJni)
+                *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
+            else
+                *ins++ = (u4) args->l;
             break;
         case 'F':
         case 'I':
index f2a481b..22f066f 100644 (file)
@@ -138,8 +138,12 @@ struct StackSaveArea {
     const Method* method;
 
     union {
-        /* for JNI native methods: top of local reference storage */
-        Object**    localRefTop;
+        /* for JNI native methods: bottom of local reference segment */
+#ifdef USE_INDIRECT_REF
+        u4          localRefCookie;
+#else
+        Object**    localRefCookie;
+#endif
 
         /* for interpreted methods: saved current PC, for exception stack
          * traces and debugger traces */
@@ -191,16 +195,18 @@ bool dvmPushLocalFrame(Thread* thread, const Method* method);
 bool dvmPopLocalFrame(Thread* thread);
 
 /*
- * Call an interpreted method from native code.
+ * Call an interpreted method from native code.  If this is being called
+ * from a JNI function, references in the argument list will be converted
+ * back to pointers.
  *
  * "obj" should be NULL for "direct" methods.
  */
-void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
-    JValue* pResult, va_list args);
-void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
-    JValue* pResult, const jvalue* args);
 void dvmCallMethod(Thread* self, const Method* method, Object* obj,
     JValue* pResult, ...);
+void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
+    bool fromJni, JValue* pResult, va_list args);
+void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
+    bool fromJni, JValue* pResult, const jvalue* args);
 
 /*
  * Invoke a method, using the specified arguments and return type, through
index 004ee13..90e3750 100644 (file)
@@ -430,9 +430,9 @@ common_invokeMethodNoRange:
     @ Prep for the native call
     @ r0=methodToCall, r1=newFp, r10=newSaveArea
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r10, #offStackSaveArea_localRefTop] @newFp->localRefTop=refNext
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
 
     mov     r2, r0                      @ r2<- methodToCall
@@ -456,11 +456,11 @@ dalvik_mterp:
 
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index 5997c35..5b93583 100644 (file)
@@ -862,7 +862,11 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
             FINISH(0);                              // jump to method start
         } else {
             /* set this up for JNI locals, even if not a JNI native */
-            newSaveArea->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
+#ifdef USE_INDIRECT_REF
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+#else
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
+#endif
 
             self->curFrame = newFp;
 
index 716df3d..a69247e 100644 (file)
@@ -154,7 +154,8 @@ MTERP_OFFSET(offStackSaveArea_prevFrame, StackSaveArea, prevFrame, 4)
 MTERP_OFFSET(offStackSaveArea_savedPc,  StackSaveArea, savedPc, 8)
 MTERP_OFFSET(offStackSaveArea_method,   StackSaveArea, method, 12)
 MTERP_OFFSET(offStackSaveArea_currentPc, StackSaveArea, xtra.currentPc, 16)
-MTERP_OFFSET(offStackSaveArea_localRefTop, StackSaveArea, xtra.localRefTop, 16)
+MTERP_OFFSET(offStackSaveArea_localRefCookie, \
+                                        StackSaveArea, xtra.localRefCookie, 16)
 MTERP_OFFSET(offStackSaveArea_returnAddr, StackSaveArea, returnAddr, 20)
 MTERP_SIZEOF(sizeofStackSaveArea,       StackSaveArea, 24)
 #else
@@ -162,7 +163,8 @@ MTERP_OFFSET(offStackSaveArea_prevFrame, StackSaveArea, prevFrame, 0)
 MTERP_OFFSET(offStackSaveArea_savedPc,  StackSaveArea, savedPc, 4)
 MTERP_OFFSET(offStackSaveArea_method,   StackSaveArea, method, 8)
 MTERP_OFFSET(offStackSaveArea_currentPc, StackSaveArea, xtra.currentPc, 12)
-MTERP_OFFSET(offStackSaveArea_localRefTop, StackSaveArea, xtra.localRefTop, 12)
+MTERP_OFFSET(offStackSaveArea_localRefCookie, \
+                                        StackSaveArea, xtra.localRefCookie, 12)
 MTERP_OFFSET(offStackSaveArea_returnAddr, StackSaveArea, returnAddr, 16)
 MTERP_SIZEOF(sizeofStackSaveArea,       StackSaveArea, 20)
 #endif
@@ -198,8 +200,13 @@ MTERP_OFFSET(offInlineOperation_func,   InlineOperation, func, 0)
 MTERP_OFFSET(offThread_stackOverflowed, Thread, stackOverflowed, 40)
 MTERP_OFFSET(offThread_curFrame,        Thread, curFrame, 44)
 MTERP_OFFSET(offThread_exception,       Thread, exception, 48)
-MTERP_OFFSET(offThread_jniLocal_nextEntry, \
-                                        Thread, jniLocalRefTable.nextEntry, 80)
+#ifdef USE_INDIRECT_REF
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+                                Thread, jniLocalRefTable.segmentState.all, 76)
+#else
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+                                Thread, jniLocalRefTable.nextEntry, 76)
+#endif
 
 /* Object fields */
 MTERP_OFFSET(offObject_clazz,           Object, clazz, 0)
index b0aa69b..2df532f 100644 (file)
@@ -9902,9 +9902,9 @@ common_invokeMethodNoRange:
     @ Prep for the native call
     @ r0=methodToCall, r1=newFp, r10=newSaveArea
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r10, #offStackSaveArea_localRefTop] @newFp->localRefTop=refNext
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
 
     mov     r2, r0                      @ r2<- methodToCall
@@ -9928,11 +9928,11 @@ dalvik_mterp:
 
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index 5a8ae4c..61b2697 100644 (file)
@@ -9420,9 +9420,9 @@ common_invokeMethodNoRange:
     @ Prep for the native call
     @ r0=methodToCall, r1=newFp, r10=newSaveArea
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r10, #offStackSaveArea_localRefTop] @newFp->localRefTop=refNext
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
 
     mov     r2, r0                      @ r2<- methodToCall
@@ -9446,11 +9446,11 @@ dalvik_mterp:
 
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index 3f2069c..bafd442 100644 (file)
@@ -9896,9 +9896,9 @@ common_invokeMethodNoRange:
     @ Prep for the native call
     @ r0=methodToCall, r1=newFp, r10=newSaveArea
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r10, #offStackSaveArea_localRefTop] @newFp->localRefTop=refNext
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
 
     mov     r2, r0                      @ r2<- methodToCall
@@ -9922,11 +9922,11 @@ dalvik_mterp:
 
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index 0555a30..8d018c1 100644 (file)
@@ -9356,9 +9356,9 @@ common_invokeMethodNoRange:
     @ Prep for the native call
     @ r0=methodToCall, r1=newFp, r10=newSaveArea
     ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
-    ldr     r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
     str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
-    str     r9, [r10, #offStackSaveArea_localRefTop] @newFp->localRefTop=refNext
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
     mov     r9, r3                      @ r9<- glue->self (preserve)
 
     mov     r2, r0                      @ r2<- methodToCall
@@ -9382,11 +9382,11 @@ dalvik_mterp:
 
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
-    ldr     r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
-    str     r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index 52007b0..79c98f6 100644 (file)
@@ -8700,8 +8700,8 @@ common_invokeMethodNoRange:
     GET_GLUE(%ecx)                      # %ecx<- pMterpGlue
     movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
     movl        offGlue_self(%ecx), %ecx        # %ecx<- glue->self
-    movl        offThread_jniLocal_nextEntry(%ecx), %eax # %eax<- glue->self->thread->refNext
-    movl        %eax, offStackSaveArea_localRefTop(%edx) # newSaveArea->localRefTop<- refNext
+    movl        offThread_jniLocal_topCookie(%ecx), %eax # %eax<- self->localRef->...
+    movl        %eax, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
     movl        %edx, OUT_ARG4(%esp)    # save newSaveArea
     movl        LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
     movl        %edx, offThread_curFrame(%ecx)  # glue->self->curFrame<- newFP
@@ -8717,10 +8717,10 @@ common_invokeMethodNoRange:
     lea         4(%esp), %esp
     movl        OUT_ARG4(%esp), %ecx    # %ecx<- newSaveArea
     movl        OUT_ARG3(%esp), %eax    # %eax<- glue->self
-    movl        offStackSaveArea_localRefTop(%ecx), %edx # %edx<- newSaveArea->localRefTop
+    movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
     cmp         $0, offThread_exception(%eax) # check for exception
     movl        rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
-    movl        %edx, offThread_jniLocal_nextEntry(%eax) # glue->self<- newSaveArea->localRefTop
+    movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
     UNSPILL(rPC)
     jne         common_exceptionThrown  # handle exception
     FETCH_INST_WORD(3)
index bb1d0ea..4e832d8 100644 (file)
@@ -3895,7 +3895,11 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
             FINISH(0);                              // jump to method start
         } else {
             /* set this up for JNI locals, even if not a JNI native */
-            newSaveArea->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
+#ifdef USE_INDIRECT_REF
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+#else
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
+#endif
 
             self->curFrame = newFp;
 
index 90b2a75..4b92639 100644 (file)
@@ -4186,7 +4186,11 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
             FINISH(0);                              // jump to method start
         } else {
             /* set this up for JNI locals, even if not a JNI native */
-            newSaveArea->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
+#ifdef USE_INDIRECT_REF
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+#else
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
+#endif
 
             self->curFrame = newFp;
 
index c28bf5b..1db6e87 100644 (file)
@@ -3900,7 +3900,11 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
             FINISH(0);                              // jump to method start
         } else {
             /* set this up for JNI locals, even if not a JNI native */
-            newSaveArea->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
+#ifdef USE_INDIRECT_REF
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+#else
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
+#endif
 
             self->curFrame = newFp;
 
index 9bb70d1..07536c4 100644 (file)
@@ -2050,7 +2050,11 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
             FINISH(0);                              // jump to method start
         } else {
             /* set this up for JNI locals, even if not a JNI native */
-            newSaveArea->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
+#ifdef USE_INDIRECT_REF
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+#else
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
+#endif
 
             self->curFrame = newFp;
 
index d86207a..c39fa16 100644 (file)
@@ -200,8 +200,8 @@ common_invokeMethodNoRange:
     GET_GLUE(%ecx)                      # %ecx<- pMterpGlue
     movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
     movl        offGlue_self(%ecx), %ecx        # %ecx<- glue->self
-    movl        offThread_jniLocal_nextEntry(%ecx), %eax # %eax<- glue->self->thread->refNext
-    movl        %eax, offStackSaveArea_localRefTop(%edx) # newSaveArea->localRefTop<- refNext
+    movl        offThread_jniLocal_topCookie(%ecx), %eax # %eax<- self->localRef->...
+    movl        %eax, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
     movl        %edx, OUT_ARG4(%esp)    # save newSaveArea
     movl        LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
     movl        %edx, offThread_curFrame(%ecx)  # glue->self->curFrame<- newFP
@@ -217,10 +217,10 @@ common_invokeMethodNoRange:
     lea         4(%esp), %esp
     movl        OUT_ARG4(%esp), %ecx    # %ecx<- newSaveArea
     movl        OUT_ARG3(%esp), %eax    # %eax<- glue->self
-    movl        offStackSaveArea_localRefTop(%ecx), %edx # %edx<- newSaveArea->localRefTop
+    movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
     cmp         $$0, offThread_exception(%eax) # check for exception
     movl        rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
-    movl        %edx, offThread_jniLocal_nextEntry(%eax) # glue->self<- newSaveArea->localRefTop
+    movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
     UNSPILL(rPC)
     jne         common_exceptionThrown  # handle exception
     FETCH_INST_WORD(3)