Home | History | Annotate | Download | only in vm
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * Dalvik implementation of JNI interfaces.
     19  */
     20 #include "Dalvik.h"
     21 #include "JniInternal.h"
     22 
     23 #include <stdlib.h>
     24 #include <stdarg.h>
     25 #include <limits.h>
     26 
     27 /*
     28 Native methods and interaction with the GC
     29 
     30 All JNI methods must start by changing their thread status to
     31 THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
     32 returning to native code.  The switch to "running" triggers a thread
     33 suspension check.
     34 
     35 With a rudimentary GC we should be able to skip the status change for
     36 simple functions, e.g.  IsSameObject, GetJavaVM, GetStringLength, maybe
     37 even access to fields with primitive types.  Our options are more limited
     38 with a compacting GC, so we should replace JNI_ENTER with JNI_ENTER_NCGC
     39 or somesuch on the "lite" functions if we want to try this optimization.
     40 
     41 For performance reasons we do as little error-checking as possible here.
     42 For example, we don't check to make sure the correct type of Object is
     43 passed in when setting a field, and we don't prevent you from storing
     44 new values in a "final" field.  Such things are best handled in the
     45 "check" version.  For actions that are common, dangerous, and must be
     46 checked at runtime, such as array bounds checks, we do the tests here.
     47 
     48 
     49 General notes on local/global reference tracking
     50 
     51 JNI provides explicit control over natively-held references that the GC
     52 needs to know about.  These can be local, in which case they're released
     53 when the native method returns into the VM, or global, which are held
     54 until explicitly released.  (There are also weak-global references,
     55 which have the lifespan and visibility of global references, but the
     56 object they refer to may be collected.)
     57 
     58 The references can be created with explicit JNI NewLocalRef / NewGlobalRef
     59 calls.  The former is very unusual, the latter is reasonably common
     60 (e.g. for caching references to class objects).
     61 
     62 Local references are most often created as a side-effect of JNI functions.
     63 For example, the AllocObject/NewObject functions must create local
     64 references to the objects returned, because nothing else in the GC root
     65 set has a reference to the new objects.
     66 
     67 The most common mode of operation is for a method to create zero or
     68 more local references and return.  Explicit "local delete" operations
     69 are expected to be exceedingly rare, except when walking through an
     70 object array, and the Push/PopLocalFrame calls are expected to be used
     71 infrequently.  For efficient operation, we want to add new local refs
     72 with a simple store/increment operation; to avoid infinite growth in
     73 pathological situations, we need to reclaim the space used by deleted
     74 entries.
     75 
     76 If we just want to maintain a list for the GC root set, we can use an
     77 expanding append-only array that compacts when objects are deleted.
     78 In typical situations, e.g. running through an array of objects, we will
     79 be deleting one of the most recently added entries, so we can minimize
     80 the number of elements moved (or avoid having to move any).
     81 
     82 If we want to conceal the pointer values from native code, which is
     83 necessary to allow the GC to move JNI-referenced objects around, then we
     84 have to use a more complicated indirection mechanism.
     85 
     86 The spec says, "Local references are only valid in the thread in which
     87 they are created.  The native code must not pass local references from
     88 one thread to another."
     89 
     90 
     91 Pinned objects
     92 
     93 For some large chunks of data, notably primitive arrays and String data,
     94 JNI allows the VM to choose whether it wants to pin the array object or
     95 make a copy.  We currently pin the memory for better execution performance.
     96 
     97 TODO: we're using simple root set references to pin primitive array data,
     98 because they have the property we need (i.e. the pointer we return is
     99 guaranteed valid until we explicitly release it).  However, if we have a
    100 compacting GC and don't want to pin all memory held by all global refs,
    101 we need to treat these differently.
    102 
    103 
    104 Global reference tracking
    105 
    106 There should be a small "active" set centered around the most-recently
    107 added items.
    108 
    109 Because it's global, access to it has to be synchronized.  Additions and
    110 removals require grabbing a mutex.  If the table serves as an indirection
    111 mechanism (i.e. it's not just a list for the benefit of the garbage
    112 collector), reference lookups may also require grabbing a mutex.
    113 
    114 The JNI spec does not define any sort of limit, so the list must be able
    115 to expand to a reasonable size.  It may be useful to log significant
    116 increases in usage to help identify resource leaks.
    117 
    118 
    119 Weak-global reference tracking
    120 
    121 [TBD]
    122 
    123 
    124 Local reference tracking
    125 
    126 The table of local references can be stored on the interpreted stack or
    127 in a parallel data structure (one per thread).
    128 
    129 *** Approach #1: use the interpreted stack
    130 
    131 The easiest place to tuck it is between the frame ptr and the first saved
    132 register, which is always in0.  (See the ASCII art in Stack.h.)  We can
    133 shift the "VM-specific goop" and frame ptr down, effectively inserting
    134 the JNI local refs in the space normally occupied by local variables.
    135 
    136 (Three things are accessed from the frame pointer:
    137  (1) framePtr[N] is register vN, used to get at "ins" and "locals".
    138  (2) framePtr - sizeof(StackSaveArea) is the VM frame goop.
    139  (3) framePtr - sizeof(StackSaveArea) - numOuts is where the "outs" go.
    140 The only thing that isn't determined by an offset from the current FP
    141 is the previous frame.  However, tucking things below the previous frame
    142 can be problematic because the "outs" of the previous frame overlap with
    143 the "ins" of the current frame.  If the "ins" are altered they must be
    144 restored before we return.  For a native method call, the easiest and
    145 safest thing to disrupt is #1, because there are no locals and the "ins"
    146 are all copied to the native stack.)
    147 
    148 We can implement Push/PopLocalFrame with the existing stack frame calls,
    149 making sure we copy some goop from the previous frame (notably the method
    150 ptr, so that dvmGetCurrentJNIMethod() doesn't require extra effort).
    151 
    152 We can pre-allocate the storage at the time the stack frame is first
    153 set up, but we have to be careful.  When calling from interpreted code
    154 the frame ptr points directly at the arguments we're passing, but we can
    155 offset the args pointer when calling the native bridge.
    156 
    157 To manage the local ref collection, we need to be able to find three
    158 things: (1) the start of the region, (2) the end of the region, and (3)
    159 the next available entry.  The last is only required for quick adds.
    160 We currently have two easily-accessible pointers, the current FP and the
    161 previous frame's FP.  (The "stack pointer" shown in the ASCII art doesn't
    162 actually exist in the interpreted world.)
    163 
    164 We can't use the current FP to find the first "in", because we want to
    165 insert the variable-sized local refs table between them.  It's awkward
    166 to use the previous frame's FP because native methods invoked via
    167 dvmCallMethod() or dvmInvokeMethod() don't have "ins", but native methods
    168 invoked from interpreted code do.  We can either track the local refs
    169 table size with a field in the stack frame, or insert unnecessary items
    170 so that all native stack frames have "ins".
    171 
    172 Assuming we can find the region bounds, we still need pointer #3
    173 for an efficient implementation.  This can be stored in an otherwise
    174 unused-for-native field in the frame goop.
    175 
    176 When we run out of room we have to make more space.  If we start allocating
    177 locals immediately below in0 and grow downward, we will detect end-of-space
    178 by running into the current frame's FP.  We then memmove() the goop down
    179 (memcpy if we guarantee the additional size is larger than the frame).
    180 This is nice because we only have to move sizeof(StackSaveArea) bytes
    181 each time.
    182 
    183 Stack walking should be okay so long as nothing tries to access the
    184 "ins" by an offset from the FP.  In theory the "ins" could be read by
    185 the debugger or SIGQUIT handler looking for "this" or other arguments,
    186 but in practice this behavior isn't expected to work for native methods,
    187 so we can simply disallow it.
    188 
    189 A conservative GC can just scan the entire stack from top to bottom to find
    190 all references.  An exact GC will need to understand the actual layout.
    191 
    192 *** Approach #2: use a parallel stack
    193 
    194 Each Thread/JNIEnv points to a reference table.  The struct has
    195 a system-heap-allocated array of references and a pointer to the
    196 next-available entry ("nextEntry").
    197 
    198 Each stack frame has a pointer to what it sees as the "bottom" element
    199 in the array (we can double-up the "currentPc" field).  This is set to
    200 "nextEntry" when the frame is pushed on.  As local references are added
    201 or removed, "nextEntry" is updated.
    202 
    203 We implement Push/PopLocalFrame with actual stack frames.  Before a JNI
    204 frame gets popped, we set "nextEntry" to the "top" pointer of the current
    205 frame, effectively releasing the references.
    206 
    207 The GC will scan all references from the start of the table to the
    208 "nextEntry" pointer.
    209 
    210 *** Comparison
    211 
    212 All approaches will return a failure result when they run out of local
    213 reference space.  For #1 that means blowing out the stack, for #2 it's
    214 running out of room in the array.
    215 
    216 Compared to #1, approach #2:
    217  - Needs only one pointer in the stack frame goop.
    218  - Makes pre-allocating storage unnecessary.
    219  - Doesn't contend with interpreted stack depth for space.  In most
    220    cases, if something blows out the local ref storage, it's because the
    221    JNI code was misbehaving rather than called from way down.
    222  - Allows the GC to do a linear scan per thread in a buffer that is 100%
    223    references.  The GC can be slightly less smart when scanning the stack.
    224  - Will be easier to work with if we combine native and interpeted stacks.
    225 
    226  - Isn't as clean, especially when popping frames, since we have to do
    227    explicit work.  Fortunately we only have to do it when popping native
    228    method calls off, so it doesn't add overhead to interpreted code paths.
    229  - Is awkward to expand dynamically.  We'll want to pre-allocate the full
    230    amount of space; this is fine, since something on the order of 1KB should
    231    be plenty.  The JNI spec allows us to limit this.
    232  - Requires the GC to scan even more memory.  With the references embedded
    233    in the stack we get better locality of reference.
    234 
    235 */
    236 
    237 /* fwd */
    238 static const struct JNINativeInterface gNativeInterface;
    239 static jobject addGlobalReference(Object* obj);
    240 
    241 #ifdef WITH_JNI_STACK_CHECK
    242 # define COMPUTE_STACK_SUM(_self)   computeStackSum(_self);
    243 # define CHECK_STACK_SUM(_self)     checkStackSum(_self);
    244 //static void computeStackSum(Thread* self);
    245 //static void checkStackSum(Thread* self);
    246 #else
    247 # define COMPUTE_STACK_SUM(_self)   ((void)0)
    248 # define CHECK_STACK_SUM(_self)     ((void)0)
    249 #endif
    250 
    251 
    252 /*
    253  * ===========================================================================
    254  *      Utility functions
    255  * ===========================================================================
    256  */
    257 
    258 /*
    259  * Entry/exit processing for all JNI calls.
    260  *
    261  * If TRUSTED_JNIENV is set, we get to skip the (curiously expensive)
    262  * thread-local storage lookup on our Thread*.  If the caller has passed
    263  * the wrong JNIEnv in, we're going to be accessing unsynchronized
    264  * structures from more than one thread, and things are going to fail
    265  * in bizarre ways.  This is only sensible if the native code has been
    266  * fully exercised with CheckJNI enabled.
    267  */
    268 #define TRUSTED_JNIENV
    269 #ifdef TRUSTED_JNIENV
    270 # define JNI_ENTER()                                                        \
    271         Thread* _self = ((JNIEnvExt*)env)->self;                            \
    272         CHECK_STACK_SUM(_self);                                             \
    273         dvmChangeStatus(_self, THREAD_RUNNING)
    274 #else
    275 # define JNI_ENTER()                                                        \
    276         Thread* _self = dvmThreadSelf();                                    \
    277         UNUSED_PARAMETER(env);                                              \
    278         CHECK_STACK_SUM(_self);                                             \
    279         dvmChangeStatus(_self, THREAD_RUNNING)
    280 #endif
    281 #define JNI_EXIT()                                                          \
    282         dvmChangeStatus(_self, THREAD_NATIVE);                              \
    283         COMPUTE_STACK_SUM(_self)
    284 
    285 #define kGlobalRefsTableInitialSize 512
    286 #define kGlobalRefsTableMaxSize     51200       /* arbitrary, must be < 64K */
    287 #define kGrefWaterInterval          100
    288 #define kTrackGrefUsage             true
    289 
    290 #define kPinTableInitialSize        16
    291 #define kPinTableMaxSize            1024
    292 #define kPinComplainThreshold       10
    293 
    294 /*
    295  * Allocate the global references table, and look up some classes for
    296  * the benefit of direct buffer access.
    297  */
    298 bool dvmJniStartup(void)
    299 {
    300 #ifdef USE_INDIRECT_REF
    301     if (!dvmInitIndirectRefTable(&gDvm.jniGlobalRefTable,
    302             kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize,
    303             kIndirectKindGlobal))
    304         return false;
    305 #else
    306     if (!dvmInitReferenceTable(&gDvm.jniGlobalRefTable,
    307             kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize))
    308         return false;
    309 #endif
    310 
    311     dvmInitMutex(&gDvm.jniGlobalRefLock);
    312     gDvm.jniGlobalRefLoMark = 0;
    313     gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
    314 
    315     if (!dvmInitReferenceTable(&gDvm.jniPinRefTable,
    316             kPinTableInitialSize, kPinTableMaxSize))
    317         return false;
    318 
    319     dvmInitMutex(&gDvm.jniPinRefLock);
    320 
    321     Method* meth;
    322 
    323     /*
    324      * Grab the PhantomReference constructor.
    325      */
    326     gDvm.classJavaLangRefPhantomReference =
    327         dvmFindSystemClassNoInit("Ljava/lang/ref/PhantomReference;");
    328     if (gDvm.classJavaLangRefPhantomReference == NULL) {
    329         LOGE("Unable to find PhantomReference class\n");
    330         return false;
    331     }
    332     meth= dvmFindDirectMethodByDescriptor(gDvm.classJavaLangRefPhantomReference,
    333         "<init>", "(Ljava/lang/Object;Ljava/lang/ref/ReferenceQueue;)V");
    334     if (meth == NULL) {
    335         LOGE("Unable to find constructor for PhantomReference\n");
    336         return false;
    337     }
    338     gDvm.methJavaLangRefPhantomReference_init = meth;
    339 
    340 
    341     /*
    342      * Look up and cache pointers to some direct buffer classes, fields,
    343      * and methods.
    344      */
    345     ClassObject* platformAddressClass =
    346         dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddress;");
    347     ClassObject* platformAddressFactoryClass =
    348         dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddressFactory;");
    349     ClassObject* directBufferClass =
    350         dvmFindSystemClassNoInit("Lorg/apache/harmony/nio/internal/DirectBuffer;");
    351     ClassObject* readWriteBufferClass =
    352         dvmFindSystemClassNoInit("Ljava/nio/ReadWriteDirectByteBuffer;");
    353     ClassObject* bufferClass =
    354         dvmFindSystemClassNoInit("Ljava/nio/Buffer;");
    355 
    356     if (platformAddressClass == NULL || platformAddressFactoryClass == NULL ||
    357         directBufferClass == NULL || readWriteBufferClass == NULL ||
    358         bufferClass == NULL)
    359     {
    360         LOGE("Unable to find internal direct buffer classes\n");
    361         return false;
    362     }
    363     gDvm.classJavaNioReadWriteDirectByteBuffer = readWriteBufferClass;
    364     gDvm.classOrgApacheHarmonyNioInternalDirectBuffer = directBufferClass;
    365     /* need a global reference for extended CheckJNI tests */
    366     gDvm.jclassOrgApacheHarmonyNioInternalDirectBuffer =
    367         addGlobalReference((Object*) directBufferClass);
    368 
    369     /*
    370      * We need a Method* here rather than a vtable offset, because
    371      * DirectBuffer is an interface class.
    372      */
    373     meth = dvmFindVirtualMethodByDescriptor(
    374                 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer,
    375                 "getEffectiveAddress",
    376                 "()Lorg/apache/harmony/luni/platform/PlatformAddress;");
    377     if (meth == NULL) {
    378         LOGE("Unable to find PlatformAddress.getEffectiveAddress\n");
    379         return false;
    380     }
    381     gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress = meth;
    382 
    383     meth = dvmFindVirtualMethodByDescriptor(platformAddressClass,
    384                 "toLong", "()J");
    385     if (meth == NULL) {
    386         LOGE("Unable to find PlatformAddress.toLong\n");
    387         return false;
    388     }
    389     gDvm.voffOrgApacheHarmonyLuniPlatformPlatformAddress_toLong =
    390         meth->methodIndex;
    391 
    392     meth = dvmFindDirectMethodByDescriptor(platformAddressFactoryClass,
    393                 "on",
    394                 "(I)Lorg/apache/harmony/luni/platform/PlatformAddress;");
    395     if (meth == NULL) {
    396         LOGE("Unable to find PlatformAddressFactory.on\n");
    397         return false;
    398     }
    399     gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on = meth;
    400 
    401     meth = dvmFindDirectMethodByDescriptor(readWriteBufferClass,
    402                 "<init>",
    403                 "(Lorg/apache/harmony/luni/platform/PlatformAddress;II)V");
    404     if (meth == NULL) {
    405         LOGE("Unable to find ReadWriteDirectByteBuffer.<init>\n");
    406         return false;
    407     }
    408     gDvm.methJavaNioReadWriteDirectByteBuffer_init = meth;
    409 
    410     gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr =
    411         dvmFindFieldOffset(platformAddressClass, "osaddr", "I");
    412     if (gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr < 0) {
    413         LOGE("Unable to find PlatformAddress.osaddr\n");
    414         return false;
    415     }
    416 
    417     gDvm.offJavaNioBuffer_capacity =
    418         dvmFindFieldOffset(bufferClass, "capacity", "I");
    419     if (gDvm.offJavaNioBuffer_capacity < 0) {
    420         LOGE("Unable to find Buffer.capacity\n");
    421         return false;
    422     }
    423 
    424     gDvm.offJavaNioBuffer_effectiveDirectAddress =
    425         dvmFindFieldOffset(bufferClass, "effectiveDirectAddress", "I");
    426     if (gDvm.offJavaNioBuffer_effectiveDirectAddress < 0) {
    427         LOGE("Unable to find Buffer.effectiveDirectAddress\n");
    428         return false;
    429     }
    430 
    431     return true;
    432 }
    433 
    434 /*
    435  * Free the global references table.
    436  */
    437 void dvmJniShutdown(void)
    438 {
    439 #ifdef USE_INDIRECT_REF
    440     dvmClearIndirectRefTable(&gDvm.jniGlobalRefTable);
    441 #else
    442     dvmClearReferenceTable(&gDvm.jniGlobalRefTable);
    443 #endif
    444     dvmClearReferenceTable(&gDvm.jniPinRefTable);
    445 }
    446 
    447 
    448 /*
    449  * Find the JNIEnv associated with the current thread.
    450  *
    451  * Currently stored in the Thread struct.  Could also just drop this into
    452  * thread-local storage.
    453  */
    454 JNIEnvExt* dvmGetJNIEnvForThread(void)
    455 {
    456     Thread* self = dvmThreadSelf();
    457     if (self == NULL)
    458         return NULL;
    459     return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
    460 }
    461 
    462 /*
    463  * Create a new JNIEnv struct and add it to the VM's list.
    464  *
    465  * "self" will be NULL for the main thread, since the VM hasn't started
    466  * yet; the value will be filled in later.
    467  */
    468 JNIEnv* dvmCreateJNIEnv(Thread* self)
    469 {
    470     JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
    471     JNIEnvExt* newEnv;
    472 
    473     //if (self != NULL)
    474     //    LOGI("Ent CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
    475 
    476     assert(vm != NULL);
    477 
    478     newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
    479     newEnv->funcTable = &gNativeInterface;
    480     newEnv->vm = vm;
    481     newEnv->forceDataCopy = vm->forceDataCopy;
    482     if (self != NULL) {
    483         dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
    484         assert(newEnv->envThreadId != 0);
    485     } else {
    486         /* make it obvious if we fail to initialize these later */
    487         newEnv->envThreadId = 0x77777775;
    488         newEnv->self = (Thread*) 0x77777779;
    489     }
    490     if (vm->useChecked)
    491         dvmUseCheckedJniEnv(newEnv);
    492 
    493     dvmLockMutex(&vm->envListLock);
    494 
    495     /* insert at head of list */
    496     newEnv->next = vm->envList;
    497     assert(newEnv->prev == NULL);
    498     if (vm->envList == NULL)            // rare, but possible
    499         vm->envList = newEnv;
    500     else
    501         vm->envList->prev = newEnv;
    502     vm->envList = newEnv;
    503 
    504     dvmUnlockMutex(&vm->envListLock);
    505 
    506     //if (self != NULL)
    507     //    LOGI("Xit CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
    508     return (JNIEnv*) newEnv;
    509 }
    510 
    511 /*
    512  * Remove a JNIEnv struct from the list and free it.
    513  */
    514 void dvmDestroyJNIEnv(JNIEnv* env)
    515 {
    516     JNIEnvExt* extEnv = (JNIEnvExt*) env;
    517     JavaVMExt* vm = extEnv->vm;
    518     Thread* self;
    519 
    520     if (env == NULL)
    521         return;
    522 
    523     self = dvmThreadSelf();
    524     assert(self != NULL);
    525 
    526     //LOGI("Ent DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
    527 
    528     dvmLockMutex(&vm->envListLock);
    529 
    530     if (extEnv == vm->envList) {
    531         assert(extEnv->prev == NULL);
    532         vm->envList = extEnv->next;
    533     } else {
    534         assert(extEnv->prev != NULL);
    535         extEnv->prev->next = extEnv->next;
    536     }
    537     if (extEnv->next != NULL)
    538         extEnv->next->prev = extEnv->prev;
    539 
    540     dvmUnlockMutex(&extEnv->vm->envListLock);
    541 
    542     free(env);
    543     //LOGI("Xit DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
    544 }
    545 
    546 
    547 /*
    548  * Retrieve the ReferenceTable struct for the current thread.
    549  *
    550  * Going through "env" rather than dvmThreadSelf() is faster but will
    551  * get weird if the JNI code is passing the wrong JNIEnv around.
    552  */
    553 #ifdef USE_INDIRECT_REF
    554 static inline IndirectRefTable* getLocalRefTable(JNIEnv* env)
    555 #else
    556 static inline ReferenceTable* getLocalRefTable(JNIEnv* env)
    557 #endif
    558 {
    559     //return &dvmThreadSelf()->jniLocalRefTable;
    560     return &((JNIEnvExt*)env)->self->jniLocalRefTable;
    561 }
    562 
    563 #ifdef USE_INDIRECT_REF
    564 /*
    565  * Convert an indirect reference to an Object reference.  The indirect
    566  * reference may be local, global, or weak-global.
    567  *
    568  * If "jobj" is NULL or an invalid indirect reference, this returns NULL.
    569  */
    570 Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj)
    571 {
    572     if (jobj == NULL)
    573         return NULL;
    574 
    575     Object* result;
    576 
    577     switch (dvmGetIndirectRefType(jobj)) {
    578     case kIndirectKindLocal:
    579         {
    580             IndirectRefTable* pRefTable = getLocalRefTable(env);
    581             result = dvmGetFromIndirectRefTable(pRefTable, jobj);
    582         }
    583         break;
    584     case kIndirectKindGlobal:
    585         {
    586             // TODO: find a way to avoid the mutex activity here
    587             IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
    588             dvmLockMutex(&gDvm.jniGlobalRefLock);
    589             result = dvmGetFromIndirectRefTable(pRefTable, jobj);
    590             dvmUnlockMutex(&gDvm.jniGlobalRefLock);
    591         }
    592         break;
    593     case kIndirectKindWeakGlobal:
    594         {
    595             // TODO: implement
    596             LOGE("weak-global not yet supported\n");
    597             result = NULL;
    598             dvmAbort();
    599         }
    600         break;
    601     case kIndirectKindInvalid:
    602     default:
    603         LOGW("Invalid indirect reference %p in decodeIndirectRef\n", jobj);
    604         dvmAbort();
    605         result = NULL;
    606         break;
    607     }
    608 
    609     return result;
    610 }
    611 #else
    612     /* use trivial inline in JniInternal.h for performance */
    613 #endif
    614 
    615 /*
    616  * Add a local reference for an object to the current stack frame.  When
    617  * the native function returns, the reference will be discarded.
    618  *
    619  * We need to allow the same reference to be added multiple times.
    620  *
    621  * This will be called on otherwise unreferenced objects.  We cannot do
    622  * GC allocations here, and it's best if we don't grab a mutex.
    623  *
    624  * Returns the local reference (currently just the same pointer that was
    625  * passed in), or NULL on failure.
    626  */
    627 static jobject addLocalReference(JNIEnv* env, Object* obj)
    628 {
    629     if (obj == NULL)
    630         return NULL;
    631 
    632     jobject jobj;
    633 
    634 #ifdef USE_INDIRECT_REF
    635     IndirectRefTable* pRefTable = getLocalRefTable(env);
    636     void* curFrame = ((JNIEnvExt*)env)->self->curFrame;
    637     u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
    638 
    639     jobj = (jobject) dvmAddToIndirectRefTable(pRefTable, cookie, obj);
    640     if (jobj == NULL) {
    641         dvmDumpIndirectRefTable(pRefTable, "JNI local");
    642         LOGE("Failed adding to JNI local ref table (has %d entries)\n",
    643             (int) dvmIndirectRefTableEntries(pRefTable));
    644         dvmDumpThread(dvmThreadSelf(), false);
    645         dvmAbort();     // spec says call FatalError; this is equivalent
    646     } else {
    647         LOGVV("LREF add %p  (%s.%s) (ent=%d)\n", obj,
    648             dvmGetCurrentJNIMethod()->clazz->descriptor,
    649             dvmGetCurrentJNIMethod()->name,
    650             (int) dvmReferenceTableEntries(pRefTable));
    651     }
    652 #else
    653     ReferenceTable* pRefTable = getLocalRefTable(env);
    654 
    655     if (!dvmAddToReferenceTable(pRefTable, obj)) {
    656         dvmDumpReferenceTable(pRefTable, "JNI local");
    657         LOGE("Failed adding to JNI local ref table (has %d entries)\n",
    658             (int) dvmReferenceTableEntries(pRefTable));
    659         dvmDumpThread(dvmThreadSelf(), false);
    660         dvmAbort();     // spec says call FatalError; this is equivalent
    661     } else {
    662         LOGVV("LREF add %p  (%s.%s) (ent=%d)\n", obj,
    663             dvmGetCurrentJNIMethod()->clazz->descriptor,
    664             dvmGetCurrentJNIMethod()->name,
    665             (int) dvmReferenceTableEntries(pRefTable));
    666     }
    667 
    668     jobj = (jobject) obj;
    669 #endif
    670 
    671     return jobj;
    672 }
    673 
    674 /*
    675  * Ensure that at least "capacity" references can be held in the local
    676  * refs table of the current thread.
    677  */
    678 static bool ensureLocalCapacity(JNIEnv* env, int capacity)
    679 {
    680 #ifdef USE_INDIRECT_REF
    681     IndirectRefTable* pRefTable = getLocalRefTable(env);
    682     int numEntries = dvmIndirectRefTableEntries(pRefTable);
    683     // TODO: this isn't quite right, since "numEntries" includes holes
    684     return ((kJniLocalRefMax - numEntries) >= capacity);
    685 #else
    686     ReferenceTable* pRefTable = getLocalRefTable(env);
    687 
    688     return (kJniLocalRefMax - (pRefTable->nextEntry - pRefTable->table) >= capacity);
    689 #endif
    690 }
    691 
    692 /*
    693  * Explicitly delete a reference from the local list.
    694  */
    695 static void deleteLocalReference(JNIEnv* env, jobject jobj)
    696 {
    697     if (jobj == NULL)
    698         return;
    699 
    700 #ifdef USE_INDIRECT_REF
    701     IndirectRefTable* pRefTable = getLocalRefTable(env);
    702     Thread* self = ((JNIEnvExt*)env)->self;
    703     u4 cookie = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefCookie;
    704 
    705     if (!dvmRemoveFromIndirectRefTable(pRefTable, cookie, jobj)) {
    706         /*
    707          * Attempting to delete a local reference that is not in the
    708          * topmost local reference frame is a no-op.  DeleteLocalRef returns
    709          * void and doesn't throw any exceptions, but we should probably
    710          * complain about it so the user will notice that things aren't
    711          * going quite the way they expect.
    712          */
    713         LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry\n", jobj);
    714     }
    715 #else
    716     ReferenceTable* pRefTable = getLocalRefTable(env);
    717     Thread* self = ((JNIEnvExt*)env)->self;
    718     Object** bottom = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefCookie;
    719 
    720     if (!dvmRemoveFromReferenceTable(pRefTable, bottom, (Object*) jobj)) {
    721         /*
    722          * Attempting to delete a local reference that is not in the
    723          * topmost local reference frame is a no-op.  DeleteLocalRef returns
    724          * void and doesn't throw any exceptions, but we should probably
    725          * complain about it so the user will notice that things aren't
    726          * going quite the way they expect.
    727          */
    728         LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry (valid=%d)\n",
    729             jobj, dvmIsValidObject((Object*) jobj));
    730     }
    731 #endif
    732 }
    733 
    734 /*
    735  * Add a global reference for an object.
    736  *
    737  * We may add the same object more than once.  Add/remove calls are paired,
    738  * so it needs to appear on the list multiple times.
    739  */
    740 static jobject addGlobalReference(Object* obj)
    741 {
    742     if (obj == NULL)
    743         return NULL;
    744 
    745     //LOGI("adding obj=%p\n", obj);
    746     //dvmDumpThread(dvmThreadSelf(), false);
    747 
    748     if (false && ((Object*)obj)->clazz == gDvm.classJavaLangClass) {
    749         ClassObject* clazz = (ClassObject*) obj;
    750         LOGI("-------\n");
    751         LOGI("Adding global ref on class %s\n", clazz->descriptor);
    752         dvmDumpThread(dvmThreadSelf(), false);
    753     }
    754     if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
    755         StringObject* strObj = (StringObject*) obj;
    756         char* str = dvmCreateCstrFromString(strObj);
    757         if (strcmp(str, "sync-response") == 0) {
    758             LOGI("-------\n");
    759             LOGI("Adding global ref on string '%s'\n", str);
    760             dvmDumpThread(dvmThreadSelf(), false);
    761             //dvmAbort();
    762         }
    763         free(str);
    764     }
    765     if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
    766         ArrayObject* arrayObj = (ArrayObject*) obj;
    767         if (arrayObj->length == 8192 /*&&
    768             dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
    769         {
    770             LOGI("Adding global ref on byte array %p (len=%d)\n",
    771                 arrayObj, arrayObj->length);
    772             dvmDumpThread(dvmThreadSelf(), false);
    773         }
    774     }
    775 
    776     jobject jobj;
    777 
    778     dvmLockMutex(&gDvm.jniGlobalRefLock);
    779 
    780     /*
    781      * Throwing an exception on failure is problematic, because JNI code
    782      * may not be expecting an exception, and things sort of cascade.  We
    783      * want to have a hard limit to catch leaks during debugging, but this
    784      * otherwise needs to expand until memory is consumed.  As a practical
    785      * matter, if we have many thousands of global references, chances are
    786      * we're either leaking global ref table entries or we're going to
    787      * run out of space in the GC heap.
    788      */
    789 #ifdef USE_INDIRECT_REF
    790     jobj = dvmAddToIndirectRefTable(&gDvm.jniGlobalRefTable, IRT_FIRST_SEGMENT,
    791             obj);
    792     if (jobj == NULL) {
    793         dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
    794         LOGE("Failed adding to JNI global ref table (%d entries)\n",
    795             (int) dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable));
    796         dvmAbort();
    797     }
    798 
    799     LOGVV("GREF add %p  (%s.%s)\n", obj,
    800         dvmGetCurrentJNIMethod()->clazz->descriptor,
    801         dvmGetCurrentJNIMethod()->name);
    802 
    803     /* GREF usage tracking; should probably be disabled for production env */
    804     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    805         int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
    806         // TODO: adjust for "holes"
    807         if (count > gDvm.jniGlobalRefHiMark) {
    808             LOGD("GREF has increased to %d\n", count);
    809             gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
    810             gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
    811 
    812             /* watch for "excessive" use; not generally appropriate */
    813             if (count >= gDvm.jniGrefLimit) {
    814                 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
    815                 if (vm->warnError) {
    816                     dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable,
    817                         "JNI global");
    818                     LOGE("Excessive JNI global references (%d)\n", count);
    819                     dvmAbort();
    820                 } else {
    821                     LOGW("Excessive JNI global references (%d)\n", count);
    822                 }
    823             }
    824         }
    825     }
    826 #else
    827     if (!dvmAddToReferenceTable(&gDvm.jniGlobalRefTable, obj)) {
    828         dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
    829         LOGE("Failed adding to JNI global ref table (%d entries)\n",
    830             (int) dvmReferenceTableEntries(&gDvm.jniGlobalRefTable));
    831         dvmAbort();
    832     }
    833     jobj = (jobject) obj;
    834 
    835     LOGVV("GREF add %p  (%s.%s)\n", obj,
    836         dvmGetCurrentJNIMethod()->clazz->descriptor,
    837         dvmGetCurrentJNIMethod()->name);
    838 
    839     /* GREF usage tracking; should probably be disabled for production env */
    840     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    841         int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
    842         if (count > gDvm.jniGlobalRefHiMark) {
    843             LOGD("GREF has increased to %d\n", count);
    844             gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
    845             gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
    846 
    847             /* watch for "excessive" use; not generally appropriate */
    848             if (count >= gDvm.jniGrefLimit) {
    849                 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
    850                 if (vm->warnError) {
    851                     dvmDumpReferenceTable(&gDvm.jniGlobalRefTable,"JNI global");
    852                     LOGE("Excessive JNI global references (%d)\n", count);
    853                     dvmAbort();
    854                 } else {
    855                     LOGW("Excessive JNI global references (%d)\n", count);
    856                 }
    857             }
    858         }
    859     }
    860 #endif
    861 
    862 bail:
    863     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
    864     return jobj;
    865 }
    866 
    867 /*
    868  * Remove a global reference.  In most cases it's the entry most recently
    869  * added, which makes this pretty quick.
    870  *
    871  * Thought: if it's not the most recent entry, just null it out.  When we
    872  * fill up, do a compaction pass before we expand the list.
    873  */
    874 static void deleteGlobalReference(jobject jobj)
    875 {
    876     if (jobj == NULL)
    877         return;
    878 
    879     dvmLockMutex(&gDvm.jniGlobalRefLock);
    880 
    881 #ifdef USE_INDIRECT_REF
    882     if (!dvmRemoveFromIndirectRefTable(&gDvm.jniGlobalRefTable,
    883             IRT_FIRST_SEGMENT, jobj))
    884     {
    885         LOGW("JNI: DeleteGlobalRef(%p) failed to find entry\n", jobj);
    886         goto bail;
    887     }
    888 
    889     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    890         int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
    891         // TODO: not quite right, need to subtract holes
    892         if (count < gDvm.jniGlobalRefLoMark) {
    893             LOGD("GREF has decreased to %d\n", count);
    894             gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
    895             gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
    896         }
    897     }
    898 #else
    899     if (!dvmRemoveFromReferenceTable(&gDvm.jniGlobalRefTable,
    900             gDvm.jniGlobalRefTable.table, jobj))
    901     {
    902         LOGW("JNI: DeleteGlobalRef(%p) failed to find entry (valid=%d)\n",
    903             jobj, dvmIsValidObject((Object*) jobj));
    904         goto bail;
    905     }
    906 
    907     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    908         int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
    909         if (count < gDvm.jniGlobalRefLoMark) {
    910             LOGD("GREF has decreased to %d\n", count);
    911             gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
    912             gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
    913         }
    914     }
    915 #endif
    916 
    917 bail:
    918     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
    919 }
    920 
    921 
    922 /*
    923  * Get the "magic" JNI weak global ReferenceQueue.  It's allocated on
    924  * first use.
    925  *
    926  * Returns NULL with an exception raised if allocation fails.
    927  */
    928 static Object* getWeakGlobalRefQueue(void)
    929 {
    930     /* use an indirect variable to avoid "type-punned pointer" complaints */
    931     Object** pGlobalQ = &gDvm.jniWeakGlobalRefQueue;
    932 
    933     if (*pGlobalQ != NULL)
    934         return *pGlobalQ;
    935 
    936     ClassObject* clazz = dvmFindSystemClass("Ljava/lang/ref/ReferenceQueue;");
    937     if (clazz == NULL) {
    938         LOGE("Unable to find java.lang.ref.ReferenceQueue");
    939         dvmAbort();
    940     }
    941 
    942     /*
    943      * Create an instance of ReferenceQueue.  The object is never actually
    944      * used for anything, so we don't need to call a constructor.  (We could
    945      * get away with using an instance of Object, but this is cleaner.)
    946      */
    947     Object* queue = dvmAllocObject(clazz, ALLOC_DEFAULT);
    948     if (queue == NULL) {
    949         LOGW("Failed allocating weak global ref queue\n");
    950         assert(dvmCheckException(dvmThreadSelf()));
    951         return NULL;
    952     }
    953     dvmReleaseTrackedAlloc(queue, NULL);
    954 
    955     /*
    956      * Save it, using atomic ops to ensure we don't double-up.  The gDvm
    957      * field is known to the GC.
    958      */
    959     if (!ATOMIC_CMP_SWAP((int*) pGlobalQ, 0, (int) queue)) {
    960         LOGD("WOW: lost race to create weak global ref queue\n");
    961         queue = *pGlobalQ;
    962     }
    963 
    964     return queue;
    965 }
    966 
    967 
    968 /*
    969  * We create a PhantomReference that references the object, add a
    970  * global reference to it, and then flip some bits before returning it.
    971  * The last step ensures that we detect it as special and that only
    972  * appropriate calls will accept it.
    973  *
    974  * On failure, returns NULL with an exception pending.
    975  */
    976 static jweak createWeakGlobalRef(JNIEnv* env, jobject jobj)
    977 {
    978     if (jobj == NULL)
    979         return NULL;
    980 
    981     Thread* self = ((JNIEnvExt*)env)->self;
    982     Object* obj = dvmDecodeIndirectRef(env, jobj);
    983     Object* weakGlobalQueue = getWeakGlobalRefQueue();
    984     Object* phantomObj;
    985     jobject phantomRef;
    986 
    987     /*
    988      * Allocate a PhantomReference, then call the constructor to set
    989      * the referent and the reference queue.
    990      *
    991      * We use a "magic" reference queue that the GC knows about; it behaves
    992      * more like a queueless WeakReference, clearing the referent and
    993      * not calling enqueue().
    994      */
    995     if (!dvmIsClassInitialized(gDvm.classJavaLangRefPhantomReference))
    996         dvmInitClass(gDvm.classJavaLangRefPhantomReference);
    997     phantomObj = dvmAllocObject(gDvm.classJavaLangRefPhantomReference,
    998             ALLOC_DEFAULT);
    999     if (phantomObj == NULL) {
   1000         assert(dvmCheckException(self));
   1001         LOGW("Failed on WeakGlobalRef alloc\n");
   1002         return NULL;
   1003     }
   1004 
   1005     JValue unused;
   1006     dvmCallMethod(self, gDvm.methJavaLangRefPhantomReference_init, phantomObj,
   1007         &unused, jobj, weakGlobalQueue);
   1008     dvmReleaseTrackedAlloc(phantomObj, self);
   1009 
   1010     if (dvmCheckException(self)) {
   1011         LOGW("PhantomReference init failed\n");
   1012         return NULL;
   1013     }
   1014 
   1015     LOGV("+++ WGR: created phantom ref %p for object %p\n", phantomObj, obj);
   1016 
   1017     /*
   1018      * Add it to the global reference table, and mangle the pointer.
   1019      */
   1020     phantomRef = addGlobalReference(phantomObj);
   1021     return dvmObfuscateWeakGlobalRef(phantomRef);
   1022 }
   1023 
   1024 /*
   1025  * Delete the global reference that's keeping the PhantomReference around.
   1026  * The PhantomReference will eventually be discarded by the GC.
   1027  */
   1028 static void deleteWeakGlobalRef(JNIEnv* env, jweak wref)
   1029 {
   1030     if (wref == NULL)
   1031         return;
   1032 
   1033     jobject phantomRef = dvmNormalizeWeakGlobalRef(wref);
   1034     deleteGlobalReference(phantomRef);
   1035 }
   1036 
   1037 /*
   1038  * Extract the referent from a PhantomReference.  Used for weak global
   1039  * references.
   1040  *
   1041  * "jwobj" is a "mangled" WGR pointer.
   1042  */
   1043 static Object* getPhantomReferent(JNIEnv* env, jweak jwobj)
   1044 {
   1045     jobject jobj = dvmNormalizeWeakGlobalRef(jwobj);
   1046     Object* obj = dvmDecodeIndirectRef(env, jobj);
   1047 
   1048     if (obj->clazz != gDvm.classJavaLangRefPhantomReference) {
   1049         LOGE("%p is not a phantom reference (%s)\n",
   1050             jwobj, obj->clazz->descriptor);
   1051         return NULL;
   1052     }
   1053 
   1054     return dvmGetFieldObject(obj, gDvm.offJavaLangRefReference_referent);
   1055 }
   1056 
   1057 
   1058 /*
   1059  * Objects don't currently move, so we just need to create a reference
   1060  * that will ensure the array object isn't collected.
   1061  *
   1062  * We use a separate reference table, which is part of the GC root set.
   1063  */
   1064 static void pinPrimitiveArray(ArrayObject* arrayObj)
   1065 {
   1066     if (arrayObj == NULL)
   1067         return;
   1068 
   1069     dvmLockMutex(&gDvm.jniPinRefLock);
   1070     if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
   1071         dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
   1072         LOGE("Failed adding to JNI pinned array ref table (%d entries)\n",
   1073             (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
   1074         dvmDumpThread(dvmThreadSelf(), false);
   1075         dvmAbort();
   1076     }
   1077 
   1078     /*
   1079      * If we're watching global ref usage, also keep an eye on these.
   1080      *
   1081      * The total number of pinned primitive arrays should be pretty small.
   1082      * A single array should not be pinned more than once or twice; any
   1083      * more than that is a strong indicator that a Release function is
   1084      * not being called.
   1085      */
   1086     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
   1087         int count = 0;
   1088         Object** ppObj = gDvm.jniPinRefTable.table;
   1089         while (ppObj < gDvm.jniPinRefTable.nextEntry) {
   1090             if (*ppObj++ == (Object*) arrayObj)
   1091                 count++;
   1092         }
   1093 
   1094         if (count > kPinComplainThreshold) {
   1095             LOGW("JNI: pin count on array %p (%s) is now %d\n",
   1096                 arrayObj, arrayObj->obj.clazz->descriptor, count);
   1097             /* keep going */
   1098         }
   1099     }
   1100 
   1101     dvmUnlockMutex(&gDvm.jniPinRefLock);
   1102 }
   1103 
   1104 /*
   1105  * Un-pin the array object.  If an object was pinned twice, it must be
   1106  * unpinned twice before it's free to move.
   1107  */
   1108 static void unpinPrimitiveArray(ArrayObject* arrayObj)
   1109 {
   1110     if (arrayObj == NULL)
   1111         return;
   1112 
   1113     dvmLockMutex(&gDvm.jniPinRefLock);
   1114     if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
   1115             gDvm.jniPinRefTable.table, (Object*) arrayObj))
   1116     {
   1117         LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)\n",
   1118             arrayObj, dvmIsValidObject((Object*) arrayObj));
   1119         goto bail;
   1120     }
   1121 
   1122 bail:
   1123     dvmUnlockMutex(&gDvm.jniPinRefLock);
   1124 }
   1125 
   1126 /*
   1127  * Dump the contents of the JNI reference tables to the log file.
   1128  *
   1129  * We only dump the local refs associated with the current thread.
   1130  */
   1131 void dvmDumpJniReferenceTables(void)
   1132 {
   1133     Thread* self = dvmThreadSelf();
   1134     JNIEnv* env = self->jniEnv;
   1135     ReferenceTable* pLocalRefs = getLocalRefTable(env);
   1136 
   1137 #ifdef USE_INDIRECT_REF
   1138     dvmDumpIndirectRefTable(pLocalRefs, "JNI local");
   1139     dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
   1140 #else
   1141     dvmDumpReferenceTable(pLocalRefs, "JNI local");
   1142     dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
   1143 #endif
   1144     dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
   1145 }
   1146 
   1147 /*
   1148  * GC helper function to mark all JNI global references.
   1149  *
   1150  * We're currently handling the "pin" table here too.
   1151  */
   1152 void dvmGcMarkJniGlobalRefs()
   1153 {
   1154     Object** op;
   1155 
   1156     dvmLockMutex(&gDvm.jniGlobalRefLock);
   1157 
   1158 #ifdef USE_INDIRECT_REF
   1159     IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
   1160     op = pRefTable->table;
   1161     int numEntries = dvmIndirectRefTableEntries(pRefTable);
   1162     int i;
   1163 
   1164     for (i = 0; i < numEntries; i++) {
   1165         Object* obj = *op;
   1166         if (obj != NULL)
   1167             dvmMarkObjectNonNull(obj);
   1168         op++;
   1169     }
   1170 #else
   1171     op = gDvm.jniGlobalRefTable.table;
   1172     while ((uintptr_t)op < (uintptr_t)gDvm.jniGlobalRefTable.nextEntry) {
   1173         dvmMarkObjectNonNull(*(op++));
   1174     }
   1175 #endif
   1176 
   1177     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
   1178 
   1179 
   1180     dvmLockMutex(&gDvm.jniPinRefLock);
   1181 
   1182     op = gDvm.jniPinRefTable.table;
   1183     while ((uintptr_t)op < (uintptr_t)gDvm.jniPinRefTable.nextEntry) {
   1184         dvmMarkObjectNonNull(*(op++));
   1185     }
   1186 
   1187     dvmUnlockMutex(&gDvm.jniPinRefLock);
   1188 }
   1189 
   1190 
   1191 #ifndef USE_INDIRECT_REF
   1192 /*
   1193  * Determine if "obj" appears in the argument list for the native method.
   1194  *
   1195  * We use the "shorty" signature to determine which argument slots hold
   1196  * reference types.
   1197  */
   1198 static bool findInArgList(Thread* self, Object* obj)
   1199 {
   1200     const Method* meth;
   1201     u4* fp;
   1202     int i;
   1203 
   1204     fp = self->curFrame;
   1205     while (1) {
   1206         /*
   1207          * Back up over JNI PushLocalFrame frames.  This works because the
   1208          * previous frame on the interpreted stack is either a break frame
   1209          * (if we called here via native code) or an interpreted method (if
   1210          * we called here via the interpreter).  In both cases the method
   1211          * pointer won't match.
   1212          */
   1213         StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
   1214         meth = saveArea->method;
   1215         if (meth != SAVEAREA_FROM_FP(saveArea->prevFrame)->method)
   1216             break;
   1217         fp = saveArea->prevFrame;
   1218     }
   1219 
   1220     LOGVV("+++ scanning %d args in %s (%s)\n",
   1221         meth->insSize, meth->name, meth->shorty);
   1222     const char* shorty = meth->shorty +1;       /* skip return type char */
   1223     for (i = 0; i < meth->insSize; i++) {
   1224         if (i == 0 && !dvmIsStaticMethod(meth)) {
   1225             /* first arg is "this" ref, not represented in "shorty" */
   1226             if (fp[i] == (u4) obj)
   1227                 return true;
   1228         } else {
   1229             /* if this is a reference type, see if it matches */
   1230             switch (*shorty) {
   1231             case 'L':
   1232                 if (fp[i] == (u4) obj)
   1233                     return true;
   1234                 break;
   1235             case 'D':
   1236             case 'J':
   1237                 i++;
   1238                 break;
   1239             case '\0':
   1240                 LOGE("Whoops! ran off the end of %s (%d)\n",
   1241                     meth->shorty, meth->insSize);
   1242                 break;
   1243             default:
   1244                 if (fp[i] == (u4) obj)
   1245                     LOGI("NOTE: ref %p match on arg type %c\n", obj, *shorty);
   1246                 break;
   1247             }
   1248             shorty++;
   1249         }
   1250     }
   1251 
   1252     /*
   1253      * For static methods, we also pass a class pointer in.
   1254      */
   1255     if (dvmIsStaticMethod(meth)) {
   1256         //LOGI("+++ checking class pointer in %s\n", meth->name);
   1257         if ((void*)obj == (void*)meth->clazz)
   1258             return true;
   1259     }
   1260     return false;
   1261 }
   1262 #endif
   1263 
   1264 /*
   1265  * Verify that a reference passed in from native code is one that the
   1266  * code is allowed to have.
   1267  *
   1268  * It's okay for native code to pass us a reference that:
   1269  *  - was passed in as an argument when invoked by native code (and hence
   1270  *    is in the JNI local refs table)
   1271  *  - was returned to it from JNI (and is now in the local refs table)
   1272  *  - is present in the JNI global refs table
   1273  *
   1274  * Used by -Xcheck:jni and GetObjectRefType.
   1275  *
   1276  * NOTE: in the current VM, global and local references are identical.  If
   1277  * something is both global and local, we can't tell them apart, and always
   1278  * return "local".
   1279  */
   1280 jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj)
   1281 {
   1282 #ifdef USE_INDIRECT_REF
   1283     /*
   1284      * IndirectRefKind is currently defined as an exact match of
   1285      * jobjectRefType, so this is easy.  We have to decode it to determine
   1286      * if it's a valid reference and not merely valid-looking.
   1287      */
   1288     Object* obj = dvmDecodeIndirectRef(env, jobj);
   1289 
   1290     if (obj == NULL) {
   1291         /* invalid ref, or jobj was NULL */
   1292         return JNIInvalidRefType;
   1293     } else {
   1294         return (jobjectRefType) dvmGetIndirectRefType(jobj);
   1295     }
   1296 #else
   1297     ReferenceTable* pRefTable = getLocalRefTable(env);
   1298     Thread* self = dvmThreadSelf();
   1299     //Object** top;
   1300     Object** ptr;
   1301 
   1302     if (dvmIsWeakGlobalRef(jobj)) {
   1303         return JNIWeakGlobalRefType;
   1304     }
   1305 
   1306     /* check args */
   1307     if (findInArgList(self, jobj)) {
   1308         //LOGI("--- REF found %p on stack\n", jobj);
   1309         return JNILocalRefType;
   1310     }
   1311 
   1312     /* check locals */
   1313     if (dvmFindInReferenceTable(pRefTable, pRefTable->table, jobj) != NULL) {
   1314         //LOGI("--- REF found %p in locals\n", jobj);
   1315         return JNILocalRefType;
   1316     }
   1317 
   1318     /* check globals */
   1319     dvmLockMutex(&gDvm.jniGlobalRefLock);
   1320     if (dvmFindInReferenceTable(&gDvm.jniGlobalRefTable,
   1321             gDvm.jniGlobalRefTable.table, jobj))
   1322     {
   1323         //LOGI("--- REF found %p in globals\n", jobj);
   1324         dvmUnlockMutex(&gDvm.jniGlobalRefLock);
   1325         return JNIGlobalRefType;
   1326     }
   1327     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
   1328 
   1329     /* not found! */
   1330     return JNIInvalidRefType;
   1331 #endif
   1332 }
   1333 
   1334 /*
   1335  * Register a method that uses JNI calling conventions.
   1336  */
   1337 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
   1338     const char* signature, void* fnPtr)
   1339 {
   1340     Method* method;
   1341     bool result = false;
   1342 
   1343     if (fnPtr == NULL)
   1344         goto bail;
   1345 
   1346     method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
   1347     if (method == NULL)
   1348         method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
   1349     if (method == NULL) {
   1350         LOGW("ERROR: Unable to find decl for native %s.%s %s\n",
   1351             clazz->descriptor, methodName, signature);
   1352         goto bail;
   1353     }
   1354 
   1355     if (!dvmIsNativeMethod(method)) {
   1356         LOGW("Unable to register: not native: %s.%s %s\n",
   1357             clazz->descriptor, methodName, signature);
   1358         goto bail;
   1359     }
   1360 
   1361     if (method->nativeFunc != dvmResolveNativeMethod) {
   1362         LOGW("Warning: %s.%s %s was already registered/resolved?\n",
   1363             clazz->descriptor, methodName, signature);
   1364         /* keep going, I guess */
   1365     }
   1366 
   1367     dvmUseJNIBridge(method, fnPtr);
   1368 
   1369     LOGV("JNI-registered %s.%s %s\n", clazz->descriptor, methodName,
   1370         signature);
   1371     result = true;
   1372 
   1373 bail:
   1374     return result;
   1375 }
   1376 
   1377 /*
   1378  * Returns "true" if CheckJNI is enabled in the VM.
   1379  */
   1380 static bool dvmIsCheckJNIEnabled(void)
   1381 {
   1382     JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
   1383     return vm->useChecked;
   1384 }
   1385 
   1386 /*
   1387  * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
   1388  * to point at the actual function.
   1389  */
   1390 void dvmUseJNIBridge(Method* method, void* func)
   1391 {
   1392     enum {
   1393         kJNIGeneral = 0,
   1394         kJNISync = 1,
   1395         kJNIVirtualNoRef = 2,
   1396         kJNIStaticNoRef = 3,
   1397     } kind;
   1398     static const DalvikBridgeFunc stdFunc[] = {
   1399         dvmCallJNIMethod_general,
   1400         dvmCallJNIMethod_synchronized,
   1401         dvmCallJNIMethod_virtualNoRef,
   1402         dvmCallJNIMethod_staticNoRef
   1403     };
   1404     static const DalvikBridgeFunc checkFunc[] = {
   1405         dvmCheckCallJNIMethod_general,
   1406         dvmCheckCallJNIMethod_synchronized,
   1407         dvmCheckCallJNIMethod_virtualNoRef,
   1408         dvmCheckCallJNIMethod_staticNoRef
   1409     };
   1410 
   1411     bool hasRefArg = false;
   1412 
   1413     if (dvmIsSynchronizedMethod(method)) {
   1414         /* use version with synchronization; calls into general handler */
   1415         kind = kJNISync;
   1416     } else {
   1417         /*
   1418          * Do a quick scan through the "shorty" signature to see if the method
   1419          * takes any reference arguments.
   1420          */
   1421         const char* cp = method->shorty;
   1422         while (*++cp != '\0') {     /* pre-incr to skip return type */
   1423             if (*cp == 'L') {
   1424                 /* 'L' used for both object and array references */
   1425                 hasRefArg = true;
   1426                 break;
   1427             }
   1428         }
   1429 
   1430         if (hasRefArg) {
   1431             /* use general handler to slurp up reference args */
   1432             kind = kJNIGeneral;
   1433         } else {
   1434             /* virtual methods have a ref in args[0] (not in signature) */
   1435             if (dvmIsStaticMethod(method))
   1436                 kind = kJNIStaticNoRef;
   1437             else
   1438                 kind = kJNIVirtualNoRef;
   1439         }
   1440     }
   1441 
   1442     if (dvmIsCheckJNIEnabled()) {
   1443         dvmSetNativeFunc(method, checkFunc[kind], func);
   1444     } else {
   1445         dvmSetNativeFunc(method, stdFunc[kind], func);
   1446     }
   1447 }
   1448 
   1449 /*
   1450  * Get the method currently being executed by examining the interp stack.
   1451  */
   1452 const Method* dvmGetCurrentJNIMethod(void)
   1453 {
   1454     assert(dvmThreadSelf() != NULL);
   1455 
   1456     void* fp = dvmThreadSelf()->curFrame;
   1457     const Method* meth = SAVEAREA_FROM_FP(fp)->method;
   1458 
   1459     assert(meth != NULL);
   1460     assert(dvmIsNativeMethod(meth));
   1461     return meth;
   1462 }
   1463 
   1464 
   1465 /*
   1466  * Track a JNI MonitorEnter in the current thread.
   1467  *
   1468  * The goal is to be able to "implicitly" release all JNI-held monitors
   1469  * when the thread detaches.
   1470  *
   1471  * Monitors may be entered multiple times, so we add a new entry for each
   1472  * enter call.  It would be more efficient to keep a counter.  At present
   1473  * there's no real motivation to improve this however.
   1474  */
   1475 static void trackMonitorEnter(Thread* self, Object* obj)
   1476 {
   1477     static const int kInitialSize = 16;
   1478     ReferenceTable* refTable = &self->jniMonitorRefTable;
   1479 
   1480     /* init table on first use */
   1481     if (refTable->table == NULL) {
   1482         assert(refTable->maxEntries == 0);
   1483 
   1484         if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
   1485             LOGE("Unable to initialize monitor tracking table\n");
   1486             dvmAbort();
   1487         }
   1488     }
   1489 
   1490     if (!dvmAddToReferenceTable(refTable, obj)) {
   1491         /* ran out of memory? could throw exception instead */
   1492         LOGE("Unable to add entry to monitor tracking table\n");
   1493         dvmAbort();
   1494     } else {
   1495         LOGVV("--- added monitor %p\n", obj);
   1496     }
   1497 }
   1498 
   1499 
   1500 /*
   1501  * Track a JNI MonitorExit in the current thread.
   1502  */
   1503 static void trackMonitorExit(Thread* self, Object* obj)
   1504 {
   1505     ReferenceTable* pRefTable = &self->jniMonitorRefTable;
   1506 
   1507     if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
   1508         LOGE("JNI monitor %p not found in tracking list\n", obj);
   1509         /* keep going? */
   1510     } else {
   1511         LOGVV("--- removed monitor %p\n", obj);
   1512     }
   1513 }
   1514 
   1515 /*
   1516  * Release all monitors held by the jniMonitorRefTable list.
   1517  */
   1518 void dvmReleaseJniMonitors(Thread* self)
   1519 {
   1520     ReferenceTable* pRefTable = &self->jniMonitorRefTable;
   1521     Object** top = pRefTable->table;
   1522 
   1523     if (top == NULL)
   1524         return;
   1525 
   1526     Object** ptr = pRefTable->nextEntry;
   1527     while (--ptr >= top) {
   1528         if (!dvmUnlockObject(self, *ptr)) {
   1529             LOGW("Unable to unlock monitor %p at thread detach\n", *ptr);
   1530         } else {
   1531             LOGVV("--- detach-releasing monitor %p\n", *ptr);
   1532         }
   1533     }
   1534 
   1535     /* zap it */
   1536     pRefTable->nextEntry = pRefTable->table;
   1537 }
   1538 
   1539 #ifdef WITH_JNI_STACK_CHECK
   1540 /*
   1541  * Compute a CRC on the entire interpreted stack.
   1542  *
   1543  * Would be nice to compute it on "self" as well, but there are parts of
   1544  * the Thread that can be altered by other threads (e.g. prev/next pointers).
   1545  */
   1546 static void computeStackSum(Thread* self)
   1547 {
   1548     const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
   1549     u4 crc = dvmInitCrc32();
   1550     self->stackCrc = 0;
   1551     crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
   1552     self->stackCrc = crc;
   1553 }
   1554 
   1555 /*
   1556  * Compute a CRC on the entire interpreted stack, and compare it to what
   1557  * we previously computed.
   1558  *
   1559  * We can execute JNI directly from native code without calling in from
   1560  * interpreted code during VM initialization and immediately after JNI
   1561  * thread attachment.  Another opportunity exists during JNI_OnLoad.  Rather
   1562  * than catching these cases we just ignore them here, which is marginally
   1563  * less accurate but reduces the amount of code we have to touch with #ifdefs.
   1564  */
   1565 static void checkStackSum(Thread* self)
   1566 {
   1567     const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
   1568     u4 stackCrc, crc;
   1569 
   1570     stackCrc = self->stackCrc;
   1571     self->stackCrc = 0;
   1572     crc = dvmInitCrc32();
   1573     crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
   1574     if (crc != stackCrc) {
   1575         const Method* meth = dvmGetCurrentJNIMethod();
   1576         if (dvmComputeExactFrameDepth(self->curFrame) == 1) {
   1577             LOGD("JNI: bad stack CRC (0x%08x) -- okay during init\n",
   1578                 stackCrc);
   1579         } else if (strcmp(meth->name, "nativeLoad") == 0 &&
   1580                   (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0))
   1581         {
   1582             LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad\n",
   1583                 stackCrc);
   1584         } else {
   1585             LOGW("JNI: bad stack CRC (%08x vs %08x)\n", crc, stackCrc);
   1586             dvmAbort();
   1587         }
   1588     }
   1589     self->stackCrc = (u4) -1;       /* make logic errors more noticeable */
   1590 }
   1591 #endif
   1592 
   1593 
   1594 /*
   1595  * ===========================================================================
   1596  *      JNI call bridge
   1597  * ===========================================================================
   1598  */
   1599 
   1600 /*
   1601  * The functions here form a bridge between interpreted code and JNI native
   1602  * functions.  The basic task is to convert an array of primitives and
   1603  * references into C-style function arguments.  This is architecture-specific
   1604  * and usually requires help from assembly code.
   1605  *
   1606  * The bridge takes four arguments: the array of parameters, a place to
   1607  * store the function result (if any), the method to call, and a pointer
   1608  * to the current thread.
   1609  *
   1610  * These functions aren't called directly from elsewhere in the VM.
   1611  * A pointer in the Method struct points to one of these, and when a native
   1612  * method is invoked the interpreter jumps to it.
   1613  *
   1614  * (The "internal native" methods are invoked the same way, but instead
   1615  * of calling through a bridge, the target method is called directly.)
   1616  *
   1617  * The "args" array should not be modified, but we do so anyway for
   1618  * performance reasons.  We know that it points to the "outs" area on
   1619  * the current method's interpreted stack.  This area is ignored by the
   1620  * precise GC, because there is no register map for a native method (for
   1621  * an interpreted method the args would be listed in the argument set).
   1622  * We know all of the values exist elsewhere on the interpreted stack,
   1623  * because the method call setup copies them right before making the call,
   1624  * so we don't have to worry about concealing stuff from the GC.
   1625  *
   1626  * If we don't want to modify "args", we either have to create a local
   1627  * copy and modify it before calling dvmPlatformInvoke, or we have to do
   1628  * the local reference replacement within dvmPlatformInvoke.  The latter
   1629  * has some performance advantages, though if we can inline the local
   1630  * reference adds we may win when there's a lot of reference args (unless
   1631  * we want to code up some local ref table manipulation in assembly.
   1632  */
   1633 
   1634 /*
   1635  * If necessary, convert the value in pResult from a local/global reference
   1636  * to an object pointer.
   1637  */
   1638 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
   1639     const Method* method, Thread* self)
   1640 {
   1641 #ifdef USE_INDIRECT_REF
   1642     if (method->shorty[0] == 'L' && !dvmCheckException(self) &&
   1643             pResult->l != NULL)
   1644     {
   1645         pResult->l = dvmDecodeIndirectRef(env, pResult->l);
   1646     }
   1647 #endif
   1648 }
   1649 
   1650 /*
   1651  * General form, handles all cases.
   1652  */
   1653 void dvmCallJNIMethod_general(const u4* args, JValue* pResult,
   1654     const Method* method, Thread* self)
   1655 {
   1656     int oldStatus;
   1657     u4* modArgs = (u4*) args;
   1658     jclass staticMethodClass;
   1659     JNIEnv* env = self->jniEnv;
   1660 
   1661     assert(method->insns != NULL);
   1662 
   1663     //LOGI("JNI calling %p (%s.%s:%s):\n", method->insns,
   1664     //    method->clazz->descriptor, method->name, method->shorty);
   1665 
   1666 #ifdef USE_INDIRECT_REF
   1667     /*
   1668      * Walk the argument list, creating local references for appropriate
   1669      * arguments.
   1670      */
   1671     int idx = 0;
   1672     if (dvmIsStaticMethod(method)) {
   1673         /* add the class object we pass in */
   1674         staticMethodClass = addLocalReference(env, (Object*) method->clazz);
   1675         if (staticMethodClass == NULL) {
   1676             assert(dvmCheckException(self));
   1677             return;
   1678         }
   1679     } else {
   1680         /* add "this" */
   1681         staticMethodClass = NULL;
   1682         jobject thisObj = addLocalReference(env, (Object*) modArgs[0]);
   1683         if (thisObj == NULL) {
   1684             assert(dvmCheckException(self));
   1685             return;
   1686         }
   1687         modArgs[idx] = (u4) thisObj;
   1688         idx = 1;
   1689     }
   1690 
   1691     const char* shorty = &method->shorty[1];        /* skip return type */
   1692     while (*shorty != '\0') {
   1693         switch (*shorty++) {
   1694         case 'L':
   1695             //LOGI("  local %d: 0x%08x\n", idx, modArgs[idx]);
   1696             if (modArgs[idx] != 0) {
   1697                 //if (!dvmIsValidObject((Object*) modArgs[idx]))
   1698                 //    dvmAbort();
   1699                 jobject argObj = addLocalReference(env, (Object*) modArgs[idx]);
   1700                 if (argObj == NULL) {
   1701                     assert(dvmCheckException(self));
   1702                     return;
   1703                 }
   1704                 modArgs[idx] = (u4) argObj;
   1705             }
   1706             break;
   1707         case 'D':
   1708         case 'J':
   1709             idx++;
   1710             break;
   1711         default:
   1712             /* Z B C S I -- do nothing */
   1713             break;
   1714         }
   1715 
   1716         idx++;
   1717     }
   1718 #else
   1719     staticMethodClass = dvmIsStaticMethod(method) ?
   1720         (jclass) method->clazz : NULL;
   1721 #endif
   1722 
   1723     oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
   1724 
   1725     COMPUTE_STACK_SUM(self);
   1726     dvmPlatformInvoke(env, staticMethodClass,
   1727         method->jniArgInfo, method->insSize, modArgs, method->shorty,
   1728         (void*)method->insns, pResult);
   1729     CHECK_STACK_SUM(self);
   1730 
   1731     dvmChangeStatus(self, oldStatus);
   1732 
   1733     convertReferenceResult(env, pResult, method, self);
   1734 }
   1735 
   1736 /*
   1737  * Handler for the unusual case of a synchronized native method.
   1738  *
   1739  * Lock the object, then call through the general function.
   1740  */
   1741 void dvmCallJNIMethod_synchronized(const u4* args, JValue* pResult,
   1742     const Method* method, Thread* self)
   1743 {
   1744     Object* lockObj;
   1745 
   1746     assert(dvmIsSynchronizedMethod(method));
   1747 
   1748     if (dvmIsStaticMethod(method))
   1749         lockObj = (Object*) method->clazz;
   1750     else
   1751         lockObj = (Object*) args[0];
   1752 
   1753     LOGVV("Calling %s.%s: locking %p (%s)\n",
   1754         method->clazz->descriptor, method->name,
   1755         lockObj, lockObj->clazz->descriptor);
   1756 
   1757     dvmLockObject(self, lockObj);
   1758     dvmCallJNIMethod_general(args, pResult, method, self);
   1759     dvmUnlockObject(self, lockObj);
   1760 }
   1761 
   1762 /*
   1763  * Virtual method call, no reference arguments.
   1764  *
   1765  * We need to local-ref the "this" argument, found in args[0].
   1766  */
   1767 void dvmCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult,
   1768     const Method* method, Thread* self)
   1769 {
   1770     u4* modArgs = (u4*) args;
   1771     int oldStatus;
   1772 
   1773 #ifdef USE_INDIRECT_REF
   1774     jobject thisObj = addLocalReference(self->jniEnv, (Object*) args[0]);
   1775     if (thisObj == NULL) {
   1776         assert(dvmCheckException(self));
   1777         return;
   1778     }
   1779     modArgs[0] = (u4) thisObj;
   1780 #endif
   1781 
   1782     oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
   1783 
   1784     COMPUTE_STACK_SUM(self);
   1785     dvmPlatformInvoke(self->jniEnv, NULL,
   1786         method->jniArgInfo, method->insSize, modArgs, method->shorty,
   1787         (void*)method->insns, pResult);
   1788     CHECK_STACK_SUM(self);
   1789 
   1790     dvmChangeStatus(self, oldStatus);
   1791 
   1792     convertReferenceResult(self->jniEnv, pResult, method, self);
   1793 }
   1794 
   1795 /*
   1796  * Static method call, no reference arguments.
   1797  *
   1798  * We need to local-ref the class reference.
   1799  */
   1800 void dvmCallJNIMethod_staticNoRef(const u4* args, JValue* pResult,
   1801     const Method* method, Thread* self)
   1802 {
   1803     jclass staticMethodClass;
   1804     int oldStatus;
   1805 
   1806 #ifdef USE_INDIRECT_REF
   1807     staticMethodClass = addLocalReference(self->jniEnv, (Object*)method->clazz);
   1808     if (staticMethodClass == NULL) {
   1809         assert(dvmCheckException(self));
   1810         return;
   1811     }
   1812 #else
   1813     staticMethodClass = (jobject) method->clazz;
   1814 #endif
   1815 
   1816     oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
   1817 
   1818     COMPUTE_STACK_SUM(self);
   1819     dvmPlatformInvoke(self->jniEnv, staticMethodClass,
   1820         method->jniArgInfo, method->insSize, args, method->shorty,
   1821         (void*)method->insns, pResult);
   1822     CHECK_STACK_SUM(self);
   1823 
   1824     dvmChangeStatus(self, oldStatus);
   1825 
   1826     convertReferenceResult(self->jniEnv, pResult, method, self);
   1827 }
   1828 
   1829 /*
   1830  * Extract the return type enum from the "jniArgInfo" field.
   1831  */
   1832 DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
   1833 {
   1834     return (jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT;
   1835 }
   1836 
   1837 
   1838 /*
   1839  * ===========================================================================
   1840  *      JNI implementation
   1841  * ===========================================================================
   1842  */
   1843 
   1844 /*
   1845  * Return the version of the native method interface.
   1846  */
   1847 static jint GetVersion(JNIEnv* env)
   1848 {
   1849     JNI_ENTER();
   1850     /*
   1851      * There is absolutely no need to toggle the mode for correct behavior.
   1852      * However, it does provide native code with a simple "suspend self
   1853      * if necessary" call.
   1854      */
   1855     JNI_EXIT();
   1856     return JNI_VERSION_1_6;
   1857 }
   1858 
   1859 /*
   1860  * Create a new class from a bag of bytes.
   1861  *
   1862  * This is not currently supported within Dalvik.
   1863  */
   1864 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
   1865     const jbyte* buf, jsize bufLen)
   1866 {
   1867     UNUSED_PARAMETER(name);
   1868     UNUSED_PARAMETER(loader);
   1869     UNUSED_PARAMETER(buf);
   1870     UNUSED_PARAMETER(bufLen);
   1871 
   1872     JNI_ENTER();
   1873     LOGW("JNI DefineClass is not supported\n");
   1874     JNI_EXIT();
   1875     return NULL;
   1876 }
   1877 
   1878 /*
   1879  * Find a class by name.
   1880  *
   1881  * We have to use the "no init" version of FindClass here, because we might
   1882  * be getting the class prior to registering native methods that will be
   1883  * used in <clinit>.
   1884  *
   1885  * We need to get the class loader associated with the current native
   1886  * method.  If there is no native method, e.g. we're calling this from native
   1887  * code right after creating the VM, the spec says we need to use the class
   1888  * loader returned by "ClassLoader.getBaseClassLoader".  There is no such
   1889  * method, but it's likely they meant ClassLoader.getSystemClassLoader.
   1890  * We can't get that until after the VM has initialized though.
   1891  */
   1892 static jclass FindClass(JNIEnv* env, const char* name)
   1893 {
   1894     JNI_ENTER();
   1895 
   1896     const Method* thisMethod;
   1897     ClassObject* clazz;
   1898     jclass jclazz = NULL;
   1899     Object* loader;
   1900     char* descriptor = NULL;
   1901 
   1902     thisMethod = dvmGetCurrentJNIMethod();
   1903     assert(thisMethod != NULL);
   1904 
   1905     descriptor = dvmNameToDescriptor(name);
   1906     if (descriptor == NULL) {
   1907         clazz = NULL;
   1908         goto bail;
   1909     }
   1910 
   1911     //Thread* self = dvmThreadSelf();
   1912     if (_self->classLoaderOverride != NULL) {
   1913         /* hack for JNI_OnLoad */
   1914         assert(strcmp(thisMethod->name, "nativeLoad") == 0);
   1915         loader = _self->classLoaderOverride;
   1916     } else if (thisMethod == gDvm.methFakeNativeEntry) {
   1917         /* start point of invocation interface */
   1918         if (!gDvm.initializing)
   1919             loader = dvmGetSystemClassLoader();
   1920         else
   1921             loader = NULL;
   1922     } else {
   1923         loader = thisMethod->clazz->classLoader;
   1924     }
   1925 
   1926     clazz = dvmFindClassNoInit(descriptor, loader);
   1927     jclazz = addLocalReference(env, (Object*) clazz);
   1928 
   1929 bail:
   1930     free(descriptor);
   1931 
   1932     JNI_EXIT();
   1933     return jclazz;
   1934 }
   1935 
   1936 /*
   1937  * Return the superclass of a class.
   1938  */
   1939 static jclass GetSuperclass(JNIEnv* env, jclass jclazz)
   1940 {
   1941     JNI_ENTER();
   1942     jclass jsuper = NULL;
   1943 
   1944     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1945     if (clazz != NULL)
   1946         jsuper = addLocalReference(env, (Object*)clazz->super);
   1947     JNI_EXIT();
   1948     return jsuper;
   1949 }
   1950 
   1951 /*
   1952  * Determine whether an object of clazz1 can be safely cast to clazz2.
   1953  *
   1954  * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
   1955  */
   1956 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2)
   1957 {
   1958     JNI_ENTER();
   1959 
   1960     ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1);
   1961     ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2);
   1962 
   1963     jboolean result = dvmInstanceof(clazz1, clazz2);
   1964 
   1965     JNI_EXIT();
   1966     return result;
   1967 }
   1968 
   1969 /*
   1970  * Given a java.lang.reflect.Method or .Constructor, return a methodID.
   1971  */
   1972 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod)
   1973 {
   1974     JNI_ENTER();
   1975     jmethodID methodID;
   1976     Object* method = dvmDecodeIndirectRef(env, jmethod);
   1977     methodID = (jmethodID) dvmGetMethodFromReflectObj(method);
   1978     JNI_EXIT();
   1979     return methodID;
   1980 }
   1981 
   1982 /*
   1983  * Given a java.lang.reflect.Field, return a fieldID.
   1984  */
   1985 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield)
   1986 {
   1987     JNI_ENTER();
   1988     jfieldID fieldID;
   1989     Object* field = dvmDecodeIndirectRef(env, jfield);
   1990     fieldID = (jfieldID) dvmGetFieldFromReflectObj(field);
   1991     JNI_EXIT();
   1992     return fieldID;
   1993 }
   1994 
   1995 /*
   1996  * Convert a methodID to a java.lang.reflect.Method or .Constructor.
   1997  *
   1998  * (The "isStatic" field does not appear in the spec.)
   1999  *
   2000  * Throws OutOfMemory and returns NULL on failure.
   2001  */
   2002 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID,
   2003     jboolean isStatic)
   2004 {
   2005     JNI_ENTER();
   2006     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
   2007     Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
   2008     dvmReleaseTrackedAlloc(obj, NULL);
   2009     jobject jobj = addLocalReference(env, obj);
   2010     JNI_EXIT();
   2011     return jobj;
   2012 }
   2013 
   2014 /*
   2015  * Convert a fieldID to a java.lang.reflect.Field.
   2016  *
   2017  * (The "isStatic" field does not appear in the spec.)
   2018  *
   2019  * Throws OutOfMemory and returns NULL on failure.
   2020  */
   2021 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID,
   2022     jboolean isStatic)
   2023 {
   2024     JNI_ENTER();
   2025     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
   2026     Object* obj = dvmCreateReflectObjForField(jcls, (Field*) fieldID);
   2027     dvmReleaseTrackedAlloc(obj, NULL);
   2028     jobject jobj = addLocalReference(env, obj);
   2029     JNI_EXIT();
   2030     return jobj;
   2031 }
   2032 
   2033 /*
   2034  * Take this exception and throw it.
   2035  */
   2036 static jint Throw(JNIEnv* env, jthrowable jobj)
   2037 {
   2038     JNI_ENTER();
   2039 
   2040     jint retval;
   2041 
   2042     if (jobj != NULL) {
   2043         Object* obj = dvmDecodeIndirectRef(env, jobj);
   2044         dvmSetException(_self, obj);
   2045         retval = JNI_OK;
   2046     } else {
   2047         retval = JNI_ERR;
   2048     }
   2049 
   2050     JNI_EXIT();
   2051     return retval;
   2052 }
   2053 
   2054 /*
   2055  * Constructs an exception object from the specified class with the message
   2056  * specified by "message", and throws it.
   2057  */
   2058 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message)
   2059 {
   2060     JNI_ENTER();
   2061 
   2062     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2063     dvmThrowExceptionByClass(clazz, message);
   2064     // TODO: should return failure if this didn't work (e.g. OOM)
   2065 
   2066     JNI_EXIT();
   2067     return JNI_OK;
   2068 }
   2069 
   2070 /*
   2071  * If an exception is being thrown, return the exception object.  Otherwise,
   2072  * return NULL.
   2073  *
   2074  * TODO: if there is no pending exception, we should be able to skip the
   2075  * enter/exit checks.  If we find one, we need to enter and then re-fetch
   2076  * the exception (in case it got moved by a compacting GC).
   2077  */
   2078 static jthrowable ExceptionOccurred(JNIEnv* env)
   2079 {
   2080     JNI_ENTER();
   2081 
   2082     Object* exception;
   2083     jobject localException;
   2084 
   2085     exception = dvmGetException(_self);
   2086     localException = addLocalReference(env, exception);
   2087     if (localException == NULL && exception != NULL) {
   2088         /*
   2089          * We were unable to add a new local reference, and threw a new
   2090          * exception.  We can't return "exception", because it's not a
   2091          * local reference.  So we have to return NULL, indicating that
   2092          * there was no exception, even though it's pretty much raining
   2093          * exceptions in here.
   2094          */
   2095         LOGW("JNI WARNING: addLocal/exception combo\n");
   2096     }
   2097 
   2098     JNI_EXIT();
   2099     return localException;
   2100 }
   2101 
   2102 /*
   2103  * Print an exception and stack trace to stderr.
   2104  */
   2105 static void ExceptionDescribe(JNIEnv* env)
   2106 {
   2107     JNI_ENTER();
   2108 
   2109     Object* exception = dvmGetException(_self);
   2110     if (exception != NULL) {
   2111         dvmPrintExceptionStackTrace();
   2112     } else {
   2113         LOGI("Odd: ExceptionDescribe called, but no exception pending\n");
   2114     }
   2115 
   2116     JNI_EXIT();
   2117 }
   2118 
   2119 /*
   2120  * Clear the exception currently being thrown.
   2121  *
   2122  * TODO: we should be able to skip the enter/exit stuff.
   2123  */
   2124 static void ExceptionClear(JNIEnv* env)
   2125 {
   2126     JNI_ENTER();
   2127     dvmClearException(_self);
   2128     JNI_EXIT();
   2129 }
   2130 
   2131 /*
   2132  * Kill the VM.  This function does not return.
   2133  */
   2134 static void FatalError(JNIEnv* env, const char* msg)
   2135 {
   2136     //dvmChangeStatus(NULL, THREAD_RUNNING);
   2137     LOGE("JNI posting fatal error: %s\n", msg);
   2138     dvmAbort();
   2139 }
   2140 
   2141 /*
   2142  * Push a new JNI frame on the stack, with a new set of locals.
   2143  *
   2144  * The new frame must have the same method pointer.  (If for no other
   2145  * reason than FindClass needs it to get the appropriate class loader.)
   2146  */
   2147 static jint PushLocalFrame(JNIEnv* env, jint capacity)
   2148 {
   2149     JNI_ENTER();
   2150     int result = JNI_OK;
   2151     if (!ensureLocalCapacity(env, capacity) ||
   2152         !dvmPushLocalFrame(_self /*dvmThreadSelf()*/, dvmGetCurrentJNIMethod()))
   2153     {
   2154         /* yes, OutOfMemoryError, not StackOverflowError */
   2155         dvmClearException(_self);
   2156         dvmThrowException("Ljava/lang/OutOfMemoryError;",
   2157             "out of stack in JNI PushLocalFrame");
   2158         result = JNI_ERR;
   2159     }
   2160     JNI_EXIT();
   2161     return result;
   2162 }
   2163 
   2164 /*
   2165  * Pop the local frame off.  If "result" is not null, add it as a
   2166  * local reference on the now-current frame.
   2167  */
   2168 static jobject PopLocalFrame(JNIEnv* env, jobject jresult)
   2169 {
   2170     JNI_ENTER();
   2171     Object* result = dvmDecodeIndirectRef(env, jresult);
   2172     if (!dvmPopLocalFrame(_self /*dvmThreadSelf()*/)) {
   2173         LOGW("JNI WARNING: too many PopLocalFrame calls\n");
   2174         dvmClearException(_self);
   2175         dvmThrowException("Ljava/lang/RuntimeException;",
   2176             "too many PopLocalFrame calls");
   2177     }
   2178     jresult = addLocalReference(env, result);
   2179     JNI_EXIT();
   2180     return result;
   2181 }
   2182 
   2183 /*
   2184  * Add a reference to the global list.
   2185  */
   2186 static jobject NewGlobalRef(JNIEnv* env, jobject jobj)
   2187 {
   2188     Object* obj;
   2189 
   2190     JNI_ENTER();
   2191     if (dvmIsWeakGlobalRef(jobj))
   2192         obj = getPhantomReferent(env, (jweak) jobj);
   2193     else
   2194         obj = dvmDecodeIndirectRef(env, jobj);
   2195     jobject retval = addGlobalReference(obj);
   2196     JNI_EXIT();
   2197     return retval;
   2198 }
   2199 
   2200 /*
   2201  * Delete a reference from the global list.
   2202  */
   2203 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef)
   2204 {
   2205     JNI_ENTER();
   2206     deleteGlobalReference(jglobalRef);
   2207     JNI_EXIT();
   2208 }
   2209 
   2210 
   2211 /*
   2212  * Add a reference to the local list.
   2213  */
   2214 static jobject NewLocalRef(JNIEnv* env, jobject jobj)
   2215 {
   2216     Object* obj;
   2217 
   2218     JNI_ENTER();
   2219     if (dvmIsWeakGlobalRef(jobj))
   2220         obj = getPhantomReferent(env, (jweak) jobj);
   2221     else
   2222         obj = dvmDecodeIndirectRef(env, jobj);
   2223     jobject retval = addLocalReference(env, obj);
   2224     JNI_EXIT();
   2225     return retval;
   2226 }
   2227 
   2228 /*
   2229  * Delete a reference from the local list.
   2230  */
   2231 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef)
   2232 {
   2233     JNI_ENTER();
   2234     deleteLocalReference(env, jlocalRef);
   2235     JNI_EXIT();
   2236 }
   2237 
   2238 /*
   2239  * Ensure that the local references table can hold at least this many
   2240  * references.
   2241  */
   2242 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity)
   2243 {
   2244     JNI_ENTER();
   2245     bool okay = ensureLocalCapacity(env, capacity);
   2246     if (!okay) {
   2247         dvmThrowException("Ljava/lang/OutOfMemoryError;",
   2248             "can't ensure local reference capacity");
   2249     }
   2250     JNI_EXIT();
   2251     if (okay)
   2252         return 0;
   2253     else
   2254         return -1;
   2255 }
   2256 
   2257 
   2258 /*
   2259  * Determine whether two Object references refer to the same underlying object.
   2260  */
   2261 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2)
   2262 {
   2263     JNI_ENTER();
   2264     Object* obj1 = dvmDecodeIndirectRef(env, jref1);
   2265     Object* obj2 = dvmDecodeIndirectRef(env, jref2);
   2266     jboolean result = (obj1 == obj2);
   2267     JNI_EXIT();
   2268     return result;
   2269 }
   2270 
   2271 /*
   2272  * Allocate a new object without invoking any constructors.
   2273  */
   2274 static jobject AllocObject(JNIEnv* env, jclass jclazz)
   2275 {
   2276     JNI_ENTER();
   2277 
   2278     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2279     jobject result;
   2280 
   2281     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2282         assert(dvmCheckException(_self));
   2283         result = NULL;
   2284     } else {
   2285         Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   2286         result = addLocalReference(env, newObj);
   2287     }
   2288 
   2289     JNI_EXIT();
   2290     return result;
   2291 }
   2292 
   2293 /*
   2294  * Allocate a new object and invoke the supplied constructor.
   2295  */
   2296 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...)
   2297 {
   2298     JNI_ENTER();
   2299     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2300     jobject result;
   2301 
   2302     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2303         assert(dvmCheckException(_self));
   2304         result = NULL;
   2305     } else {
   2306         Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   2307         result = addLocalReference(env, newObj);
   2308         if (newObj != NULL) {
   2309             JValue unused;
   2310             va_list args;
   2311             va_start(args, methodID);
   2312             dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused,
   2313                 args);
   2314             va_end(args);
   2315         }
   2316     }
   2317 
   2318     JNI_EXIT();
   2319     return result;
   2320 }
   2321 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID,
   2322     va_list args)
   2323 {
   2324     JNI_ENTER();
   2325     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2326     jobject result;
   2327 
   2328     Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   2329     result = addLocalReference(env, newObj);
   2330     if (newObj != NULL) {
   2331         JValue unused;
   2332         dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused, args);
   2333     }
   2334 
   2335     JNI_EXIT();
   2336     return result;
   2337 }
   2338 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID,
   2339     jvalue* args)
   2340 {
   2341     JNI_ENTER();
   2342     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2343     jobject result;
   2344 
   2345     Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   2346     result = addLocalReference(env, newObj);
   2347     if (newObj != NULL) {
   2348         JValue unused;
   2349         dvmCallMethodA(_self, (Method*) methodID, newObj, true, &unused, args);
   2350     }
   2351 
   2352     JNI_EXIT();
   2353     return result;
   2354 }
   2355 
   2356 /*
   2357  * Returns the class of an object.
   2358  *
   2359  * JNI spec says: obj must not be NULL.
   2360  */
   2361 static jclass GetObjectClass(JNIEnv* env, jobject jobj)
   2362 {
   2363     JNI_ENTER();
   2364 
   2365     assert(jobj != NULL);
   2366 
   2367     Object* obj = dvmDecodeIndirectRef(env, jobj);
   2368     jclass jclazz = addLocalReference(env, (Object*) obj->clazz);
   2369 
   2370     JNI_EXIT();
   2371     return jclazz;
   2372 }
   2373 
   2374 /*
   2375  * Determine whether "obj" is an instance of "clazz".
   2376  */
   2377 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz)
   2378 {
   2379     JNI_ENTER();
   2380 
   2381     assert(jclazz != NULL);
   2382 
   2383     jboolean result;
   2384 
   2385     if (jobj == NULL) {
   2386         result = true;
   2387     } else {
   2388         Object* obj = dvmDecodeIndirectRef(env, jobj);
   2389         ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2390         result = dvmInstanceof(obj->clazz, clazz);
   2391     }
   2392 
   2393     JNI_EXIT();
   2394     return result;
   2395 }
   2396 
   2397 /*
   2398  * Get a method ID for an instance method.
   2399  *
   2400  * JNI defines <init> as an instance method, but Dalvik considers it a
   2401  * "direct" method, so we have to special-case it here.
   2402  *
   2403  * Dalvik also puts all private methods into the "direct" list, so we
   2404  * really need to just search both lists.
   2405  */
   2406 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,
   2407     const char* sig)
   2408 {
   2409     JNI_ENTER();
   2410 
   2411     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2412     jmethodID id = NULL;
   2413 
   2414     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2415         assert(dvmCheckException(_self));
   2416     } else {
   2417         Method* meth;
   2418 
   2419         meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
   2420         if (meth == NULL) {
   2421             /* search private methods and constructors; non-hierarchical */
   2422             meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
   2423         }
   2424         if (meth != NULL && dvmIsStaticMethod(meth)) {
   2425             IF_LOGD() {
   2426                 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
   2427                 LOGD("GetMethodID: not returning static method %s.%s %s\n",
   2428                     clazz->descriptor, meth->name, desc);
   2429                 free(desc);
   2430             }
   2431             meth = NULL;
   2432         }
   2433         if (meth == NULL) {
   2434             LOGD("GetMethodID: method not found: %s.%s:%s\n",
   2435                 clazz->descriptor, name, sig);
   2436             dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
   2437         }
   2438 
   2439         /*
   2440          * The method's class may not be the same as clazz, but if
   2441          * it isn't this must be a virtual method and the class must
   2442          * be a superclass (and, hence, already initialized).
   2443          */
   2444         if (meth != NULL) {
   2445             assert(dvmIsClassInitialized(meth->clazz) ||
   2446                    dvmIsClassInitializing(meth->clazz));
   2447         }
   2448         id = (jmethodID) meth;
   2449     }
   2450     JNI_EXIT();
   2451     return id;
   2452 }
   2453 
   2454 /*
   2455  * Get a field ID (instance fields).
   2456  */
   2457 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,
   2458     const char* name, const char* sig)
   2459 {
   2460     JNI_ENTER();
   2461 
   2462     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2463     jfieldID id;
   2464 
   2465     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2466         assert(dvmCheckException(_self));
   2467         id = NULL;
   2468     } else {
   2469         id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
   2470         if (id == NULL) {
   2471             LOGD("GetFieldID: unable to find field %s.%s:%s\n",
   2472                 clazz->descriptor, name, sig);
   2473             dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
   2474         }
   2475     }
   2476     JNI_EXIT();
   2477     return id;
   2478 }
   2479 
   2480 /*
   2481  * Get the method ID for a static method in a class.
   2482  */
   2483 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz,
   2484     const char* name, const char* sig)
   2485 {
   2486     JNI_ENTER();
   2487 
   2488     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2489     jmethodID id;
   2490 
   2491     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2492         assert(dvmCheckException(_self));
   2493         id = NULL;
   2494     } else {
   2495         Method* meth;
   2496 
   2497         meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
   2498 
   2499         /* make sure it's static, not virtual+private */
   2500         if (meth != NULL && !dvmIsStaticMethod(meth)) {
   2501             IF_LOGD() {
   2502                 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
   2503                 LOGD("GetStaticMethodID: "
   2504                     "not returning nonstatic method %s.%s %s\n",
   2505                     clazz->descriptor, meth->name, desc);
   2506                 free(desc);
   2507             }
   2508             meth = NULL;
   2509         }
   2510 
   2511         id = (jmethodID) meth;
   2512         if (id == NULL)
   2513             dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
   2514     }
   2515 
   2516     JNI_EXIT();
   2517     return id;
   2518 }
   2519 
   2520 /*
   2521  * Get a field ID (static fields).
   2522  */
   2523 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz,
   2524     const char* name, const char* sig)
   2525 {
   2526     JNI_ENTER();
   2527 
   2528     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2529     jfieldID id;
   2530 
   2531     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2532         assert(dvmCheckException(_self));
   2533         id = NULL;
   2534     } else {
   2535         id = (jfieldID) dvmFindStaticField(clazz, name, sig);
   2536         if (id == NULL)
   2537             dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
   2538     }
   2539     JNI_EXIT();
   2540     return id;
   2541 }
   2542 
   2543 /*
   2544  * Get a static field.
   2545  *
   2546  * If we get an object reference, add it to the local refs list.
   2547  */
   2548 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref)                       \
   2549     static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz,      \
   2550         jfieldID fieldID)                                                   \
   2551     {                                                                       \
   2552         UNUSED_PARAMETER(jclazz);                                           \
   2553         JNI_ENTER();                                                        \
   2554         StaticField* sfield = (StaticField*) fieldID;                       \
   2555         _ctype value;                                                       \
   2556         if (_isref) {   /* only when _ctype==jobject */                     \
   2557             Object* obj = dvmGetStaticFieldObject(sfield);                  \
   2558             value = (_ctype)(u4)addLocalReference(env, obj);                \
   2559         } else {                                                            \
   2560             value = dvmGetStaticField##_jname(sfield);                      \
   2561         }                                                                   \
   2562         JNI_EXIT();                                                         \
   2563         return value;                                                       \
   2564     }
   2565 GET_STATIC_TYPE_FIELD(jobject, Object, true);
   2566 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
   2567 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
   2568 GET_STATIC_TYPE_FIELD(jchar, Char, false);
   2569 GET_STATIC_TYPE_FIELD(jshort, Short, false);
   2570 GET_STATIC_TYPE_FIELD(jint, Int, false);
   2571 GET_STATIC_TYPE_FIELD(jlong, Long, false);
   2572 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
   2573 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
   2574 
   2575 /*
   2576  * Set a static field.
   2577  */
   2578 #define SET_STATIC_TYPE_FIELD(_ctype, _jname, _isref)                       \
   2579     static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz,        \
   2580         jfieldID fieldID, _ctype value)                                     \
   2581     {                                                                       \
   2582         UNUSED_PARAMETER(jclazz);                                           \
   2583         JNI_ENTER();                                                        \
   2584         StaticField* sfield = (StaticField*) fieldID;                       \
   2585         if (_isref) {   /* only when _ctype==jobject */                     \
   2586             Object* valObj = dvmDecodeIndirectRef(env, (jobject)(u4)value); \
   2587             dvmSetStaticFieldObject(sfield, valObj);                        \
   2588         } else {                                                            \
   2589             dvmSetStaticField##_jname(sfield, value);                       \
   2590         }                                                                   \
   2591         JNI_EXIT();                                                         \
   2592     }
   2593 SET_STATIC_TYPE_FIELD(jobject, Object, true);
   2594 SET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
   2595 SET_STATIC_TYPE_FIELD(jbyte, Byte, false);
   2596 SET_STATIC_TYPE_FIELD(jchar, Char, false);
   2597 SET_STATIC_TYPE_FIELD(jshort, Short, false);
   2598 SET_STATIC_TYPE_FIELD(jint, Int, false);
   2599 SET_STATIC_TYPE_FIELD(jlong, Long, false);
   2600 SET_STATIC_TYPE_FIELD(jfloat, Float, false);
   2601 SET_STATIC_TYPE_FIELD(jdouble, Double, false);
   2602 
   2603 /*
   2604  * Get an instance field.
   2605  *
   2606  * If we get an object reference, add it to the local refs list.
   2607  */
   2608 #define GET_TYPE_FIELD(_ctype, _jname, _isref)                              \
   2609     static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj,             \
   2610         jfieldID fieldID)                                                   \
   2611     {                                                                       \
   2612         JNI_ENTER();                                                        \
   2613         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2614         InstField* field = (InstField*) fieldID;                            \
   2615         _ctype value;                                                       \
   2616         if (_isref) {   /* only when _ctype==jobject */                     \
   2617             Object* valObj = dvmGetFieldObject(obj, field->byteOffset);     \
   2618             value = (_ctype)(u4)addLocalReference(env, valObj);             \
   2619         } else {                                                            \
   2620             value = dvmGetField##_jname(obj, field->byteOffset);            \
   2621         }                                                                   \
   2622         JNI_EXIT();                                                         \
   2623         return value;                                                       \
   2624     }
   2625 GET_TYPE_FIELD(jobject, Object, true);
   2626 GET_TYPE_FIELD(jboolean, Boolean, false);
   2627 GET_TYPE_FIELD(jbyte, Byte, false);
   2628 GET_TYPE_FIELD(jchar, Char, false);
   2629 GET_TYPE_FIELD(jshort, Short, false);
   2630 GET_TYPE_FIELD(jint, Int, false);
   2631 GET_TYPE_FIELD(jlong, Long, false);
   2632 GET_TYPE_FIELD(jfloat, Float, false);
   2633 GET_TYPE_FIELD(jdouble, Double, false);
   2634 
   2635 /*
   2636  * Set an instance field.
   2637  */
   2638 #define SET_TYPE_FIELD(_ctype, _jname, _isref)                              \
   2639     static void Set##_jname##Field(JNIEnv* env, jobject jobj,               \
   2640         jfieldID fieldID, _ctype value)                                     \
   2641     {                                                                       \
   2642         JNI_ENTER();                                                        \
   2643         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2644         InstField* field = (InstField*) fieldID;                            \
   2645         if (_isref) {   /* only when _ctype==jobject */                     \
   2646             Object* valObj = dvmDecodeIndirectRef(env, (jobject)(u4)value); \
   2647             dvmSetFieldObject(obj, field->byteOffset, valObj);              \
   2648         } else {                                                            \
   2649             dvmSetField##_jname(obj, field->byteOffset, value);             \
   2650         }                                                                   \
   2651         JNI_EXIT();                                                         \
   2652     }
   2653 SET_TYPE_FIELD(jobject, Object, true);
   2654 SET_TYPE_FIELD(jboolean, Boolean, false);
   2655 SET_TYPE_FIELD(jbyte, Byte, false);
   2656 SET_TYPE_FIELD(jchar, Char, false);
   2657 SET_TYPE_FIELD(jshort, Short, false);
   2658 SET_TYPE_FIELD(jint, Int, false);
   2659 SET_TYPE_FIELD(jlong, Long, false);
   2660 SET_TYPE_FIELD(jfloat, Float, false);
   2661 SET_TYPE_FIELD(jdouble, Double, false);
   2662 
   2663 /*
   2664  * Make a virtual method call.
   2665  *
   2666  * Three versions (..., va_list, jvalue[]) for each return type.  If we're
   2667  * returning an Object, we have to add it to the local references table.
   2668  */
   2669 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref)              \
   2670     static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj,           \
   2671         jmethodID methodID, ...)                                            \
   2672     {                                                                       \
   2673         JNI_ENTER();                                                        \
   2674         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2675         const Method* meth;                                                 \
   2676         va_list args;                                                       \
   2677         JValue result;                                                      \
   2678         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   2679         if (meth == NULL) {                                                 \
   2680             JNI_EXIT();                                                     \
   2681             return _retfail;                                                \
   2682         }                                                                   \
   2683         va_start(args, methodID);                                           \
   2684         dvmCallMethodV(_self, meth, obj, true, &result, args);              \
   2685         va_end(args);                                                       \
   2686         if (_isref && !dvmCheckException(_self))                            \
   2687             result.l = addLocalReference(env, result.l);                    \
   2688         JNI_EXIT();                                                         \
   2689         return _retok;                                                      \
   2690     }                                                                       \
   2691     static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj,          \
   2692         jmethodID methodID, va_list args)                                   \
   2693     {                                                                       \
   2694         JNI_ENTER();                                                        \
   2695         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2696         const Method* meth;                                                 \
   2697         JValue result;                                                      \
   2698         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   2699         if (meth == NULL) {                                                 \
   2700             JNI_EXIT();                                                     \
   2701             return _retfail;                                                \
   2702         }                                                                   \
   2703         dvmCallMethodV(_self, meth, obj, true, &result, args);              \
   2704         if (_isref && !dvmCheckException(_self))                            \
   2705             result.l = addLocalReference(env, result.l);                    \
   2706         JNI_EXIT();                                                         \
   2707         return _retok;                                                      \
   2708     }                                                                       \
   2709     static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj,          \
   2710         jmethodID methodID, jvalue* args)                                   \
   2711     {                                                                       \
   2712         JNI_ENTER();                                                        \
   2713         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2714         const Method* meth;                                                 \
   2715         JValue result;                                                      \
   2716         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   2717         if (meth == NULL) {                                                 \
   2718             JNI_EXIT();                                                     \
   2719             return _retfail;                                                \
   2720         }                                                                   \
   2721         dvmCallMethodA(_self, meth, obj, true, &result, args);              \
   2722         if (_isref && !dvmCheckException(_self))                            \
   2723             result.l = addLocalReference(env, result.l);                    \
   2724         JNI_EXIT();                                                         \
   2725         return _retok;                                                      \
   2726     }
   2727 CALL_VIRTUAL(jobject, Object, NULL, result.l, true);
   2728 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
   2729 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
   2730 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
   2731 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
   2732 CALL_VIRTUAL(jint, Int, 0, result.i, false);
   2733 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
   2734 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
   2735 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
   2736 CALL_VIRTUAL(void, Void, , , false);
   2737 
   2738 /*
   2739  * Make a "non-virtual" method call.  We're still calling a virtual method,
   2740  * but this time we're not doing an indirection through the object's vtable.
   2741  * The "clazz" parameter defines which implementation of a method we want.
   2742  *
   2743  * Three versions (..., va_list, jvalue[]) for each return type.
   2744  */
   2745 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref)           \
   2746     static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
   2747         jclass jclazz, jmethodID methodID, ...)                             \
   2748     {                                                                       \
   2749         JNI_ENTER();                                                        \
   2750         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2751         ClassObject* clazz =                                                \
   2752             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2753         const Method* meth;                                                 \
   2754         va_list args;                                                       \
   2755         JValue result;                                                      \
   2756         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2757         if (meth == NULL) {                                                 \
   2758             JNI_EXIT();                                                     \
   2759             return _retfail;                                                \
   2760         }                                                                   \
   2761         va_start(args, methodID);                                           \
   2762         dvmCallMethodV(_self, meth, obj, true, &result, args);              \
   2763         if (_isref && !dvmCheckException(_self))                            \
   2764             result.l = addLocalReference(env, result.l);                    \
   2765         va_end(args);                                                       \
   2766         JNI_EXIT();                                                         \
   2767         return _retok;                                                      \
   2768     }                                                                       \
   2769     static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
   2770         jclass jclazz, jmethodID methodID, va_list args)                    \
   2771     {                                                                       \
   2772         JNI_ENTER();                                                        \
   2773         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2774         ClassObject* clazz =                                                \
   2775             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2776         const Method* meth;                                                 \
   2777         JValue result;                                                      \
   2778         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2779         if (meth == NULL) {                                                 \
   2780             JNI_EXIT();                                                     \
   2781             return _retfail;                                                \
   2782         }                                                                   \
   2783         dvmCallMethodV(_self, meth, obj, true, &result, args);              \
   2784         if (_isref && !dvmCheckException(_self))                            \
   2785             result.l = addLocalReference(env, result.l);                    \
   2786         JNI_EXIT();                                                         \
   2787         return _retok;                                                      \
   2788     }                                                                       \
   2789     static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
   2790         jclass jclazz, jmethodID methodID, jvalue* args)                    \
   2791     {                                                                       \
   2792         JNI_ENTER();                                                        \
   2793         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2794         ClassObject* clazz =                                                \
   2795             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2796         const Method* meth;                                                 \
   2797         JValue result;                                                      \
   2798         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2799         if (meth == NULL) {                                                 \
   2800             JNI_EXIT();                                                     \
   2801             return _retfail;                                                \
   2802         }                                                                   \
   2803         dvmCallMethodA(_self, meth, obj, true, &result, args);              \
   2804         if (_isref && !dvmCheckException(_self))                            \
   2805             result.l = addLocalReference(env, result.l);                    \
   2806         JNI_EXIT();                                                         \
   2807         return _retok;                                                      \
   2808     }
   2809 CALL_NONVIRTUAL(jobject, Object, NULL, result.l, true);
   2810 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
   2811 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
   2812 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
   2813 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
   2814 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
   2815 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
   2816 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
   2817 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
   2818 CALL_NONVIRTUAL(void, Void, , , false);
   2819 
   2820 
   2821 /*
   2822  * Call a static method.
   2823  */
   2824 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref)               \
   2825     static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,    \
   2826         jmethodID methodID, ...)                                            \
   2827     {                                                                       \
   2828         UNUSED_PARAMETER(jclazz);                                           \
   2829         JNI_ENTER();                                                        \
   2830         JValue result;                                                      \
   2831         va_list args;                                                       \
   2832         va_start(args, methodID);                                           \
   2833         dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
   2834         va_end(args);                                                       \
   2835         if (_isref && !dvmCheckException(_self))                            \
   2836             result.l = addLocalReference(env, result.l);                    \
   2837         JNI_EXIT();                                                         \
   2838         return _retok;                                                      \
   2839     }                                                                       \
   2840     static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,   \
   2841         jmethodID methodID, va_list args)                                   \
   2842     {                                                                       \
   2843         UNUSED_PARAMETER(jclazz);                                           \
   2844         JNI_ENTER();                                                        \
   2845         JValue result;                                                      \
   2846         dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
   2847         if (_isref && !dvmCheckException(_self))                            \
   2848             result.l = addLocalReference(env, result.l);                    \
   2849         JNI_EXIT();                                                         \
   2850         return _retok;                                                      \
   2851     }                                                                       \
   2852     static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,   \
   2853         jmethodID methodID, jvalue* args)                                   \
   2854     {                                                                       \
   2855         UNUSED_PARAMETER(jclazz);                                           \
   2856         JNI_ENTER();                                                        \
   2857         JValue result;                                                      \
   2858         dvmCallMethodA(_self, (Method*)methodID, NULL, true, &result, args);\
   2859         if (_isref && !dvmCheckException(_self))                            \
   2860             result.l = addLocalReference(env, result.l);                    \
   2861         JNI_EXIT();                                                         \
   2862         return _retok;                                                      \
   2863     }
   2864 CALL_STATIC(jobject, Object, NULL, result.l, true);
   2865 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
   2866 CALL_STATIC(jbyte, Byte, 0, result.b, false);
   2867 CALL_STATIC(jchar, Char, 0, result.c, false);
   2868 CALL_STATIC(jshort, Short, 0, result.s, false);
   2869 CALL_STATIC(jint, Int, 0, result.i, false);
   2870 CALL_STATIC(jlong, Long, 0, result.j, false);
   2871 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
   2872 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
   2873 CALL_STATIC(void, Void, , , false);
   2874 
   2875 /*
   2876  * Create a new String from Unicode data.
   2877  *
   2878  * If "len" is zero, we will return an empty string even if "unicodeChars"
   2879  * is NULL.  (The JNI spec is vague here.)
   2880  */
   2881 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len)
   2882 {
   2883     JNI_ENTER();
   2884     jobject retval;
   2885 
   2886     StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
   2887     if (jstr == NULL) {
   2888         retval = NULL;
   2889     } else {
   2890         dvmReleaseTrackedAlloc((Object*) jstr, NULL);
   2891         retval = addLocalReference(env, (Object*) jstr);
   2892     }
   2893 
   2894     JNI_EXIT();
   2895     return retval;
   2896 }
   2897 
   2898 /*
   2899  * Return the length of a String in Unicode character units.
   2900  */
   2901 static jsize GetStringLength(JNIEnv* env, jstring jstr)
   2902 {
   2903     JNI_ENTER();
   2904 
   2905     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2906     jsize len = dvmStringLen(strObj);
   2907 
   2908     JNI_EXIT();
   2909     return len;
   2910 }
   2911 
   2912 
   2913 /*
   2914  * Get a string's character data.
   2915  *
   2916  * The result is guaranteed to be valid until ReleaseStringChars is
   2917  * called, which means we have to pin it or return a copy.
   2918  */
   2919 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy)
   2920 {
   2921     JNI_ENTER();
   2922 
   2923     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2924     ArrayObject* strChars = dvmStringCharArray(strObj);
   2925 
   2926     pinPrimitiveArray(strChars);
   2927 
   2928     const u2* data = dvmStringChars(strObj);
   2929     if (isCopy != NULL)
   2930         *isCopy = JNI_FALSE;
   2931 
   2932     JNI_EXIT();
   2933     return (jchar*)data;
   2934 }
   2935 
   2936 /*
   2937  * Release our grip on some characters from a string.
   2938  */
   2939 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars)
   2940 {
   2941     JNI_ENTER();
   2942     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2943     ArrayObject* strChars = dvmStringCharArray(strObj);
   2944     unpinPrimitiveArray(strChars);
   2945     JNI_EXIT();
   2946 }
   2947 
   2948 /*
   2949  * Create a new java.lang.String object from chars in modified UTF-8 form.
   2950  *
   2951  * The spec doesn't say how to handle a NULL string.  Popular desktop VMs
   2952  * accept it and return a NULL pointer in response.
   2953  */
   2954 static jstring NewStringUTF(JNIEnv* env, const char* bytes)
   2955 {
   2956     JNI_ENTER();
   2957 
   2958     jstring result;
   2959 
   2960     if (bytes == NULL) {
   2961         result = NULL;
   2962     } else {
   2963         /* note newStr could come back NULL on OOM */
   2964         StringObject* newStr = dvmCreateStringFromCstr(bytes, ALLOC_DEFAULT);
   2965         result = addLocalReference(env, (Object*) newStr);
   2966         dvmReleaseTrackedAlloc((Object*)newStr, NULL);
   2967     }
   2968 
   2969     JNI_EXIT();
   2970     return result;
   2971 }
   2972 
   2973 /*
   2974  * Return the length in bytes of the modified UTF-8 form of the string.
   2975  */
   2976 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr)
   2977 {
   2978     JNI_ENTER();
   2979 
   2980     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2981     jsize len = dvmStringUtf8ByteLen(strObj);
   2982 
   2983     JNI_EXIT();
   2984     return len;
   2985 }
   2986 
   2987 /*
   2988  * Convert "string" to modified UTF-8 and return a pointer.  The returned
   2989  * value must be released with ReleaseStringUTFChars.
   2990  *
   2991  * According to the JNI reference, "Returns a pointer to a UTF-8 string,
   2992  * or NULL if the operation fails. Returns NULL if and only if an invocation
   2993  * of this function has thrown an exception."
   2994  *
   2995  * The behavior here currently follows that of other open-source VMs, which
   2996  * quietly return NULL if "string" is NULL.  We should consider throwing an
   2997  * NPE.  (The CheckJNI code blows up if you try to pass in a NULL string,
   2998  * which should catch this sort of thing during development.)  Certain other
   2999  * VMs will crash with a segmentation fault.
   3000  */
   3001 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr,
   3002     jboolean* isCopy)
   3003 {
   3004     JNI_ENTER();
   3005     char* newStr;
   3006 
   3007     if (jstr == NULL) {
   3008         /* this shouldn't happen; throw NPE? */
   3009         newStr = NULL;
   3010     } else {
   3011         if (isCopy != NULL)
   3012             *isCopy = JNI_TRUE;
   3013 
   3014         StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3015         newStr = dvmCreateCstrFromString(strObj);
   3016         if (newStr == NULL) {
   3017             /* assume memory failure */
   3018             dvmThrowException("Ljava/lang/OutOfMemoryError;",
   3019                 "native heap string alloc failed");
   3020         }
   3021     }
   3022 
   3023     JNI_EXIT();
   3024     return newStr;
   3025 }
   3026 
   3027 /*
   3028  * Release a string created by GetStringUTFChars().
   3029  */
   3030 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf)
   3031 {
   3032     JNI_ENTER();
   3033     free((char*)utf);
   3034     JNI_EXIT();
   3035 }
   3036 
   3037 /*
   3038  * Return the capacity of the array.
   3039  */
   3040 static jsize GetArrayLength(JNIEnv* env, jarray jarr)
   3041 {
   3042     JNI_ENTER();
   3043 
   3044     ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3045     jsize length = arrObj->length;
   3046 
   3047     JNI_EXIT();
   3048     return length;
   3049 }
   3050 
   3051 /*
   3052  * Construct a new array that holds objects from class "elementClass".
   3053  */
   3054 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
   3055     jclass jelementClass, jobject jinitialElement)
   3056 {
   3057     JNI_ENTER();
   3058 
   3059     jobjectArray newArray = NULL;
   3060     ClassObject* elemClassObj =
   3061         (ClassObject*) dvmDecodeIndirectRef(env, jelementClass);
   3062 
   3063     if (elemClassObj == NULL) {
   3064         dvmThrowException("Ljava/lang/NullPointerException;",
   3065             "JNI NewObjectArray");
   3066         goto bail;
   3067     }
   3068 
   3069     ArrayObject* newObj =
   3070         dvmAllocObjectArray(elemClassObj, length, ALLOC_DEFAULT);
   3071     if (newObj == NULL) {
   3072         assert(dvmCheckException(_self));
   3073         goto bail;
   3074     }
   3075     newArray = addLocalReference(env, (Object*) newObj);
   3076     dvmReleaseTrackedAlloc((Object*) newObj, NULL);
   3077 
   3078     /*
   3079      * Initialize the array.  Trashes "length".
   3080      */
   3081     if (jinitialElement != NULL) {
   3082         Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement);
   3083         Object** arrayData = (Object**) newObj->contents;
   3084 
   3085         while (length--)
   3086             *arrayData++ = initialElement;
   3087     }
   3088 
   3089 
   3090 bail:
   3091     JNI_EXIT();
   3092     return newArray;
   3093 }
   3094 
   3095 /*
   3096  * Get one element of an Object array.
   3097  *
   3098  * Add the object to the local references table in case the array goes away.
   3099  */
   3100 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
   3101     jsize index)
   3102 {
   3103     JNI_ENTER();
   3104 
   3105     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3106     jobject retval = NULL;
   3107 
   3108     assert(arrayObj != NULL);
   3109 
   3110     /* check the array bounds */
   3111     if (index < 0 || index >= (int) arrayObj->length) {
   3112         dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
   3113             arrayObj->obj.clazz->descriptor);
   3114         goto bail;
   3115     }
   3116 
   3117     Object* value = ((Object**) arrayObj->contents)[index];
   3118     retval = addLocalReference(env, value);
   3119 
   3120 bail:
   3121     JNI_EXIT();
   3122     return retval;
   3123 }
   3124 
   3125 /*
   3126  * Set one element of an Object array.
   3127  */
   3128 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
   3129     jsize index, jobject jobj)
   3130 {
   3131     JNI_ENTER();
   3132 
   3133     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3134 
   3135     assert(arrayObj != NULL);
   3136 
   3137     /* check the array bounds */
   3138     if (index < 0 || index >= (int) arrayObj->length) {
   3139         dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
   3140             arrayObj->obj.clazz->descriptor);
   3141         goto bail;
   3142     }
   3143 
   3144     //LOGV("JNI: set element %d in array %p to %p\n", index, array, value);
   3145 
   3146     Object* obj = dvmDecodeIndirectRef(env, jobj);
   3147     ((Object**) arrayObj->contents)[index] = obj;
   3148 
   3149 bail:
   3150     JNI_EXIT();
   3151 }
   3152 
   3153 /*
   3154  * Create a new array of primitive elements.
   3155  */
   3156 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar)                     \
   3157     static _artype New##_jname##Array(JNIEnv* env, jsize length)            \
   3158     {                                                                       \
   3159         JNI_ENTER();                                                        \
   3160         ArrayObject* arrayObj;                                              \
   3161         arrayObj = dvmAllocPrimitiveArray(_typechar, length,                \
   3162             ALLOC_DEFAULT);                                                 \
   3163         jarray jarr = NULL;                                                 \
   3164         if (arrayObj != NULL) {                                             \
   3165             jarr = addLocalReference(env, (Object*) arrayObj);              \
   3166             dvmReleaseTrackedAlloc((Object*) arrayObj, NULL);               \
   3167         }                                                                   \
   3168         JNI_EXIT();                                                         \
   3169         return (_artype)jarr;                                               \
   3170     }
   3171 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
   3172 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
   3173 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
   3174 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
   3175 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
   3176 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
   3177 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
   3178 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
   3179 
   3180 /*
   3181  * Get a pointer to a C array of primitive elements from an array object
   3182  * of the matching type.
   3183  *
   3184  * In a compacting GC, we either need to return a copy of the elements or
   3185  * "pin" the memory.  Otherwise we run the risk of native code using the
   3186  * buffer as the destination of e.g. a blocking read() call that wakes up
   3187  * during a GC.
   3188  */
   3189 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                        \
   3190     static _ctype* Get##_jname##ArrayElements(JNIEnv* env,                  \
   3191         _ctype##Array jarr, jboolean* isCopy)                               \
   3192     {                                                                       \
   3193         JNI_ENTER();                                                        \
   3194         _ctype* data;                                                       \
   3195         ArrayObject* arrayObj =                                             \
   3196             (ArrayObject*) dvmDecodeIndirectRef(env, jarr);                 \
   3197         pinPrimitiveArray(arrayObj);                                        \
   3198         data = (_ctype*) arrayObj->contents;                                \
   3199         if (isCopy != NULL)                                                 \
   3200             *isCopy = JNI_FALSE;                                            \
   3201         JNI_EXIT();                                                         \
   3202         return data;                                                        \
   3203     }
   3204 
   3205 /*
   3206  * Release the storage locked down by the "get" function.
   3207  *
   3208  * The spec says, "'mode' has no effect if 'elems' is not a copy of the
   3209  * elements in 'array'."  They apparently did not anticipate the need to
   3210  * un-pin memory.
   3211  */
   3212 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                    \
   3213     static void Release##_jname##ArrayElements(JNIEnv* env,                 \
   3214         _ctype##Array jarr, _ctype* elems, jint mode)                       \
   3215     {                                                                       \
   3216         UNUSED_PARAMETER(elems);                                            \
   3217         JNI_ENTER();                                                        \
   3218         if (mode != JNI_COMMIT) {                                           \
   3219             ArrayObject* arrayObj =                                         \
   3220                 (ArrayObject*) dvmDecodeIndirectRef(env, jarr);             \
   3221             unpinPrimitiveArray(arrayObj);                                  \
   3222         }                                                                   \
   3223         JNI_EXIT();                                                         \
   3224     }
   3225 
   3226 /*
   3227  * Copy a section of a primitive array to a buffer.
   3228  */
   3229 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname)                          \
   3230     static void Get##_jname##ArrayRegion(JNIEnv* env,                       \
   3231         _ctype##Array jarr, jsize start, jsize len, _ctype* buf)            \
   3232     {                                                                       \
   3233         JNI_ENTER();                                                        \
   3234         ArrayObject* arrayObj =                                             \
   3235             (ArrayObject*) dvmDecodeIndirectRef(env, jarr);                 \
   3236         _ctype* data = (_ctype*) arrayObj->contents;                        \
   3237         if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
   3238             dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
   3239                 arrayObj->obj.clazz->descriptor);                           \
   3240         } else {                                                            \
   3241             memcpy(buf, data + start, len * sizeof(_ctype));                \
   3242         }                                                                   \
   3243         JNI_EXIT();                                                         \
   3244     }
   3245 
   3246 /*
   3247  * Copy a section of a primitive array to a buffer.
   3248  */
   3249 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname)                          \
   3250     static void Set##_jname##ArrayRegion(JNIEnv* env,                       \
   3251         _ctype##Array jarr, jsize start, jsize len, const _ctype* buf)      \
   3252     {                                                                       \
   3253         JNI_ENTER();                                                        \
   3254         ArrayObject* arrayObj =                                             \
   3255             (ArrayObject*) dvmDecodeIndirectRef(env, jarr);                 \
   3256         _ctype* data = (_ctype*) arrayObj->contents;                        \
   3257         if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
   3258             dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
   3259                 arrayObj->obj.clazz->descriptor);                           \
   3260         } else {                                                            \
   3261             memcpy(data + start, buf, len * sizeof(_ctype));                \
   3262         }                                                                   \
   3263         JNI_EXIT();                                                         \
   3264     }
   3265 
   3266 /*
   3267  * 4-in-1:
   3268  *  Get<Type>ArrayElements
   3269  *  Release<Type>ArrayElements
   3270  *  Get<Type>ArrayRegion
   3271  *  Set<Type>ArrayRegion
   3272  */
   3273 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname)                           \
   3274     GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                           \
   3275     RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                       \
   3276     GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);                             \
   3277     SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
   3278 
   3279 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
   3280 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
   3281 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
   3282 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
   3283 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
   3284 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
   3285 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
   3286 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
   3287 
   3288 /*
   3289  * Register one or more native functions in one class.
   3290  */
   3291 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
   3292     const JNINativeMethod* methods, jint nMethods)
   3293 {
   3294     JNI_ENTER();
   3295 
   3296     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   3297     jint retval = JNI_OK;
   3298     int i;
   3299 
   3300     if (gDvm.verboseJni) {
   3301         LOGI("[Registering JNI native methods for class %s]\n",
   3302             clazz->descriptor);
   3303     }
   3304 
   3305     for (i = 0; i < nMethods; i++) {
   3306         if (!dvmRegisterJNIMethod(clazz, methods[i].name,
   3307                 methods[i].signature, methods[i].fnPtr))
   3308         {
   3309             retval = JNI_ERR;
   3310         }
   3311     }
   3312 
   3313     JNI_EXIT();
   3314     return retval;
   3315 }
   3316 
   3317 /*
   3318  * Un-register a native function.
   3319  */
   3320 static jint UnregisterNatives(JNIEnv* env, jclass jclazz)
   3321 {
   3322     JNI_ENTER();
   3323     /*
   3324      * The JNI docs refer to this as a way to reload/relink native libraries,
   3325      * and say it "should not be used in normal native code".
   3326      *
   3327      * We can implement it if we decide we need it.
   3328      */
   3329     JNI_EXIT();
   3330     return JNI_ERR;
   3331 }
   3332 
   3333 /*
   3334  * Lock the monitor.
   3335  *
   3336  * We have to track all monitor enters and exits, so that we can undo any
   3337  * outstanding synchronization before the thread exits.
   3338  */
   3339 static jint MonitorEnter(JNIEnv* env, jobject jobj)
   3340 {
   3341     JNI_ENTER();
   3342     Object* obj = dvmDecodeIndirectRef(env, jobj);
   3343     dvmLockObject(_self, obj);
   3344     trackMonitorEnter(_self, obj);
   3345     JNI_EXIT();
   3346     return JNI_OK;
   3347 }
   3348 
   3349 /*
   3350  * Unlock the monitor.
   3351  *
   3352  * Throws an IllegalMonitorStateException if the current thread
   3353  * doesn't own the monitor.  (dvmUnlockObject() takes care of the throw.)
   3354  *
   3355  * According to the 1.6 spec, it's legal to call here with an exception
   3356  * pending.  If this fails, we'll stomp the original exception.
   3357  */
   3358 static jint MonitorExit(JNIEnv* env, jobject jobj)
   3359 {
   3360     JNI_ENTER();
   3361     Object* obj = dvmDecodeIndirectRef(env, jobj);
   3362     bool success = dvmUnlockObject(_self, obj);
   3363     if (success)
   3364         trackMonitorExit(_self, obj);
   3365     JNI_EXIT();
   3366     return success ? JNI_OK : JNI_ERR;
   3367 }
   3368 
   3369 /*
   3370  * Return the JavaVM interface associated with the current thread.
   3371  */
   3372 static jint GetJavaVM(JNIEnv* env, JavaVM** vm)
   3373 {
   3374     JNI_ENTER();
   3375     //*vm = gDvm.vmList;
   3376     *vm = (JavaVM*) ((JNIEnvExt*)env)->vm;
   3377     JNI_EXIT();
   3378     if (*vm == NULL)
   3379         return JNI_ERR;
   3380     else
   3381         return JNI_OK;
   3382 }
   3383 
   3384 /*
   3385  * Copies "len" Unicode characters, from offset "start".
   3386  */
   3387 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len,
   3388     jchar* buf)
   3389 {
   3390     JNI_ENTER();
   3391     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3392     if (start + len > dvmStringLen(strObj))
   3393         dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
   3394     else
   3395         memcpy(buf, dvmStringChars(strObj) + start, len * sizeof(u2));
   3396     JNI_EXIT();
   3397 }
   3398 
   3399 /*
   3400  * Translates "len" Unicode characters, from offset "start", into
   3401  * modified UTF-8 encoding.
   3402  */
   3403 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start,
   3404     jsize len, char* buf)
   3405 {
   3406     JNI_ENTER();
   3407     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3408     if (start + len > dvmStringLen(strObj))
   3409         dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
   3410     else
   3411         dvmCreateCstrFromStringRegion(strObj, start, len, buf);
   3412     JNI_EXIT();
   3413 }
   3414 
   3415 /*
   3416  * Get a raw pointer to array data.
   3417  *
   3418  * The caller is expected to call "release" before doing any JNI calls
   3419  * or blocking I/O operations.
   3420  *
   3421  * We need to pin the memory or block GC.
   3422  */
   3423 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr,
   3424     jboolean* isCopy)
   3425 {
   3426     JNI_ENTER();
   3427     void* data;
   3428     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3429     pinPrimitiveArray(arrayObj);
   3430     data = arrayObj->contents;
   3431     if (isCopy != NULL)
   3432         *isCopy = JNI_FALSE;
   3433     JNI_EXIT();
   3434     return data;
   3435 }
   3436 
   3437 /*
   3438  * Release an array obtained with GetPrimitiveArrayCritical.
   3439  */
   3440 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr,
   3441     void* carray, jint mode)
   3442 {
   3443     JNI_ENTER();
   3444     if (mode != JNI_COMMIT) {
   3445         ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3446         unpinPrimitiveArray(arrayObj);
   3447     }
   3448     JNI_EXIT();
   3449 }
   3450 
   3451 /*
   3452  * Like GetStringChars, but with restricted use.
   3453  */
   3454 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr,
   3455     jboolean* isCopy)
   3456 {
   3457     JNI_ENTER();
   3458     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3459     ArrayObject* strChars = dvmStringCharArray(strObj);
   3460 
   3461     pinPrimitiveArray(strChars);
   3462 
   3463     const u2* data = dvmStringChars(strObj);
   3464     if (isCopy != NULL)
   3465         *isCopy = JNI_FALSE;
   3466 
   3467     JNI_EXIT();
   3468     return (jchar*)data;
   3469 }
   3470 
   3471 /*
   3472  * Like ReleaseStringChars, but with restricted use.
   3473  */
   3474 static void ReleaseStringCritical(JNIEnv* env, jstring jstr,
   3475     const jchar* carray)
   3476 {
   3477     JNI_ENTER();
   3478     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3479     ArrayObject* strChars = dvmStringCharArray(strObj);
   3480     unpinPrimitiveArray(strChars);
   3481     JNI_EXIT();
   3482 }
   3483 
   3484 /*
   3485  * Create a new weak global reference.
   3486  */
   3487 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj)
   3488 {
   3489     JNI_ENTER();
   3490     jweak wref = createWeakGlobalRef(env, obj);
   3491     JNI_EXIT();
   3492     return wref;
   3493 }
   3494 
   3495 /*
   3496  * Delete the specified weak global reference.
   3497  */
   3498 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref)
   3499 {
   3500     JNI_ENTER();
   3501     deleteWeakGlobalRef(env, wref);
   3502     JNI_EXIT();
   3503 }
   3504 
   3505 /*
   3506  * Quick check for pending exceptions.
   3507  *
   3508  * TODO: we should be able to skip the enter/exit macros here.
   3509  */
   3510 static jboolean ExceptionCheck(JNIEnv* env)
   3511 {
   3512     JNI_ENTER();
   3513     bool result = dvmCheckException(_self);
   3514     JNI_EXIT();
   3515     return result;
   3516 }
   3517 
   3518 /*
   3519  * Returns the type of the object referred to by "obj".  It can be local,
   3520  * global, or weak global.
   3521  *
   3522  * In the current implementation, references can be global and local at
   3523  * the same time, so while the return value is accurate it may not tell
   3524  * the whole story.
   3525  */
   3526 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj)
   3527 {
   3528     JNI_ENTER();
   3529     jobjectRefType type = dvmGetJNIRefType(env, jobj);
   3530     JNI_EXIT();
   3531     return type;
   3532 }
   3533 
   3534 /*
   3535  * Allocate and return a new java.nio.ByteBuffer for this block of memory.
   3536  *
   3537  * "address" may not be NULL, and "capacity" must be > 0.  (These are only
   3538  * verified when CheckJNI is enabled.)
   3539  */
   3540 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)
   3541 {
   3542     JNI_ENTER();
   3543 
   3544     Thread* self = _self /*dvmThreadSelf()*/;
   3545     Object* platformAddress = NULL;
   3546     JValue callResult;
   3547     jobject result = NULL;
   3548     ClassObject* tmpClazz;
   3549 
   3550     tmpClazz = gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on->clazz;
   3551     if (!dvmIsClassInitialized(tmpClazz) && !dvmInitClass(tmpClazz))
   3552         goto bail;
   3553 
   3554     /* get an instance of PlatformAddress that wraps the provided address */
   3555     dvmCallMethod(self,
   3556         gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on,
   3557         NULL, &callResult, address);
   3558     if (dvmGetException(self) != NULL || callResult.l == NULL)
   3559         goto bail;
   3560 
   3561     /* don't let the GC discard it */
   3562     platformAddress = (Object*) callResult.l;
   3563     dvmAddTrackedAlloc(platformAddress, self);
   3564     LOGV("tracking %p for address=%p\n", platformAddress, address);
   3565 
   3566     /* create an instance of java.nio.ReadWriteDirectByteBuffer */
   3567     tmpClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
   3568     if (!dvmIsClassInitialized(tmpClazz) && !dvmInitClass(tmpClazz))
   3569         goto bail;
   3570     Object* newObj = dvmAllocObject(tmpClazz, ALLOC_DONT_TRACK);
   3571     if (newObj != NULL) {
   3572         /* call the (PlatformAddress, int, int) constructor */
   3573         result = addLocalReference(env, newObj);
   3574         dvmCallMethod(self, gDvm.methJavaNioReadWriteDirectByteBuffer_init,
   3575             newObj, &callResult, platformAddress, (jint) capacity, (jint) 0);
   3576         if (dvmGetException(self) != NULL) {
   3577             deleteLocalReference(env, result);
   3578             result = NULL;
   3579             goto bail;
   3580         }
   3581     }
   3582 
   3583 bail:
   3584     if (platformAddress != NULL)
   3585         dvmReleaseTrackedAlloc(platformAddress, self);
   3586     JNI_EXIT();
   3587     return result;
   3588 }
   3589 
   3590 /*
   3591  * Get the starting address of the buffer for the specified java.nio.Buffer.
   3592  *
   3593  * If this is not a "direct" buffer, we return NULL.
   3594  */
   3595 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf)
   3596 {
   3597     JNI_ENTER();
   3598 
   3599     Object* bufObj = dvmDecodeIndirectRef(env, jbuf);
   3600     Thread* self = _self /*dvmThreadSelf()*/;
   3601     void* result;
   3602 
   3603     /*
   3604      * All Buffer objects have an effectiveDirectAddress field.  If it's
   3605      * nonzero, we can just return that value.  If not, we have to call
   3606      * through DirectBuffer.getEffectiveAddress(), which as a side-effect
   3607      * will set the effectiveDirectAddress field for direct buffers (and
   3608      * things that wrap direct buffers).
   3609      */
   3610     result = (void*) dvmGetFieldInt(bufObj,
   3611             gDvm.offJavaNioBuffer_effectiveDirectAddress);
   3612     if (result != NULL) {
   3613         //LOGI("fast path for %p\n", buf);
   3614         goto bail;
   3615     }
   3616 
   3617     /*
   3618      * Start by determining if the object supports the DirectBuffer
   3619      * interfaces.  Note this does not guarantee that it's a direct buffer.
   3620      */
   3621     if (!dvmInstanceof(bufObj->clazz,
   3622             gDvm.classOrgApacheHarmonyNioInternalDirectBuffer))
   3623     {
   3624         goto bail;
   3625     }
   3626 
   3627     /*
   3628      * Get a PlatformAddress object with the effective address.
   3629      *
   3630      * If this isn't a direct buffer, the result will be NULL and/or an
   3631      * exception will have been thrown.
   3632      */
   3633     JValue callResult;
   3634     const Method* meth = dvmGetVirtualizedMethod(bufObj->clazz,
   3635         gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress);
   3636     dvmCallMethodA(self, meth, bufObj, false, &callResult, NULL);
   3637     if (dvmGetException(self) != NULL) {
   3638         dvmClearException(self);
   3639         callResult.l = NULL;
   3640     }
   3641 
   3642     Object* platformAddr = callResult.l;
   3643     if (platformAddr == NULL) {
   3644         LOGV("Got request for address of non-direct buffer\n");
   3645         goto bail;
   3646     }
   3647 
   3648     /*
   3649      * Extract the address from the PlatformAddress object.  Instead of
   3650      * calling the toLong() method, just grab the field directly.  This
   3651      * is faster but more fragile.
   3652      */
   3653     result = (void*) dvmGetFieldInt(platformAddr,
   3654                 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr);
   3655 
   3656     //LOGI("slow path for %p --> %p\n", buf, result);
   3657 
   3658 bail:
   3659     JNI_EXIT();
   3660     return result;
   3661 }
   3662 
   3663 /*
   3664  * Get the capacity of the buffer for the specified java.nio.Buffer.
   3665  *
   3666  * Returns -1 if the object is not a direct buffer.  (We actually skip
   3667  * this check, since it's expensive to determine, and just return the
   3668  * capacity regardless.)
   3669  */
   3670 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf)
   3671 {
   3672     JNI_ENTER();
   3673 
   3674     /*
   3675      * The capacity is always in the Buffer.capacity field.
   3676      *
   3677      * (The "check" version should verify that this is actually a Buffer,
   3678      * but we're not required to do so here.)
   3679      */
   3680     Object* buf = dvmDecodeIndirectRef(env, jbuf);
   3681     jlong result = dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
   3682 
   3683     JNI_EXIT();
   3684     return result;
   3685 }
   3686 
   3687 
   3688 /*
   3689  * ===========================================================================
   3690  *      JNI invocation functions
   3691  * ===========================================================================
   3692  */
   3693 
   3694 /*
   3695  * Handle AttachCurrentThread{AsDaemon}.
   3696  *
   3697  * We need to make sure the VM is actually running.  For example, if we start
   3698  * up, issue an Attach, and the VM exits almost immediately, by the time the
   3699  * attaching happens the VM could already be shutting down.
   3700  *
   3701  * It's hard to avoid a race condition here because we don't want to hold
   3702  * a lock across the entire operation.  What we can do is temporarily
   3703  * increment the thread count to prevent a VM exit.
   3704  *
   3705  * This could potentially still have problems if a daemon thread calls here
   3706  * while the VM is shutting down.  dvmThreadSelf() will work, since it just
   3707  * uses pthread TLS, but dereferencing "vm" could fail.  Such is life when
   3708  * you shut down a VM while threads are still running inside it.
   3709  *
   3710  * Remember that some code may call this as a way to find the per-thread
   3711  * JNIEnv pointer.  Don't do excess work for that case.
   3712  */
   3713 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args,
   3714     bool isDaemon)
   3715 {
   3716     JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
   3717     Thread* self;
   3718     bool result = false;
   3719 
   3720     /*
   3721      * Return immediately if we're already one with the VM.
   3722      */
   3723     self = dvmThreadSelf();
   3724     if (self != NULL) {
   3725         *p_env = self->jniEnv;
   3726         return JNI_OK;
   3727     }
   3728 
   3729     /*
   3730      * No threads allowed in zygote mode.
   3731      */
   3732     if (gDvm.zygote) {
   3733         return JNI_ERR;
   3734     }
   3735 
   3736     /* increment the count to keep the VM from bailing while we run */
   3737     dvmLockThreadList(NULL);
   3738     if (gDvm.nonDaemonThreadCount == 0) {
   3739         // dead or dying
   3740         LOGV("Refusing to attach thread '%s' -- VM is shutting down\n",
   3741             (thr_args == NULL) ? "(unknown)" : args->name);
   3742         dvmUnlockThreadList();
   3743         return JNI_ERR;
   3744     }
   3745     gDvm.nonDaemonThreadCount++;
   3746     dvmUnlockThreadList();
   3747 
   3748     /* tweak the JavaVMAttachArgs as needed */
   3749     JavaVMAttachArgs argsCopy;
   3750     if (args == NULL) {
   3751         /* allow the v1.1 calling convention */
   3752         argsCopy.version = JNI_VERSION_1_2;
   3753         argsCopy.name = NULL;
   3754         argsCopy.group = dvmGetMainThreadGroup();
   3755     } else {
   3756         assert(args->version >= JNI_VERSION_1_2);
   3757 
   3758         argsCopy.version = args->version;
   3759         argsCopy.name = args->name;
   3760         if (args->group != NULL)
   3761             argsCopy.group = args->group;
   3762         else
   3763             argsCopy.group = dvmGetMainThreadGroup();
   3764     }
   3765 
   3766     result = dvmAttachCurrentThread(&argsCopy, isDaemon);
   3767 
   3768     /* restore the count */
   3769     dvmLockThreadList(NULL);
   3770     gDvm.nonDaemonThreadCount--;
   3771     dvmUnlockThreadList();
   3772 
   3773     /*
   3774      * Change the status to indicate that we're out in native code.  This
   3775      * call is not guarded with state-change macros, so we have to do it
   3776      * by hand.
   3777      */
   3778     if (result) {
   3779         self = dvmThreadSelf();
   3780         assert(self != NULL);
   3781         dvmChangeStatus(self, THREAD_NATIVE);
   3782         *p_env = self->jniEnv;
   3783         return JNI_OK;
   3784     } else {
   3785         return JNI_ERR;
   3786     }
   3787 }
   3788 
   3789 /*
   3790  * Attach the current thread to the VM.  If the thread is already attached,
   3791  * this is a no-op.
   3792  */
   3793 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args)
   3794 {
   3795     return attachThread(vm, p_env, thr_args, false);
   3796 }
   3797 
   3798 /*
   3799  * Like AttachCurrentThread, but set the "daemon" flag.
   3800  */
   3801 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env,
   3802     void* thr_args)
   3803 {
   3804     return attachThread(vm, p_env, thr_args, true);
   3805 }
   3806 
   3807 /*
   3808  * Dissociate the current thread from the VM.
   3809  */
   3810 static jint DetachCurrentThread(JavaVM* vm)
   3811 {
   3812     Thread* self = dvmThreadSelf();
   3813 
   3814     if (self == NULL)               /* not attached, can't do anything */
   3815         return JNI_ERR;
   3816 
   3817     /* switch to "running" to check for suspension */
   3818     dvmChangeStatus(self, THREAD_RUNNING);
   3819 
   3820     /* detach the thread */
   3821     dvmDetachCurrentThread();
   3822 
   3823     /* (no need to change status back -- we have no status) */
   3824     return JNI_OK;
   3825 }
   3826 
   3827 /*
   3828  * If current thread is attached to VM, return the associated JNIEnv.
   3829  * Otherwise, stuff NULL in and return JNI_EDETACHED.
   3830  *
   3831  * JVMTI overloads this by specifying a magic value for "version", so we
   3832  * do want to check that here.
   3833  */
   3834 static jint GetEnv(JavaVM* vm, void** env, jint version)
   3835 {
   3836     Thread* self = dvmThreadSelf();
   3837 
   3838     if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6)
   3839         return JNI_EVERSION;
   3840 
   3841     if (self == NULL) {
   3842         *env = NULL;
   3843     } else {
   3844         /* TODO: status change is probably unnecessary */
   3845         dvmChangeStatus(self, THREAD_RUNNING);
   3846         *env = (void*) dvmGetThreadJNIEnv(self);
   3847         dvmChangeStatus(self, THREAD_NATIVE);
   3848     }
   3849     if (*env == NULL)
   3850         return JNI_EDETACHED;
   3851     else
   3852         return JNI_OK;
   3853 }
   3854 
   3855 /*
   3856  * Destroy the VM.  This may be called from any thread.
   3857  *
   3858  * If the current thread is attached, wait until the current thread is
   3859  * the only non-daemon user-level thread.  If the current thread is not
   3860  * attached, we attach it and do the processing as usual.  (If the attach
   3861  * fails, it's probably because all the non-daemon threads have already
   3862  * exited and the VM doesn't want to let us back in.)
   3863  *
   3864  * TODO: we don't really deal with the situation where more than one thread
   3865  * has called here.  One thread wins, the other stays trapped waiting on
   3866  * the condition variable forever.  Not sure this situation is interesting
   3867  * in real life.
   3868  */
   3869 static jint DestroyJavaVM(JavaVM* vm)
   3870 {
   3871     JavaVMExt* ext = (JavaVMExt*) vm;
   3872     Thread* self;
   3873 
   3874     if (ext == NULL)
   3875         return JNI_ERR;
   3876 
   3877     if (gDvm.verboseShutdown)
   3878         LOGD("DestroyJavaVM waiting for non-daemon threads to exit\n");
   3879 
   3880     /*
   3881      * Sleep on a condition variable until it's okay to exit.
   3882      */
   3883     self = dvmThreadSelf();
   3884     if (self == NULL) {
   3885         JNIEnv* tmpEnv;
   3886         if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
   3887             LOGV("Unable to reattach main for Destroy; assuming VM is "
   3888                  "shutting down (count=%d)\n",
   3889                 gDvm.nonDaemonThreadCount);
   3890             goto shutdown;
   3891         } else {
   3892             LOGV("Attached to wait for shutdown in Destroy\n");
   3893         }
   3894     }
   3895     dvmChangeStatus(self, THREAD_VMWAIT);
   3896 
   3897     dvmLockThreadList(self);
   3898     gDvm.nonDaemonThreadCount--;    // remove current thread from count
   3899 
   3900     while (gDvm.nonDaemonThreadCount > 0)
   3901         pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
   3902 
   3903     dvmUnlockThreadList();
   3904     self = NULL;
   3905 
   3906 shutdown:
   3907     // TODO: call System.exit() to run any registered shutdown hooks
   3908     // (this may not return -- figure out how this should work)
   3909 
   3910     if (gDvm.verboseShutdown)
   3911         LOGD("DestroyJavaVM shutting VM down\n");
   3912     dvmShutdown();
   3913 
   3914     // TODO - free resources associated with JNI-attached daemon threads
   3915     free(ext->envList);
   3916     free(ext);
   3917 
   3918     return JNI_OK;
   3919 }
   3920 
   3921 
   3922 /*
   3923  * ===========================================================================
   3924  *      Function tables
   3925  * ===========================================================================
   3926  */
   3927 
   3928 static const struct JNINativeInterface gNativeInterface = {
   3929     NULL,
   3930     NULL,
   3931     NULL,
   3932     NULL,
   3933 
   3934     GetVersion,
   3935 
   3936     DefineClass,
   3937     FindClass,
   3938 
   3939     FromReflectedMethod,
   3940     FromReflectedField,
   3941     ToReflectedMethod,
   3942 
   3943     GetSuperclass,
   3944     IsAssignableFrom,
   3945 
   3946     ToReflectedField,
   3947 
   3948     Throw,
   3949     ThrowNew,
   3950     ExceptionOccurred,
   3951     ExceptionDescribe,
   3952     ExceptionClear,
   3953     FatalError,
   3954 
   3955     PushLocalFrame,
   3956     PopLocalFrame,
   3957 
   3958     NewGlobalRef,
   3959     DeleteGlobalRef,
   3960     DeleteLocalRef,
   3961     IsSameObject,
   3962     NewLocalRef,
   3963     EnsureLocalCapacity,
   3964 
   3965     AllocObject,
   3966     NewObject,
   3967     NewObjectV,
   3968     NewObjectA,
   3969 
   3970     GetObjectClass,
   3971     IsInstanceOf,
   3972 
   3973     GetMethodID,
   3974 
   3975     CallObjectMethod,
   3976     CallObjectMethodV,
   3977     CallObjectMethodA,
   3978     CallBooleanMethod,
   3979     CallBooleanMethodV,
   3980     CallBooleanMethodA,
   3981     CallByteMethod,
   3982     CallByteMethodV,
   3983     CallByteMethodA,
   3984     CallCharMethod,
   3985     CallCharMethodV,
   3986     CallCharMethodA,
   3987     CallShortMethod,
   3988     CallShortMethodV,
   3989     CallShortMethodA,
   3990     CallIntMethod,
   3991     CallIntMethodV,
   3992     CallIntMethodA,
   3993     CallLongMethod,
   3994     CallLongMethodV,
   3995     CallLongMethodA,
   3996     CallFloatMethod,
   3997     CallFloatMethodV,
   3998     CallFloatMethodA,
   3999     CallDoubleMethod,
   4000     CallDoubleMethodV,
   4001     CallDoubleMethodA,
   4002     CallVoidMethod,
   4003     CallVoidMethodV,
   4004     CallVoidMethodA,
   4005 
   4006     CallNonvirtualObjectMethod,
   4007     CallNonvirtualObjectMethodV,
   4008     CallNonvirtualObjectMethodA,
   4009     CallNonvirtualBooleanMethod,
   4010     CallNonvirtualBooleanMethodV,
   4011     CallNonvirtualBooleanMethodA,
   4012     CallNonvirtualByteMethod,
   4013     CallNonvirtualByteMethodV,
   4014     CallNonvirtualByteMethodA,
   4015     CallNonvirtualCharMethod,
   4016     CallNonvirtualCharMethodV,
   4017     CallNonvirtualCharMethodA,
   4018     CallNonvirtualShortMethod,
   4019     CallNonvirtualShortMethodV,
   4020     CallNonvirtualShortMethodA,
   4021     CallNonvirtualIntMethod,
   4022     CallNonvirtualIntMethodV,
   4023     CallNonvirtualIntMethodA,
   4024     CallNonvirtualLongMethod,
   4025     CallNonvirtualLongMethodV,
   4026     CallNonvirtualLongMethodA,
   4027     CallNonvirtualFloatMethod,
   4028     CallNonvirtualFloatMethodV,
   4029     CallNonvirtualFloatMethodA,
   4030     CallNonvirtualDoubleMethod,
   4031     CallNonvirtualDoubleMethodV,
   4032     CallNonvirtualDoubleMethodA,
   4033     CallNonvirtualVoidMethod,
   4034     CallNonvirtualVoidMethodV,
   4035     CallNonvirtualVoidMethodA,
   4036 
   4037     GetFieldID,
   4038 
   4039     GetObjectField,
   4040     GetBooleanField,
   4041     GetByteField,
   4042     GetCharField,
   4043     GetShortField,
   4044     GetIntField,
   4045     GetLongField,
   4046     GetFloatField,
   4047     GetDoubleField,
   4048     SetObjectField,
   4049     SetBooleanField,
   4050     SetByteField,
   4051     SetCharField,
   4052     SetShortField,
   4053     SetIntField,
   4054     SetLongField,
   4055     SetFloatField,
   4056     SetDoubleField,
   4057 
   4058     GetStaticMethodID,
   4059 
   4060     CallStaticObjectMethod,
   4061     CallStaticObjectMethodV,
   4062     CallStaticObjectMethodA,
   4063     CallStaticBooleanMethod,
   4064     CallStaticBooleanMethodV,
   4065     CallStaticBooleanMethodA,
   4066     CallStaticByteMethod,
   4067     CallStaticByteMethodV,
   4068     CallStaticByteMethodA,
   4069     CallStaticCharMethod,
   4070     CallStaticCharMethodV,
   4071     CallStaticCharMethodA,
   4072     CallStaticShortMethod,
   4073     CallStaticShortMethodV,
   4074     CallStaticShortMethodA,
   4075     CallStaticIntMethod,
   4076     CallStaticIntMethodV,
   4077     CallStaticIntMethodA,
   4078     CallStaticLongMethod,
   4079     CallStaticLongMethodV,
   4080     CallStaticLongMethodA,
   4081     CallStaticFloatMethod,
   4082     CallStaticFloatMethodV,
   4083     CallStaticFloatMethodA,
   4084     CallStaticDoubleMethod,
   4085     CallStaticDoubleMethodV,
   4086     CallStaticDoubleMethodA,
   4087     CallStaticVoidMethod,
   4088     CallStaticVoidMethodV,
   4089     CallStaticVoidMethodA,
   4090 
   4091     GetStaticFieldID,
   4092 
   4093     GetStaticObjectField,
   4094     GetStaticBooleanField,
   4095     GetStaticByteField,
   4096     GetStaticCharField,
   4097     GetStaticShortField,
   4098     GetStaticIntField,
   4099     GetStaticLongField,
   4100     GetStaticFloatField,
   4101     GetStaticDoubleField,
   4102 
   4103     SetStaticObjectField,
   4104     SetStaticBooleanField,
   4105     SetStaticByteField,
   4106     SetStaticCharField,
   4107     SetStaticShortField,
   4108     SetStaticIntField,
   4109     SetStaticLongField,
   4110     SetStaticFloatField,
   4111     SetStaticDoubleField,
   4112 
   4113     NewString,
   4114 
   4115     GetStringLength,
   4116     GetStringChars,
   4117     ReleaseStringChars,
   4118 
   4119     NewStringUTF,
   4120     GetStringUTFLength,
   4121     GetStringUTFChars,
   4122     ReleaseStringUTFChars,
   4123 
   4124     GetArrayLength,
   4125     NewObjectArray,
   4126     GetObjectArrayElement,
   4127     SetObjectArrayElement,
   4128 
   4129     NewBooleanArray,
   4130     NewByteArray,
   4131     NewCharArray,
   4132     NewShortArray,
   4133     NewIntArray,
   4134     NewLongArray,
   4135     NewFloatArray,
   4136     NewDoubleArray,
   4137 
   4138     GetBooleanArrayElements,
   4139     GetByteArrayElements,
   4140     GetCharArrayElements,
   4141     GetShortArrayElements,
   4142     GetIntArrayElements,
   4143     GetLongArrayElements,
   4144     GetFloatArrayElements,
   4145     GetDoubleArrayElements,
   4146 
   4147     ReleaseBooleanArrayElements,
   4148     ReleaseByteArrayElements,
   4149     ReleaseCharArrayElements,
   4150     ReleaseShortArrayElements,
   4151     ReleaseIntArrayElements,
   4152     ReleaseLongArrayElements,
   4153     ReleaseFloatArrayElements,
   4154     ReleaseDoubleArrayElements,
   4155 
   4156     GetBooleanArrayRegion,
   4157     GetByteArrayRegion,
   4158     GetCharArrayRegion,
   4159     GetShortArrayRegion,
   4160     GetIntArrayRegion,
   4161     GetLongArrayRegion,
   4162     GetFloatArrayRegion,
   4163     GetDoubleArrayRegion,
   4164     SetBooleanArrayRegion,
   4165     SetByteArrayRegion,
   4166     SetCharArrayRegion,
   4167     SetShortArrayRegion,
   4168     SetIntArrayRegion,
   4169     SetLongArrayRegion,
   4170     SetFloatArrayRegion,
   4171     SetDoubleArrayRegion,
   4172 
   4173     RegisterNatives,
   4174     UnregisterNatives,
   4175 
   4176     MonitorEnter,
   4177     MonitorExit,
   4178 
   4179     GetJavaVM,
   4180 
   4181     GetStringRegion,
   4182     GetStringUTFRegion,
   4183 
   4184     GetPrimitiveArrayCritical,
   4185     ReleasePrimitiveArrayCritical,
   4186 
   4187     GetStringCritical,
   4188     ReleaseStringCritical,
   4189 
   4190     NewWeakGlobalRef,
   4191     DeleteWeakGlobalRef,
   4192 
   4193     ExceptionCheck,
   4194 
   4195     NewDirectByteBuffer,
   4196     GetDirectBufferAddress,
   4197     GetDirectBufferCapacity,
   4198 
   4199     GetObjectRefType
   4200 };
   4201 static const struct JNIInvokeInterface gInvokeInterface = {
   4202     NULL,
   4203     NULL,
   4204     NULL,
   4205 
   4206     DestroyJavaVM,
   4207     AttachCurrentThread,
   4208     DetachCurrentThread,
   4209 
   4210     GetEnv,
   4211 
   4212     AttachCurrentThreadAsDaemon,
   4213 };
   4214 
   4215 
   4216 /*
   4217  * ===========================================================================
   4218  *      VM/Env creation
   4219  * ===========================================================================
   4220  */
   4221 
   4222 /*
   4223  * Enable "checked JNI" after the VM has partially started.  This must
   4224  * only be called in "zygote" mode, when we have one thread running.
   4225  *
   4226  * This doesn't attempt to rewrite the JNI call bridge associated with
   4227  * native methods, so we won't get those checks for any methods that have
   4228  * already been resolved.
   4229  */
   4230 void dvmLateEnableCheckedJni(void)
   4231 {
   4232     JNIEnvExt* extEnv;
   4233     JavaVMExt* extVm;
   4234 
   4235     extEnv = dvmGetJNIEnvForThread();
   4236     if (extEnv == NULL) {
   4237         LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv\n");
   4238         return;
   4239     }
   4240     extVm = extEnv->vm;
   4241     assert(extVm != NULL);
   4242 
   4243     if (!extVm->useChecked) {
   4244         LOGD("Late-enabling CheckJNI\n");
   4245         dvmUseCheckedJniVm(extVm);
   4246         extVm->useChecked = true;
   4247         dvmUseCheckedJniEnv(extEnv);
   4248 
   4249         /* currently no way to pick up jniopts features */
   4250     } else {
   4251         LOGD("Not late-enabling CheckJNI (already on)\n");
   4252     }
   4253 }
   4254 
   4255 /*
   4256  * Not supported.
   4257  */
   4258 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args)
   4259 {
   4260     return JNI_ERR;
   4261 }
   4262 
   4263 /*
   4264  * Return a buffer full of created VMs.
   4265  *
   4266  * We always have zero or one.
   4267  */
   4268 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
   4269 {
   4270     if (gDvm.vmList != NULL) {
   4271         *nVMs = 1;
   4272 
   4273         if (bufLen > 0)
   4274             *vmBuf++ = gDvm.vmList;
   4275     } else {
   4276         *nVMs = 0;
   4277     }
   4278 
   4279     return JNI_OK;
   4280 }
   4281 
   4282 
   4283 /*
   4284  * Create a new VM instance.
   4285  *
   4286  * The current thread becomes the main VM thread.  We return immediately,
   4287  * which effectively means the caller is executing in a native method.
   4288  */
   4289 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)
   4290 {
   4291     const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
   4292     JNIEnvExt* pEnv = NULL;
   4293     JavaVMExt* pVM = NULL;
   4294     const char** argv;
   4295     int argc = 0;
   4296     int i, curOpt;
   4297     int result = JNI_ERR;
   4298     bool checkJni = false;
   4299     bool warnError = true;
   4300     bool forceDataCopy = false;
   4301 
   4302     if (args->version < JNI_VERSION_1_2)
   4303         return JNI_EVERSION;
   4304 
   4305     // TODO: don't allow creation of multiple VMs -- one per customer for now
   4306 
   4307     /* zero globals; not strictly necessary the first time a VM is started */
   4308     memset(&gDvm, 0, sizeof(gDvm));
   4309 
   4310     /*
   4311      * Set up structures for JNIEnv and VM.
   4312      */
   4313     //pEnv = (JNIEnvExt*) malloc(sizeof(JNIEnvExt));
   4314     pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
   4315 
   4316     //memset(pEnv, 0, sizeof(JNIEnvExt));
   4317     //pEnv->funcTable = &gNativeInterface;
   4318     //pEnv->vm = pVM;
   4319     memset(pVM, 0, sizeof(JavaVMExt));
   4320     pVM->funcTable = &gInvokeInterface;
   4321     pVM->envList = pEnv;
   4322     dvmInitMutex(&pVM->envListLock);
   4323 
   4324     argv = (const char**) malloc(sizeof(char*) * (args->nOptions));
   4325     memset(argv, 0, sizeof(char*) * (args->nOptions));
   4326 
   4327     curOpt = 0;
   4328 
   4329     /*
   4330      * Convert JNI args to argv.
   4331      *
   4332      * We have to pull out vfprintf/exit/abort, because they use the
   4333      * "extraInfo" field to pass function pointer "hooks" in.  We also
   4334      * look for the -Xcheck:jni stuff here.
   4335      */
   4336     for (i = 0; i < args->nOptions; i++) {
   4337         const char* optStr = args->options[i].optionString;
   4338 
   4339         if (optStr == NULL) {
   4340             fprintf(stderr, "ERROR: arg %d string was null\n", i);
   4341             goto bail;
   4342         } else if (strcmp(optStr, "vfprintf") == 0) {
   4343             gDvm.vfprintfHook = args->options[i].extraInfo;
   4344         } else if (strcmp(optStr, "exit") == 0) {
   4345             gDvm.exitHook = args->options[i].extraInfo;
   4346         } else if (strcmp(optStr, "abort") == 0) {
   4347             gDvm.abortHook = args->options[i].extraInfo;
   4348         } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
   4349             checkJni = true;
   4350         } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
   4351             const char* jniOpts = optStr + 9;
   4352             while (jniOpts != NULL) {
   4353                 jniOpts++;      /* skip past ':' or ',' */
   4354                 if (strncmp(jniOpts, "warnonly", 8) == 0) {
   4355                     warnError = false;
   4356                 } else if (strncmp(jniOpts, "forcecopy", 9) == 0) {
   4357                     forceDataCopy = true;
   4358                 } else {
   4359                     LOGW("unknown jni opt starting at '%s'\n", jniOpts);
   4360                 }
   4361                 jniOpts = strchr(jniOpts, ',');
   4362             }
   4363         } else {
   4364             /* regular option */
   4365             argv[curOpt++] = optStr;
   4366         }
   4367     }
   4368     argc = curOpt;
   4369 
   4370     if (checkJni) {
   4371         dvmUseCheckedJniVm(pVM);
   4372         pVM->useChecked = true;
   4373     }
   4374     pVM->warnError = warnError;
   4375     pVM->forceDataCopy = forceDataCopy;
   4376 
   4377     /* set this up before initializing VM, so it can create some JNIEnvs */
   4378     gDvm.vmList = (JavaVM*) pVM;
   4379 
   4380     /*
   4381      * Create an env for main thread.  We need to have something set up
   4382      * here because some of the class initialization we do when starting
   4383      * up the VM will call into native code.
   4384      */
   4385     pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
   4386 
   4387     /* initialize VM */
   4388     gDvm.initializing = true;
   4389     if (dvmStartup(argc, argv, args->ignoreUnrecognized, (JNIEnv*)pEnv) != 0) {
   4390         free(pEnv);
   4391         free(pVM);
   4392         goto bail;
   4393     }
   4394 
   4395     /*
   4396      * Success!  Return stuff to caller.
   4397      */
   4398     dvmChangeStatus(NULL, THREAD_NATIVE);
   4399     *p_env = (JNIEnv*) pEnv;
   4400     *p_vm = (JavaVM*) pVM;
   4401     result = JNI_OK;
   4402 
   4403 bail:
   4404     gDvm.initializing = false;
   4405     if (result == JNI_OK)
   4406         LOGV("JNI_CreateJavaVM succeeded\n");
   4407     else
   4408         LOGW("JNI_CreateJavaVM failed\n");
   4409     free(argv);
   4410     return result;
   4411 }
   4412