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     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
    863     return jobj;
    864 }
    865 
    866 /*
    867  * Remove a global reference.  In most cases it's the entry most recently
    868  * added, which makes this pretty quick.
    869  *
    870  * Thought: if it's not the most recent entry, just null it out.  When we
    871  * fill up, do a compaction pass before we expand the list.
    872  */
    873 static void deleteGlobalReference(jobject jobj)
    874 {
    875     if (jobj == NULL)
    876         return;
    877 
    878     dvmLockMutex(&gDvm.jniGlobalRefLock);
    879 
    880 #ifdef USE_INDIRECT_REF
    881     if (!dvmRemoveFromIndirectRefTable(&gDvm.jniGlobalRefTable,
    882             IRT_FIRST_SEGMENT, jobj))
    883     {
    884         LOGW("JNI: DeleteGlobalRef(%p) failed to find entry\n", jobj);
    885         goto bail;
    886     }
    887 
    888     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    889         int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
    890         // TODO: not quite right, need to subtract holes
    891         if (count < gDvm.jniGlobalRefLoMark) {
    892             LOGD("GREF has decreased to %d\n", count);
    893             gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
    894             gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
    895         }
    896     }
    897 #else
    898     if (!dvmRemoveFromReferenceTable(&gDvm.jniGlobalRefTable,
    899             gDvm.jniGlobalRefTable.table, jobj))
    900     {
    901         LOGW("JNI: DeleteGlobalRef(%p) failed to find entry (valid=%d)\n",
    902             jobj, dvmIsValidObject((Object*) jobj));
    903         goto bail;
    904     }
    905 
    906     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    907         int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
    908         if (count < gDvm.jniGlobalRefLoMark) {
    909             LOGD("GREF has decreased to %d\n", count);
    910             gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
    911             gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
    912         }
    913     }
    914 #endif
    915 
    916 bail:
    917     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
    918 }
    919 
    920 /*
    921  * We create a PhantomReference that references the object, add a
    922  * global reference to it, and then flip some bits before returning it.
    923  * The last step ensures that we detect it as special and that only
    924  * appropriate calls will accept it.
    925  *
    926  * On failure, returns NULL with an exception pending.
    927  */
    928 static jweak createWeakGlobalRef(JNIEnv* env, jobject jobj)
    929 {
    930     if (jobj == NULL)
    931         return NULL;
    932 
    933     Thread* self = ((JNIEnvExt*)env)->self;
    934     Object* obj = dvmDecodeIndirectRef(env, jobj);
    935     Object* phantomObj;
    936     jobject phantomRef;
    937 
    938     /*
    939      * Allocate a PhantomReference, then call the constructor to set
    940      * the referent and the reference queue.
    941      *
    942      * We use a "magic" reference queue that the GC knows about; it behaves
    943      * more like a queueless WeakReference, clearing the referent and
    944      * not calling enqueue().
    945      */
    946     if (!dvmIsClassInitialized(gDvm.classJavaLangRefPhantomReference))
    947         dvmInitClass(gDvm.classJavaLangRefPhantomReference);
    948     phantomObj = dvmAllocObject(gDvm.classJavaLangRefPhantomReference,
    949             ALLOC_DEFAULT);
    950     if (phantomObj == NULL) {
    951         assert(dvmCheckException(self));
    952         LOGW("Failed on WeakGlobalRef alloc\n");
    953         return NULL;
    954     }
    955 
    956     JValue unused;
    957     dvmCallMethod(self, gDvm.methJavaLangRefPhantomReference_init, phantomObj,
    958         &unused, obj, NULL);
    959     dvmReleaseTrackedAlloc(phantomObj, self);
    960 
    961     if (dvmCheckException(self)) {
    962         LOGW("PhantomReference init failed\n");
    963         return NULL;
    964     }
    965 
    966     LOGV("+++ WGR: created phantom ref %p for object %p\n", phantomObj, obj);
    967 
    968     /*
    969      * Add it to the global reference table, and mangle the pointer.
    970      */
    971     phantomRef = addGlobalReference(phantomObj);
    972     return dvmObfuscateWeakGlobalRef(phantomRef);
    973 }
    974 
    975 /*
    976  * Delete the global reference that's keeping the PhantomReference around.
    977  * The PhantomReference will eventually be discarded by the GC.
    978  */
    979 static void deleteWeakGlobalRef(JNIEnv* env, jweak wref)
    980 {
    981     if (wref == NULL)
    982         return;
    983 
    984     jobject phantomRef = dvmNormalizeWeakGlobalRef(wref);
    985     deleteGlobalReference(phantomRef);
    986 }
    987 
    988 /*
    989  * Extract the referent from a PhantomReference.  Used for weak global
    990  * references.
    991  *
    992  * "jwobj" is a "mangled" WGR pointer.
    993  */
    994 static Object* getPhantomReferent(JNIEnv* env, jweak jwobj)
    995 {
    996     jobject jobj = dvmNormalizeWeakGlobalRef(jwobj);
    997     Object* obj = dvmDecodeIndirectRef(env, jobj);
    998 
    999     if (obj->clazz != gDvm.classJavaLangRefPhantomReference) {
   1000         LOGE("%p is not a phantom reference (%s)\n",
   1001             jwobj, obj->clazz->descriptor);
   1002         return NULL;
   1003     }
   1004 
   1005     return dvmGetFieldObject(obj, gDvm.offJavaLangRefReference_referent);
   1006 }
   1007 
   1008 
   1009 /*
   1010  * Objects don't currently move, so we just need to create a reference
   1011  * that will ensure the array object isn't collected.
   1012  *
   1013  * We use a separate reference table, which is part of the GC root set.
   1014  */
   1015 static void pinPrimitiveArray(ArrayObject* arrayObj)
   1016 {
   1017     if (arrayObj == NULL)
   1018         return;
   1019 
   1020     dvmLockMutex(&gDvm.jniPinRefLock);
   1021     if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
   1022         dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
   1023         LOGE("Failed adding to JNI pinned array ref table (%d entries)\n",
   1024             (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
   1025         dvmDumpThread(dvmThreadSelf(), false);
   1026         dvmAbort();
   1027     }
   1028 
   1029     /*
   1030      * If we're watching global ref usage, also keep an eye on these.
   1031      *
   1032      * The total number of pinned primitive arrays should be pretty small.
   1033      * A single array should not be pinned more than once or twice; any
   1034      * more than that is a strong indicator that a Release function is
   1035      * not being called.
   1036      */
   1037     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
   1038         int count = 0;
   1039         Object** ppObj = gDvm.jniPinRefTable.table;
   1040         while (ppObj < gDvm.jniPinRefTable.nextEntry) {
   1041             if (*ppObj++ == (Object*) arrayObj)
   1042                 count++;
   1043         }
   1044 
   1045         if (count > kPinComplainThreshold) {
   1046             LOGW("JNI: pin count on array %p (%s) is now %d\n",
   1047                 arrayObj, arrayObj->obj.clazz->descriptor, count);
   1048             /* keep going */
   1049         }
   1050     }
   1051 
   1052     dvmUnlockMutex(&gDvm.jniPinRefLock);
   1053 }
   1054 
   1055 /*
   1056  * Un-pin the array object.  If an object was pinned twice, it must be
   1057  * unpinned twice before it's free to move.
   1058  */
   1059 static void unpinPrimitiveArray(ArrayObject* arrayObj)
   1060 {
   1061     if (arrayObj == NULL)
   1062         return;
   1063 
   1064     dvmLockMutex(&gDvm.jniPinRefLock);
   1065     if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
   1066             gDvm.jniPinRefTable.table, (Object*) arrayObj))
   1067     {
   1068         LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)\n",
   1069             arrayObj, dvmIsValidObject((Object*) arrayObj));
   1070         goto bail;
   1071     }
   1072 
   1073 bail:
   1074     dvmUnlockMutex(&gDvm.jniPinRefLock);
   1075 }
   1076 
   1077 /*
   1078  * Dump the contents of the JNI reference tables to the log file.
   1079  *
   1080  * We only dump the local refs associated with the current thread.
   1081  */
   1082 void dvmDumpJniReferenceTables(void)
   1083 {
   1084     Thread* self = dvmThreadSelf();
   1085     JNIEnv* env = self->jniEnv;
   1086     ReferenceTable* pLocalRefs = getLocalRefTable(env);
   1087 
   1088 #ifdef USE_INDIRECT_REF
   1089     dvmDumpIndirectRefTable(pLocalRefs, "JNI local");
   1090     dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
   1091 #else
   1092     dvmDumpReferenceTable(pLocalRefs, "JNI local");
   1093     dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
   1094 #endif
   1095     dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
   1096 }
   1097 
   1098 /*
   1099  * GC helper function to mark all JNI global references.
   1100  *
   1101  * We're currently handling the "pin" table here too.
   1102  */
   1103 void dvmGcMarkJniGlobalRefs()
   1104 {
   1105     Object** op;
   1106 
   1107     dvmLockMutex(&gDvm.jniGlobalRefLock);
   1108 
   1109 #ifdef USE_INDIRECT_REF
   1110     IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
   1111     op = pRefTable->table;
   1112     int numEntries = dvmIndirectRefTableEntries(pRefTable);
   1113     int i;
   1114 
   1115     for (i = 0; i < numEntries; i++) {
   1116         Object* obj = *op;
   1117         if (obj != NULL)
   1118             dvmMarkObjectNonNull(obj);
   1119         op++;
   1120     }
   1121 #else
   1122     op = gDvm.jniGlobalRefTable.table;
   1123     while ((uintptr_t)op < (uintptr_t)gDvm.jniGlobalRefTable.nextEntry) {
   1124         dvmMarkObjectNonNull(*(op++));
   1125     }
   1126 #endif
   1127 
   1128     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
   1129 
   1130 
   1131     dvmLockMutex(&gDvm.jniPinRefLock);
   1132 
   1133     op = gDvm.jniPinRefTable.table;
   1134     while ((uintptr_t)op < (uintptr_t)gDvm.jniPinRefTable.nextEntry) {
   1135         dvmMarkObjectNonNull(*(op++));
   1136     }
   1137 
   1138     dvmUnlockMutex(&gDvm.jniPinRefLock);
   1139 }
   1140 
   1141 
   1142 #ifndef USE_INDIRECT_REF
   1143 /*
   1144  * Determine if "obj" appears in the argument list for the native method.
   1145  *
   1146  * We use the "shorty" signature to determine which argument slots hold
   1147  * reference types.
   1148  */
   1149 static bool findInArgList(Thread* self, Object* obj)
   1150 {
   1151     const Method* meth;
   1152     u4* fp;
   1153     int i;
   1154 
   1155     fp = self->curFrame;
   1156     while (1) {
   1157         /*
   1158          * Back up over JNI PushLocalFrame frames.  This works because the
   1159          * previous frame on the interpreted stack is either a break frame
   1160          * (if we called here via native code) or an interpreted method (if
   1161          * we called here via the interpreter).  In both cases the method
   1162          * pointer won't match.
   1163          */
   1164         StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
   1165         meth = saveArea->method;
   1166         if (meth != SAVEAREA_FROM_FP(saveArea->prevFrame)->method)
   1167             break;
   1168         fp = saveArea->prevFrame;
   1169     }
   1170 
   1171     LOGVV("+++ scanning %d args in %s (%s)\n",
   1172         meth->insSize, meth->name, meth->shorty);
   1173     const char* shorty = meth->shorty +1;       /* skip return type char */
   1174     for (i = 0; i < meth->insSize; i++) {
   1175         if (i == 0 && !dvmIsStaticMethod(meth)) {
   1176             /* first arg is "this" ref, not represented in "shorty" */
   1177             if (fp[i] == (u4) obj)
   1178                 return true;
   1179         } else {
   1180             /* if this is a reference type, see if it matches */
   1181             switch (*shorty) {
   1182             case 'L':
   1183                 if (fp[i] == (u4) obj)
   1184                     return true;
   1185                 break;
   1186             case 'D':
   1187             case 'J':
   1188                 i++;
   1189                 break;
   1190             case '\0':
   1191                 LOGE("Whoops! ran off the end of %s (%d)\n",
   1192                     meth->shorty, meth->insSize);
   1193                 break;
   1194             default:
   1195                 if (fp[i] == (u4) obj)
   1196                     LOGI("NOTE: ref %p match on arg type %c\n", obj, *shorty);
   1197                 break;
   1198             }
   1199             shorty++;
   1200         }
   1201     }
   1202 
   1203     /*
   1204      * For static methods, we also pass a class pointer in.
   1205      */
   1206     if (dvmIsStaticMethod(meth)) {
   1207         //LOGI("+++ checking class pointer in %s\n", meth->name);
   1208         if ((void*)obj == (void*)meth->clazz)
   1209             return true;
   1210     }
   1211     return false;
   1212 }
   1213 #endif
   1214 
   1215 /*
   1216  * Verify that a reference passed in from native code is one that the
   1217  * code is allowed to have.
   1218  *
   1219  * It's okay for native code to pass us a reference that:
   1220  *  - was passed in as an argument when invoked by native code (and hence
   1221  *    is in the JNI local refs table)
   1222  *  - was returned to it from JNI (and is now in the local refs table)
   1223  *  - is present in the JNI global refs table
   1224  *
   1225  * Used by -Xcheck:jni and GetObjectRefType.
   1226  *
   1227  * NOTE: in the current VM, global and local references are identical.  If
   1228  * something is both global and local, we can't tell them apart, and always
   1229  * return "local".
   1230  */
   1231 jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj)
   1232 {
   1233 #ifdef USE_INDIRECT_REF
   1234     /*
   1235      * IndirectRefKind is currently defined as an exact match of
   1236      * jobjectRefType, so this is easy.  We have to decode it to determine
   1237      * if it's a valid reference and not merely valid-looking.
   1238      */
   1239     Object* obj = dvmDecodeIndirectRef(env, jobj);
   1240 
   1241     if (obj == NULL) {
   1242         /* invalid ref, or jobj was NULL */
   1243         return JNIInvalidRefType;
   1244     } else {
   1245         return (jobjectRefType) dvmGetIndirectRefType(jobj);
   1246     }
   1247 #else
   1248     ReferenceTable* pRefTable = getLocalRefTable(env);
   1249     Thread* self = dvmThreadSelf();
   1250 
   1251     if (dvmIsWeakGlobalRef(jobj)) {
   1252         return JNIWeakGlobalRefType;
   1253     }
   1254 
   1255     /* check args */
   1256     if (findInArgList(self, jobj)) {
   1257         //LOGI("--- REF found %p on stack\n", jobj);
   1258         return JNILocalRefType;
   1259     }
   1260 
   1261     /* check locals */
   1262     if (dvmFindInReferenceTable(pRefTable, pRefTable->table, jobj) != NULL) {
   1263         //LOGI("--- REF found %p in locals\n", jobj);
   1264         return JNILocalRefType;
   1265     }
   1266 
   1267     /* check globals */
   1268     dvmLockMutex(&gDvm.jniGlobalRefLock);
   1269     if (dvmFindInReferenceTable(&gDvm.jniGlobalRefTable,
   1270             gDvm.jniGlobalRefTable.table, jobj))
   1271     {
   1272         //LOGI("--- REF found %p in globals\n", jobj);
   1273         dvmUnlockMutex(&gDvm.jniGlobalRefLock);
   1274         return JNIGlobalRefType;
   1275     }
   1276     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
   1277 
   1278     /* not found! */
   1279     return JNIInvalidRefType;
   1280 #endif
   1281 }
   1282 
   1283 /*
   1284  * Register a method that uses JNI calling conventions.
   1285  */
   1286 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
   1287     const char* signature, void* fnPtr)
   1288 {
   1289     Method* method;
   1290     bool result = false;
   1291 
   1292     if (fnPtr == NULL)
   1293         goto bail;
   1294 
   1295     method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
   1296     if (method == NULL)
   1297         method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
   1298     if (method == NULL) {
   1299         LOGW("ERROR: Unable to find decl for native %s.%s:%s\n",
   1300             clazz->descriptor, methodName, signature);
   1301         goto bail;
   1302     }
   1303 
   1304     if (!dvmIsNativeMethod(method)) {
   1305         LOGW("Unable to register: not native: %s.%s:%s\n",
   1306             clazz->descriptor, methodName, signature);
   1307         goto bail;
   1308     }
   1309 
   1310     if (method->nativeFunc != dvmResolveNativeMethod) {
   1311         /* this is allowed, but unusual */
   1312         LOGV("Note: %s.%s:%s was already registered\n",
   1313             clazz->descriptor, methodName, signature);
   1314     }
   1315 
   1316     dvmUseJNIBridge(method, fnPtr);
   1317 
   1318     LOGV("JNI-registered %s.%s:%s\n", clazz->descriptor, methodName,
   1319         signature);
   1320     result = true;
   1321 
   1322 bail:
   1323     return result;
   1324 }
   1325 
   1326 /*
   1327  * Returns "true" if CheckJNI is enabled in the VM.
   1328  */
   1329 static bool dvmIsCheckJNIEnabled(void)
   1330 {
   1331     JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
   1332     return vm->useChecked;
   1333 }
   1334 
   1335 /*
   1336  * Returns the appropriate JNI bridge for 'method', also taking into account
   1337  * the -Xcheck:jni setting.
   1338  */
   1339 static DalvikBridgeFunc dvmSelectJNIBridge(const Method* method)
   1340 {
   1341     enum {
   1342         kJNIGeneral = 0,
   1343         kJNISync = 1,
   1344         kJNIVirtualNoRef = 2,
   1345         kJNIStaticNoRef = 3,
   1346     } kind;
   1347     static const DalvikBridgeFunc stdFunc[] = {
   1348         dvmCallJNIMethod_general,
   1349         dvmCallJNIMethod_synchronized,
   1350         dvmCallJNIMethod_virtualNoRef,
   1351         dvmCallJNIMethod_staticNoRef
   1352     };
   1353     static const DalvikBridgeFunc checkFunc[] = {
   1354         dvmCheckCallJNIMethod_general,
   1355         dvmCheckCallJNIMethod_synchronized,
   1356         dvmCheckCallJNIMethod_virtualNoRef,
   1357         dvmCheckCallJNIMethod_staticNoRef
   1358     };
   1359 
   1360     bool hasRefArg = false;
   1361 
   1362     if (dvmIsSynchronizedMethod(method)) {
   1363         /* use version with synchronization; calls into general handler */
   1364         kind = kJNISync;
   1365     } else {
   1366         /*
   1367          * Do a quick scan through the "shorty" signature to see if the method
   1368          * takes any reference arguments.
   1369          */
   1370         const char* cp = method->shorty;
   1371         while (*++cp != '\0') {     /* pre-incr to skip return type */
   1372             if (*cp == 'L') {
   1373                 /* 'L' used for both object and array references */
   1374                 hasRefArg = true;
   1375                 break;
   1376             }
   1377         }
   1378 
   1379         if (hasRefArg) {
   1380             /* use general handler to slurp up reference args */
   1381             kind = kJNIGeneral;
   1382         } else {
   1383             /* virtual methods have a ref in args[0] (not in signature) */
   1384             if (dvmIsStaticMethod(method))
   1385                 kind = kJNIStaticNoRef;
   1386             else
   1387                 kind = kJNIVirtualNoRef;
   1388         }
   1389     }
   1390 
   1391     return dvmIsCheckJNIEnabled() ? checkFunc[kind] : stdFunc[kind];
   1392 }
   1393 
   1394 /*
   1395  * Trace a call into native code.
   1396  */
   1397 static void dvmTraceCallJNIMethod(const u4* args, JValue* pResult,
   1398     const Method* method, Thread* self)
   1399 {
   1400     dvmLogNativeMethodEntry(method, args);
   1401     DalvikBridgeFunc bridge = dvmSelectJNIBridge(method);
   1402     (*bridge)(args, pResult, method, self);
   1403     dvmLogNativeMethodExit(method, self, *pResult);
   1404 }
   1405 
   1406 /**
   1407  * Returns true if the -Xjnitrace setting implies we should trace 'method'.
   1408  */
   1409 static bool shouldTrace(Method* method)
   1410 {
   1411     return gDvm.jniTrace && strstr(method->clazz->descriptor, gDvm.jniTrace);
   1412 }
   1413 
   1414 /*
   1415  * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
   1416  * to point at the actual function.
   1417  */
   1418 void dvmUseJNIBridge(Method* method, void* func)
   1419 {
   1420     DalvikBridgeFunc bridge = shouldTrace(method)
   1421         ? dvmTraceCallJNIMethod
   1422         : dvmSelectJNIBridge(method);
   1423     dvmSetNativeFunc(method, bridge, func);
   1424 }
   1425 
   1426 /*
   1427  * Get the method currently being executed by examining the interp stack.
   1428  */
   1429 const Method* dvmGetCurrentJNIMethod(void)
   1430 {
   1431     assert(dvmThreadSelf() != NULL);
   1432 
   1433     void* fp = dvmThreadSelf()->curFrame;
   1434     const Method* meth = SAVEAREA_FROM_FP(fp)->method;
   1435 
   1436     assert(meth != NULL);
   1437     assert(dvmIsNativeMethod(meth));
   1438     return meth;
   1439 }
   1440 
   1441 
   1442 /*
   1443  * Track a JNI MonitorEnter in the current thread.
   1444  *
   1445  * The goal is to be able to "implicitly" release all JNI-held monitors
   1446  * when the thread detaches.
   1447  *
   1448  * Monitors may be entered multiple times, so we add a new entry for each
   1449  * enter call.  It would be more efficient to keep a counter.  At present
   1450  * there's no real motivation to improve this however.
   1451  */
   1452 static void trackMonitorEnter(Thread* self, Object* obj)
   1453 {
   1454     static const int kInitialSize = 16;
   1455     ReferenceTable* refTable = &self->jniMonitorRefTable;
   1456 
   1457     /* init table on first use */
   1458     if (refTable->table == NULL) {
   1459         assert(refTable->maxEntries == 0);
   1460 
   1461         if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
   1462             LOGE("Unable to initialize monitor tracking table\n");
   1463             dvmAbort();
   1464         }
   1465     }
   1466 
   1467     if (!dvmAddToReferenceTable(refTable, obj)) {
   1468         /* ran out of memory? could throw exception instead */
   1469         LOGE("Unable to add entry to monitor tracking table\n");
   1470         dvmAbort();
   1471     } else {
   1472         LOGVV("--- added monitor %p\n", obj);
   1473     }
   1474 }
   1475 
   1476 
   1477 /*
   1478  * Track a JNI MonitorExit in the current thread.
   1479  */
   1480 static void trackMonitorExit(Thread* self, Object* obj)
   1481 {
   1482     ReferenceTable* pRefTable = &self->jniMonitorRefTable;
   1483 
   1484     if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
   1485         LOGE("JNI monitor %p not found in tracking list\n", obj);
   1486         /* keep going? */
   1487     } else {
   1488         LOGVV("--- removed monitor %p\n", obj);
   1489     }
   1490 }
   1491 
   1492 /*
   1493  * Release all monitors held by the jniMonitorRefTable list.
   1494  */
   1495 void dvmReleaseJniMonitors(Thread* self)
   1496 {
   1497     ReferenceTable* pRefTable = &self->jniMonitorRefTable;
   1498     Object** top = pRefTable->table;
   1499 
   1500     if (top == NULL)
   1501         return;
   1502 
   1503     Object** ptr = pRefTable->nextEntry;
   1504     while (--ptr >= top) {
   1505         if (!dvmUnlockObject(self, *ptr)) {
   1506             LOGW("Unable to unlock monitor %p at thread detach\n", *ptr);
   1507         } else {
   1508             LOGVV("--- detach-releasing monitor %p\n", *ptr);
   1509         }
   1510     }
   1511 
   1512     /* zap it */
   1513     pRefTable->nextEntry = pRefTable->table;
   1514 }
   1515 
   1516 /*
   1517  * Determine if the specified class can be instantiated from JNI.  This
   1518  * is used by AllocObject / NewObject, which are documented as throwing
   1519  * an exception for abstract and interface classes, and not accepting
   1520  * array classes.  We also want to reject attempts to create new Class
   1521  * objects, since only DefineClass should do that.
   1522  */
   1523 static bool canAllocClass(ClassObject* clazz)
   1524 {
   1525     if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
   1526         /* JNI spec defines what this throws */
   1527         dvmThrowExceptionFmt("Ljava/lang/InstantiationException;",
   1528             "Can't instantiate %s (abstract or interface)", clazz->descriptor);
   1529         return false;
   1530     } else if (dvmIsArrayClass(clazz) || clazz == gDvm.classJavaLangClass) {
   1531         /* spec says "must not" for arrays, ignores Class */
   1532         dvmThrowExceptionFmt("Ljava/lang/IllegalArgumentException;",
   1533             "Can't instantiate %s (array or Class) with this JNI function",
   1534             clazz->descriptor);
   1535         return false;
   1536     }
   1537 
   1538     return true;
   1539 }
   1540 
   1541 #ifdef WITH_JNI_STACK_CHECK
   1542 /*
   1543  * Compute a CRC on the entire interpreted stack.
   1544  *
   1545  * Would be nice to compute it on "self" as well, but there are parts of
   1546  * the Thread that can be altered by other threads (e.g. prev/next pointers).
   1547  */
   1548 static void computeStackSum(Thread* self)
   1549 {
   1550     const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
   1551     u4 crc = dvmInitCrc32();
   1552     self->stackCrc = 0;
   1553     crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
   1554     self->stackCrc = crc;
   1555 }
   1556 
   1557 /*
   1558  * Compute a CRC on the entire interpreted stack, and compare it to what
   1559  * we previously computed.
   1560  *
   1561  * We can execute JNI directly from native code without calling in from
   1562  * interpreted code during VM initialization and immediately after JNI
   1563  * thread attachment.  Another opportunity exists during JNI_OnLoad.  Rather
   1564  * than catching these cases we just ignore them here, which is marginally
   1565  * less accurate but reduces the amount of code we have to touch with #ifdefs.
   1566  */
   1567 static void checkStackSum(Thread* self)
   1568 {
   1569     const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
   1570     u4 stackCrc, crc;
   1571 
   1572     stackCrc = self->stackCrc;
   1573     self->stackCrc = 0;
   1574     crc = dvmInitCrc32();
   1575     crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
   1576     if (crc != stackCrc) {
   1577         const Method* meth = dvmGetCurrentJNIMethod();
   1578         if (dvmComputeExactFrameDepth(self->curFrame) == 1) {
   1579             LOGD("JNI: bad stack CRC (0x%08x) -- okay during init\n",
   1580                 stackCrc);
   1581         } else if (strcmp(meth->name, "nativeLoad") == 0 &&
   1582                   (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0))
   1583         {
   1584             LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad\n",
   1585                 stackCrc);
   1586         } else {
   1587             LOGW("JNI: bad stack CRC (%08x vs %08x)\n", crc, stackCrc);
   1588             dvmAbort();
   1589         }
   1590     }
   1591     self->stackCrc = (u4) -1;       /* make logic errors more noticeable */
   1592 }
   1593 #endif
   1594 
   1595 
   1596 /*
   1597  * ===========================================================================
   1598  *      JNI call bridge
   1599  * ===========================================================================
   1600  */
   1601 
   1602 /*
   1603  * The functions here form a bridge between interpreted code and JNI native
   1604  * functions.  The basic task is to convert an array of primitives and
   1605  * references into C-style function arguments.  This is architecture-specific
   1606  * and usually requires help from assembly code.
   1607  *
   1608  * The bridge takes four arguments: the array of parameters, a place to
   1609  * store the function result (if any), the method to call, and a pointer
   1610  * to the current thread.
   1611  *
   1612  * These functions aren't called directly from elsewhere in the VM.
   1613  * A pointer in the Method struct points to one of these, and when a native
   1614  * method is invoked the interpreter jumps to it.
   1615  *
   1616  * (The "internal native" methods are invoked the same way, but instead
   1617  * of calling through a bridge, the target method is called directly.)
   1618  *
   1619  * The "args" array should not be modified, but we do so anyway for
   1620  * performance reasons.  We know that it points to the "outs" area on
   1621  * the current method's interpreted stack.  This area is ignored by the
   1622  * precise GC, because there is no register map for a native method (for
   1623  * an interpreted method the args would be listed in the argument set).
   1624  * We know all of the values exist elsewhere on the interpreted stack,
   1625  * because the method call setup copies them right before making the call,
   1626  * so we don't have to worry about concealing stuff from the GC.
   1627  *
   1628  * If we don't want to modify "args", we either have to create a local
   1629  * copy and modify it before calling dvmPlatformInvoke, or we have to do
   1630  * the local reference replacement within dvmPlatformInvoke.  The latter
   1631  * has some performance advantages, though if we can inline the local
   1632  * reference adds we may win when there's a lot of reference args (unless
   1633  * we want to code up some local ref table manipulation in assembly.
   1634  */
   1635 
   1636 /*
   1637  * If necessary, convert the value in pResult from a local/global reference
   1638  * to an object pointer.
   1639  */
   1640 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
   1641     const Method* method, Thread* self)
   1642 {
   1643 #ifdef USE_INDIRECT_REF
   1644     if (method->shorty[0] == 'L' && !dvmCheckException(self) &&
   1645             pResult->l != NULL)
   1646     {
   1647         pResult->l = dvmDecodeIndirectRef(env, pResult->l);
   1648     }
   1649 #endif
   1650 }
   1651 
   1652 /*
   1653  * General form, handles all cases.
   1654  */
   1655 void dvmCallJNIMethod_general(const u4* args, JValue* pResult,
   1656     const Method* method, Thread* self)
   1657 {
   1658     int oldStatus;
   1659     u4* modArgs = (u4*) args;
   1660     jclass staticMethodClass;
   1661     JNIEnv* env = self->jniEnv;
   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     ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
   1726     assert(method->insns != NULL);
   1727 
   1728     COMPUTE_STACK_SUM(self);
   1729     dvmPlatformInvoke(env, staticMethodClass,
   1730         method->jniArgInfo, method->insSize, modArgs, method->shorty,
   1731         (void*)method->insns, pResult);
   1732     CHECK_STACK_SUM(self);
   1733 
   1734     dvmChangeStatus(self, oldStatus);
   1735 
   1736     convertReferenceResult(env, pResult, method, self);
   1737 }
   1738 
   1739 /*
   1740  * Handler for the unusual case of a synchronized native method.
   1741  *
   1742  * Lock the object, then call through the general function.
   1743  */
   1744 void dvmCallJNIMethod_synchronized(const u4* args, JValue* pResult,
   1745     const Method* method, Thread* self)
   1746 {
   1747     Object* lockObj;
   1748 
   1749     assert(dvmIsSynchronizedMethod(method));
   1750 
   1751     if (dvmIsStaticMethod(method))
   1752         lockObj = (Object*) method->clazz;
   1753     else
   1754         lockObj = (Object*) args[0];
   1755 
   1756     LOGVV("Calling %s.%s: locking %p (%s)\n",
   1757         method->clazz->descriptor, method->name,
   1758         lockObj, lockObj->clazz->descriptor);
   1759 
   1760     dvmLockObject(self, lockObj);
   1761     dvmCallJNIMethod_general(args, pResult, method, self);
   1762     dvmUnlockObject(self, lockObj);
   1763 }
   1764 
   1765 /*
   1766  * Virtual method call, no reference arguments.
   1767  *
   1768  * We need to local-ref the "this" argument, found in args[0].
   1769  */
   1770 void dvmCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult,
   1771     const Method* method, Thread* self)
   1772 {
   1773     u4* modArgs = (u4*) args;
   1774     int oldStatus;
   1775 
   1776 #ifdef USE_INDIRECT_REF
   1777     jobject thisObj = addLocalReference(self->jniEnv, (Object*) args[0]);
   1778     if (thisObj == NULL) {
   1779         assert(dvmCheckException(self));
   1780         return;
   1781     }
   1782     modArgs[0] = (u4) thisObj;
   1783 #endif
   1784 
   1785     oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
   1786 
   1787     ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
   1788 
   1789     COMPUTE_STACK_SUM(self);
   1790     dvmPlatformInvoke(self->jniEnv, NULL,
   1791         method->jniArgInfo, method->insSize, modArgs, method->shorty,
   1792         (void*)method->insns, pResult);
   1793     CHECK_STACK_SUM(self);
   1794 
   1795     dvmChangeStatus(self, oldStatus);
   1796 
   1797     convertReferenceResult(self->jniEnv, pResult, method, self);
   1798 }
   1799 
   1800 /*
   1801  * Static method call, no reference arguments.
   1802  *
   1803  * We need to local-ref the class reference.
   1804  */
   1805 void dvmCallJNIMethod_staticNoRef(const u4* args, JValue* pResult,
   1806     const Method* method, Thread* self)
   1807 {
   1808     jclass staticMethodClass;
   1809     int oldStatus;
   1810 
   1811 #ifdef USE_INDIRECT_REF
   1812     staticMethodClass = addLocalReference(self->jniEnv, (Object*)method->clazz);
   1813     if (staticMethodClass == NULL) {
   1814         assert(dvmCheckException(self));
   1815         return;
   1816     }
   1817 #else
   1818     staticMethodClass = (jobject) method->clazz;
   1819 #endif
   1820 
   1821     oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
   1822 
   1823     ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
   1824 
   1825     COMPUTE_STACK_SUM(self);
   1826     dvmPlatformInvoke(self->jniEnv, staticMethodClass,
   1827         method->jniArgInfo, method->insSize, args, method->shorty,
   1828         (void*)method->insns, pResult);
   1829     CHECK_STACK_SUM(self);
   1830 
   1831     dvmChangeStatus(self, oldStatus);
   1832 
   1833     convertReferenceResult(self->jniEnv, pResult, method, self);
   1834 }
   1835 
   1836 /*
   1837  * Extract the return type enum from the "jniArgInfo" field.
   1838  */
   1839 DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
   1840 {
   1841     return (jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT;
   1842 }
   1843 
   1844 
   1845 /*
   1846  * ===========================================================================
   1847  *      JNI implementation
   1848  * ===========================================================================
   1849  */
   1850 
   1851 /*
   1852  * Return the version of the native method interface.
   1853  */
   1854 static jint GetVersion(JNIEnv* env)
   1855 {
   1856     JNI_ENTER();
   1857     /*
   1858      * There is absolutely no need to toggle the mode for correct behavior.
   1859      * However, it does provide native code with a simple "suspend self
   1860      * if necessary" call.
   1861      */
   1862     JNI_EXIT();
   1863     return JNI_VERSION_1_6;
   1864 }
   1865 
   1866 /*
   1867  * Create a new class from a bag of bytes.
   1868  *
   1869  * This is not currently supported within Dalvik.
   1870  */
   1871 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
   1872     const jbyte* buf, jsize bufLen)
   1873 {
   1874     UNUSED_PARAMETER(name);
   1875     UNUSED_PARAMETER(loader);
   1876     UNUSED_PARAMETER(buf);
   1877     UNUSED_PARAMETER(bufLen);
   1878 
   1879     JNI_ENTER();
   1880     LOGW("JNI DefineClass is not supported\n");
   1881     JNI_EXIT();
   1882     return NULL;
   1883 }
   1884 
   1885 /*
   1886  * Find a class by name.
   1887  *
   1888  * We have to use the "no init" version of FindClass here, because we might
   1889  * be getting the class prior to registering native methods that will be
   1890  * used in <clinit>.
   1891  *
   1892  * We need to get the class loader associated with the current native
   1893  * method.  If there is no native method, e.g. we're calling this from native
   1894  * code right after creating the VM, the spec says we need to use the class
   1895  * loader returned by "ClassLoader.getBaseClassLoader".  There is no such
   1896  * method, but it's likely they meant ClassLoader.getSystemClassLoader.
   1897  * We can't get that until after the VM has initialized though.
   1898  */
   1899 static jclass FindClass(JNIEnv* env, const char* name)
   1900 {
   1901     JNI_ENTER();
   1902 
   1903     const Method* thisMethod;
   1904     ClassObject* clazz;
   1905     jclass jclazz = NULL;
   1906     Object* loader;
   1907     char* descriptor = NULL;
   1908 
   1909     thisMethod = dvmGetCurrentJNIMethod();
   1910     assert(thisMethod != NULL);
   1911 
   1912     descriptor = dvmNameToDescriptor(name);
   1913     if (descriptor == NULL) {
   1914         clazz = NULL;
   1915         goto bail;
   1916     }
   1917 
   1918     //Thread* self = dvmThreadSelf();
   1919     if (_self->classLoaderOverride != NULL) {
   1920         /* hack for JNI_OnLoad */
   1921         assert(strcmp(thisMethod->name, "nativeLoad") == 0);
   1922         loader = _self->classLoaderOverride;
   1923     } else if (thisMethod == gDvm.methFakeNativeEntry) {
   1924         /* start point of invocation interface */
   1925         if (!gDvm.initializing)
   1926             loader = dvmGetSystemClassLoader();
   1927         else
   1928             loader = NULL;
   1929     } else {
   1930         loader = thisMethod->clazz->classLoader;
   1931     }
   1932 
   1933     clazz = dvmFindClassNoInit(descriptor, loader);
   1934     jclazz = addLocalReference(env, (Object*) clazz);
   1935 
   1936 bail:
   1937     free(descriptor);
   1938 
   1939     JNI_EXIT();
   1940     return jclazz;
   1941 }
   1942 
   1943 /*
   1944  * Return the superclass of a class.
   1945  */
   1946 static jclass GetSuperclass(JNIEnv* env, jclass jclazz)
   1947 {
   1948     JNI_ENTER();
   1949     jclass jsuper = NULL;
   1950 
   1951     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1952     if (clazz != NULL)
   1953         jsuper = addLocalReference(env, (Object*)clazz->super);
   1954     JNI_EXIT();
   1955     return jsuper;
   1956 }
   1957 
   1958 /*
   1959  * Determine whether an object of clazz1 can be safely cast to clazz2.
   1960  *
   1961  * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
   1962  */
   1963 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2)
   1964 {
   1965     JNI_ENTER();
   1966 
   1967     ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1);
   1968     ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2);
   1969 
   1970     jboolean result = dvmInstanceof(clazz1, clazz2);
   1971 
   1972     JNI_EXIT();
   1973     return result;
   1974 }
   1975 
   1976 /*
   1977  * Given a java.lang.reflect.Method or .Constructor, return a methodID.
   1978  */
   1979 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod)
   1980 {
   1981     JNI_ENTER();
   1982     jmethodID methodID;
   1983     Object* method = dvmDecodeIndirectRef(env, jmethod);
   1984     methodID = (jmethodID) dvmGetMethodFromReflectObj(method);
   1985     JNI_EXIT();
   1986     return methodID;
   1987 }
   1988 
   1989 /*
   1990  * Given a java.lang.reflect.Field, return a fieldID.
   1991  */
   1992 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield)
   1993 {
   1994     JNI_ENTER();
   1995     jfieldID fieldID;
   1996     Object* field = dvmDecodeIndirectRef(env, jfield);
   1997     fieldID = (jfieldID) dvmGetFieldFromReflectObj(field);
   1998     JNI_EXIT();
   1999     return fieldID;
   2000 }
   2001 
   2002 /*
   2003  * Convert a methodID to a java.lang.reflect.Method or .Constructor.
   2004  *
   2005  * (The "isStatic" field does not appear in the spec.)
   2006  *
   2007  * Throws OutOfMemory and returns NULL on failure.
   2008  */
   2009 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID,
   2010     jboolean isStatic)
   2011 {
   2012     JNI_ENTER();
   2013     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
   2014     Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
   2015     dvmReleaseTrackedAlloc(obj, NULL);
   2016     jobject jobj = addLocalReference(env, obj);
   2017     JNI_EXIT();
   2018     return jobj;
   2019 }
   2020 
   2021 /*
   2022  * Convert a fieldID to a java.lang.reflect.Field.
   2023  *
   2024  * (The "isStatic" field does not appear in the spec.)
   2025  *
   2026  * Throws OutOfMemory and returns NULL on failure.
   2027  */
   2028 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID,
   2029     jboolean isStatic)
   2030 {
   2031     JNI_ENTER();
   2032     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
   2033     Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
   2034     dvmReleaseTrackedAlloc(obj, NULL);
   2035     jobject jobj = addLocalReference(env, obj);
   2036     JNI_EXIT();
   2037     return jobj;
   2038 }
   2039 
   2040 /*
   2041  * Take this exception and throw it.
   2042  */
   2043 static jint Throw(JNIEnv* env, jthrowable jobj)
   2044 {
   2045     JNI_ENTER();
   2046 
   2047     jint retval;
   2048 
   2049     if (jobj != NULL) {
   2050         Object* obj = dvmDecodeIndirectRef(env, jobj);
   2051         dvmSetException(_self, obj);
   2052         retval = JNI_OK;
   2053     } else {
   2054         retval = JNI_ERR;
   2055     }
   2056 
   2057     JNI_EXIT();
   2058     return retval;
   2059 }
   2060 
   2061 /*
   2062  * Constructs an exception object from the specified class with the message
   2063  * specified by "message", and throws it.
   2064  */
   2065 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message)
   2066 {
   2067     JNI_ENTER();
   2068 
   2069     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2070     dvmThrowExceptionByClass(clazz, message);
   2071     // TODO: should return failure if this didn't work (e.g. OOM)
   2072 
   2073     JNI_EXIT();
   2074     return JNI_OK;
   2075 }
   2076 
   2077 /*
   2078  * If an exception is being thrown, return the exception object.  Otherwise,
   2079  * return NULL.
   2080  *
   2081  * TODO: if there is no pending exception, we should be able to skip the
   2082  * enter/exit checks.  If we find one, we need to enter and then re-fetch
   2083  * the exception (in case it got moved by a compacting GC).
   2084  */
   2085 static jthrowable ExceptionOccurred(JNIEnv* env)
   2086 {
   2087     JNI_ENTER();
   2088 
   2089     Object* exception;
   2090     jobject localException;
   2091 
   2092     exception = dvmGetException(_self);
   2093     localException = addLocalReference(env, exception);
   2094     if (localException == NULL && exception != NULL) {
   2095         /*
   2096          * We were unable to add a new local reference, and threw a new
   2097          * exception.  We can't return "exception", because it's not a
   2098          * local reference.  So we have to return NULL, indicating that
   2099          * there was no exception, even though it's pretty much raining
   2100          * exceptions in here.
   2101          */
   2102         LOGW("JNI WARNING: addLocal/exception combo\n");
   2103     }
   2104 
   2105     JNI_EXIT();
   2106     return localException;
   2107 }
   2108 
   2109 /*
   2110  * Print an exception and stack trace to stderr.
   2111  */
   2112 static void ExceptionDescribe(JNIEnv* env)
   2113 {
   2114     JNI_ENTER();
   2115 
   2116     Object* exception = dvmGetException(_self);
   2117     if (exception != NULL) {
   2118         dvmPrintExceptionStackTrace();
   2119     } else {
   2120         LOGI("Odd: ExceptionDescribe called, but no exception pending\n");
   2121     }
   2122 
   2123     JNI_EXIT();
   2124 }
   2125 
   2126 /*
   2127  * Clear the exception currently being thrown.
   2128  *
   2129  * TODO: we should be able to skip the enter/exit stuff.
   2130  */
   2131 static void ExceptionClear(JNIEnv* env)
   2132 {
   2133     JNI_ENTER();
   2134     dvmClearException(_self);
   2135     JNI_EXIT();
   2136 }
   2137 
   2138 /*
   2139  * Kill the VM.  This function does not return.
   2140  */
   2141 static void FatalError(JNIEnv* env, const char* msg)
   2142 {
   2143     //dvmChangeStatus(NULL, THREAD_RUNNING);
   2144     LOGE("JNI posting fatal error: %s\n", msg);
   2145     dvmAbort();
   2146 }
   2147 
   2148 /*
   2149  * Push a new JNI frame on the stack, with a new set of locals.
   2150  *
   2151  * The new frame must have the same method pointer.  (If for no other
   2152  * reason than FindClass needs it to get the appropriate class loader.)
   2153  */
   2154 static jint PushLocalFrame(JNIEnv* env, jint capacity)
   2155 {
   2156     JNI_ENTER();
   2157     int result = JNI_OK;
   2158     if (!ensureLocalCapacity(env, capacity) ||
   2159         !dvmPushLocalFrame(_self /*dvmThreadSelf()*/, dvmGetCurrentJNIMethod()))
   2160     {
   2161         /* yes, OutOfMemoryError, not StackOverflowError */
   2162         dvmClearException(_self);
   2163         dvmThrowException("Ljava/lang/OutOfMemoryError;",
   2164             "out of stack in JNI PushLocalFrame");
   2165         result = JNI_ERR;
   2166     }
   2167     JNI_EXIT();
   2168     return result;
   2169 }
   2170 
   2171 /*
   2172  * Pop the local frame off.  If "result" is not null, add it as a
   2173  * local reference on the now-current frame.
   2174  */
   2175 static jobject PopLocalFrame(JNIEnv* env, jobject jresult)
   2176 {
   2177     JNI_ENTER();
   2178     Object* result = dvmDecodeIndirectRef(env, jresult);
   2179     if (!dvmPopLocalFrame(_self /*dvmThreadSelf()*/)) {
   2180         LOGW("JNI WARNING: too many PopLocalFrame calls\n");
   2181         dvmClearException(_self);
   2182         dvmThrowException("Ljava/lang/RuntimeException;",
   2183             "too many PopLocalFrame calls");
   2184     }
   2185     jresult = addLocalReference(env, result);
   2186     JNI_EXIT();
   2187     return result;
   2188 }
   2189 
   2190 /*
   2191  * Add a reference to the global list.
   2192  */
   2193 static jobject NewGlobalRef(JNIEnv* env, jobject jobj)
   2194 {
   2195     Object* obj;
   2196 
   2197     JNI_ENTER();
   2198     if (dvmIsWeakGlobalRef(jobj))
   2199         obj = getPhantomReferent(env, (jweak) jobj);
   2200     else
   2201         obj = dvmDecodeIndirectRef(env, jobj);
   2202     jobject retval = addGlobalReference(obj);
   2203     JNI_EXIT();
   2204     return retval;
   2205 }
   2206 
   2207 /*
   2208  * Delete a reference from the global list.
   2209  */
   2210 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef)
   2211 {
   2212     JNI_ENTER();
   2213     deleteGlobalReference(jglobalRef);
   2214     JNI_EXIT();
   2215 }
   2216 
   2217 
   2218 /*
   2219  * Add a reference to the local list.
   2220  */
   2221 static jobject NewLocalRef(JNIEnv* env, jobject jobj)
   2222 {
   2223     Object* obj;
   2224 
   2225     JNI_ENTER();
   2226     if (dvmIsWeakGlobalRef(jobj))
   2227         obj = getPhantomReferent(env, (jweak) jobj);
   2228     else
   2229         obj = dvmDecodeIndirectRef(env, jobj);
   2230     jobject retval = addLocalReference(env, obj);
   2231     JNI_EXIT();
   2232     return retval;
   2233 }
   2234 
   2235 /*
   2236  * Delete a reference from the local list.
   2237  */
   2238 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef)
   2239 {
   2240     JNI_ENTER();
   2241     deleteLocalReference(env, jlocalRef);
   2242     JNI_EXIT();
   2243 }
   2244 
   2245 /*
   2246  * Ensure that the local references table can hold at least this many
   2247  * references.
   2248  */
   2249 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity)
   2250 {
   2251     JNI_ENTER();
   2252     bool okay = ensureLocalCapacity(env, capacity);
   2253     if (!okay) {
   2254         dvmThrowException("Ljava/lang/OutOfMemoryError;",
   2255             "can't ensure local reference capacity");
   2256     }
   2257     JNI_EXIT();
   2258     if (okay)
   2259         return 0;
   2260     else
   2261         return -1;
   2262 }
   2263 
   2264 
   2265 /*
   2266  * Determine whether two Object references refer to the same underlying object.
   2267  */
   2268 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2)
   2269 {
   2270     JNI_ENTER();
   2271     Object* obj1 = dvmDecodeIndirectRef(env, jref1);
   2272     Object* obj2 = dvmDecodeIndirectRef(env, jref2);
   2273     jboolean result = (obj1 == obj2);
   2274     JNI_EXIT();
   2275     return result;
   2276 }
   2277 
   2278 /*
   2279  * Allocate a new object without invoking any constructors.
   2280  */
   2281 static jobject AllocObject(JNIEnv* env, jclass jclazz)
   2282 {
   2283     JNI_ENTER();
   2284 
   2285     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2286     jobject result;
   2287 
   2288     if (!canAllocClass(clazz) ||
   2289         (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
   2290     {
   2291         assert(dvmCheckException(_self));
   2292         result = NULL;
   2293     } else {
   2294         Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   2295         result = addLocalReference(env, newObj);
   2296     }
   2297 
   2298     JNI_EXIT();
   2299     return result;
   2300 }
   2301 
   2302 /*
   2303  * Allocate a new object and invoke the supplied constructor.
   2304  */
   2305 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...)
   2306 {
   2307     JNI_ENTER();
   2308     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2309     jobject result;
   2310 
   2311     if (!canAllocClass(clazz) ||
   2312         (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
   2313     {
   2314         assert(dvmCheckException(_self));
   2315         result = NULL;
   2316     } else {
   2317         Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   2318         result = addLocalReference(env, newObj);
   2319         if (newObj != NULL) {
   2320             JValue unused;
   2321             va_list args;
   2322             va_start(args, methodID);
   2323             dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused,
   2324                 args);
   2325             va_end(args);
   2326         }
   2327     }
   2328 
   2329     JNI_EXIT();
   2330     return result;
   2331 }
   2332 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID,
   2333     va_list args)
   2334 {
   2335     JNI_ENTER();
   2336     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2337     jobject result;
   2338 
   2339     if (!canAllocClass(clazz) ||
   2340         (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
   2341     {
   2342         assert(dvmCheckException(_self));
   2343         result = NULL;
   2344     } else {
   2345         Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   2346         result = addLocalReference(env, newObj);
   2347         if (newObj != NULL) {
   2348             JValue unused;
   2349             dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused,
   2350                 args);
   2351         }
   2352     }
   2353 
   2354     JNI_EXIT();
   2355     return result;
   2356 }
   2357 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID,
   2358     jvalue* args)
   2359 {
   2360     JNI_ENTER();
   2361     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2362     jobject result;
   2363 
   2364     if (!canAllocClass(clazz) ||
   2365         (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
   2366     {
   2367         assert(dvmCheckException(_self));
   2368         result = NULL;
   2369     } else {
   2370         Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   2371         result = addLocalReference(env, newObj);
   2372         if (newObj != NULL) {
   2373             JValue unused;
   2374             dvmCallMethodA(_self, (Method*) methodID, newObj, true, &unused,
   2375                 args);
   2376         }
   2377     }
   2378 
   2379     JNI_EXIT();
   2380     return result;
   2381 }
   2382 
   2383 /*
   2384  * Returns the class of an object.
   2385  *
   2386  * JNI spec says: obj must not be NULL.
   2387  */
   2388 static jclass GetObjectClass(JNIEnv* env, jobject jobj)
   2389 {
   2390     JNI_ENTER();
   2391 
   2392     assert(jobj != NULL);
   2393 
   2394     Object* obj = dvmDecodeIndirectRef(env, jobj);
   2395     jclass jclazz = addLocalReference(env, (Object*) obj->clazz);
   2396 
   2397     JNI_EXIT();
   2398     return jclazz;
   2399 }
   2400 
   2401 /*
   2402  * Determine whether "obj" is an instance of "clazz".
   2403  */
   2404 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz)
   2405 {
   2406     JNI_ENTER();
   2407 
   2408     assert(jclazz != NULL);
   2409 
   2410     jboolean result;
   2411 
   2412     if (jobj == NULL) {
   2413         result = true;
   2414     } else {
   2415         Object* obj = dvmDecodeIndirectRef(env, jobj);
   2416         ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2417         result = dvmInstanceof(obj->clazz, clazz);
   2418     }
   2419 
   2420     JNI_EXIT();
   2421     return result;
   2422 }
   2423 
   2424 /*
   2425  * Get a method ID for an instance method.
   2426  *
   2427  * JNI defines <init> as an instance method, but Dalvik considers it a
   2428  * "direct" method, so we have to special-case it here.
   2429  *
   2430  * Dalvik also puts all private methods into the "direct" list, so we
   2431  * really need to just search both lists.
   2432  */
   2433 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,
   2434     const char* sig)
   2435 {
   2436     JNI_ENTER();
   2437 
   2438     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2439     jmethodID id = NULL;
   2440 
   2441     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2442         assert(dvmCheckException(_self));
   2443     } else {
   2444         Method* meth;
   2445 
   2446         meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
   2447         if (meth == NULL) {
   2448             /* search private methods and constructors; non-hierarchical */
   2449             meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
   2450         }
   2451         if (meth != NULL && dvmIsStaticMethod(meth)) {
   2452             IF_LOGD() {
   2453                 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
   2454                 LOGD("GetMethodID: not returning static method %s.%s %s\n",
   2455                     clazz->descriptor, meth->name, desc);
   2456                 free(desc);
   2457             }
   2458             meth = NULL;
   2459         }
   2460         if (meth == NULL) {
   2461             LOGD("GetMethodID: method not found: %s.%s:%s\n",
   2462                 clazz->descriptor, name, sig);
   2463             dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
   2464         }
   2465 
   2466         /*
   2467          * The method's class may not be the same as clazz, but if
   2468          * it isn't this must be a virtual method and the class must
   2469          * be a superclass (and, hence, already initialized).
   2470          */
   2471         if (meth != NULL) {
   2472             assert(dvmIsClassInitialized(meth->clazz) ||
   2473                    dvmIsClassInitializing(meth->clazz));
   2474         }
   2475         id = (jmethodID) meth;
   2476     }
   2477     JNI_EXIT();
   2478     return id;
   2479 }
   2480 
   2481 /*
   2482  * Get a field ID (instance fields).
   2483  */
   2484 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,
   2485     const char* name, const char* sig)
   2486 {
   2487     JNI_ENTER();
   2488 
   2489     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2490     jfieldID id;
   2491 
   2492     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2493         assert(dvmCheckException(_self));
   2494         id = NULL;
   2495     } else {
   2496         id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
   2497         if (id == NULL) {
   2498             LOGD("GetFieldID: unable to find field %s.%s:%s\n",
   2499                 clazz->descriptor, name, sig);
   2500             dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
   2501         }
   2502     }
   2503     JNI_EXIT();
   2504     return id;
   2505 }
   2506 
   2507 /*
   2508  * Get the method ID for a static method in a class.
   2509  */
   2510 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz,
   2511     const char* name, const char* sig)
   2512 {
   2513     JNI_ENTER();
   2514 
   2515     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2516     jmethodID id;
   2517 
   2518     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2519         assert(dvmCheckException(_self));
   2520         id = NULL;
   2521     } else {
   2522         Method* meth;
   2523 
   2524         meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
   2525 
   2526         /* make sure it's static, not virtual+private */
   2527         if (meth != NULL && !dvmIsStaticMethod(meth)) {
   2528             IF_LOGD() {
   2529                 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
   2530                 LOGD("GetStaticMethodID: "
   2531                     "not returning nonstatic method %s.%s %s\n",
   2532                     clazz->descriptor, meth->name, desc);
   2533                 free(desc);
   2534             }
   2535             meth = NULL;
   2536         }
   2537 
   2538         id = (jmethodID) meth;
   2539         if (id == NULL)
   2540             dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
   2541     }
   2542 
   2543     JNI_EXIT();
   2544     return id;
   2545 }
   2546 
   2547 /*
   2548  * Get a field ID (static fields).
   2549  */
   2550 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz,
   2551     const char* name, const char* sig)
   2552 {
   2553     JNI_ENTER();
   2554 
   2555     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2556     jfieldID id;
   2557 
   2558     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   2559         assert(dvmCheckException(_self));
   2560         id = NULL;
   2561     } else {
   2562         id = (jfieldID) dvmFindStaticField(clazz, name, sig);
   2563         if (id == NULL)
   2564             dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
   2565     }
   2566     JNI_EXIT();
   2567     return id;
   2568 }
   2569 
   2570 /*
   2571  * Get a static field.
   2572  *
   2573  * If we get an object reference, add it to the local refs list.
   2574  */
   2575 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref)                       \
   2576     static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz,      \
   2577         jfieldID fieldID)                                                   \
   2578     {                                                                       \
   2579         UNUSED_PARAMETER(jclazz);                                           \
   2580         JNI_ENTER();                                                        \
   2581         StaticField* sfield = (StaticField*) fieldID;                       \
   2582         _ctype value;                                                       \
   2583         if (dvmIsVolatileField(&sfield->field)) {                           \
   2584             if (_isref) {   /* only when _ctype==jobject */                 \
   2585                 Object* obj = dvmGetStaticFieldObjectVolatile(sfield);      \
   2586                 value = (_ctype)(u4)addLocalReference(env, obj);            \
   2587             } else {                                                        \
   2588                 value = dvmGetStaticField##_jname##Volatile(sfield);        \
   2589             }                                                               \
   2590         } else {                                                            \
   2591             if (_isref) {                                                   \
   2592                 Object* obj = dvmGetStaticFieldObject(sfield);              \
   2593                 value = (_ctype)(u4)addLocalReference(env, obj);            \
   2594             } else {                                                        \
   2595                 value = dvmGetStaticField##_jname(sfield);                  \
   2596             }                                                               \
   2597         }                                                                   \
   2598         JNI_EXIT();                                                         \
   2599         return value;                                                       \
   2600     }
   2601 GET_STATIC_TYPE_FIELD(jobject, Object, true);
   2602 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
   2603 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
   2604 GET_STATIC_TYPE_FIELD(jchar, Char, false);
   2605 GET_STATIC_TYPE_FIELD(jshort, Short, false);
   2606 GET_STATIC_TYPE_FIELD(jint, Int, false);
   2607 GET_STATIC_TYPE_FIELD(jlong, Long, false);
   2608 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
   2609 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
   2610 
   2611 /*
   2612  * Set a static field.
   2613  */
   2614 #define SET_STATIC_TYPE_FIELD(_ctype, _jname, _isref)                       \
   2615     static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz,        \
   2616         jfieldID fieldID, _ctype value)                                     \
   2617     {                                                                       \
   2618         UNUSED_PARAMETER(jclazz);                                           \
   2619         JNI_ENTER();                                                        \
   2620         StaticField* sfield = (StaticField*) fieldID;                       \
   2621         if (dvmIsVolatileField(&sfield->field)) {                           \
   2622             if (_isref) {   /* only when _ctype==jobject */                 \
   2623                 Object* valObj =                                            \
   2624                     dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
   2625                 dvmSetStaticFieldObjectVolatile(sfield, valObj);            \
   2626             } else {                                                        \
   2627                 dvmSetStaticField##_jname##Volatile(sfield, value);         \
   2628             }                                                               \
   2629         } else {                                                            \
   2630             if (_isref) {                                                   \
   2631                 Object* valObj =                                            \
   2632                     dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
   2633                 dvmSetStaticFieldObject(sfield, valObj);                    \
   2634             } else {                                                        \
   2635                 dvmSetStaticField##_jname(sfield, value);                   \
   2636             }                                                               \
   2637         }                                                                   \
   2638         JNI_EXIT();                                                         \
   2639     }
   2640 SET_STATIC_TYPE_FIELD(jobject, Object, true);
   2641 SET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
   2642 SET_STATIC_TYPE_FIELD(jbyte, Byte, false);
   2643 SET_STATIC_TYPE_FIELD(jchar, Char, false);
   2644 SET_STATIC_TYPE_FIELD(jshort, Short, false);
   2645 SET_STATIC_TYPE_FIELD(jint, Int, false);
   2646 SET_STATIC_TYPE_FIELD(jlong, Long, false);
   2647 SET_STATIC_TYPE_FIELD(jfloat, Float, false);
   2648 SET_STATIC_TYPE_FIELD(jdouble, Double, false);
   2649 
   2650 /*
   2651  * Get an instance field.
   2652  *
   2653  * If we get an object reference, add it to the local refs list.
   2654  */
   2655 #define GET_TYPE_FIELD(_ctype, _jname, _isref)                              \
   2656     static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj,             \
   2657         jfieldID fieldID)                                                   \
   2658     {                                                                       \
   2659         JNI_ENTER();                                                        \
   2660         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2661         InstField* field = (InstField*) fieldID;                            \
   2662         _ctype value;                                                       \
   2663         if (dvmIsVolatileField(&field->field)) {                            \
   2664             if (_isref) {   /* only when _ctype==jobject */                 \
   2665                 Object* valObj =                                            \
   2666                     dvmGetFieldObjectVolatile(obj, field->byteOffset);      \
   2667                 value = (_ctype)(u4)addLocalReference(env, valObj);         \
   2668             } else {                                                        \
   2669                 value =                                                     \
   2670                     dvmGetField##_jname##Volatile(obj, field->byteOffset);  \
   2671             }                                                               \
   2672         } else {                                                            \
   2673             if (_isref) {                                                   \
   2674                 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
   2675                 value = (_ctype)(u4)addLocalReference(env, valObj);         \
   2676             } else {                                                        \
   2677                 value = dvmGetField##_jname(obj, field->byteOffset);        \
   2678             }                                                               \
   2679         }                                                                   \
   2680         JNI_EXIT();                                                         \
   2681         return value;                                                       \
   2682     }
   2683 GET_TYPE_FIELD(jobject, Object, true);
   2684 GET_TYPE_FIELD(jboolean, Boolean, false);
   2685 GET_TYPE_FIELD(jbyte, Byte, false);
   2686 GET_TYPE_FIELD(jchar, Char, false);
   2687 GET_TYPE_FIELD(jshort, Short, false);
   2688 GET_TYPE_FIELD(jint, Int, false);
   2689 GET_TYPE_FIELD(jlong, Long, false);
   2690 GET_TYPE_FIELD(jfloat, Float, false);
   2691 GET_TYPE_FIELD(jdouble, Double, false);
   2692 
   2693 /*
   2694  * Set an instance field.
   2695  */
   2696 #define SET_TYPE_FIELD(_ctype, _jname, _isref)                              \
   2697     static void Set##_jname##Field(JNIEnv* env, jobject jobj,               \
   2698         jfieldID fieldID, _ctype value)                                     \
   2699     {                                                                       \
   2700         JNI_ENTER();                                                        \
   2701         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2702         InstField* field = (InstField*) fieldID;                            \
   2703         if (dvmIsVolatileField(&field->field)) {                            \
   2704             if (_isref) {   /* only when _ctype==jobject */                 \
   2705                 Object* valObj =                                            \
   2706                     dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
   2707                 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj);  \
   2708             } else {                                                        \
   2709                 dvmSetField##_jname##Volatile(obj,                          \
   2710                     field->byteOffset, value);                              \
   2711             }                                                               \
   2712         } else {                                                            \
   2713             if (_isref) {                                                   \
   2714                 Object* valObj =                                            \
   2715                     dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
   2716                 dvmSetFieldObject(obj, field->byteOffset, valObj);          \
   2717             } else {                                                        \
   2718                 dvmSetField##_jname(obj, field->byteOffset, value);         \
   2719             }                                                               \
   2720         }                                                                   \
   2721         JNI_EXIT();                                                         \
   2722     }
   2723 SET_TYPE_FIELD(jobject, Object, true);
   2724 SET_TYPE_FIELD(jboolean, Boolean, false);
   2725 SET_TYPE_FIELD(jbyte, Byte, false);
   2726 SET_TYPE_FIELD(jchar, Char, false);
   2727 SET_TYPE_FIELD(jshort, Short, false);
   2728 SET_TYPE_FIELD(jint, Int, false);
   2729 SET_TYPE_FIELD(jlong, Long, false);
   2730 SET_TYPE_FIELD(jfloat, Float, false);
   2731 SET_TYPE_FIELD(jdouble, Double, false);
   2732 
   2733 /*
   2734  * Make a virtual method call.
   2735  *
   2736  * Three versions (..., va_list, jvalue[]) for each return type.  If we're
   2737  * returning an Object, we have to add it to the local references table.
   2738  */
   2739 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref)              \
   2740     static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj,           \
   2741         jmethodID methodID, ...)                                            \
   2742     {                                                                       \
   2743         JNI_ENTER();                                                        \
   2744         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2745         const Method* meth;                                                 \
   2746         va_list args;                                                       \
   2747         JValue result;                                                      \
   2748         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   2749         if (meth == NULL) {                                                 \
   2750             JNI_EXIT();                                                     \
   2751             return _retfail;                                                \
   2752         }                                                                   \
   2753         va_start(args, methodID);                                           \
   2754         dvmCallMethodV(_self, meth, obj, true, &result, args);              \
   2755         va_end(args);                                                       \
   2756         if (_isref && !dvmCheckException(_self))                            \
   2757             result.l = addLocalReference(env, result.l);                    \
   2758         JNI_EXIT();                                                         \
   2759         return _retok;                                                      \
   2760     }                                                                       \
   2761     static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj,          \
   2762         jmethodID methodID, va_list args)                                   \
   2763     {                                                                       \
   2764         JNI_ENTER();                                                        \
   2765         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2766         const Method* meth;                                                 \
   2767         JValue result;                                                      \
   2768         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   2769         if (meth == NULL) {                                                 \
   2770             JNI_EXIT();                                                     \
   2771             return _retfail;                                                \
   2772         }                                                                   \
   2773         dvmCallMethodV(_self, meth, obj, true, &result, args);              \
   2774         if (_isref && !dvmCheckException(_self))                            \
   2775             result.l = addLocalReference(env, result.l);                    \
   2776         JNI_EXIT();                                                         \
   2777         return _retok;                                                      \
   2778     }                                                                       \
   2779     static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj,          \
   2780         jmethodID methodID, jvalue* args)                                   \
   2781     {                                                                       \
   2782         JNI_ENTER();                                                        \
   2783         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2784         const Method* meth;                                                 \
   2785         JValue result;                                                      \
   2786         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   2787         if (meth == NULL) {                                                 \
   2788             JNI_EXIT();                                                     \
   2789             return _retfail;                                                \
   2790         }                                                                   \
   2791         dvmCallMethodA(_self, meth, obj, true, &result, args);              \
   2792         if (_isref && !dvmCheckException(_self))                            \
   2793             result.l = addLocalReference(env, result.l);                    \
   2794         JNI_EXIT();                                                         \
   2795         return _retok;                                                      \
   2796     }
   2797 CALL_VIRTUAL(jobject, Object, NULL, result.l, true);
   2798 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
   2799 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
   2800 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
   2801 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
   2802 CALL_VIRTUAL(jint, Int, 0, result.i, false);
   2803 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
   2804 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
   2805 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
   2806 CALL_VIRTUAL(void, Void, , , false);
   2807 
   2808 /*
   2809  * Make a "non-virtual" method call.  We're still calling a virtual method,
   2810  * but this time we're not doing an indirection through the object's vtable.
   2811  * The "clazz" parameter defines which implementation of a method we want.
   2812  *
   2813  * Three versions (..., va_list, jvalue[]) for each return type.
   2814  */
   2815 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref)           \
   2816     static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
   2817         jclass jclazz, jmethodID methodID, ...)                             \
   2818     {                                                                       \
   2819         JNI_ENTER();                                                        \
   2820         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2821         ClassObject* clazz =                                                \
   2822             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2823         const Method* meth;                                                 \
   2824         va_list args;                                                       \
   2825         JValue result;                                                      \
   2826         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2827         if (meth == NULL) {                                                 \
   2828             JNI_EXIT();                                                     \
   2829             return _retfail;                                                \
   2830         }                                                                   \
   2831         va_start(args, methodID);                                           \
   2832         dvmCallMethodV(_self, meth, obj, true, &result, args);              \
   2833         if (_isref && !dvmCheckException(_self))                            \
   2834             result.l = addLocalReference(env, result.l);                    \
   2835         va_end(args);                                                       \
   2836         JNI_EXIT();                                                         \
   2837         return _retok;                                                      \
   2838     }                                                                       \
   2839     static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
   2840         jclass jclazz, jmethodID methodID, va_list args)                    \
   2841     {                                                                       \
   2842         JNI_ENTER();                                                        \
   2843         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2844         ClassObject* clazz =                                                \
   2845             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2846         const Method* meth;                                                 \
   2847         JValue result;                                                      \
   2848         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2849         if (meth == NULL) {                                                 \
   2850             JNI_EXIT();                                                     \
   2851             return _retfail;                                                \
   2852         }                                                                   \
   2853         dvmCallMethodV(_self, meth, obj, true, &result, args);              \
   2854         if (_isref && !dvmCheckException(_self))                            \
   2855             result.l = addLocalReference(env, result.l);                    \
   2856         JNI_EXIT();                                                         \
   2857         return _retok;                                                      \
   2858     }                                                                       \
   2859     static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
   2860         jclass jclazz, jmethodID methodID, jvalue* args)                    \
   2861     {                                                                       \
   2862         JNI_ENTER();                                                        \
   2863         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2864         ClassObject* clazz =                                                \
   2865             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2866         const Method* meth;                                                 \
   2867         JValue result;                                                      \
   2868         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2869         if (meth == NULL) {                                                 \
   2870             JNI_EXIT();                                                     \
   2871             return _retfail;                                                \
   2872         }                                                                   \
   2873         dvmCallMethodA(_self, meth, obj, true, &result, args);              \
   2874         if (_isref && !dvmCheckException(_self))                            \
   2875             result.l = addLocalReference(env, result.l);                    \
   2876         JNI_EXIT();                                                         \
   2877         return _retok;                                                      \
   2878     }
   2879 CALL_NONVIRTUAL(jobject, Object, NULL, result.l, true);
   2880 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
   2881 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
   2882 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
   2883 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
   2884 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
   2885 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
   2886 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
   2887 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
   2888 CALL_NONVIRTUAL(void, Void, , , false);
   2889 
   2890 
   2891 /*
   2892  * Call a static method.
   2893  */
   2894 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref)               \
   2895     static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,    \
   2896         jmethodID methodID, ...)                                            \
   2897     {                                                                       \
   2898         UNUSED_PARAMETER(jclazz);                                           \
   2899         JNI_ENTER();                                                        \
   2900         JValue result;                                                      \
   2901         va_list args;                                                       \
   2902         va_start(args, methodID);                                           \
   2903         dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
   2904         va_end(args);                                                       \
   2905         if (_isref && !dvmCheckException(_self))                            \
   2906             result.l = addLocalReference(env, result.l);                    \
   2907         JNI_EXIT();                                                         \
   2908         return _retok;                                                      \
   2909     }                                                                       \
   2910     static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,   \
   2911         jmethodID methodID, va_list args)                                   \
   2912     {                                                                       \
   2913         UNUSED_PARAMETER(jclazz);                                           \
   2914         JNI_ENTER();                                                        \
   2915         JValue result;                                                      \
   2916         dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
   2917         if (_isref && !dvmCheckException(_self))                            \
   2918             result.l = addLocalReference(env, result.l);                    \
   2919         JNI_EXIT();                                                         \
   2920         return _retok;                                                      \
   2921     }                                                                       \
   2922     static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,   \
   2923         jmethodID methodID, jvalue* args)                                   \
   2924     {                                                                       \
   2925         UNUSED_PARAMETER(jclazz);                                           \
   2926         JNI_ENTER();                                                        \
   2927         JValue result;                                                      \
   2928         dvmCallMethodA(_self, (Method*)methodID, NULL, true, &result, args);\
   2929         if (_isref && !dvmCheckException(_self))                            \
   2930             result.l = addLocalReference(env, result.l);                    \
   2931         JNI_EXIT();                                                         \
   2932         return _retok;                                                      \
   2933     }
   2934 CALL_STATIC(jobject, Object, NULL, result.l, true);
   2935 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
   2936 CALL_STATIC(jbyte, Byte, 0, result.b, false);
   2937 CALL_STATIC(jchar, Char, 0, result.c, false);
   2938 CALL_STATIC(jshort, Short, 0, result.s, false);
   2939 CALL_STATIC(jint, Int, 0, result.i, false);
   2940 CALL_STATIC(jlong, Long, 0, result.j, false);
   2941 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
   2942 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
   2943 CALL_STATIC(void, Void, , , false);
   2944 
   2945 /*
   2946  * Create a new String from Unicode data.
   2947  *
   2948  * If "len" is zero, we will return an empty string even if "unicodeChars"
   2949  * is NULL.  (The JNI spec is vague here.)
   2950  */
   2951 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len)
   2952 {
   2953     JNI_ENTER();
   2954     jobject retval;
   2955 
   2956     StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
   2957     if (jstr == NULL) {
   2958         retval = NULL;
   2959     } else {
   2960         dvmReleaseTrackedAlloc((Object*) jstr, NULL);
   2961         retval = addLocalReference(env, (Object*) jstr);
   2962     }
   2963 
   2964     JNI_EXIT();
   2965     return retval;
   2966 }
   2967 
   2968 /*
   2969  * Return the length of a String in Unicode character units.
   2970  */
   2971 static jsize GetStringLength(JNIEnv* env, jstring jstr)
   2972 {
   2973     JNI_ENTER();
   2974 
   2975     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2976     jsize len = dvmStringLen(strObj);
   2977 
   2978     JNI_EXIT();
   2979     return len;
   2980 }
   2981 
   2982 
   2983 /*
   2984  * Get a string's character data.
   2985  *
   2986  * The result is guaranteed to be valid until ReleaseStringChars is
   2987  * called, which means we have to pin it or return a copy.
   2988  */
   2989 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy)
   2990 {
   2991     JNI_ENTER();
   2992 
   2993     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2994     ArrayObject* strChars = dvmStringCharArray(strObj);
   2995 
   2996     pinPrimitiveArray(strChars);
   2997 
   2998     const u2* data = dvmStringChars(strObj);
   2999     if (isCopy != NULL)
   3000         *isCopy = JNI_FALSE;
   3001 
   3002     JNI_EXIT();
   3003     return (jchar*)data;
   3004 }
   3005 
   3006 /*
   3007  * Release our grip on some characters from a string.
   3008  */
   3009 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars)
   3010 {
   3011     JNI_ENTER();
   3012     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3013     ArrayObject* strChars = dvmStringCharArray(strObj);
   3014     unpinPrimitiveArray(strChars);
   3015     JNI_EXIT();
   3016 }
   3017 
   3018 /*
   3019  * Create a new java.lang.String object from chars in modified UTF-8 form.
   3020  *
   3021  * The spec doesn't say how to handle a NULL string.  Popular desktop VMs
   3022  * accept it and return a NULL pointer in response.
   3023  */
   3024 static jstring NewStringUTF(JNIEnv* env, const char* bytes)
   3025 {
   3026     JNI_ENTER();
   3027 
   3028     jstring result;
   3029 
   3030     if (bytes == NULL) {
   3031         result = NULL;
   3032     } else {
   3033         /* note newStr could come back NULL on OOM */
   3034         StringObject* newStr = dvmCreateStringFromCstr(bytes);
   3035         result = addLocalReference(env, (Object*) newStr);
   3036         dvmReleaseTrackedAlloc((Object*)newStr, NULL);
   3037     }
   3038 
   3039     JNI_EXIT();
   3040     return result;
   3041 }
   3042 
   3043 /*
   3044  * Return the length in bytes of the modified UTF-8 form of the string.
   3045  */
   3046 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr)
   3047 {
   3048     JNI_ENTER();
   3049 
   3050     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3051     jsize len = dvmStringUtf8ByteLen(strObj);
   3052 
   3053     JNI_EXIT();
   3054     return len;
   3055 }
   3056 
   3057 /*
   3058  * Convert "string" to modified UTF-8 and return a pointer.  The returned
   3059  * value must be released with ReleaseStringUTFChars.
   3060  *
   3061  * According to the JNI reference, "Returns a pointer to a UTF-8 string,
   3062  * or NULL if the operation fails. Returns NULL if and only if an invocation
   3063  * of this function has thrown an exception."
   3064  *
   3065  * The behavior here currently follows that of other open-source VMs, which
   3066  * quietly return NULL if "string" is NULL.  We should consider throwing an
   3067  * NPE.  (The CheckJNI code blows up if you try to pass in a NULL string,
   3068  * which should catch this sort of thing during development.)  Certain other
   3069  * VMs will crash with a segmentation fault.
   3070  */
   3071 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr,
   3072     jboolean* isCopy)
   3073 {
   3074     JNI_ENTER();
   3075     char* newStr;
   3076 
   3077     if (jstr == NULL) {
   3078         /* this shouldn't happen; throw NPE? */
   3079         newStr = NULL;
   3080     } else {
   3081         if (isCopy != NULL)
   3082             *isCopy = JNI_TRUE;
   3083 
   3084         StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3085         newStr = dvmCreateCstrFromString(strObj);
   3086         if (newStr == NULL) {
   3087             /* assume memory failure */
   3088             dvmThrowException("Ljava/lang/OutOfMemoryError;",
   3089                 "native heap string alloc failed");
   3090         }
   3091     }
   3092 
   3093     JNI_EXIT();
   3094     return newStr;
   3095 }
   3096 
   3097 /*
   3098  * Release a string created by GetStringUTFChars().
   3099  */
   3100 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf)
   3101 {
   3102     JNI_ENTER();
   3103     free((char*)utf);
   3104     JNI_EXIT();
   3105 }
   3106 
   3107 /*
   3108  * Return the capacity of the array.
   3109  */
   3110 static jsize GetArrayLength(JNIEnv* env, jarray jarr)
   3111 {
   3112     JNI_ENTER();
   3113 
   3114     ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3115     jsize length = arrObj->length;
   3116 
   3117     JNI_EXIT();
   3118     return length;
   3119 }
   3120 
   3121 /*
   3122  * Construct a new array that holds objects from class "elementClass".
   3123  */
   3124 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
   3125     jclass jelementClass, jobject jinitialElement)
   3126 {
   3127     JNI_ENTER();
   3128 
   3129     jobjectArray newArray = NULL;
   3130     ClassObject* elemClassObj =
   3131         (ClassObject*) dvmDecodeIndirectRef(env, jelementClass);
   3132 
   3133     if (elemClassObj == NULL) {
   3134         dvmThrowException("Ljava/lang/NullPointerException;",
   3135             "JNI NewObjectArray");
   3136         goto bail;
   3137     }
   3138 
   3139     ArrayObject* newObj =
   3140         dvmAllocObjectArray(elemClassObj, length, ALLOC_DEFAULT);
   3141     if (newObj == NULL) {
   3142         assert(dvmCheckException(_self));
   3143         goto bail;
   3144     }
   3145     newArray = addLocalReference(env, (Object*) newObj);
   3146     dvmReleaseTrackedAlloc((Object*) newObj, NULL);
   3147 
   3148     /*
   3149      * Initialize the array.  Trashes "length".
   3150      */
   3151     if (jinitialElement != NULL) {
   3152         Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement);
   3153         Object** arrayData = (Object**) newObj->contents;
   3154 
   3155         while (length--)
   3156             *arrayData++ = initialElement;
   3157     }
   3158 
   3159 
   3160 bail:
   3161     JNI_EXIT();
   3162     return newArray;
   3163 }
   3164 
   3165 /*
   3166  * Get one element of an Object array.
   3167  *
   3168  * Add the object to the local references table in case the array goes away.
   3169  */
   3170 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
   3171     jsize index)
   3172 {
   3173     JNI_ENTER();
   3174 
   3175     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3176     jobject retval = NULL;
   3177 
   3178     assert(arrayObj != NULL);
   3179 
   3180     /* check the array bounds */
   3181     if (index < 0 || index >= (int) arrayObj->length) {
   3182         dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
   3183             arrayObj->obj.clazz->descriptor);
   3184         goto bail;
   3185     }
   3186 
   3187     Object* value = ((Object**) arrayObj->contents)[index];
   3188     retval = addLocalReference(env, value);
   3189 
   3190 bail:
   3191     JNI_EXIT();
   3192     return retval;
   3193 }
   3194 
   3195 /*
   3196  * Set one element of an Object array.
   3197  */
   3198 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
   3199     jsize index, jobject jobj)
   3200 {
   3201     JNI_ENTER();
   3202 
   3203     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3204 
   3205     assert(arrayObj != NULL);
   3206 
   3207     /* check the array bounds */
   3208     if (index < 0 || index >= (int) arrayObj->length) {
   3209         dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
   3210             arrayObj->obj.clazz->descriptor);
   3211         goto bail;
   3212     }
   3213 
   3214     //LOGV("JNI: set element %d in array %p to %p\n", index, array, value);
   3215 
   3216     Object* obj = dvmDecodeIndirectRef(env, jobj);
   3217     dvmSetObjectArrayElement(arrayObj, index, obj);
   3218 
   3219 bail:
   3220     JNI_EXIT();
   3221 }
   3222 
   3223 /*
   3224  * Create a new array of primitive elements.
   3225  */
   3226 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar)                     \
   3227     static _artype New##_jname##Array(JNIEnv* env, jsize length)            \
   3228     {                                                                       \
   3229         JNI_ENTER();                                                        \
   3230         ArrayObject* arrayObj;                                              \
   3231         arrayObj = dvmAllocPrimitiveArray(_typechar, length,                \
   3232             ALLOC_DEFAULT);                                                 \
   3233         jarray jarr = NULL;                                                 \
   3234         if (arrayObj != NULL) {                                             \
   3235             jarr = addLocalReference(env, (Object*) arrayObj);              \
   3236             dvmReleaseTrackedAlloc((Object*) arrayObj, NULL);               \
   3237         }                                                                   \
   3238         JNI_EXIT();                                                         \
   3239         return (_artype)jarr;                                               \
   3240     }
   3241 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
   3242 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
   3243 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
   3244 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
   3245 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
   3246 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
   3247 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
   3248 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
   3249 
   3250 /*
   3251  * Get a pointer to a C array of primitive elements from an array object
   3252  * of the matching type.
   3253  *
   3254  * In a compacting GC, we either need to return a copy of the elements or
   3255  * "pin" the memory.  Otherwise we run the risk of native code using the
   3256  * buffer as the destination of e.g. a blocking read() call that wakes up
   3257  * during a GC.
   3258  */
   3259 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                        \
   3260     static _ctype* Get##_jname##ArrayElements(JNIEnv* env,                  \
   3261         _ctype##Array jarr, jboolean* isCopy)                               \
   3262     {                                                                       \
   3263         JNI_ENTER();                                                        \
   3264         _ctype* data;                                                       \
   3265         ArrayObject* arrayObj =                                             \
   3266             (ArrayObject*) dvmDecodeIndirectRef(env, jarr);                 \
   3267         pinPrimitiveArray(arrayObj);                                        \
   3268         data = (_ctype*) arrayObj->contents;                                \
   3269         if (isCopy != NULL)                                                 \
   3270             *isCopy = JNI_FALSE;                                            \
   3271         JNI_EXIT();                                                         \
   3272         return data;                                                        \
   3273     }
   3274 
   3275 /*
   3276  * Release the storage locked down by the "get" function.
   3277  *
   3278  * The spec says, "'mode' has no effect if 'elems' is not a copy of the
   3279  * elements in 'array'."  They apparently did not anticipate the need to
   3280  * un-pin memory.
   3281  */
   3282 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                    \
   3283     static void Release##_jname##ArrayElements(JNIEnv* env,                 \
   3284         _ctype##Array jarr, _ctype* elems, jint mode)                       \
   3285     {                                                                       \
   3286         UNUSED_PARAMETER(elems);                                            \
   3287         JNI_ENTER();                                                        \
   3288         if (mode != JNI_COMMIT) {                                           \
   3289             ArrayObject* arrayObj =                                         \
   3290                 (ArrayObject*) dvmDecodeIndirectRef(env, jarr);             \
   3291             unpinPrimitiveArray(arrayObj);                                  \
   3292         }                                                                   \
   3293         JNI_EXIT();                                                         \
   3294     }
   3295 
   3296 /*
   3297  * Copy a section of a primitive array to a buffer.
   3298  */
   3299 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname)                          \
   3300     static void Get##_jname##ArrayRegion(JNIEnv* env,                       \
   3301         _ctype##Array jarr, jsize start, jsize len, _ctype* buf)            \
   3302     {                                                                       \
   3303         JNI_ENTER();                                                        \
   3304         ArrayObject* arrayObj =                                             \
   3305             (ArrayObject*) dvmDecodeIndirectRef(env, jarr);                 \
   3306         _ctype* data = (_ctype*) arrayObj->contents;                        \
   3307         if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
   3308             dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
   3309                 arrayObj->obj.clazz->descriptor);                           \
   3310         } else {                                                            \
   3311             memcpy(buf, data + start, len * sizeof(_ctype));                \
   3312         }                                                                   \
   3313         JNI_EXIT();                                                         \
   3314     }
   3315 
   3316 /*
   3317  * Copy a section of a primitive array from a buffer.
   3318  */
   3319 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname)                          \
   3320     static void Set##_jname##ArrayRegion(JNIEnv* env,                       \
   3321         _ctype##Array jarr, jsize start, jsize len, const _ctype* buf)      \
   3322     {                                                                       \
   3323         JNI_ENTER();                                                        \
   3324         ArrayObject* arrayObj =                                             \
   3325             (ArrayObject*) dvmDecodeIndirectRef(env, jarr);                 \
   3326         _ctype* data = (_ctype*) arrayObj->contents;                        \
   3327         if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
   3328             dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
   3329                 arrayObj->obj.clazz->descriptor);                           \
   3330         } else {                                                            \
   3331             memcpy(data + start, buf, len * sizeof(_ctype));                \
   3332         }                                                                   \
   3333         JNI_EXIT();                                                         \
   3334     }
   3335 
   3336 /*
   3337  * 4-in-1:
   3338  *  Get<Type>ArrayElements
   3339  *  Release<Type>ArrayElements
   3340  *  Get<Type>ArrayRegion
   3341  *  Set<Type>ArrayRegion
   3342  */
   3343 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname)                           \
   3344     GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                           \
   3345     RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                       \
   3346     GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);                             \
   3347     SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
   3348 
   3349 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
   3350 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
   3351 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
   3352 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
   3353 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
   3354 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
   3355 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
   3356 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
   3357 
   3358 /*
   3359  * Register one or more native functions in one class.
   3360  *
   3361  * This can be called multiple times on the same method, allowing the
   3362  * caller to redefine the method implementation at will.
   3363  */
   3364 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
   3365     const JNINativeMethod* methods, jint nMethods)
   3366 {
   3367     JNI_ENTER();
   3368 
   3369     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   3370     jint retval = JNI_OK;
   3371     int i;
   3372 
   3373     if (gDvm.verboseJni) {
   3374         LOGI("[Registering JNI native methods for class %s]\n",
   3375             clazz->descriptor);
   3376     }
   3377 
   3378     for (i = 0; i < nMethods; i++) {
   3379         if (!dvmRegisterJNIMethod(clazz, methods[i].name,
   3380                 methods[i].signature, methods[i].fnPtr))
   3381         {
   3382             retval = JNI_ERR;
   3383         }
   3384     }
   3385 
   3386     JNI_EXIT();
   3387     return retval;
   3388 }
   3389 
   3390 /*
   3391  * Un-register all native methods associated with the class.
   3392  *
   3393  * The JNI docs refer to this as a way to reload/relink native libraries,
   3394  * and say it "should not be used in normal native code".  In particular,
   3395  * there is no need to do this during shutdown, and you do not need to do
   3396  * this before redefining a method implementation with RegisterNatives.
   3397  *
   3398  * It's chiefly useful for a native "plugin"-style library that wasn't
   3399  * loaded with System.loadLibrary() (since there's no way to unload those).
   3400  * For example, the library could upgrade itself by:
   3401  *
   3402  *  1. call UnregisterNatives to unbind the old methods
   3403  *  2. ensure that no code is still executing inside it (somehow)
   3404  *  3. dlclose() the library
   3405  *  4. dlopen() the new library
   3406  *  5. use RegisterNatives to bind the methods from the new library
   3407  *
   3408  * The above can work correctly without the UnregisterNatives call, but
   3409  * creates a window of opportunity in which somebody might try to call a
   3410  * method that is pointing at unmapped memory, crashing the VM.  In theory
   3411  * the same guards that prevent dlclose() from unmapping executing code could
   3412  * prevent that anyway, but with this we can be more thorough and also deal
   3413  * with methods that only exist in the old or new form of the library (maybe
   3414  * the lib wants to try the call and catch the UnsatisfiedLinkError).
   3415  */
   3416 static jint UnregisterNatives(JNIEnv* env, jclass jclazz)
   3417 {
   3418     JNI_ENTER();
   3419 
   3420     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   3421     if (gDvm.verboseJni) {
   3422         LOGI("[Unregistering JNI native methods for class %s]\n",
   3423             clazz->descriptor);
   3424     }
   3425     dvmUnregisterJNINativeMethods(clazz);
   3426 
   3427     JNI_EXIT();
   3428     return JNI_OK;
   3429 }
   3430 
   3431 /*
   3432  * Lock the monitor.
   3433  *
   3434  * We have to track all monitor enters and exits, so that we can undo any
   3435  * outstanding synchronization before the thread exits.
   3436  */
   3437 static jint MonitorEnter(JNIEnv* env, jobject jobj)
   3438 {
   3439     JNI_ENTER();
   3440     Object* obj = dvmDecodeIndirectRef(env, jobj);
   3441     dvmLockObject(_self, obj);
   3442     trackMonitorEnter(_self, obj);
   3443     JNI_EXIT();
   3444     return JNI_OK;
   3445 }
   3446 
   3447 /*
   3448  * Unlock the monitor.
   3449  *
   3450  * Throws an IllegalMonitorStateException if the current thread
   3451  * doesn't own the monitor.  (dvmUnlockObject() takes care of the throw.)
   3452  *
   3453  * According to the 1.6 spec, it's legal to call here with an exception
   3454  * pending.  If this fails, we'll stomp the original exception.
   3455  */
   3456 static jint MonitorExit(JNIEnv* env, jobject jobj)
   3457 {
   3458     JNI_ENTER();
   3459     Object* obj = dvmDecodeIndirectRef(env, jobj);
   3460     bool success = dvmUnlockObject(_self, obj);
   3461     if (success)
   3462         trackMonitorExit(_self, obj);
   3463     JNI_EXIT();
   3464     return success ? JNI_OK : JNI_ERR;
   3465 }
   3466 
   3467 /*
   3468  * Return the JavaVM interface associated with the current thread.
   3469  */
   3470 static jint GetJavaVM(JNIEnv* env, JavaVM** vm)
   3471 {
   3472     JNI_ENTER();
   3473     //*vm = gDvm.vmList;
   3474     *vm = (JavaVM*) ((JNIEnvExt*)env)->vm;
   3475     JNI_EXIT();
   3476     if (*vm == NULL)
   3477         return JNI_ERR;
   3478     else
   3479         return JNI_OK;
   3480 }
   3481 
   3482 /*
   3483  * Copies "len" Unicode characters, from offset "start".
   3484  */
   3485 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len,
   3486     jchar* buf)
   3487 {
   3488     JNI_ENTER();
   3489     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3490     if (start + len > dvmStringLen(strObj))
   3491         dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
   3492     else
   3493         memcpy(buf, dvmStringChars(strObj) + start, len * sizeof(u2));
   3494     JNI_EXIT();
   3495 }
   3496 
   3497 /*
   3498  * Translates "len" Unicode characters, from offset "start", into
   3499  * modified UTF-8 encoding.
   3500  */
   3501 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start,
   3502     jsize len, char* buf)
   3503 {
   3504     JNI_ENTER();
   3505     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3506     if (start + len > dvmStringLen(strObj))
   3507         dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
   3508     else
   3509         dvmCreateCstrFromStringRegion(strObj, start, len, buf);
   3510     JNI_EXIT();
   3511 }
   3512 
   3513 /*
   3514  * Get a raw pointer to array data.
   3515  *
   3516  * The caller is expected to call "release" before doing any JNI calls
   3517  * or blocking I/O operations.
   3518  *
   3519  * We need to pin the memory or block GC.
   3520  */
   3521 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr,
   3522     jboolean* isCopy)
   3523 {
   3524     JNI_ENTER();
   3525     void* data;
   3526     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3527     pinPrimitiveArray(arrayObj);
   3528     data = arrayObj->contents;
   3529     if (isCopy != NULL)
   3530         *isCopy = JNI_FALSE;
   3531     JNI_EXIT();
   3532     return data;
   3533 }
   3534 
   3535 /*
   3536  * Release an array obtained with GetPrimitiveArrayCritical.
   3537  */
   3538 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr,
   3539     void* carray, jint mode)
   3540 {
   3541     JNI_ENTER();
   3542     if (mode != JNI_COMMIT) {
   3543         ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   3544         unpinPrimitiveArray(arrayObj);
   3545     }
   3546     JNI_EXIT();
   3547 }
   3548 
   3549 /*
   3550  * Like GetStringChars, but with restricted use.
   3551  */
   3552 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr,
   3553     jboolean* isCopy)
   3554 {
   3555     JNI_ENTER();
   3556     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3557     ArrayObject* strChars = dvmStringCharArray(strObj);
   3558 
   3559     pinPrimitiveArray(strChars);
   3560 
   3561     const u2* data = dvmStringChars(strObj);
   3562     if (isCopy != NULL)
   3563         *isCopy = JNI_FALSE;
   3564 
   3565     JNI_EXIT();
   3566     return (jchar*)data;
   3567 }
   3568 
   3569 /*
   3570  * Like ReleaseStringChars, but with restricted use.
   3571  */
   3572 static void ReleaseStringCritical(JNIEnv* env, jstring jstr,
   3573     const jchar* carray)
   3574 {
   3575     JNI_ENTER();
   3576     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   3577     ArrayObject* strChars = dvmStringCharArray(strObj);
   3578     unpinPrimitiveArray(strChars);
   3579     JNI_EXIT();
   3580 }
   3581 
   3582 /*
   3583  * Create a new weak global reference.
   3584  */
   3585 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj)
   3586 {
   3587     JNI_ENTER();
   3588     jweak wref = createWeakGlobalRef(env, obj);
   3589     JNI_EXIT();
   3590     return wref;
   3591 }
   3592 
   3593 /*
   3594  * Delete the specified weak global reference.
   3595  */
   3596 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref)
   3597 {
   3598     JNI_ENTER();
   3599     deleteWeakGlobalRef(env, wref);
   3600     JNI_EXIT();
   3601 }
   3602 
   3603 /*
   3604  * Quick check for pending exceptions.
   3605  *
   3606  * TODO: we should be able to skip the enter/exit macros here.
   3607  */
   3608 static jboolean ExceptionCheck(JNIEnv* env)
   3609 {
   3610     JNI_ENTER();
   3611     bool result = dvmCheckException(_self);
   3612     JNI_EXIT();
   3613     return result;
   3614 }
   3615 
   3616 /*
   3617  * Returns the type of the object referred to by "obj".  It can be local,
   3618  * global, or weak global.
   3619  *
   3620  * In the current implementation, references can be global and local at
   3621  * the same time, so while the return value is accurate it may not tell
   3622  * the whole story.
   3623  */
   3624 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj)
   3625 {
   3626     JNI_ENTER();
   3627     jobjectRefType type = dvmGetJNIRefType(env, jobj);
   3628     JNI_EXIT();
   3629     return type;
   3630 }
   3631 
   3632 /*
   3633  * Allocate and return a new java.nio.ByteBuffer for this block of memory.
   3634  *
   3635  * "address" may not be NULL, and "capacity" must be > 0.  (These are only
   3636  * verified when CheckJNI is enabled.)
   3637  */
   3638 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)
   3639 {
   3640     JNI_ENTER();
   3641 
   3642     Thread* self = _self /*dvmThreadSelf()*/;
   3643     Object* platformAddress = NULL;
   3644     JValue callResult;
   3645     jobject result = NULL;
   3646     ClassObject* tmpClazz;
   3647 
   3648     tmpClazz = gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on->clazz;
   3649     if (!dvmIsClassInitialized(tmpClazz) && !dvmInitClass(tmpClazz))
   3650         goto bail;
   3651 
   3652     /* get an instance of PlatformAddress that wraps the provided address */
   3653     dvmCallMethod(self,
   3654         gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on,
   3655         NULL, &callResult, address);
   3656     if (dvmGetException(self) != NULL || callResult.l == NULL)
   3657         goto bail;
   3658 
   3659     /* don't let the GC discard it */
   3660     platformAddress = (Object*) callResult.l;
   3661     dvmAddTrackedAlloc(platformAddress, self);
   3662     LOGV("tracking %p for address=%p\n", platformAddress, address);
   3663 
   3664     /* create an instance of java.nio.ReadWriteDirectByteBuffer */
   3665     tmpClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
   3666     if (!dvmIsClassInitialized(tmpClazz) && !dvmInitClass(tmpClazz))
   3667         goto bail;
   3668     Object* newObj = dvmAllocObject(tmpClazz, ALLOC_DONT_TRACK);
   3669     if (newObj != NULL) {
   3670         /* call the (PlatformAddress, int, int) constructor */
   3671         result = addLocalReference(env, newObj);
   3672         dvmCallMethod(self, gDvm.methJavaNioReadWriteDirectByteBuffer_init,
   3673             newObj, &callResult, platformAddress, (jint) capacity, (jint) 0);
   3674         if (dvmGetException(self) != NULL) {
   3675             deleteLocalReference(env, result);
   3676             result = NULL;
   3677             goto bail;
   3678         }
   3679     }
   3680 
   3681 bail:
   3682     if (platformAddress != NULL)
   3683         dvmReleaseTrackedAlloc(platformAddress, self);
   3684     JNI_EXIT();
   3685     return result;
   3686 }
   3687 
   3688 /*
   3689  * Get the starting address of the buffer for the specified java.nio.Buffer.
   3690  *
   3691  * If this is not a "direct" buffer, we return NULL.
   3692  */
   3693 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf)
   3694 {
   3695     JNI_ENTER();
   3696 
   3697     Object* bufObj = dvmDecodeIndirectRef(env, jbuf);
   3698     Thread* self = _self /*dvmThreadSelf()*/;
   3699     void* result;
   3700 
   3701     /*
   3702      * All Buffer objects have an effectiveDirectAddress field.  If it's
   3703      * nonzero, we can just return that value.  If not, we have to call
   3704      * through DirectBuffer.getEffectiveAddress(), which as a side-effect
   3705      * will set the effectiveDirectAddress field for direct buffers (and
   3706      * things that wrap direct buffers).
   3707      */
   3708     result = (void*) dvmGetFieldInt(bufObj,
   3709             gDvm.offJavaNioBuffer_effectiveDirectAddress);
   3710     if (result != NULL) {
   3711         //LOGI("fast path for %p\n", buf);
   3712         goto bail;
   3713     }
   3714 
   3715     /*
   3716      * Start by determining if the object supports the DirectBuffer
   3717      * interfaces.  Note this does not guarantee that it's a direct buffer.
   3718      */
   3719     if (!dvmInstanceof(bufObj->clazz,
   3720             gDvm.classOrgApacheHarmonyNioInternalDirectBuffer))
   3721     {
   3722         goto bail;
   3723     }
   3724 
   3725     /*
   3726      * Get a PlatformAddress object with the effective address.
   3727      *
   3728      * If this isn't a direct buffer, the result will be NULL and/or an
   3729      * exception will have been thrown.
   3730      */
   3731     JValue callResult;
   3732     const Method* meth = dvmGetVirtualizedMethod(bufObj->clazz,
   3733         gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress);
   3734     dvmCallMethodA(self, meth, bufObj, false, &callResult, NULL);
   3735     if (dvmGetException(self) != NULL) {
   3736         dvmClearException(self);
   3737         callResult.l = NULL;
   3738     }
   3739 
   3740     Object* platformAddr = callResult.l;
   3741     if (platformAddr == NULL) {
   3742         LOGV("Got request for address of non-direct buffer\n");
   3743         goto bail;
   3744     }
   3745 
   3746     /*
   3747      * Extract the address from the PlatformAddress object.  Instead of
   3748      * calling the toLong() method, just grab the field directly.  This
   3749      * is faster but more fragile.
   3750      */
   3751     result = (void*) dvmGetFieldInt(platformAddr,
   3752                 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr);
   3753 
   3754     //LOGI("slow path for %p --> %p\n", buf, result);
   3755 
   3756 bail:
   3757     JNI_EXIT();
   3758     return result;
   3759 }
   3760 
   3761 /*
   3762  * Get the capacity of the buffer for the specified java.nio.Buffer.
   3763  *
   3764  * Returns -1 if the object is not a direct buffer.  (We actually skip
   3765  * this check, since it's expensive to determine, and just return the
   3766  * capacity regardless.)
   3767  */
   3768 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf)
   3769 {
   3770     JNI_ENTER();
   3771 
   3772     /*
   3773      * The capacity is always in the Buffer.capacity field.
   3774      *
   3775      * (The "check" version should verify that this is actually a Buffer,
   3776      * but we're not required to do so here.)
   3777      */
   3778     Object* buf = dvmDecodeIndirectRef(env, jbuf);
   3779     jlong result = dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
   3780 
   3781     JNI_EXIT();
   3782     return result;
   3783 }
   3784 
   3785 
   3786 /*
   3787  * ===========================================================================
   3788  *      JNI invocation functions
   3789  * ===========================================================================
   3790  */
   3791 
   3792 /*
   3793  * Handle AttachCurrentThread{AsDaemon}.
   3794  *
   3795  * We need to make sure the VM is actually running.  For example, if we start
   3796  * up, issue an Attach, and the VM exits almost immediately, by the time the
   3797  * attaching happens the VM could already be shutting down.
   3798  *
   3799  * It's hard to avoid a race condition here because we don't want to hold
   3800  * a lock across the entire operation.  What we can do is temporarily
   3801  * increment the thread count to prevent a VM exit.
   3802  *
   3803  * This could potentially still have problems if a daemon thread calls here
   3804  * while the VM is shutting down.  dvmThreadSelf() will work, since it just
   3805  * uses pthread TLS, but dereferencing "vm" could fail.  Such is life when
   3806  * you shut down a VM while threads are still running inside it.
   3807  *
   3808  * Remember that some code may call this as a way to find the per-thread
   3809  * JNIEnv pointer.  Don't do excess work for that case.
   3810  */
   3811 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args,
   3812     bool isDaemon)
   3813 {
   3814     JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
   3815     Thread* self;
   3816     bool result = false;
   3817 
   3818     /*
   3819      * Return immediately if we're already one with the VM.
   3820      */
   3821     self = dvmThreadSelf();
   3822     if (self != NULL) {
   3823         *p_env = self->jniEnv;
   3824         return JNI_OK;
   3825     }
   3826 
   3827     /*
   3828      * No threads allowed in zygote mode.
   3829      */
   3830     if (gDvm.zygote) {
   3831         return JNI_ERR;
   3832     }
   3833 
   3834     /* increment the count to keep the VM from bailing while we run */
   3835     dvmLockThreadList(NULL);
   3836     if (gDvm.nonDaemonThreadCount == 0) {
   3837         // dead or dying
   3838         LOGV("Refusing to attach thread '%s' -- VM is shutting down\n",
   3839             (thr_args == NULL) ? "(unknown)" : args->name);
   3840         dvmUnlockThreadList();
   3841         return JNI_ERR;
   3842     }
   3843     gDvm.nonDaemonThreadCount++;
   3844     dvmUnlockThreadList();
   3845 
   3846     /* tweak the JavaVMAttachArgs as needed */
   3847     JavaVMAttachArgs argsCopy;
   3848     if (args == NULL) {
   3849         /* allow the v1.1 calling convention */
   3850         argsCopy.version = JNI_VERSION_1_2;
   3851         argsCopy.name = NULL;
   3852         argsCopy.group = dvmGetMainThreadGroup();
   3853     } else {
   3854         assert(args->version >= JNI_VERSION_1_2);
   3855 
   3856         argsCopy.version = args->version;
   3857         argsCopy.name = args->name;
   3858         if (args->group != NULL)
   3859             argsCopy.group = args->group;
   3860         else
   3861             argsCopy.group = dvmGetMainThreadGroup();
   3862     }
   3863 
   3864     result = dvmAttachCurrentThread(&argsCopy, isDaemon);
   3865 
   3866     /* restore the count */
   3867     dvmLockThreadList(NULL);
   3868     gDvm.nonDaemonThreadCount--;
   3869     dvmUnlockThreadList();
   3870 
   3871     /*
   3872      * Change the status to indicate that we're out in native code.  This
   3873      * call is not guarded with state-change macros, so we have to do it
   3874      * by hand.
   3875      */
   3876     if (result) {
   3877         self = dvmThreadSelf();
   3878         assert(self != NULL);
   3879         dvmChangeStatus(self, THREAD_NATIVE);
   3880         *p_env = self->jniEnv;
   3881         return JNI_OK;
   3882     } else {
   3883         return JNI_ERR;
   3884     }
   3885 }
   3886 
   3887 /*
   3888  * Attach the current thread to the VM.  If the thread is already attached,
   3889  * this is a no-op.
   3890  */
   3891 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args)
   3892 {
   3893     return attachThread(vm, p_env, thr_args, false);
   3894 }
   3895 
   3896 /*
   3897  * Like AttachCurrentThread, but set the "daemon" flag.
   3898  */
   3899 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env,
   3900     void* thr_args)
   3901 {
   3902     return attachThread(vm, p_env, thr_args, true);
   3903 }
   3904 
   3905 /*
   3906  * Dissociate the current thread from the VM.
   3907  */
   3908 static jint DetachCurrentThread(JavaVM* vm)
   3909 {
   3910     Thread* self = dvmThreadSelf();
   3911 
   3912     if (self == NULL)               /* not attached, can't do anything */
   3913         return JNI_ERR;
   3914 
   3915     /* switch to "running" to check for suspension */
   3916     dvmChangeStatus(self, THREAD_RUNNING);
   3917 
   3918     /* detach the thread */
   3919     dvmDetachCurrentThread();
   3920 
   3921     /* (no need to change status back -- we have no status) */
   3922     return JNI_OK;
   3923 }
   3924 
   3925 /*
   3926  * If current thread is attached to VM, return the associated JNIEnv.
   3927  * Otherwise, stuff NULL in and return JNI_EDETACHED.
   3928  *
   3929  * JVMTI overloads this by specifying a magic value for "version", so we
   3930  * do want to check that here.
   3931  */
   3932 static jint GetEnv(JavaVM* vm, void** env, jint version)
   3933 {
   3934     Thread* self = dvmThreadSelf();
   3935 
   3936     if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6)
   3937         return JNI_EVERSION;
   3938 
   3939     if (self == NULL) {
   3940         *env = NULL;
   3941     } else {
   3942         /* TODO: status change is probably unnecessary */
   3943         dvmChangeStatus(self, THREAD_RUNNING);
   3944         *env = (void*) dvmGetThreadJNIEnv(self);
   3945         dvmChangeStatus(self, THREAD_NATIVE);
   3946     }
   3947     if (*env == NULL)
   3948         return JNI_EDETACHED;
   3949     else
   3950         return JNI_OK;
   3951 }
   3952 
   3953 /*
   3954  * Destroy the VM.  This may be called from any thread.
   3955  *
   3956  * If the current thread is attached, wait until the current thread is
   3957  * the only non-daemon user-level thread.  If the current thread is not
   3958  * attached, we attach it and do the processing as usual.  (If the attach
   3959  * fails, it's probably because all the non-daemon threads have already
   3960  * exited and the VM doesn't want to let us back in.)
   3961  *
   3962  * TODO: we don't really deal with the situation where more than one thread
   3963  * has called here.  One thread wins, the other stays trapped waiting on
   3964  * the condition variable forever.  Not sure this situation is interesting
   3965  * in real life.
   3966  */
   3967 static jint DestroyJavaVM(JavaVM* vm)
   3968 {
   3969     JavaVMExt* ext = (JavaVMExt*) vm;
   3970     Thread* self;
   3971 
   3972     if (ext == NULL)
   3973         return JNI_ERR;
   3974 
   3975     if (gDvm.verboseShutdown)
   3976         LOGD("DestroyJavaVM waiting for non-daemon threads to exit\n");
   3977 
   3978     /*
   3979      * Sleep on a condition variable until it's okay to exit.
   3980      */
   3981     self = dvmThreadSelf();
   3982     if (self == NULL) {
   3983         JNIEnv* tmpEnv;
   3984         if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
   3985             LOGV("Unable to reattach main for Destroy; assuming VM is "
   3986                  "shutting down (count=%d)\n",
   3987                 gDvm.nonDaemonThreadCount);
   3988             goto shutdown;
   3989         } else {
   3990             LOGV("Attached to wait for shutdown in Destroy\n");
   3991         }
   3992     }
   3993     dvmChangeStatus(self, THREAD_VMWAIT);
   3994 
   3995     dvmLockThreadList(self);
   3996     gDvm.nonDaemonThreadCount--;    // remove current thread from count
   3997 
   3998     while (gDvm.nonDaemonThreadCount > 0)
   3999         pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
   4000 
   4001     dvmUnlockThreadList();
   4002     self = NULL;
   4003 
   4004 shutdown:
   4005     // TODO: call System.exit() to run any registered shutdown hooks
   4006     // (this may not return -- figure out how this should work)
   4007 
   4008     if (gDvm.verboseShutdown)
   4009         LOGD("DestroyJavaVM shutting VM down\n");
   4010     dvmShutdown();
   4011 
   4012     // TODO - free resources associated with JNI-attached daemon threads
   4013     free(ext->envList);
   4014     free(ext);
   4015 
   4016     return JNI_OK;
   4017 }
   4018 
   4019 
   4020 /*
   4021  * ===========================================================================
   4022  *      Function tables
   4023  * ===========================================================================
   4024  */
   4025 
   4026 static const struct JNINativeInterface gNativeInterface = {
   4027     NULL,
   4028     NULL,
   4029     NULL,
   4030     NULL,
   4031 
   4032     GetVersion,
   4033 
   4034     DefineClass,
   4035     FindClass,
   4036 
   4037     FromReflectedMethod,
   4038     FromReflectedField,
   4039     ToReflectedMethod,
   4040 
   4041     GetSuperclass,
   4042     IsAssignableFrom,
   4043 
   4044     ToReflectedField,
   4045 
   4046     Throw,
   4047     ThrowNew,
   4048     ExceptionOccurred,
   4049     ExceptionDescribe,
   4050     ExceptionClear,
   4051     FatalError,
   4052 
   4053     PushLocalFrame,
   4054     PopLocalFrame,
   4055 
   4056     NewGlobalRef,
   4057     DeleteGlobalRef,
   4058     DeleteLocalRef,
   4059     IsSameObject,
   4060     NewLocalRef,
   4061     EnsureLocalCapacity,
   4062 
   4063     AllocObject,
   4064     NewObject,
   4065     NewObjectV,
   4066     NewObjectA,
   4067 
   4068     GetObjectClass,
   4069     IsInstanceOf,
   4070 
   4071     GetMethodID,
   4072 
   4073     CallObjectMethod,
   4074     CallObjectMethodV,
   4075     CallObjectMethodA,
   4076     CallBooleanMethod,
   4077     CallBooleanMethodV,
   4078     CallBooleanMethodA,
   4079     CallByteMethod,
   4080     CallByteMethodV,
   4081     CallByteMethodA,
   4082     CallCharMethod,
   4083     CallCharMethodV,
   4084     CallCharMethodA,
   4085     CallShortMethod,
   4086     CallShortMethodV,
   4087     CallShortMethodA,
   4088     CallIntMethod,
   4089     CallIntMethodV,
   4090     CallIntMethodA,
   4091     CallLongMethod,
   4092     CallLongMethodV,
   4093     CallLongMethodA,
   4094     CallFloatMethod,
   4095     CallFloatMethodV,
   4096     CallFloatMethodA,
   4097     CallDoubleMethod,
   4098     CallDoubleMethodV,
   4099     CallDoubleMethodA,
   4100     CallVoidMethod,
   4101     CallVoidMethodV,
   4102     CallVoidMethodA,
   4103 
   4104     CallNonvirtualObjectMethod,
   4105     CallNonvirtualObjectMethodV,
   4106     CallNonvirtualObjectMethodA,
   4107     CallNonvirtualBooleanMethod,
   4108     CallNonvirtualBooleanMethodV,
   4109     CallNonvirtualBooleanMethodA,
   4110     CallNonvirtualByteMethod,
   4111     CallNonvirtualByteMethodV,
   4112     CallNonvirtualByteMethodA,
   4113     CallNonvirtualCharMethod,
   4114     CallNonvirtualCharMethodV,
   4115     CallNonvirtualCharMethodA,
   4116     CallNonvirtualShortMethod,
   4117     CallNonvirtualShortMethodV,
   4118     CallNonvirtualShortMethodA,
   4119     CallNonvirtualIntMethod,
   4120     CallNonvirtualIntMethodV,
   4121     CallNonvirtualIntMethodA,
   4122     CallNonvirtualLongMethod,
   4123     CallNonvirtualLongMethodV,
   4124     CallNonvirtualLongMethodA,
   4125     CallNonvirtualFloatMethod,
   4126     CallNonvirtualFloatMethodV,
   4127     CallNonvirtualFloatMethodA,
   4128     CallNonvirtualDoubleMethod,
   4129     CallNonvirtualDoubleMethodV,
   4130     CallNonvirtualDoubleMethodA,
   4131     CallNonvirtualVoidMethod,
   4132     CallNonvirtualVoidMethodV,
   4133     CallNonvirtualVoidMethodA,
   4134 
   4135     GetFieldID,
   4136 
   4137     GetObjectField,
   4138     GetBooleanField,
   4139     GetByteField,
   4140     GetCharField,
   4141     GetShortField,
   4142     GetIntField,
   4143     GetLongField,
   4144     GetFloatField,
   4145     GetDoubleField,
   4146     SetObjectField,
   4147     SetBooleanField,
   4148     SetByteField,
   4149     SetCharField,
   4150     SetShortField,
   4151     SetIntField,
   4152     SetLongField,
   4153     SetFloatField,
   4154     SetDoubleField,
   4155 
   4156     GetStaticMethodID,
   4157 
   4158     CallStaticObjectMethod,
   4159     CallStaticObjectMethodV,
   4160     CallStaticObjectMethodA,
   4161     CallStaticBooleanMethod,
   4162     CallStaticBooleanMethodV,
   4163     CallStaticBooleanMethodA,
   4164     CallStaticByteMethod,
   4165     CallStaticByteMethodV,
   4166     CallStaticByteMethodA,
   4167     CallStaticCharMethod,
   4168     CallStaticCharMethodV,
   4169     CallStaticCharMethodA,
   4170     CallStaticShortMethod,
   4171     CallStaticShortMethodV,
   4172     CallStaticShortMethodA,
   4173     CallStaticIntMethod,
   4174     CallStaticIntMethodV,
   4175     CallStaticIntMethodA,
   4176     CallStaticLongMethod,
   4177     CallStaticLongMethodV,
   4178     CallStaticLongMethodA,
   4179     CallStaticFloatMethod,
   4180     CallStaticFloatMethodV,
   4181     CallStaticFloatMethodA,
   4182     CallStaticDoubleMethod,
   4183     CallStaticDoubleMethodV,
   4184     CallStaticDoubleMethodA,
   4185     CallStaticVoidMethod,
   4186     CallStaticVoidMethodV,
   4187     CallStaticVoidMethodA,
   4188 
   4189     GetStaticFieldID,
   4190 
   4191     GetStaticObjectField,
   4192     GetStaticBooleanField,
   4193     GetStaticByteField,
   4194     GetStaticCharField,
   4195     GetStaticShortField,
   4196     GetStaticIntField,
   4197     GetStaticLongField,
   4198     GetStaticFloatField,
   4199     GetStaticDoubleField,
   4200 
   4201     SetStaticObjectField,
   4202     SetStaticBooleanField,
   4203     SetStaticByteField,
   4204     SetStaticCharField,
   4205     SetStaticShortField,
   4206     SetStaticIntField,
   4207     SetStaticLongField,
   4208     SetStaticFloatField,
   4209     SetStaticDoubleField,
   4210 
   4211     NewString,
   4212 
   4213     GetStringLength,
   4214     GetStringChars,
   4215     ReleaseStringChars,
   4216 
   4217     NewStringUTF,
   4218     GetStringUTFLength,
   4219     GetStringUTFChars,
   4220     ReleaseStringUTFChars,
   4221 
   4222     GetArrayLength,
   4223     NewObjectArray,
   4224     GetObjectArrayElement,
   4225     SetObjectArrayElement,
   4226 
   4227     NewBooleanArray,
   4228     NewByteArray,
   4229     NewCharArray,
   4230     NewShortArray,
   4231     NewIntArray,
   4232     NewLongArray,
   4233     NewFloatArray,
   4234     NewDoubleArray,
   4235 
   4236     GetBooleanArrayElements,
   4237     GetByteArrayElements,
   4238     GetCharArrayElements,
   4239     GetShortArrayElements,
   4240     GetIntArrayElements,
   4241     GetLongArrayElements,
   4242     GetFloatArrayElements,
   4243     GetDoubleArrayElements,
   4244 
   4245     ReleaseBooleanArrayElements,
   4246     ReleaseByteArrayElements,
   4247     ReleaseCharArrayElements,
   4248     ReleaseShortArrayElements,
   4249     ReleaseIntArrayElements,
   4250     ReleaseLongArrayElements,
   4251     ReleaseFloatArrayElements,
   4252     ReleaseDoubleArrayElements,
   4253 
   4254     GetBooleanArrayRegion,
   4255     GetByteArrayRegion,
   4256     GetCharArrayRegion,
   4257     GetShortArrayRegion,
   4258     GetIntArrayRegion,
   4259     GetLongArrayRegion,
   4260     GetFloatArrayRegion,
   4261     GetDoubleArrayRegion,
   4262     SetBooleanArrayRegion,
   4263     SetByteArrayRegion,
   4264     SetCharArrayRegion,
   4265     SetShortArrayRegion,
   4266     SetIntArrayRegion,
   4267     SetLongArrayRegion,
   4268     SetFloatArrayRegion,
   4269     SetDoubleArrayRegion,
   4270 
   4271     RegisterNatives,
   4272     UnregisterNatives,
   4273 
   4274     MonitorEnter,
   4275     MonitorExit,
   4276 
   4277     GetJavaVM,
   4278 
   4279     GetStringRegion,
   4280     GetStringUTFRegion,
   4281 
   4282     GetPrimitiveArrayCritical,
   4283     ReleasePrimitiveArrayCritical,
   4284 
   4285     GetStringCritical,
   4286     ReleaseStringCritical,
   4287 
   4288     NewWeakGlobalRef,
   4289     DeleteWeakGlobalRef,
   4290 
   4291     ExceptionCheck,
   4292 
   4293     NewDirectByteBuffer,
   4294     GetDirectBufferAddress,
   4295     GetDirectBufferCapacity,
   4296 
   4297     GetObjectRefType
   4298 };
   4299 static const struct JNIInvokeInterface gInvokeInterface = {
   4300     NULL,
   4301     NULL,
   4302     NULL,
   4303 
   4304     DestroyJavaVM,
   4305     AttachCurrentThread,
   4306     DetachCurrentThread,
   4307 
   4308     GetEnv,
   4309 
   4310     AttachCurrentThreadAsDaemon,
   4311 };
   4312 
   4313 
   4314 /*
   4315  * ===========================================================================
   4316  *      VM/Env creation
   4317  * ===========================================================================
   4318  */
   4319 
   4320 /*
   4321  * Enable "checked JNI" after the VM has partially started.  This must
   4322  * only be called in "zygote" mode, when we have one thread running.
   4323  *
   4324  * This doesn't attempt to rewrite the JNI call bridge associated with
   4325  * native methods, so we won't get those checks for any methods that have
   4326  * already been resolved.
   4327  */
   4328 void dvmLateEnableCheckedJni(void)
   4329 {
   4330     JNIEnvExt* extEnv;
   4331     JavaVMExt* extVm;
   4332 
   4333     extEnv = dvmGetJNIEnvForThread();
   4334     if (extEnv == NULL) {
   4335         LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv\n");
   4336         return;
   4337     }
   4338     extVm = extEnv->vm;
   4339     assert(extVm != NULL);
   4340 
   4341     if (!extVm->useChecked) {
   4342         LOGD("Late-enabling CheckJNI\n");
   4343         dvmUseCheckedJniVm(extVm);
   4344         extVm->useChecked = true;
   4345         dvmUseCheckedJniEnv(extEnv);
   4346 
   4347         /* currently no way to pick up jniopts features */
   4348     } else {
   4349         LOGD("Not late-enabling CheckJNI (already on)\n");
   4350     }
   4351 }
   4352 
   4353 /*
   4354  * Not supported.
   4355  */
   4356 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args)
   4357 {
   4358     return JNI_ERR;
   4359 }
   4360 
   4361 /*
   4362  * Return a buffer full of created VMs.
   4363  *
   4364  * We always have zero or one.
   4365  */
   4366 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
   4367 {
   4368     if (gDvm.vmList != NULL) {
   4369         *nVMs = 1;
   4370 
   4371         if (bufLen > 0)
   4372             *vmBuf++ = gDvm.vmList;
   4373     } else {
   4374         *nVMs = 0;
   4375     }
   4376 
   4377     return JNI_OK;
   4378 }
   4379 
   4380 
   4381 /*
   4382  * Create a new VM instance.
   4383  *
   4384  * The current thread becomes the main VM thread.  We return immediately,
   4385  * which effectively means the caller is executing in a native method.
   4386  */
   4387 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)
   4388 {
   4389     const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
   4390     JNIEnvExt* pEnv = NULL;
   4391     JavaVMExt* pVM = NULL;
   4392     const char** argv;
   4393     int argc = 0;
   4394     int i, curOpt;
   4395     int result = JNI_ERR;
   4396     bool checkJni = false;
   4397     bool warnError = true;
   4398     bool forceDataCopy = false;
   4399 
   4400     if (args->version < JNI_VERSION_1_2)
   4401         return JNI_EVERSION;
   4402 
   4403     // TODO: don't allow creation of multiple VMs -- one per customer for now
   4404 
   4405     /* zero globals; not strictly necessary the first time a VM is started */
   4406     memset(&gDvm, 0, sizeof(gDvm));
   4407 
   4408     /*
   4409      * Set up structures for JNIEnv and VM.
   4410      */
   4411     //pEnv = (JNIEnvExt*) malloc(sizeof(JNIEnvExt));
   4412     pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
   4413 
   4414     //memset(pEnv, 0, sizeof(JNIEnvExt));
   4415     //pEnv->funcTable = &gNativeInterface;
   4416     //pEnv->vm = pVM;
   4417     memset(pVM, 0, sizeof(JavaVMExt));
   4418     pVM->funcTable = &gInvokeInterface;
   4419     pVM->envList = pEnv;
   4420     dvmInitMutex(&pVM->envListLock);
   4421 
   4422     argv = (const char**) malloc(sizeof(char*) * (args->nOptions));
   4423     memset(argv, 0, sizeof(char*) * (args->nOptions));
   4424 
   4425     curOpt = 0;
   4426 
   4427     /*
   4428      * Convert JNI args to argv.
   4429      *
   4430      * We have to pull out vfprintf/exit/abort, because they use the
   4431      * "extraInfo" field to pass function pointer "hooks" in.  We also
   4432      * look for the -Xcheck:jni stuff here.
   4433      */
   4434     for (i = 0; i < args->nOptions; i++) {
   4435         const char* optStr = args->options[i].optionString;
   4436 
   4437         if (optStr == NULL) {
   4438             fprintf(stderr, "ERROR: arg %d string was null\n", i);
   4439             goto bail;
   4440         } else if (strcmp(optStr, "vfprintf") == 0) {
   4441             gDvm.vfprintfHook = args->options[i].extraInfo;
   4442         } else if (strcmp(optStr, "exit") == 0) {
   4443             gDvm.exitHook = args->options[i].extraInfo;
   4444         } else if (strcmp(optStr, "abort") == 0) {
   4445             gDvm.abortHook = args->options[i].extraInfo;
   4446         } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
   4447             checkJni = true;
   4448         } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
   4449             const char* jniOpts = optStr + 9;
   4450             while (jniOpts != NULL) {
   4451                 jniOpts++;      /* skip past ':' or ',' */
   4452                 if (strncmp(jniOpts, "warnonly", 8) == 0) {
   4453                     warnError = false;
   4454                 } else if (strncmp(jniOpts, "forcecopy", 9) == 0) {
   4455                     forceDataCopy = true;
   4456                 } else {
   4457                     LOGW("unknown jni opt starting at '%s'\n", jniOpts);
   4458                 }
   4459                 jniOpts = strchr(jniOpts, ',');
   4460             }
   4461         } else {
   4462             /* regular option */
   4463             argv[curOpt++] = optStr;
   4464         }
   4465     }
   4466     argc = curOpt;
   4467 
   4468     if (checkJni) {
   4469         dvmUseCheckedJniVm(pVM);
   4470         pVM->useChecked = true;
   4471     }
   4472     pVM->warnError = warnError;
   4473     pVM->forceDataCopy = forceDataCopy;
   4474 
   4475     /* set this up before initializing VM, so it can create some JNIEnvs */
   4476     gDvm.vmList = (JavaVM*) pVM;
   4477 
   4478     /*
   4479      * Create an env for main thread.  We need to have something set up
   4480      * here because some of the class initialization we do when starting
   4481      * up the VM will call into native code.
   4482      */
   4483     pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
   4484 
   4485     /* initialize VM */
   4486     gDvm.initializing = true;
   4487     if (dvmStartup(argc, argv, args->ignoreUnrecognized, (JNIEnv*)pEnv) != 0) {
   4488         free(pEnv);
   4489         free(pVM);
   4490         goto bail;
   4491     }
   4492 
   4493     /*
   4494      * Success!  Return stuff to caller.
   4495      */
   4496     dvmChangeStatus(NULL, THREAD_NATIVE);
   4497     *p_env = (JNIEnv*) pEnv;
   4498     *p_vm = (JavaVM*) pVM;
   4499     result = JNI_OK;
   4500 
   4501 bail:
   4502     gDvm.initializing = false;
   4503     if (result == JNI_OK)
   4504         LOGV("JNI_CreateJavaVM succeeded\n");
   4505     else
   4506         LOGW("JNI_CreateJavaVM failed\n");
   4507     free(argv);
   4508     return result;
   4509 }
   4510