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 #include "ScopedPthreadMutexLock.h"
     23 #include "UniquePtr.h"
     24 
     25 #include <stdlib.h>
     26 #include <stdarg.h>
     27 #include <limits.h>
     28 
     29 /*
     30 Native methods and interaction with the GC
     31 
     32 All JNI methods must start by changing their thread status to
     33 THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
     34 returning to native code.  The switch to "running" triggers a thread
     35 suspension check.
     36 
     37 With a rudimentary GC we should be able to skip the status change for
     38 simple functions, e.g.  IsSameObject, GetJavaVM, GetStringLength, maybe
     39 even access to fields with primitive types.  Our options are more limited
     40 with a compacting GC.
     41 
     42 For performance reasons we do as little error-checking as possible here.
     43 For example, we don't check to make sure the correct type of Object is
     44 passed in when setting a field, and we don't prevent you from storing
     45 new values in a "final" field.  Such things are best handled in the
     46 "check" version.  For actions that are common, dangerous, and must be
     47 checked at runtime, such as array bounds checks, we do the tests here.
     48 
     49 
     50 General notes on local/global reference tracking
     51 
     52 JNI provides explicit control over natively-held references that the GC
     53 needs to know about.  These can be local, in which case they're released
     54 when the native method returns into the VM, or global, which are held
     55 until explicitly released.  (There are also weak-global references,
     56 which have the lifespan and visibility of global references, but the
     57 object they refer to may be collected.)
     58 
     59 The references can be created with explicit JNI NewLocalRef / NewGlobalRef
     60 calls.  The former is very unusual, the latter is reasonably common
     61 (e.g. for caching references to class objects).
     62 
     63 Local references are most often created as a side-effect of JNI functions.
     64 For example, the AllocObject/NewObject functions must create local
     65 references to the objects returned, because nothing else in the GC root
     66 set has a reference to the new objects.
     67 
     68 The most common mode of operation is for a method to create zero or
     69 more local references and return.  Explicit "local delete" operations
     70 are expected to be exceedingly rare, except when walking through an
     71 object array, and the Push/PopLocalFrame calls are expected to be used
     72 infrequently.  For efficient operation, we want to add new local refs
     73 with a simple store/increment operation; to avoid infinite growth in
     74 pathological situations, we need to reclaim the space used by deleted
     75 entries.
     76 
     77 If we just want to maintain a list for the GC root set, we can use an
     78 expanding append-only array that compacts when objects are deleted.
     79 In typical situations, e.g. running through an array of objects, we will
     80 be deleting one of the most recently added entries, so we can minimize
     81 the number of elements moved (or avoid having to move any).
     82 
     83 If we want to conceal the pointer values from native code, which is
     84 necessary to allow the GC to move JNI-referenced objects around, then we
     85 have to use a more complicated indirection mechanism.
     86 
     87 The spec says, "Local references are only valid in the thread in which
     88 they are created.  The native code must not pass local references from
     89 one thread to another."
     90 
     91 
     92 Pinned objects
     93 
     94 For some large chunks of data, notably primitive arrays and String data,
     95 JNI allows the VM to choose whether it wants to pin the array object or
     96 make a copy.  We currently pin the memory for better execution performance.
     97 
     98 TODO: we're using simple root set references to pin primitive array data,
     99 because they have the property we need (i.e. the pointer we return is
    100 guaranteed valid until we explicitly release it).  However, if we have a
    101 compacting GC and don't want to pin all memory held by all global refs,
    102 we need to treat these differently.
    103 
    104 
    105 Global reference tracking
    106 
    107 There should be a small "active" set centered around the most-recently
    108 added items.
    109 
    110 Because it's global, access to it has to be synchronized.  Additions and
    111 removals require grabbing a mutex.  If the table serves as an indirection
    112 mechanism (i.e. it's not just a list for the benefit of the garbage
    113 collector), reference lookups may also require grabbing a mutex.
    114 
    115 The JNI spec does not define any sort of limit, so the list must be able
    116 to expand to a reasonable size.  It may be useful to log significant
    117 increases in usage to help identify resource leaks.
    118 
    119 
    120 Weak-global reference tracking
    121 
    122 [TBD]
    123 
    124 
    125 Local reference tracking
    126 
    127 Each Thread/JNIEnv points to an IndirectRefTable.
    128 
    129 We implement Push/PopLocalFrame with actual stack frames.  Before a JNI
    130 frame gets popped, we set "nextEntry" to the "top" pointer of the current
    131 frame, effectively releasing the references.
    132 
    133 The GC will scan all references in the table.
    134 
    135 */
    136 
    137 #ifdef WITH_JNI_STACK_CHECK
    138 # define COMPUTE_STACK_SUM(_self)   computeStackSum(_self);
    139 # define CHECK_STACK_SUM(_self)     checkStackSum(_self);
    140 
    141 /*
    142  * Compute a CRC on the entire interpreted stack.
    143  *
    144  * Would be nice to compute it on "self" as well, but there are parts of
    145  * the Thread that can be altered by other threads (e.g. prev/next pointers).
    146  */
    147 static void computeStackSum(Thread* self) {
    148     const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
    149     u4 crc = dvmInitCrc32();
    150     self->stackCrc = 0;
    151     crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
    152     self->stackCrc = crc;
    153 }
    154 
    155 /*
    156  * Compute a CRC on the entire interpreted stack, and compare it to what
    157  * we previously computed.
    158  *
    159  * We can execute JNI directly from native code without calling in from
    160  * interpreted code during VM initialization and immediately after JNI
    161  * thread attachment.  Another opportunity exists during JNI_OnLoad.  Rather
    162  * than catching these cases we just ignore them here, which is marginally
    163  * less accurate but reduces the amount of code we have to touch with #ifdefs.
    164  */
    165 static void checkStackSum(Thread* self) {
    166     const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
    167     u4 stackCrc = self->stackCrc;
    168     self->stackCrc = 0;
    169     u4 crc = dvmInitCrc32();
    170     crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
    171     if (crc != stackCrc) {
    172         const Method* meth = dvmGetCurrentJNIMethod();
    173         if (dvmComputeExactFrameDepth(self->interpSave.curFrame) == 1) {
    174             LOGD("JNI: bad stack CRC (0x%08x) -- okay during init", stackCrc);
    175         } else if (strcmp(meth->name, "nativeLoad") == 0 &&
    176                 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0)) {
    177             LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc);
    178         } else {
    179             LOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
    180             dvmAbort();
    181         }
    182     }
    183     self->stackCrc = (u4) -1;       /* make logic errors more noticeable */
    184 }
    185 
    186 #else
    187 # define COMPUTE_STACK_SUM(_self)   ((void)0)
    188 # define CHECK_STACK_SUM(_self)     ((void)0)
    189 #endif
    190 
    191 
    192 /*
    193  * ===========================================================================
    194  *      Utility functions
    195  * ===========================================================================
    196  */
    197 
    198 static inline Thread* self(JNIEnv* env) {
    199     Thread* envSelf = ((JNIEnvExt*) env)->self;
    200     // When emulating direct pointers with indirect references, it's critical
    201     // that we use the correct per-thread indirect reference table.
    202     Thread* self = gDvmJni.workAroundAppJniBugs ? dvmThreadSelf() : envSelf;
    203     if (self != envSelf) {
    204         LOGE("JNI ERROR: env->self != thread-self (%p vs. %p); auto-correcting",
    205                 envSelf, self);
    206     }
    207     return self;
    208 }
    209 
    210 /*
    211  * Entry/exit processing for all JNI calls.
    212  *
    213  * We skip the (curiously expensive) thread-local storage lookup on our Thread*.
    214  * If the caller has passed the wrong JNIEnv in, we're going to be accessing unsynchronized
    215  * structures from more than one thread, and things are going to fail
    216  * in bizarre ways.  This is only sensible if the native code has been
    217  * fully exercised with CheckJNI enabled.
    218  */
    219 class ScopedJniThreadState {
    220 public:
    221     explicit ScopedJniThreadState(JNIEnv* env) {
    222         mSelf = ::self(env);
    223         CHECK_STACK_SUM(mSelf);
    224         dvmChangeStatus(mSelf, THREAD_RUNNING);
    225     }
    226 
    227     ~ScopedJniThreadState() {
    228         dvmChangeStatus(mSelf, THREAD_NATIVE);
    229         COMPUTE_STACK_SUM(mSelf);
    230     }
    231 
    232     Thread* self() {
    233         return mSelf;
    234     }
    235 
    236 private:
    237     Thread* mSelf;
    238 
    239     // Disallow copy and assignment.
    240     ScopedJniThreadState(const ScopedJniThreadState&);
    241     void operator=(const ScopedJniThreadState&);
    242 };
    243 
    244 #define kGlobalRefsTableInitialSize 512
    245 #define kGlobalRefsTableMaxSize     51200       /* arbitrary, must be < 64K */
    246 #define kGrefWaterInterval          100
    247 #define kTrackGrefUsage             true
    248 
    249 #define kWeakGlobalRefsTableInitialSize 16
    250 
    251 #define kPinTableInitialSize        16
    252 #define kPinTableMaxSize            1024
    253 #define kPinComplainThreshold       10
    254 
    255 bool dvmJniStartup() {
    256     if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize,
    257                                  kGlobalRefsTableMaxSize,
    258                                  kIndirectKindGlobal)) {
    259         return false;
    260     }
    261     if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize,
    262                                  kGlobalRefsTableMaxSize,
    263                                  kIndirectKindWeakGlobal)) {
    264         return false;
    265     }
    266 
    267     dvmInitMutex(&gDvm.jniGlobalRefLock);
    268     dvmInitMutex(&gDvm.jniWeakGlobalRefLock);
    269     gDvm.jniGlobalRefLoMark = 0;
    270     gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
    271 
    272     if (!dvmInitReferenceTable(&gDvm.jniPinRefTable, kPinTableInitialSize, kPinTableMaxSize)) {
    273         return false;
    274     }
    275 
    276     dvmInitMutex(&gDvm.jniPinRefLock);
    277 
    278     return true;
    279 }
    280 
    281 void dvmJniShutdown() {
    282     gDvm.jniGlobalRefTable.destroy();
    283     gDvm.jniWeakGlobalRefTable.destroy();
    284     dvmClearReferenceTable(&gDvm.jniPinRefTable);
    285 }
    286 
    287 /*
    288  * Find the JNIEnv associated with the current thread.
    289  *
    290  * Currently stored in the Thread struct.  Could also just drop this into
    291  * thread-local storage.
    292  */
    293 JNIEnvExt* dvmGetJNIEnvForThread() {
    294     Thread* self = dvmThreadSelf();
    295     if (self == NULL) {
    296         return NULL;
    297     }
    298     return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
    299 }
    300 
    301 /*
    302  * Retrieve the ReferenceTable struct for the current thread.
    303  *
    304  * Going through "env" rather than dvmThreadSelf() is faster but will
    305  * get weird if the JNI code is passing the wrong JNIEnv around.
    306  */
    307 static inline IndirectRefTable* getLocalRefTable(JNIEnv* env) {
    308     return &self(env)->jniLocalRefTable;
    309 }
    310 
    311 /*
    312  * Convert an indirect reference to an Object reference.  The indirect
    313  * reference may be local, global, or weak-global.
    314  *
    315  * If "jobj" is NULL, or is a weak global reference whose reference has
    316  * been cleared, this returns NULL.  If jobj is an invalid indirect
    317  * reference, kInvalidIndirectRefObject is returned.
    318  *
    319  * Note "env" may be NULL when decoding global references.
    320  */
    321 Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj) {
    322     if (jobj == NULL) {
    323         return NULL;
    324     }
    325 
    326     switch (indirectRefKind(jobj)) {
    327     case kIndirectKindLocal:
    328         {
    329             Object* result = getLocalRefTable(env)->get(jobj);
    330             if (result == NULL) {
    331                 LOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
    332                 dvmAbort();
    333             }
    334             return result;
    335         }
    336     case kIndirectKindGlobal:
    337         {
    338             // TODO: find a way to avoid the mutex activity here
    339             IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
    340             ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
    341             Object* result = pRefTable->get(jobj);
    342             if (result == NULL) {
    343                 LOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
    344                 dvmAbort();
    345             }
    346             return result;
    347         }
    348     case kIndirectKindWeakGlobal:
    349         {
    350             // TODO: find a way to avoid the mutex activity here
    351             IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
    352             ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
    353             Object* result = pRefTable->get(jobj);
    354             if (result == kClearedJniWeakGlobal) {
    355                 result = NULL;
    356             } else if (result == NULL) {
    357                 LOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
    358                 dvmAbort();
    359             }
    360             return result;
    361         }
    362     case kIndirectKindInvalid:
    363     default:
    364         if (gDvmJni.workAroundAppJniBugs) {
    365             // Assume an invalid local reference is actually a direct pointer.
    366             return reinterpret_cast<Object*>(jobj);
    367         }
    368         LOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
    369         dvmAbort();
    370         return kInvalidIndirectRefObject;
    371     }
    372 }
    373 
    374 /*
    375  * Add a local reference for an object to the current stack frame.  When
    376  * the native function returns, the reference will be discarded.
    377  *
    378  * We need to allow the same reference to be added multiple times.
    379  *
    380  * This will be called on otherwise unreferenced objects.  We cannot do
    381  * GC allocations here, and it's best if we don't grab a mutex.
    382  *
    383  * Returns the local reference (currently just the same pointer that was
    384  * passed in), or NULL on failure.
    385  */
    386 static jobject addLocalReference(JNIEnv* env, Object* obj) {
    387     if (obj == NULL) {
    388         return NULL;
    389     }
    390 
    391     IndirectRefTable* pRefTable = getLocalRefTable(env);
    392     void* curFrame = self(env)->interpSave.curFrame;
    393     u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
    394     jobject jobj = (jobject) pRefTable->add(cookie, obj);
    395     if (jobj == NULL) {
    396         pRefTable->dump("JNI local");
    397         LOGE("Failed adding to JNI local ref table (has %zd entries)",
    398                 pRefTable->capacity());
    399         dvmDumpThread(dvmThreadSelf(), false);
    400         dvmAbort();     // spec says call FatalError; this is equivalent
    401     } else {
    402         if (false) {
    403             LOGI("LREF add %p  (%s.%s) (ent=%zd)", obj,
    404                     dvmGetCurrentJNIMethod()->clazz->descriptor,
    405                     dvmGetCurrentJNIMethod()->name,
    406                     pRefTable->capacity());
    407         }
    408     }
    409 
    410 #if 0 // TODO: fix this to understand PushLocalFrame, so we can turn it on.
    411     if (gDvmJni.useCheckJni) {
    412         size_t entryCount = pRefTable->capacity();
    413         if (entryCount > 16) {
    414             LOGW("Warning: more than 16 JNI local references: %d (most recent was a %s)", entryCount, obj->clazz->descriptor);
    415             pRefTable->dump("JNI local");
    416             dvmDumpThread(dvmThreadSelf(), false);
    417             //dvmAbort();
    418         }
    419     }
    420 #endif
    421 
    422     if (gDvmJni.workAroundAppJniBugs) {
    423         // Hand out direct pointers to support broken old apps.
    424         return reinterpret_cast<jobject>(obj);
    425     }
    426     return jobj;
    427 }
    428 
    429 /*
    430  * Ensure that at least "capacity" references can be held in the local
    431  * refs table of the current thread.
    432  */
    433 static bool ensureLocalCapacity(JNIEnv* env, int capacity) {
    434     IndirectRefTable* pRefTable = getLocalRefTable(env);
    435     int numEntries = pRefTable->capacity();
    436     // TODO: this isn't quite right, since "numEntries" includes holes
    437     return ((kJniLocalRefMax - numEntries) >= capacity);
    438 }
    439 
    440 /*
    441  * Explicitly delete a reference from the local list.
    442  */
    443 static void deleteLocalReference(JNIEnv* env, jobject jobj) {
    444     if (jobj == NULL) {
    445         return;
    446     }
    447 
    448     IndirectRefTable* pRefTable = getLocalRefTable(env);
    449     void* curFrame = self(env)->interpSave.curFrame;
    450     u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
    451     if (!pRefTable->remove(cookie, jobj)) {
    452         /*
    453          * Attempting to delete a local reference that is not in the
    454          * topmost local reference frame is a no-op.  DeleteLocalRef returns
    455          * void and doesn't throw any exceptions, but we should probably
    456          * complain about it so the user will notice that things aren't
    457          * going quite the way they expect.
    458          */
    459         LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry", jobj);
    460     }
    461 }
    462 
    463 /*
    464  * Add a global reference for an object.
    465  *
    466  * We may add the same object more than once.  Add/remove calls are paired,
    467  * so it needs to appear on the list multiple times.
    468  */
    469 static jobject addGlobalReference(Object* obj) {
    470     if (obj == NULL) {
    471         return NULL;
    472     }
    473 
    474     //LOGI("adding obj=%p", obj);
    475     //dvmDumpThread(dvmThreadSelf(), false);
    476 
    477     if (false && dvmIsClassObject((Object*)obj)) {
    478         ClassObject* clazz = (ClassObject*) obj;
    479         LOGI("-------");
    480         LOGI("Adding global ref on class %s", clazz->descriptor);
    481         dvmDumpThread(dvmThreadSelf(), false);
    482     }
    483     if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
    484         StringObject* strObj = (StringObject*) obj;
    485         char* str = dvmCreateCstrFromString(strObj);
    486         if (strcmp(str, "sync-response") == 0) {
    487             LOGI("-------");
    488             LOGI("Adding global ref on string '%s'", str);
    489             dvmDumpThread(dvmThreadSelf(), false);
    490             //dvmAbort();
    491         }
    492         free(str);
    493     }
    494     if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
    495         ArrayObject* arrayObj = (ArrayObject*) obj;
    496         if (arrayObj->length == 8192 /*&&
    497             dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
    498         {
    499             LOGI("Adding global ref on byte array %p (len=%d)",
    500                 arrayObj, arrayObj->length);
    501             dvmDumpThread(dvmThreadSelf(), false);
    502         }
    503     }
    504 
    505     ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
    506 
    507     /*
    508      * Throwing an exception on failure is problematic, because JNI code
    509      * may not be expecting an exception, and things sort of cascade.  We
    510      * want to have a hard limit to catch leaks during debugging, but this
    511      * otherwise needs to expand until memory is consumed.  As a practical
    512      * matter, if we have many thousands of global references, chances are
    513      * we're either leaking global ref table entries or we're going to
    514      * run out of space in the GC heap.
    515      */
    516     jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj);
    517     if (jobj == NULL) {
    518         gDvm.jniGlobalRefTable.dump("JNI global");
    519         LOGE("Failed adding to JNI global ref table (%zd entries)",
    520                 gDvm.jniGlobalRefTable.capacity());
    521         dvmAbort();
    522     }
    523 
    524     LOGVV("GREF add %p  (%s.%s)", obj,
    525         dvmGetCurrentJNIMethod()->clazz->descriptor,
    526         dvmGetCurrentJNIMethod()->name);
    527 
    528     /* GREF usage tracking; should probably be disabled for production env */
    529     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    530         int count = gDvm.jniGlobalRefTable.capacity();
    531         // TODO: adjust for "holes"
    532         if (count > gDvm.jniGlobalRefHiMark) {
    533             LOGD("GREF has increased to %d", count);
    534             gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
    535             gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
    536 
    537             /* watch for "excessive" use; not generally appropriate */
    538             if (count >= gDvm.jniGrefLimit) {
    539                 if (gDvmJni.warnOnly) {
    540                     LOGW("Excessive JNI global references (%d)", count);
    541                 } else {
    542                     gDvm.jniGlobalRefTable.dump("JNI global");
    543                     LOGE("Excessive JNI global references (%d)", count);
    544                     dvmAbort();
    545                 }
    546             }
    547         }
    548     }
    549     return jobj;
    550 }
    551 
    552 static jobject addWeakGlobalReference(Object* obj) {
    553     if (obj == NULL) {
    554         return NULL;
    555     }
    556 
    557     ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
    558     IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
    559     jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj);
    560     if (jobj == NULL) {
    561         LOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
    562     }
    563     return jobj;
    564 }
    565 
    566 static void deleteWeakGlobalReference(jobject jobj) {
    567     if (jobj == NULL) {
    568         return;
    569     }
    570 
    571     ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
    572     IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
    573     if (!table->remove(IRT_FIRST_SEGMENT, jobj)) {
    574         LOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj);
    575     }
    576 }
    577 
    578 /*
    579  * Remove a global reference.  In most cases it's the entry most recently
    580  * added, which makes this pretty quick.
    581  *
    582  * Thought: if it's not the most recent entry, just null it out.  When we
    583  * fill up, do a compaction pass before we expand the list.
    584  */
    585 static void deleteGlobalReference(jobject jobj) {
    586     if (jobj == NULL) {
    587         return;
    588     }
    589 
    590     ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
    591     if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) {
    592         LOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj);
    593         return;
    594     }
    595 
    596     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    597         int count = gDvm.jniGlobalRefTable.capacity();
    598         // TODO: not quite right, need to subtract holes
    599         if (count < gDvm.jniGlobalRefLoMark) {
    600             LOGD("GREF has decreased to %d", count);
    601             gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
    602             gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
    603         }
    604     }
    605 }
    606 
    607 /*
    608  * Objects don't currently move, so we just need to create a reference
    609  * that will ensure the array object isn't collected.
    610  *
    611  * We use a separate reference table, which is part of the GC root set.
    612  */
    613 static void pinPrimitiveArray(ArrayObject* arrayObj) {
    614     if (arrayObj == NULL) {
    615         return;
    616     }
    617 
    618     ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
    619 
    620     if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
    621         dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
    622         LOGE("Failed adding to JNI pinned array ref table (%d entries)",
    623            (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
    624         dvmDumpThread(dvmThreadSelf(), false);
    625         dvmAbort();
    626     }
    627 
    628     /*
    629      * If we're watching global ref usage, also keep an eye on these.
    630      *
    631      * The total number of pinned primitive arrays should be pretty small.
    632      * A single array should not be pinned more than once or twice; any
    633      * more than that is a strong indicator that a Release function is
    634      * not being called.
    635      */
    636     if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
    637         int count = 0;
    638         Object** ppObj = gDvm.jniPinRefTable.table;
    639         while (ppObj < gDvm.jniPinRefTable.nextEntry) {
    640             if (*ppObj++ == (Object*) arrayObj)
    641                 count++;
    642         }
    643 
    644         if (count > kPinComplainThreshold) {
    645             LOGW("JNI: pin count on array %p (%s) is now %d",
    646                 arrayObj, arrayObj->clazz->descriptor, count);
    647             /* keep going */
    648         }
    649     }
    650 }
    651 
    652 /*
    653  * Un-pin the array object.  If an object was pinned twice, it must be
    654  * unpinned twice before it's free to move.
    655  */
    656 static void unpinPrimitiveArray(ArrayObject* arrayObj) {
    657     if (arrayObj == NULL) {
    658         return;
    659     }
    660 
    661     ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
    662     if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
    663             gDvm.jniPinRefTable.table, (Object*) arrayObj))
    664     {
    665         LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)",
    666             arrayObj, dvmIsHeapAddress((Object*) arrayObj));
    667         return;
    668     }
    669 }
    670 
    671 /*
    672  * Dump the contents of the JNI reference tables to the log file.
    673  *
    674  * We only dump the local refs associated with the current thread.
    675  */
    676 void dvmDumpJniReferenceTables() {
    677     Thread* self = dvmThreadSelf();
    678     JNIEnv* env = self->jniEnv;
    679     IndirectRefTable* pLocalRefs = getLocalRefTable(env);
    680     pLocalRefs->dump("JNI local");
    681     gDvm.jniGlobalRefTable.dump("JNI global");
    682     dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
    683 }
    684 
    685 /*
    686  * Verify that a reference passed in from native code is one that the
    687  * code is allowed to have.
    688  *
    689  * It's okay for native code to pass us a reference that:
    690  *  - was passed in as an argument when invoked by native code (and hence
    691  *    is in the JNI local refs table)
    692  *  - was returned to it from JNI (and is now in the local refs table)
    693  *  - is present in the JNI global refs table
    694  *
    695  * Used by -Xcheck:jni and GetObjectRefType.
    696  */
    697 jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj) {
    698     /*
    699      * IndirectRefKind is currently defined as an exact match of
    700      * jobjectRefType, so this is easy.  We have to decode it to determine
    701      * if it's a valid reference and not merely valid-looking.
    702      */
    703     assert(jobj != NULL);
    704 
    705     Object* obj = dvmDecodeIndirectRef(env, jobj);
    706     if (obj == reinterpret_cast<Object*>(jobj) && gDvmJni.workAroundAppJniBugs) {
    707         // If we're handing out direct pointers, check whether 'jobj' is a direct reference
    708         // to a local reference.
    709         return getLocalRefTable(env)->contains(jobj) ? JNILocalRefType : JNIInvalidRefType;
    710     } else if (obj == kInvalidIndirectRefObject) {
    711         return JNIInvalidRefType;
    712     } else {
    713         return (jobjectRefType) indirectRefKind(jobj);
    714     }
    715 }
    716 
    717 static void dumpMethods(Method* methods, size_t methodCount, const char* name) {
    718     size_t i;
    719     for (i = 0; i < methodCount; ++i) {
    720         Method* method = &methods[i];
    721         if (strcmp(name, method->name) == 0) {
    722             char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
    723             LOGE("Candidate: %s.%s:%s", method->clazz->descriptor, name, desc);
    724             free(desc);
    725         }
    726     }
    727 }
    728 
    729 static void dumpCandidateMethods(ClassObject* clazz, const char* methodName, const char* signature) {
    730     LOGE("ERROR: couldn't find native method");
    731     LOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature);
    732     dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName);
    733     dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName);
    734 }
    735 
    736 /*
    737  * Register a method that uses JNI calling conventions.
    738  */
    739 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
    740     const char* signature, void* fnPtr)
    741 {
    742     if (fnPtr == NULL) {
    743         return false;
    744     }
    745 
    746     // If a signature starts with a '!', we take that as a sign that the native code doesn't
    747     // need the extra JNI arguments (the JNIEnv* and the jclass).
    748     bool fastJni = false;
    749     if (*signature == '!') {
    750         fastJni = true;
    751         ++signature;
    752         LOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
    753     }
    754 
    755     Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
    756     if (method == NULL) {
    757         method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
    758     }
    759     if (method == NULL) {
    760         dumpCandidateMethods(clazz, methodName, signature);
    761         return false;
    762     }
    763 
    764     if (!dvmIsNativeMethod(method)) {
    765         LOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
    766         return false;
    767     }
    768 
    769     if (fastJni) {
    770         // In this case, we have extra constraints to check...
    771         if (dvmIsSynchronizedMethod(method)) {
    772             // Synchronization is usually provided by the JNI bridge,
    773             // but we won't have one.
    774             LOGE("fast JNI method %s.%s:%s cannot be synchronized",
    775                     clazz->descriptor, methodName, signature);
    776             return false;
    777         }
    778         if (!dvmIsStaticMethod(method)) {
    779             // There's no real reason for this constraint, but since we won't
    780             // be supplying a JNIEnv* or a jobject 'this', you're effectively
    781             // static anyway, so it seems clearer to say so.
    782             LOGE("fast JNI method %s.%s:%s cannot be non-static",
    783                     clazz->descriptor, methodName, signature);
    784             return false;
    785         }
    786     }
    787 
    788     if (method->nativeFunc != dvmResolveNativeMethod) {
    789         /* this is allowed, but unusual */
    790         LOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
    791     }
    792 
    793     method->fastJni = fastJni;
    794     dvmUseJNIBridge(method, fnPtr);
    795 
    796     LOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
    797     return true;
    798 }
    799 
    800 static const char* builtInPrefixes[] = {
    801     "Landroid/",
    802     "Lcom/android/",
    803     "Lcom/google/android/",
    804     "Ldalvik/",
    805     "Ljava/",
    806     "Ljavax/",
    807     "Llibcore/",
    808     "Lorg/apache/harmony/",
    809 };
    810 
    811 static bool shouldTrace(Method* method) {
    812     const char* className = method->clazz->descriptor;
    813     // Return true if the -Xjnitrace setting implies we should trace 'method'.
    814     if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) {
    815         return true;
    816     }
    817     // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
    818     // like part of Android.
    819     if (gDvmJni.logThirdPartyJni) {
    820         for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) {
    821             if (strstr(className, builtInPrefixes[i]) == className) {
    822                 return false;
    823             }
    824         }
    825         return true;
    826     }
    827     return false;
    828 }
    829 
    830 /*
    831  * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
    832  * to point at the actual function.
    833  */
    834 void dvmUseJNIBridge(Method* method, void* func) {
    835     method->shouldTrace = shouldTrace(method);
    836 
    837     // Does the method take any reference arguments?
    838     method->noRef = true;
    839     const char* cp = method->shorty;
    840     while (*++cp != '\0') { // Pre-increment to skip return type.
    841         if (*cp == 'L') {
    842             method->noRef = false;
    843             break;
    844         }
    845     }
    846 
    847     DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
    848     dvmSetNativeFunc(method, bridge, (const u2*) func);
    849 }
    850 
    851 // TODO: rewrite this to share code with CheckJNI's tracing...
    852 static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma)
    853 {
    854     size_t len = strlen(buf);
    855     if (len >= n - 32) { // 32 should be longer than anything we could append.
    856         buf[len - 1] = '.';
    857         buf[len - 2] = '.';
    858         buf[len - 3] = '.';
    859         return;
    860     }
    861     char* p = buf + len;
    862     switch (type) {
    863     case 'B':
    864         if (value.b >= 0 && value.b < 10) {
    865             sprintf(p, "%d", value.b);
    866         } else {
    867             sprintf(p, "%#x (%d)", value.b, value.b);
    868         }
    869         break;
    870     case 'C':
    871         if (value.c < 0x7f && value.c >= ' ') {
    872             sprintf(p, "U+%x ('%c')", value.c, value.c);
    873         } else {
    874             sprintf(p, "U+%x", value.c);
    875         }
    876         break;
    877     case 'D':
    878         sprintf(p, "%g", value.d);
    879         break;
    880     case 'F':
    881         sprintf(p, "%g", value.f);
    882         break;
    883     case 'I':
    884         sprintf(p, "%d", value.i);
    885         break;
    886     case 'L':
    887         sprintf(p, "%#x", value.i);
    888         break;
    889     case 'J':
    890         sprintf(p, "%lld", value.j);
    891         break;
    892     case 'S':
    893         sprintf(p, "%d", value.s);
    894         break;
    895     case 'V':
    896         strcpy(p, "void");
    897         break;
    898     case 'Z':
    899         strcpy(p, value.z ? "true" : "false");
    900         break;
    901     default:
    902         sprintf(p, "unknown type '%c'", type);
    903         break;
    904     }
    905 
    906     if (appendComma) {
    907         strcat(p, ", ");
    908     }
    909 }
    910 
    911 static void logNativeMethodEntry(const Method* method, const u4* args)
    912 {
    913     char thisString[32] = { 0 };
    914     const u4* sp = args;
    915     if (!dvmIsStaticMethod(method)) {
    916         sprintf(thisString, "this=0x%08x ", *sp++);
    917     }
    918 
    919     char argsString[128]= { 0 };
    920     const char* desc = &method->shorty[1];
    921     while (*desc != '\0') {
    922         char argType = *desc++;
    923         JValue value;
    924         if (argType == 'D' || argType == 'J') {
    925             value.j = dvmGetArgLong(sp, 0);
    926             sp += 2;
    927         } else {
    928             value.i = *sp++;
    929         }
    930         appendValue(argType, value, argsString, sizeof(argsString),
    931         *desc != '\0');
    932     }
    933 
    934     std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
    935     char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
    936     LOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString);
    937     free(signature);
    938 }
    939 
    940 static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue)
    941 {
    942     std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
    943     char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
    944     if (dvmCheckException(self)) {
    945         Object* exception = dvmGetException(self);
    946         std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor));
    947         LOGI("<- %s %s%s threw %s", className.c_str(),
    948                 method->name, signature, exceptionClassName.c_str());
    949     } else {
    950         char returnValueString[128] = { 0 };
    951         char returnType = method->shorty[0];
    952         appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false);
    953         LOGI("<- %s %s%s returned %s", className.c_str(),
    954                 method->name, signature, returnValueString);
    955     }
    956     free(signature);
    957 }
    958 
    959 /*
    960  * Get the method currently being executed by examining the interp stack.
    961  */
    962 const Method* dvmGetCurrentJNIMethod() {
    963     assert(dvmThreadSelf() != NULL);
    964 
    965     void* fp = dvmThreadSelf()->interpSave.curFrame;
    966     const Method* meth = SAVEAREA_FROM_FP(fp)->method;
    967 
    968     assert(meth != NULL);
    969     assert(dvmIsNativeMethod(meth));
    970     return meth;
    971 }
    972 
    973 /*
    974  * Track a JNI MonitorEnter in the current thread.
    975  *
    976  * The goal is to be able to "implicitly" release all JNI-held monitors
    977  * when the thread detaches.
    978  *
    979  * Monitors may be entered multiple times, so we add a new entry for each
    980  * enter call.  It would be more efficient to keep a counter.  At present
    981  * there's no real motivation to improve this however.
    982  */
    983 static void trackMonitorEnter(Thread* self, Object* obj) {
    984     static const int kInitialSize = 16;
    985     ReferenceTable* refTable = &self->jniMonitorRefTable;
    986 
    987     /* init table on first use */
    988     if (refTable->table == NULL) {
    989         assert(refTable->maxEntries == 0);
    990 
    991         if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
    992             LOGE("Unable to initialize monitor tracking table");
    993             dvmAbort();
    994         }
    995     }
    996 
    997     if (!dvmAddToReferenceTable(refTable, obj)) {
    998         /* ran out of memory? could throw exception instead */
    999         LOGE("Unable to add entry to monitor tracking table");
   1000         dvmAbort();
   1001     } else {
   1002         LOGVV("--- added monitor %p", obj);
   1003     }
   1004 }
   1005 
   1006 /*
   1007  * Track a JNI MonitorExit in the current thread.
   1008  */
   1009 static void trackMonitorExit(Thread* self, Object* obj) {
   1010     ReferenceTable* pRefTable = &self->jniMonitorRefTable;
   1011 
   1012     if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
   1013         LOGE("JNI monitor %p not found in tracking list", obj);
   1014         /* keep going? */
   1015     } else {
   1016         LOGVV("--- removed monitor %p", obj);
   1017     }
   1018 }
   1019 
   1020 /*
   1021  * Release all monitors held by the jniMonitorRefTable list.
   1022  */
   1023 void dvmReleaseJniMonitors(Thread* self) {
   1024     ReferenceTable* pRefTable = &self->jniMonitorRefTable;
   1025     Object** top = pRefTable->table;
   1026 
   1027     if (top == NULL) {
   1028         return;
   1029     }
   1030     Object** ptr = pRefTable->nextEntry;
   1031     while (--ptr >= top) {
   1032         if (!dvmUnlockObject(self, *ptr)) {
   1033             LOGW("Unable to unlock monitor %p at thread detach", *ptr);
   1034         } else {
   1035             LOGVV("--- detach-releasing monitor %p", *ptr);
   1036         }
   1037     }
   1038 
   1039     /* zap it */
   1040     pRefTable->nextEntry = pRefTable->table;
   1041 }
   1042 
   1043 /*
   1044  * Determine if the specified class can be instantiated from JNI.  This
   1045  * is used by AllocObject / NewObject, which are documented as throwing
   1046  * an exception for abstract and interface classes, and not accepting
   1047  * array classes.  We also want to reject attempts to create new Class
   1048  * objects, since only DefineClass should do that.
   1049  */
   1050 static bool canAllocClass(ClassObject* clazz) {
   1051     if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
   1052         /* JNI spec defines what this throws */
   1053         dvmThrowInstantiationException(clazz, "abstract class or interface");
   1054         return false;
   1055     } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) {
   1056         /* spec says "must not" for arrays, ignores Class */
   1057         dvmThrowInstantiationException(clazz, "wrong JNI function");
   1058         return false;
   1059     }
   1060     return true;
   1061 }
   1062 
   1063 
   1064 /*
   1065  * ===========================================================================
   1066  *      JNI call bridge
   1067  * ===========================================================================
   1068  */
   1069 
   1070 /*
   1071  * The functions here form a bridge between interpreted code and JNI native
   1072  * functions.  The basic task is to convert an array of primitives and
   1073  * references into C-style function arguments.  This is architecture-specific
   1074  * and usually requires help from assembly code.
   1075  *
   1076  * The bridge takes four arguments: the array of parameters, a place to
   1077  * store the function result (if any), the method to call, and a pointer
   1078  * to the current thread.
   1079  *
   1080  * These functions aren't called directly from elsewhere in the VM.
   1081  * A pointer in the Method struct points to one of these, and when a native
   1082  * method is invoked the interpreter jumps to it.
   1083  *
   1084  * (The "internal native" methods are invoked the same way, but instead
   1085  * of calling through a bridge, the target method is called directly.)
   1086  *
   1087  * The "args" array should not be modified, but we do so anyway for
   1088  * performance reasons.  We know that it points to the "outs" area on
   1089  * the current method's interpreted stack.  This area is ignored by the
   1090  * precise GC, because there is no register map for a native method (for
   1091  * an interpreted method the args would be listed in the argument set).
   1092  * We know all of the values exist elsewhere on the interpreted stack,
   1093  * because the method call setup copies them right before making the call,
   1094  * so we don't have to worry about concealing stuff from the GC.
   1095  *
   1096  * If we don't want to modify "args", we either have to create a local
   1097  * copy and modify it before calling dvmPlatformInvoke, or we have to do
   1098  * the local reference replacement within dvmPlatformInvoke.  The latter
   1099  * has some performance advantages, though if we can inline the local
   1100  * reference adds we may win when there's a lot of reference args (unless
   1101  * we want to code up some local ref table manipulation in assembly.
   1102  */
   1103 
   1104 /*
   1105  * If necessary, convert the value in pResult from a local/global reference
   1106  * to an object pointer.
   1107  *
   1108  * If the returned reference is invalid, kInvalidIndirectRefObject will
   1109  * be returned in pResult.
   1110  */
   1111 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
   1112     const Method* method, Thread* self)
   1113 {
   1114     if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) {
   1115         pResult->l = dvmDecodeIndirectRef(env, (jobject) pResult->l);
   1116     }
   1117 }
   1118 
   1119 /*
   1120  * General form, handles all cases.
   1121  */
   1122 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
   1123     u4* modArgs = (u4*) args;
   1124     jclass staticMethodClass = NULL;
   1125     JNIEnv* env = self->jniEnv;
   1126 
   1127     bool isSynchronized = dvmIsSynchronizedMethod(method);
   1128     Object* lockObj;
   1129 
   1130     //LOGI("JNI calling %p (%s.%s:%s):", method->insns,
   1131     //    method->clazz->descriptor, method->name, method->shorty);
   1132 
   1133     /*
   1134      * Walk the argument list, creating local references for appropriate
   1135      * arguments.
   1136      */
   1137     int idx = 0;
   1138     if (dvmIsStaticMethod(method)) {
   1139         lockObj = (Object*) method->clazz;
   1140 
   1141         /* add the class object we pass in */
   1142         staticMethodClass = (jclass) addLocalReference(env, (Object*) method->clazz);
   1143         if (staticMethodClass == NULL) {
   1144             assert(dvmCheckException(self));
   1145             return;
   1146         }
   1147     } else {
   1148         lockObj = (Object*) args[0];
   1149 
   1150         /* add "this" */
   1151         jobject thisObj = addLocalReference(env, (Object*) modArgs[0]);
   1152         if (thisObj == NULL) {
   1153             assert(dvmCheckException(self));
   1154             return;
   1155         }
   1156         modArgs[idx] = (u4) thisObj;
   1157         idx = 1;
   1158     }
   1159 
   1160     if (!method->noRef) {
   1161         const char* shorty = &method->shorty[1];        /* skip return type */
   1162         while (*shorty != '\0') {
   1163             switch (*shorty++) {
   1164             case 'L':
   1165                 //LOGI("  local %d: 0x%08x", idx, modArgs[idx]);
   1166                 if (modArgs[idx] != 0) {
   1167                     jobject argObj = addLocalReference(env, (Object*) modArgs[idx]);
   1168                     if (argObj == NULL) {
   1169                         assert(dvmCheckException(self));
   1170                         return;
   1171                     }
   1172                     modArgs[idx] = (u4) argObj;
   1173                 }
   1174                 break;
   1175             case 'D':
   1176             case 'J':
   1177                 idx++;
   1178                 break;
   1179             default:
   1180                 /* Z B C S I -- do nothing */
   1181                 break;
   1182             }
   1183             idx++;
   1184         }
   1185     }
   1186 
   1187     if (method->shouldTrace) {
   1188         logNativeMethodEntry(method, args);
   1189     }
   1190     if (isSynchronized) {
   1191         dvmLockObject(self, lockObj);
   1192     }
   1193 
   1194     ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
   1195 
   1196     ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
   1197     assert(method->insns != NULL);
   1198 
   1199     COMPUTE_STACK_SUM(self);
   1200     dvmPlatformInvoke(method->fastJni ? NULL : env,
   1201             (ClassObject*) staticMethodClass,
   1202             method->jniArgInfo, method->insSize, modArgs, method->shorty,
   1203             (void*) method->insns, pResult);
   1204     CHECK_STACK_SUM(self);
   1205 
   1206     dvmChangeStatus(self, oldStatus);
   1207 
   1208     convertReferenceResult(env, pResult, method, self);
   1209 
   1210     if (isSynchronized) {
   1211         dvmUnlockObject(self, lockObj);
   1212     }
   1213     if (method->shouldTrace) {
   1214         logNativeMethodExit(method, self, *pResult);
   1215     }
   1216 }
   1217 
   1218 /*
   1219  * Extract the return type enum from the "jniArgInfo" field.
   1220  */
   1221 DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo) {
   1222     return static_cast<DalvikJniReturnType>((jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT);
   1223 }
   1224 
   1225 /*
   1226  * ===========================================================================
   1227  *      JNI implementation
   1228  * ===========================================================================
   1229  */
   1230 
   1231 /*
   1232  * Return the version of the native method interface.
   1233  */
   1234 static jint GetVersion(JNIEnv* env) {
   1235     /*
   1236      * There is absolutely no need to toggle the mode for correct behavior.
   1237      * However, it does provide native code with a simple "suspend self
   1238      * if necessary" call.
   1239      */
   1240     ScopedJniThreadState ts(env);
   1241     return JNI_VERSION_1_6;
   1242 }
   1243 
   1244 /*
   1245  * Create a new class from a bag of bytes.
   1246  *
   1247  * This is not currently supported within Dalvik.
   1248  */
   1249 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
   1250     const jbyte* buf, jsize bufLen)
   1251 {
   1252     UNUSED_PARAMETER(name);
   1253     UNUSED_PARAMETER(loader);
   1254     UNUSED_PARAMETER(buf);
   1255     UNUSED_PARAMETER(bufLen);
   1256 
   1257     ScopedJniThreadState ts(env);
   1258     LOGW("JNI DefineClass is not supported");
   1259     return NULL;
   1260 }
   1261 
   1262 /*
   1263  * Find a class by name.
   1264  *
   1265  * We have to use the "no init" version of FindClass here, because we might
   1266  * be getting the class prior to registering native methods that will be
   1267  * used in <clinit>.
   1268  *
   1269  * We need to get the class loader associated with the current native
   1270  * method.  If there is no native method, e.g. we're calling this from native
   1271  * code right after creating the VM, the spec says we need to use the class
   1272  * loader returned by "ClassLoader.getBaseClassLoader".  There is no such
   1273  * method, but it's likely they meant ClassLoader.getSystemClassLoader.
   1274  * We can't get that until after the VM has initialized though.
   1275  */
   1276 static jclass FindClass(JNIEnv* env, const char* name) {
   1277     ScopedJniThreadState ts(env);
   1278 
   1279     const Method* thisMethod = dvmGetCurrentJNIMethod();
   1280     assert(thisMethod != NULL);
   1281 
   1282     Object* loader;
   1283     Object* trackedLoader = NULL;
   1284     if (ts.self()->classLoaderOverride != NULL) {
   1285         /* hack for JNI_OnLoad */
   1286         assert(strcmp(thisMethod->name, "nativeLoad") == 0);
   1287         loader = ts.self()->classLoaderOverride;
   1288     } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
   1289                thisMethod == gDvm.methDalvikSystemNativeStart_run) {
   1290         /* start point of invocation interface */
   1291         if (!gDvm.initializing) {
   1292             loader = trackedLoader = dvmGetSystemClassLoader();
   1293         } else {
   1294             loader = NULL;
   1295         }
   1296     } else {
   1297         loader = thisMethod->clazz->classLoader;
   1298     }
   1299 
   1300     char* descriptor = dvmNameToDescriptor(name);
   1301     if (descriptor == NULL) {
   1302         return NULL;
   1303     }
   1304     ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
   1305     free(descriptor);
   1306 
   1307     jclass jclazz = (jclass) addLocalReference(env, (Object*) clazz);
   1308     dvmReleaseTrackedAlloc(trackedLoader, ts.self());
   1309     return jclazz;
   1310 }
   1311 
   1312 /*
   1313  * Return the superclass of a class.
   1314  */
   1315 static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
   1316     ScopedJniThreadState ts(env);
   1317     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1318     return (jclass) addLocalReference(env, (Object*)clazz->super);
   1319 }
   1320 
   1321 /*
   1322  * Determine whether an object of clazz1 can be safely cast to clazz2.
   1323  *
   1324  * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
   1325  */
   1326 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
   1327     ScopedJniThreadState ts(env);
   1328     ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1);
   1329     ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2);
   1330     return dvmInstanceof(clazz1, clazz2);
   1331 }
   1332 
   1333 /*
   1334  * Given a java.lang.reflect.Method or .Constructor, return a methodID.
   1335  */
   1336 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
   1337     ScopedJniThreadState ts(env);
   1338     Object* method = dvmDecodeIndirectRef(env, jmethod);
   1339     return (jmethodID) dvmGetMethodFromReflectObj(method);
   1340 }
   1341 
   1342 /*
   1343  * Given a java.lang.reflect.Field, return a fieldID.
   1344  */
   1345 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
   1346     ScopedJniThreadState ts(env);
   1347     Object* field = dvmDecodeIndirectRef(env, jfield);
   1348     return (jfieldID) dvmGetFieldFromReflectObj(field);
   1349 }
   1350 
   1351 /*
   1352  * Convert a methodID to a java.lang.reflect.Method or .Constructor.
   1353  *
   1354  * (The "isStatic" field does not appear in the spec.)
   1355  *
   1356  * Throws OutOfMemory and returns NULL on failure.
   1357  */
   1358 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
   1359     ScopedJniThreadState ts(env);
   1360     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
   1361     Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
   1362     dvmReleaseTrackedAlloc(obj, NULL);
   1363     return addLocalReference(env, obj);
   1364 }
   1365 
   1366 /*
   1367  * Convert a fieldID to a java.lang.reflect.Field.
   1368  *
   1369  * (The "isStatic" field does not appear in the spec.)
   1370  *
   1371  * Throws OutOfMemory and returns NULL on failure.
   1372  */
   1373 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
   1374     ScopedJniThreadState ts(env);
   1375     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
   1376     Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
   1377     dvmReleaseTrackedAlloc(obj, NULL);
   1378     return addLocalReference(env, obj);
   1379 }
   1380 
   1381 /*
   1382  * Take this exception and throw it.
   1383  */
   1384 static jint Throw(JNIEnv* env, jthrowable jobj) {
   1385     ScopedJniThreadState ts(env);
   1386     if (jobj != NULL) {
   1387         Object* obj = dvmDecodeIndirectRef(env, jobj);
   1388         dvmSetException(ts.self(), obj);
   1389         return JNI_OK;
   1390     }
   1391     return JNI_ERR;
   1392 }
   1393 
   1394 /*
   1395  * Constructs an exception object from the specified class with the message
   1396  * specified by "message", and throws it.
   1397  */
   1398 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
   1399     ScopedJniThreadState ts(env);
   1400     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1401     dvmThrowException(clazz, message);
   1402     // TODO: should return failure if this didn't work (e.g. OOM)
   1403     return JNI_OK;
   1404 }
   1405 
   1406 /*
   1407  * If an exception is being thrown, return the exception object.  Otherwise,
   1408  * return NULL.
   1409  *
   1410  * TODO: if there is no pending exception, we should be able to skip the
   1411  * enter/exit checks.  If we find one, we need to enter and then re-fetch
   1412  * the exception (in case it got moved by a compacting GC).
   1413  */
   1414 static jthrowable ExceptionOccurred(JNIEnv* env) {
   1415     ScopedJniThreadState ts(env);
   1416     Object* exception = dvmGetException(ts.self());
   1417     jthrowable localException = (jthrowable) addLocalReference(env, exception);
   1418     if (localException == NULL && exception != NULL) {
   1419         /*
   1420          * We were unable to add a new local reference, and threw a new
   1421          * exception.  We can't return "exception", because it's not a
   1422          * local reference.  So we have to return NULL, indicating that
   1423          * there was no exception, even though it's pretty much raining
   1424          * exceptions in here.
   1425          */
   1426         LOGW("JNI WARNING: addLocal/exception combo");
   1427     }
   1428     return localException;
   1429 }
   1430 
   1431 /*
   1432  * Print an exception and stack trace to stderr.
   1433  */
   1434 static void ExceptionDescribe(JNIEnv* env) {
   1435     ScopedJniThreadState ts(env);
   1436     Object* exception = dvmGetException(ts.self());
   1437     if (exception != NULL) {
   1438         dvmPrintExceptionStackTrace();
   1439     } else {
   1440         LOGI("Odd: ExceptionDescribe called, but no exception pending");
   1441     }
   1442 }
   1443 
   1444 /*
   1445  * Clear the exception currently being thrown.
   1446  *
   1447  * TODO: we should be able to skip the enter/exit stuff.
   1448  */
   1449 static void ExceptionClear(JNIEnv* env) {
   1450     ScopedJniThreadState ts(env);
   1451     dvmClearException(ts.self());
   1452 }
   1453 
   1454 /*
   1455  * Kill the VM.  This function does not return.
   1456  */
   1457 static void FatalError(JNIEnv* env, const char* msg) {
   1458     //dvmChangeStatus(NULL, THREAD_RUNNING);
   1459     LOGE("JNI posting fatal error: %s", msg);
   1460     dvmAbort();
   1461 }
   1462 
   1463 /*
   1464  * Push a new JNI frame on the stack, with a new set of locals.
   1465  *
   1466  * The new frame must have the same method pointer.  (If for no other
   1467  * reason than FindClass needs it to get the appropriate class loader.)
   1468  */
   1469 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
   1470     ScopedJniThreadState ts(env);
   1471     if (!ensureLocalCapacity(env, capacity) ||
   1472             !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
   1473     {
   1474         /* yes, OutOfMemoryError, not StackOverflowError */
   1475         dvmClearException(ts.self());
   1476         dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
   1477         return JNI_ERR;
   1478     }
   1479     return JNI_OK;
   1480 }
   1481 
   1482 /*
   1483  * Pop the local frame off.  If "jresult" is not null, add it as a
   1484  * local reference on the now-current frame.
   1485  */
   1486 static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
   1487     ScopedJniThreadState ts(env);
   1488     Object* result = dvmDecodeIndirectRef(env, jresult);
   1489     if (!dvmPopLocalFrame(ts.self())) {
   1490         LOGW("JNI WARNING: too many PopLocalFrame calls");
   1491         dvmClearException(ts.self());
   1492         dvmThrowRuntimeException("too many PopLocalFrame calls");
   1493     }
   1494     return addLocalReference(env, result);
   1495 }
   1496 
   1497 /*
   1498  * Add a reference to the global list.
   1499  */
   1500 static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
   1501     ScopedJniThreadState ts(env);
   1502     Object* obj = dvmDecodeIndirectRef(env, jobj);
   1503     return addGlobalReference(obj);
   1504 }
   1505 
   1506 /*
   1507  * Delete a reference from the global list.
   1508  */
   1509 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
   1510     ScopedJniThreadState ts(env);
   1511     deleteGlobalReference(jglobalRef);
   1512 }
   1513 
   1514 
   1515 /*
   1516  * Add a reference to the local list.
   1517  */
   1518 static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
   1519     ScopedJniThreadState ts(env);
   1520     Object* obj = dvmDecodeIndirectRef(env, jobj);
   1521     return addLocalReference(env, obj);
   1522 }
   1523 
   1524 /*
   1525  * Delete a reference from the local list.
   1526  */
   1527 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
   1528     ScopedJniThreadState ts(env);
   1529     deleteLocalReference(env, jlocalRef);
   1530 }
   1531 
   1532 /*
   1533  * Ensure that the local references table can hold at least this many
   1534  * references.
   1535  */
   1536 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
   1537     ScopedJniThreadState ts(env);
   1538     bool okay = ensureLocalCapacity(env, capacity);
   1539     if (!okay) {
   1540         dvmThrowOutOfMemoryError("can't ensure local reference capacity");
   1541     }
   1542     return okay ? 0 : -1;
   1543 }
   1544 
   1545 
   1546 /*
   1547  * Determine whether two Object references refer to the same underlying object.
   1548  */
   1549 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
   1550     ScopedJniThreadState ts(env);
   1551     Object* obj1 = dvmDecodeIndirectRef(env, jref1);
   1552     Object* obj2 = dvmDecodeIndirectRef(env, jref2);
   1553     return (obj1 == obj2);
   1554 }
   1555 
   1556 /*
   1557  * Allocate a new object without invoking any constructors.
   1558  */
   1559 static jobject AllocObject(JNIEnv* env, jclass jclazz) {
   1560     ScopedJniThreadState ts(env);
   1561 
   1562     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1563     if (!canAllocClass(clazz) ||
   1564         (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
   1565     {
   1566         assert(dvmCheckException(ts.self()));
   1567         return NULL;
   1568     }
   1569 
   1570     Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   1571     return addLocalReference(env, newObj);
   1572 }
   1573 
   1574 /*
   1575  * Allocate a new object and invoke the supplied constructor.
   1576  */
   1577 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
   1578     ScopedJniThreadState ts(env);
   1579     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1580 
   1581     if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
   1582         assert(dvmCheckException(ts.self()));
   1583         return NULL;
   1584     }
   1585 
   1586     Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   1587     jobject result = addLocalReference(env, newObj);
   1588     if (newObj != NULL) {
   1589         JValue unused;
   1590         va_list args;
   1591         va_start(args, methodID);
   1592         dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
   1593         va_end(args);
   1594     }
   1595     return result;
   1596 }
   1597 
   1598 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
   1599     ScopedJniThreadState ts(env);
   1600     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1601 
   1602     if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
   1603         assert(dvmCheckException(ts.self()));
   1604         return NULL;
   1605     }
   1606 
   1607     Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   1608     jobject result = addLocalReference(env, newObj);
   1609     if (newObj != NULL) {
   1610         JValue unused;
   1611         dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
   1612     }
   1613     return result;
   1614 }
   1615 
   1616 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
   1617     ScopedJniThreadState ts(env);
   1618     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1619 
   1620     if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
   1621         assert(dvmCheckException(ts.self()));
   1622         return NULL;
   1623     }
   1624 
   1625     Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   1626     jobject result = addLocalReference(env, newObj);
   1627     if (newObj != NULL) {
   1628         JValue unused;
   1629         dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
   1630     }
   1631     return result;
   1632 }
   1633 
   1634 /*
   1635  * Returns the class of an object.
   1636  *
   1637  * JNI spec says: obj must not be NULL.
   1638  */
   1639 static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
   1640     ScopedJniThreadState ts(env);
   1641 
   1642     assert(jobj != NULL);
   1643 
   1644     Object* obj = dvmDecodeIndirectRef(env, jobj);
   1645     return (jclass) addLocalReference(env, (Object*) obj->clazz);
   1646 }
   1647 
   1648 /*
   1649  * Determine whether "obj" is an instance of "clazz".
   1650  */
   1651 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
   1652     ScopedJniThreadState ts(env);
   1653 
   1654     assert(jclazz != NULL);
   1655     if (jobj == NULL) {
   1656         return true;
   1657     }
   1658 
   1659     Object* obj = dvmDecodeIndirectRef(env, jobj);
   1660     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1661     return dvmInstanceof(obj->clazz, clazz);
   1662 }
   1663 
   1664 /*
   1665  * Get a method ID for an instance method.
   1666  *
   1667  * While Dalvik bytecode has distinct instructions for virtual, super,
   1668  * static, direct, and interface method invocation, JNI only provides
   1669  * two functions for acquiring a method ID.  This call handles everything
   1670  * but static methods.
   1671  *
   1672  * JNI defines <init> as an instance method, but Dalvik considers it a
   1673  * "direct" method, so we have to special-case it here.
   1674  *
   1675  * Dalvik also puts all private methods into the "direct" list, so we
   1676  * really need to just search both lists.
   1677  */
   1678 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
   1679     ScopedJniThreadState ts(env);
   1680 
   1681     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1682     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   1683         assert(dvmCheckException(ts.self()));
   1684     } else if (dvmIsInterfaceClass(clazz)) {
   1685         Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
   1686         if (meth == NULL) {
   1687             dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
   1688                 "no method with name='%s' signature='%s' in interface %s",
   1689                 name, sig, clazz->descriptor);
   1690         }
   1691         return (jmethodID) meth;
   1692     }
   1693     Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
   1694     if (meth == NULL) {
   1695         /* search private methods and constructors; non-hierarchical */
   1696         meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
   1697     }
   1698     if (meth != NULL && dvmIsStaticMethod(meth)) {
   1699         IF_LOGD() {
   1700             char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
   1701             LOGD("GetMethodID: not returning static method %s.%s %s",
   1702                     clazz->descriptor, meth->name, desc);
   1703             free(desc);
   1704         }
   1705         meth = NULL;
   1706     }
   1707     if (meth == NULL) {
   1708         dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
   1709                 "no method with name='%s' signature='%s' in class %s",
   1710                 name, sig, clazz->descriptor);
   1711     } else {
   1712         /*
   1713          * The method's class may not be the same as clazz, but if
   1714          * it isn't this must be a virtual method and the class must
   1715          * be a superclass (and, hence, already initialized).
   1716          */
   1717         assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
   1718     }
   1719     return (jmethodID) meth;
   1720 }
   1721 
   1722 /*
   1723  * Get a field ID (instance fields).
   1724  */
   1725 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
   1726     ScopedJniThreadState ts(env);
   1727 
   1728     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1729 
   1730     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   1731         assert(dvmCheckException(ts.self()));
   1732         return NULL;
   1733     }
   1734 
   1735     jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
   1736     if (id == NULL) {
   1737         dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
   1738                 "no field with name='%s' signature='%s' in class %s",
   1739                 name, sig, clazz->descriptor);
   1740     }
   1741     return id;
   1742 }
   1743 
   1744 /*
   1745  * Get the method ID for a static method in a class.
   1746  */
   1747 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
   1748     ScopedJniThreadState ts(env);
   1749 
   1750     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1751     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   1752         assert(dvmCheckException(ts.self()));
   1753         return NULL;
   1754     }
   1755 
   1756     Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
   1757 
   1758     /* make sure it's static, not virtual+private */
   1759     if (meth != NULL && !dvmIsStaticMethod(meth)) {
   1760         IF_LOGD() {
   1761             char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
   1762             LOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
   1763                     clazz->descriptor, meth->name, desc);
   1764             free(desc);
   1765         }
   1766         meth = NULL;
   1767     }
   1768 
   1769     jmethodID id = (jmethodID) meth;
   1770     if (id == NULL) {
   1771         dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
   1772                 "no static method with name='%s' signature='%s' in class %s",
   1773                 name, sig, clazz->descriptor);
   1774     }
   1775     return id;
   1776 }
   1777 
   1778 /*
   1779  * Get a field ID (static fields).
   1780  */
   1781 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
   1782     ScopedJniThreadState ts(env);
   1783 
   1784     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   1785     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
   1786         assert(dvmCheckException(ts.self()));
   1787         return NULL;
   1788     }
   1789 
   1790     jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
   1791     if (id == NULL) {
   1792         dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
   1793                 "no static field with name='%s' signature='%s' in class %s",
   1794                 name, sig, clazz->descriptor);
   1795     }
   1796     return id;
   1797 }
   1798 
   1799 /*
   1800  * Get a static field.
   1801  *
   1802  * If we get an object reference, add it to the local refs list.
   1803  */
   1804 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref)                       \
   1805     static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz,      \
   1806         jfieldID fieldID)                                                   \
   1807     {                                                                       \
   1808         UNUSED_PARAMETER(jclazz);                                           \
   1809         ScopedJniThreadState ts(env);                                       \
   1810         StaticField* sfield = (StaticField*) fieldID;                       \
   1811         _ctype value;                                                       \
   1812         if (dvmIsVolatileField(sfield)) {                                   \
   1813             if (_isref) {   /* only when _ctype==jobject */                 \
   1814                 Object* obj = dvmGetStaticFieldObjectVolatile(sfield);      \
   1815                 value = (_ctype)(u4)addLocalReference(env, obj);            \
   1816             } else {                                                        \
   1817                 value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
   1818             }                                                               \
   1819         } else {                                                            \
   1820             if (_isref) {                                                   \
   1821                 Object* obj = dvmGetStaticFieldObject(sfield);              \
   1822                 value = (_ctype)(u4)addLocalReference(env, obj);            \
   1823             } else {                                                        \
   1824                 value = (_ctype) dvmGetStaticField##_jname(sfield);         \
   1825             }                                                               \
   1826         }                                                                   \
   1827         return value;                                                       \
   1828     }
   1829 GET_STATIC_TYPE_FIELD(jobject, Object, true);
   1830 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
   1831 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
   1832 GET_STATIC_TYPE_FIELD(jchar, Char, false);
   1833 GET_STATIC_TYPE_FIELD(jshort, Short, false);
   1834 GET_STATIC_TYPE_FIELD(jint, Int, false);
   1835 GET_STATIC_TYPE_FIELD(jlong, Long, false);
   1836 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
   1837 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
   1838 
   1839 /*
   1840  * Set a static field.
   1841  */
   1842 #define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref)              \
   1843     static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz,        \
   1844         jfieldID fieldID, _ctype value)                                     \
   1845     {                                                                       \
   1846         UNUSED_PARAMETER(jclazz);                                           \
   1847         ScopedJniThreadState ts(env);                                       \
   1848         StaticField* sfield = (StaticField*) fieldID;                       \
   1849         if (dvmIsVolatileField(sfield)) {                                   \
   1850             if (_isref) {   /* only when _ctype==jobject */                 \
   1851                 Object* valObj =                                            \
   1852                     dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
   1853                 dvmSetStaticFieldObjectVolatile(sfield, valObj);            \
   1854             } else {                                                        \
   1855                 dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
   1856             }                                                               \
   1857         } else {                                                            \
   1858             if (_isref) {                                                   \
   1859                 Object* valObj =                                            \
   1860                     dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
   1861                 dvmSetStaticFieldObject(sfield, valObj);                    \
   1862             } else {                                                        \
   1863                 dvmSetStaticField##_jname(sfield, (_ctype2)value);          \
   1864             }                                                               \
   1865         }                                                                   \
   1866     }
   1867 SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
   1868 SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
   1869 SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
   1870 SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
   1871 SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
   1872 SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
   1873 SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
   1874 SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
   1875 SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
   1876 
   1877 /*
   1878  * Get an instance field.
   1879  *
   1880  * If we get an object reference, add it to the local refs list.
   1881  */
   1882 #define GET_TYPE_FIELD(_ctype, _jname, _isref)                              \
   1883     static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj,             \
   1884         jfieldID fieldID)                                                   \
   1885     {                                                                       \
   1886         ScopedJniThreadState ts(env);                                       \
   1887         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   1888         InstField* field = (InstField*) fieldID;                            \
   1889         _ctype value;                                                       \
   1890         if (dvmIsVolatileField(field)) {                            \
   1891             if (_isref) {   /* only when _ctype==jobject */                 \
   1892                 Object* valObj =                                            \
   1893                     dvmGetFieldObjectVolatile(obj, field->byteOffset);      \
   1894                 value = (_ctype)(u4)addLocalReference(env, valObj);         \
   1895             } else {                                                        \
   1896                 value = (_ctype)                                            \
   1897                     dvmGetField##_jname##Volatile(obj, field->byteOffset);  \
   1898             }                                                               \
   1899         } else {                                                            \
   1900             if (_isref) {                                                   \
   1901                 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
   1902                 value = (_ctype)(u4)addLocalReference(env, valObj);         \
   1903             } else {                                                        \
   1904                 value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
   1905             }                                                               \
   1906         }                                                                   \
   1907         return value;                                                       \
   1908     }
   1909 GET_TYPE_FIELD(jobject, Object, true);
   1910 GET_TYPE_FIELD(jboolean, Boolean, false);
   1911 GET_TYPE_FIELD(jbyte, Byte, false);
   1912 GET_TYPE_FIELD(jchar, Char, false);
   1913 GET_TYPE_FIELD(jshort, Short, false);
   1914 GET_TYPE_FIELD(jint, Int, false);
   1915 GET_TYPE_FIELD(jlong, Long, false);
   1916 GET_TYPE_FIELD(jfloat, Float, false);
   1917 GET_TYPE_FIELD(jdouble, Double, false);
   1918 
   1919 /*
   1920  * Set an instance field.
   1921  */
   1922 #define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref)                     \
   1923     static void Set##_jname##Field(JNIEnv* env, jobject jobj,               \
   1924         jfieldID fieldID, _ctype value)                                     \
   1925     {                                                                       \
   1926         ScopedJniThreadState ts(env);                                       \
   1927         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   1928         InstField* field = (InstField*) fieldID;                            \
   1929         if (dvmIsVolatileField(field)) {                                    \
   1930             if (_isref) {   /* only when _ctype==jobject */                 \
   1931                 Object* valObj =                                            \
   1932                     dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
   1933                 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj);  \
   1934             } else {                                                        \
   1935                 dvmSetField##_jname##Volatile(obj,                          \
   1936                     field->byteOffset, (_ctype2)value);                     \
   1937             }                                                               \
   1938         } else {                                                            \
   1939             if (_isref) {                                                   \
   1940                 Object* valObj =                                            \
   1941                     dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
   1942                 dvmSetFieldObject(obj, field->byteOffset, valObj);          \
   1943             } else {                                                        \
   1944                 dvmSetField##_jname(obj,                                    \
   1945                     field->byteOffset, (_ctype2)value);                     \
   1946             }                                                               \
   1947         }                                                                   \
   1948     }
   1949 SET_TYPE_FIELD(jobject, Object*, Object, true);
   1950 SET_TYPE_FIELD(jboolean, bool, Boolean, false);
   1951 SET_TYPE_FIELD(jbyte, s1, Byte, false);
   1952 SET_TYPE_FIELD(jchar, u2, Char, false);
   1953 SET_TYPE_FIELD(jshort, s2, Short, false);
   1954 SET_TYPE_FIELD(jint, s4, Int, false);
   1955 SET_TYPE_FIELD(jlong, s8, Long, false);
   1956 SET_TYPE_FIELD(jfloat, float, Float, false);
   1957 SET_TYPE_FIELD(jdouble, double, Double, false);
   1958 
   1959 /*
   1960  * Make a virtual method call.
   1961  *
   1962  * Three versions (..., va_list, jvalue[]) for each return type.  If we're
   1963  * returning an Object, we have to add it to the local references table.
   1964  */
   1965 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref)              \
   1966     static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj,           \
   1967         jmethodID methodID, ...)                                            \
   1968     {                                                                       \
   1969         ScopedJniThreadState ts(env);                                       \
   1970         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   1971         const Method* meth;                                                 \
   1972         va_list args;                                                       \
   1973         JValue result;                                                      \
   1974         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   1975         if (meth == NULL) {                                                 \
   1976             return _retfail;                                                \
   1977         }                                                                   \
   1978         va_start(args, methodID);                                           \
   1979         dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
   1980         va_end(args);                                                       \
   1981         if (_isref && !dvmCheckException(ts.self()))                        \
   1982             result.l = (Object*)addLocalReference(env, result.l);           \
   1983         return _retok;                                                      \
   1984     }                                                                       \
   1985     static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj,          \
   1986         jmethodID methodID, va_list args)                                   \
   1987     {                                                                       \
   1988         ScopedJniThreadState ts(env);                                       \
   1989         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   1990         const Method* meth;                                                 \
   1991         JValue result;                                                      \
   1992         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   1993         if (meth == NULL) {                                                 \
   1994             return _retfail;                                                \
   1995         }                                                                   \
   1996         dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
   1997         if (_isref && !dvmCheckException(ts.self()))                        \
   1998             result.l = (Object*)addLocalReference(env, result.l);           \
   1999         return _retok;                                                      \
   2000     }                                                                       \
   2001     static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj,          \
   2002         jmethodID methodID, jvalue* args)                                   \
   2003     {                                                                       \
   2004         ScopedJniThreadState ts(env);                                       \
   2005         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2006         const Method* meth;                                                 \
   2007         JValue result;                                                      \
   2008         meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
   2009         if (meth == NULL) {                                                 \
   2010             return _retfail;                                                \
   2011         }                                                                   \
   2012         dvmCallMethodA(ts.self(), meth, obj, true, &result, args);          \
   2013         if (_isref && !dvmCheckException(ts.self()))                        \
   2014             result.l = (Object*)addLocalReference(env, result.l);           \
   2015         return _retok;                                                      \
   2016     }
   2017 CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
   2018 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
   2019 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
   2020 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
   2021 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
   2022 CALL_VIRTUAL(jint, Int, 0, result.i, false);
   2023 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
   2024 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
   2025 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
   2026 CALL_VIRTUAL(void, Void, , , false);
   2027 
   2028 /*
   2029  * Make a "non-virtual" method call.  We're still calling a virtual method,
   2030  * but this time we're not doing an indirection through the object's vtable.
   2031  * The "clazz" parameter defines which implementation of a method we want.
   2032  *
   2033  * Three versions (..., va_list, jvalue[]) for each return type.
   2034  */
   2035 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref)           \
   2036     static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
   2037         jclass jclazz, jmethodID methodID, ...)                             \
   2038     {                                                                       \
   2039         ScopedJniThreadState ts(env);                                       \
   2040         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2041         ClassObject* clazz =                                                \
   2042             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2043         const Method* meth;                                                 \
   2044         va_list args;                                                       \
   2045         JValue result;                                                      \
   2046         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2047         if (meth == NULL) {                                                 \
   2048             return _retfail;                                                \
   2049         }                                                                   \
   2050         va_start(args, methodID);                                           \
   2051         dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
   2052         if (_isref && !dvmCheckException(ts.self()))                        \
   2053             result.l = (Object*)addLocalReference(env, result.l);           \
   2054         va_end(args);                                                       \
   2055         return _retok;                                                      \
   2056     }                                                                       \
   2057     static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
   2058         jclass jclazz, jmethodID methodID, va_list args)                    \
   2059     {                                                                       \
   2060         ScopedJniThreadState ts(env);                                       \
   2061         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2062         ClassObject* clazz =                                                \
   2063             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2064         const Method* meth;                                                 \
   2065         JValue result;                                                      \
   2066         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2067         if (meth == NULL) {                                                 \
   2068             return _retfail;                                                \
   2069         }                                                                   \
   2070         dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
   2071         if (_isref && !dvmCheckException(ts.self()))                        \
   2072             result.l = (Object*)addLocalReference(env, result.l);           \
   2073         return _retok;                                                      \
   2074     }                                                                       \
   2075     static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
   2076         jclass jclazz, jmethodID methodID, jvalue* args)                    \
   2077     {                                                                       \
   2078         ScopedJniThreadState ts(env);                                       \
   2079         Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
   2080         ClassObject* clazz =                                                \
   2081             (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
   2082         const Method* meth;                                                 \
   2083         JValue result;                                                      \
   2084         meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
   2085         if (meth == NULL) {                                                 \
   2086             return _retfail;                                                \
   2087         }                                                                   \
   2088         dvmCallMethodA(ts.self(), meth, obj, true, &result, args);          \
   2089         if (_isref && !dvmCheckException(ts.self()))                        \
   2090             result.l = (Object*)addLocalReference(env, result.l);           \
   2091         return _retok;                                                      \
   2092     }
   2093 CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
   2094 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
   2095 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
   2096 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
   2097 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
   2098 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
   2099 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
   2100 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
   2101 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
   2102 CALL_NONVIRTUAL(void, Void, , , false);
   2103 
   2104 
   2105 /*
   2106  * Call a static method.
   2107  */
   2108 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref)               \
   2109     static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,    \
   2110         jmethodID methodID, ...)                                            \
   2111     {                                                                       \
   2112         UNUSED_PARAMETER(jclazz);                                           \
   2113         ScopedJniThreadState ts(env);                                       \
   2114         JValue result;                                                      \
   2115         va_list args;                                                       \
   2116         va_start(args, methodID);                                           \
   2117         dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
   2118         va_end(args);                                                       \
   2119         if (_isref && !dvmCheckException(ts.self()))                        \
   2120             result.l = (Object*)addLocalReference(env, result.l);           \
   2121         return _retok;                                                      \
   2122     }                                                                       \
   2123     static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,   \
   2124         jmethodID methodID, va_list args)                                   \
   2125     {                                                                       \
   2126         UNUSED_PARAMETER(jclazz);                                           \
   2127         ScopedJniThreadState ts(env);                                       \
   2128         JValue result;                                                      \
   2129         dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
   2130         if (_isref && !dvmCheckException(ts.self()))                        \
   2131             result.l = (Object*)addLocalReference(env, result.l);           \
   2132         return _retok;                                                      \
   2133     }                                                                       \
   2134     static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,   \
   2135         jmethodID methodID, jvalue* args)                                   \
   2136     {                                                                       \
   2137         UNUSED_PARAMETER(jclazz);                                           \
   2138         ScopedJniThreadState ts(env);                                       \
   2139         JValue result;                                                      \
   2140         dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
   2141         if (_isref && !dvmCheckException(ts.self()))                        \
   2142             result.l = (Object*)addLocalReference(env, result.l);           \
   2143         return _retok;                                                      \
   2144     }
   2145 CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
   2146 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
   2147 CALL_STATIC(jbyte, Byte, 0, result.b, false);
   2148 CALL_STATIC(jchar, Char, 0, result.c, false);
   2149 CALL_STATIC(jshort, Short, 0, result.s, false);
   2150 CALL_STATIC(jint, Int, 0, result.i, false);
   2151 CALL_STATIC(jlong, Long, 0, result.j, false);
   2152 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
   2153 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
   2154 CALL_STATIC(void, Void, , , false);
   2155 
   2156 /*
   2157  * Create a new String from Unicode data.
   2158  *
   2159  * If "len" is zero, we will return an empty string even if "unicodeChars"
   2160  * is NULL.  (The JNI spec is vague here.)
   2161  */
   2162 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
   2163     ScopedJniThreadState ts(env);
   2164     StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
   2165     if (jstr == NULL) {
   2166         return NULL;
   2167     }
   2168     dvmReleaseTrackedAlloc((Object*) jstr, NULL);
   2169     return (jstring) addLocalReference(env, (Object*) jstr);
   2170 }
   2171 
   2172 /*
   2173  * Return the length of a String in Unicode character units.
   2174  */
   2175 static jsize GetStringLength(JNIEnv* env, jstring jstr) {
   2176     ScopedJniThreadState ts(env);
   2177     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2178     return strObj->length();
   2179 }
   2180 
   2181 
   2182 /*
   2183  * Get a string's character data.
   2184  *
   2185  * The result is guaranteed to be valid until ReleaseStringChars is
   2186  * called, which means we have to pin it or return a copy.
   2187  */
   2188 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
   2189     ScopedJniThreadState ts(env);
   2190 
   2191     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2192     ArrayObject* strChars = strObj->array();
   2193 
   2194     pinPrimitiveArray(strChars);
   2195 
   2196     const u2* data = strObj->chars();
   2197     if (isCopy != NULL) {
   2198         *isCopy = JNI_FALSE;
   2199     }
   2200     return (jchar*) data;
   2201 }
   2202 
   2203 /*
   2204  * Release our grip on some characters from a string.
   2205  */
   2206 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
   2207     ScopedJniThreadState ts(env);
   2208     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2209     ArrayObject* strChars = strObj->array();
   2210     unpinPrimitiveArray(strChars);
   2211 }
   2212 
   2213 /*
   2214  * Create a new java.lang.String object from chars in modified UTF-8 form.
   2215  *
   2216  * The spec doesn't say how to handle a NULL string.  Popular desktop VMs
   2217  * accept it and return a NULL pointer in response.
   2218  */
   2219 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
   2220     ScopedJniThreadState ts(env);
   2221     if (bytes == NULL) {
   2222         return NULL;
   2223     }
   2224     /* note newStr could come back NULL on OOM */
   2225     StringObject* newStr = dvmCreateStringFromCstr(bytes);
   2226     jstring result = (jstring) addLocalReference(env, (Object*) newStr);
   2227     dvmReleaseTrackedAlloc((Object*)newStr, NULL);
   2228     return result;
   2229 }
   2230 
   2231 /*
   2232  * Return the length in bytes of the modified UTF-8 form of the string.
   2233  */
   2234 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
   2235     ScopedJniThreadState ts(env);
   2236     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2237     if (strObj == NULL) {
   2238         return 0; // Should we throw something or assert?
   2239     }
   2240     return strObj->utfLength();
   2241 }
   2242 
   2243 /*
   2244  * Convert "string" to modified UTF-8 and return a pointer.  The returned
   2245  * value must be released with ReleaseStringUTFChars.
   2246  *
   2247  * According to the JNI reference, "Returns a pointer to a UTF-8 string,
   2248  * or NULL if the operation fails. Returns NULL if and only if an invocation
   2249  * of this function has thrown an exception."
   2250  *
   2251  * The behavior here currently follows that of other open-source VMs, which
   2252  * quietly return NULL if "string" is NULL.  We should consider throwing an
   2253  * NPE.  (The CheckJNI code blows up if you try to pass in a NULL string,
   2254  * which should catch this sort of thing during development.)  Certain other
   2255  * VMs will crash with a segmentation fault.
   2256  */
   2257 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
   2258     ScopedJniThreadState ts(env);
   2259     if (jstr == NULL) {
   2260         /* this shouldn't happen; throw NPE? */
   2261         return NULL;
   2262     }
   2263     if (isCopy != NULL) {
   2264         *isCopy = JNI_TRUE;
   2265     }
   2266     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2267     char* newStr = dvmCreateCstrFromString(strObj);
   2268     if (newStr == NULL) {
   2269         /* assume memory failure */
   2270         dvmThrowOutOfMemoryError("native heap string alloc failed");
   2271     }
   2272     return newStr;
   2273 }
   2274 
   2275 /*
   2276  * Release a string created by GetStringUTFChars().
   2277  */
   2278 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
   2279     ScopedJniThreadState ts(env);
   2280     free((char*) utf);
   2281 }
   2282 
   2283 /*
   2284  * Return the capacity of the array.
   2285  */
   2286 static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
   2287     ScopedJniThreadState ts(env);
   2288     ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   2289     return arrObj->length;
   2290 }
   2291 
   2292 /*
   2293  * Construct a new array that holds objects from class "elementClass".
   2294  */
   2295 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
   2296     jclass jelementClass, jobject jinitialElement)
   2297 {
   2298     ScopedJniThreadState ts(env);
   2299 
   2300     if (jelementClass == NULL) {
   2301         dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
   2302         return NULL;
   2303     }
   2304 
   2305     ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(env, jelementClass);
   2306     ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
   2307     ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
   2308     if (newObj == NULL) {
   2309         assert(dvmCheckException(ts.self()));
   2310         return NULL;
   2311     }
   2312     jobjectArray newArray = (jobjectArray) addLocalReference(env, (Object*) newObj);
   2313     dvmReleaseTrackedAlloc((Object*) newObj, NULL);
   2314 
   2315     /*
   2316      * Initialize the array.
   2317      */
   2318     if (jinitialElement != NULL) {
   2319         Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement);
   2320         Object** arrayData = (Object**) (void*) newObj->contents;
   2321         for (jsize i = 0; i < length; ++i) {
   2322             arrayData[i] = initialElement;
   2323         }
   2324     }
   2325 
   2326     return newArray;
   2327 }
   2328 
   2329 static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
   2330     assert(arrayObj != NULL);
   2331     if (index < 0 || index >= (int) arrayObj->length) {
   2332         dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
   2333         return false;
   2334     }
   2335     return true;
   2336 }
   2337 
   2338 /*
   2339  * Get one element of an Object array.
   2340  *
   2341  * Add the object to the local references table in case the array goes away.
   2342  */
   2343 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
   2344     ScopedJniThreadState ts(env);
   2345 
   2346     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   2347     if (!checkArrayElementBounds(arrayObj, index)) {
   2348         return NULL;
   2349     }
   2350 
   2351     Object* value = ((Object**) (void*) arrayObj->contents)[index];
   2352     return addLocalReference(env, value);
   2353 }
   2354 
   2355 /*
   2356  * Set one element of an Object array.
   2357  */
   2358 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
   2359     ScopedJniThreadState ts(env);
   2360 
   2361     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   2362     if (!checkArrayElementBounds(arrayObj, index)) {
   2363         return;
   2364     }
   2365 
   2366     //LOGV("JNI: set element %d in array %p to %p", index, array, value);
   2367 
   2368     Object* obj = dvmDecodeIndirectRef(env, jobj);
   2369     dvmSetObjectArrayElement(arrayObj, index, obj);
   2370 }
   2371 
   2372 /*
   2373  * Create a new array of primitive elements.
   2374  */
   2375 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
   2376     static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
   2377         ScopedJniThreadState ts(env); \
   2378         ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
   2379         if (arrayObj == NULL) { \
   2380             return NULL; \
   2381         } \
   2382         _artype result = (_artype) addLocalReference(env, (Object*) arrayObj); \
   2383         dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
   2384         return result; \
   2385     }
   2386 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
   2387 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
   2388 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
   2389 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
   2390 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
   2391 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
   2392 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
   2393 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
   2394 
   2395 /*
   2396  * Get a pointer to a C array of primitive elements from an array object
   2397  * of the matching type.
   2398  *
   2399  * In a compacting GC, we either need to return a copy of the elements or
   2400  * "pin" the memory.  Otherwise we run the risk of native code using the
   2401  * buffer as the destination of e.g. a blocking read() call that wakes up
   2402  * during a GC.
   2403  */
   2404 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
   2405     static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
   2406         _ctype##Array jarr, jboolean* isCopy) \
   2407     { \
   2408         ScopedJniThreadState ts(env); \
   2409         ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
   2410         pinPrimitiveArray(arrayObj); \
   2411         _ctype* data = (_ctype*) (void*) arrayObj->contents; \
   2412         if (isCopy != NULL) { \
   2413             *isCopy = JNI_FALSE; \
   2414         } \
   2415         return data; \
   2416     }
   2417 
   2418 /*
   2419  * Release the storage locked down by the "get" function.
   2420  *
   2421  * The spec says, "'mode' has no effect if 'elems' is not a copy of the
   2422  * elements in 'array'."  They apparently did not anticipate the need to
   2423  * un-pin memory.
   2424  */
   2425 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                    \
   2426     static void Release##_jname##ArrayElements(JNIEnv* env,                 \
   2427         _ctype##Array jarr, _ctype* elems, jint mode)                       \
   2428     {                                                                       \
   2429         UNUSED_PARAMETER(elems);                                            \
   2430         if (mode != JNI_COMMIT) {                                           \
   2431             ScopedJniThreadState ts(env);                                   \
   2432             ArrayObject* arrayObj =                                         \
   2433                 (ArrayObject*) dvmDecodeIndirectRef(env, jarr);             \
   2434             unpinPrimitiveArray(arrayObj);                                  \
   2435         }                                                                   \
   2436     }
   2437 
   2438 static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
   2439     jsize len, const char* arrayIdentifier)
   2440 {
   2441     dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
   2442         "%s offset=%d length=%d %s.length=%d",
   2443         arrayObj->clazz->descriptor, start, len, arrayIdentifier,
   2444         arrayObj->length);
   2445 }
   2446 
   2447 /*
   2448  * Copy a section of a primitive array to a buffer.
   2449  */
   2450 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
   2451     static void Get##_jname##ArrayRegion(JNIEnv* env, \
   2452         _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
   2453     { \
   2454         ScopedJniThreadState ts(env); \
   2455         ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
   2456         _ctype* data = (_ctype*) (void*) arrayObj->contents; \
   2457         if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
   2458             throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
   2459         } else { \
   2460             memcpy(buf, data + start, len * sizeof(_ctype)); \
   2461         } \
   2462     }
   2463 
   2464 /*
   2465  * Copy a section of a primitive array from a buffer.
   2466  */
   2467 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
   2468     static void Set##_jname##ArrayRegion(JNIEnv* env, \
   2469         _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
   2470     { \
   2471         ScopedJniThreadState ts(env); \
   2472         ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
   2473         _ctype* data = (_ctype*) (void*) arrayObj->contents; \
   2474         if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
   2475             throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
   2476         } else { \
   2477             memcpy(data + start, buf, len * sizeof(_ctype)); \
   2478         } \
   2479     }
   2480 
   2481 /*
   2482  * 4-in-1:
   2483  *  Get<Type>ArrayElements
   2484  *  Release<Type>ArrayElements
   2485  *  Get<Type>ArrayRegion
   2486  *  Set<Type>ArrayRegion
   2487  */
   2488 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname)                           \
   2489     GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                           \
   2490     RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                       \
   2491     GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);                             \
   2492     SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
   2493 
   2494 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
   2495 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
   2496 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
   2497 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
   2498 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
   2499 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
   2500 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
   2501 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
   2502 
   2503 /*
   2504  * Register one or more native functions in one class.
   2505  *
   2506  * This can be called multiple times on the same method, allowing the
   2507  * caller to redefine the method implementation at will.
   2508  */
   2509 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
   2510     const JNINativeMethod* methods, jint nMethods)
   2511 {
   2512     ScopedJniThreadState ts(env);
   2513 
   2514     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2515 
   2516     if (gDvm.verboseJni) {
   2517         LOGI("[Registering JNI native methods for class %s]",
   2518             clazz->descriptor);
   2519     }
   2520 
   2521     for (int i = 0; i < nMethods; i++) {
   2522         if (!dvmRegisterJNIMethod(clazz, methods[i].name,
   2523                 methods[i].signature, methods[i].fnPtr))
   2524         {
   2525             return JNI_ERR;
   2526         }
   2527     }
   2528     return JNI_OK;
   2529 }
   2530 
   2531 /*
   2532  * Un-register all native methods associated with the class.
   2533  *
   2534  * The JNI docs refer to this as a way to reload/relink native libraries,
   2535  * and say it "should not be used in normal native code".  In particular,
   2536  * there is no need to do this during shutdown, and you do not need to do
   2537  * this before redefining a method implementation with RegisterNatives.
   2538  *
   2539  * It's chiefly useful for a native "plugin"-style library that wasn't
   2540  * loaded with System.loadLibrary() (since there's no way to unload those).
   2541  * For example, the library could upgrade itself by:
   2542  *
   2543  *  1. call UnregisterNatives to unbind the old methods
   2544  *  2. ensure that no code is still executing inside it (somehow)
   2545  *  3. dlclose() the library
   2546  *  4. dlopen() the new library
   2547  *  5. use RegisterNatives to bind the methods from the new library
   2548  *
   2549  * The above can work correctly without the UnregisterNatives call, but
   2550  * creates a window of opportunity in which somebody might try to call a
   2551  * method that is pointing at unmapped memory, crashing the VM.  In theory
   2552  * the same guards that prevent dlclose() from unmapping executing code could
   2553  * prevent that anyway, but with this we can be more thorough and also deal
   2554  * with methods that only exist in the old or new form of the library (maybe
   2555  * the lib wants to try the call and catch the UnsatisfiedLinkError).
   2556  */
   2557 static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
   2558     ScopedJniThreadState ts(env);
   2559 
   2560     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
   2561     if (gDvm.verboseJni) {
   2562         LOGI("[Unregistering JNI native methods for class %s]",
   2563             clazz->descriptor);
   2564     }
   2565     dvmUnregisterJNINativeMethods(clazz);
   2566     return JNI_OK;
   2567 }
   2568 
   2569 /*
   2570  * Lock the monitor.
   2571  *
   2572  * We have to track all monitor enters and exits, so that we can undo any
   2573  * outstanding synchronization before the thread exits.
   2574  */
   2575 static jint MonitorEnter(JNIEnv* env, jobject jobj) {
   2576     ScopedJniThreadState ts(env);
   2577     Object* obj = dvmDecodeIndirectRef(env, jobj);
   2578     dvmLockObject(ts.self(), obj);
   2579     trackMonitorEnter(ts.self(), obj);
   2580     return JNI_OK;
   2581 }
   2582 
   2583 /*
   2584  * Unlock the monitor.
   2585  *
   2586  * Throws an IllegalMonitorStateException if the current thread
   2587  * doesn't own the monitor.  (dvmUnlockObject() takes care of the throw.)
   2588  *
   2589  * According to the 1.6 spec, it's legal to call here with an exception
   2590  * pending.  If this fails, we'll stomp the original exception.
   2591  */
   2592 static jint MonitorExit(JNIEnv* env, jobject jobj) {
   2593     ScopedJniThreadState ts(env);
   2594     Object* obj = dvmDecodeIndirectRef(env, jobj);
   2595     bool success = dvmUnlockObject(ts.self(), obj);
   2596     if (success) {
   2597         trackMonitorExit(ts.self(), obj);
   2598     }
   2599     return success ? JNI_OK : JNI_ERR;
   2600 }
   2601 
   2602 /*
   2603  * Return the JavaVM interface associated with the current thread.
   2604  */
   2605 static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
   2606     ScopedJniThreadState ts(env);
   2607     *vm = gDvmJni.jniVm;
   2608     return (*vm == NULL) ? JNI_ERR : JNI_OK;
   2609 }
   2610 
   2611 /*
   2612  * Copies "len" Unicode characters, from offset "start".
   2613  */
   2614 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
   2615     ScopedJniThreadState ts(env);
   2616     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2617     int strLen = strObj->length();
   2618     if (((start|len) < 0) || (start + len > strLen)) {
   2619         dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
   2620         return;
   2621     }
   2622     memcpy(buf, strObj->chars() + start, len * sizeof(u2));
   2623 }
   2624 
   2625 /*
   2626  * Translates "len" Unicode characters, from offset "start", into
   2627  * modified UTF-8 encoding.
   2628  */
   2629 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
   2630     ScopedJniThreadState ts(env);
   2631     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2632     int strLen = strObj->length();
   2633     if (((start|len) < 0) || (start + len > strLen)) {
   2634         dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
   2635         return;
   2636     }
   2637     dvmGetStringUtfRegion(strObj, start, len, buf);
   2638 }
   2639 
   2640 /*
   2641  * Get a raw pointer to array data.
   2642  *
   2643  * The caller is expected to call "release" before doing any JNI calls
   2644  * or blocking I/O operations.
   2645  *
   2646  * We need to pin the memory or block GC.
   2647  */
   2648 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
   2649     ScopedJniThreadState ts(env);
   2650     ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   2651     pinPrimitiveArray(arrayObj);
   2652     void* data = arrayObj->contents;
   2653     if (isCopy != NULL) {
   2654         *isCopy = JNI_FALSE;
   2655     }
   2656     return data;
   2657 }
   2658 
   2659 /*
   2660  * Release an array obtained with GetPrimitiveArrayCritical.
   2661  */
   2662 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
   2663     if (mode != JNI_COMMIT) {
   2664         ScopedJniThreadState ts(env);
   2665         ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
   2666         unpinPrimitiveArray(arrayObj);
   2667     }
   2668 }
   2669 
   2670 /*
   2671  * Like GetStringChars, but with restricted use.
   2672  */
   2673 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
   2674     ScopedJniThreadState ts(env);
   2675 
   2676     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2677     ArrayObject* strChars = strObj->array();
   2678 
   2679     pinPrimitiveArray(strChars);
   2680 
   2681     const u2* data = strObj->chars();
   2682     if (isCopy != NULL) {
   2683         *isCopy = JNI_FALSE;
   2684     }
   2685     return (jchar*) data;
   2686 }
   2687 
   2688 /*
   2689  * Like ReleaseStringChars, but with restricted use.
   2690  */
   2691 static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
   2692     ScopedJniThreadState ts(env);
   2693     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
   2694     ArrayObject* strChars = strObj->array();
   2695     unpinPrimitiveArray(strChars);
   2696 }
   2697 
   2698 /*
   2699  * Create a new weak global reference.
   2700  */
   2701 static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
   2702     ScopedJniThreadState ts(env);
   2703     Object *obj = dvmDecodeIndirectRef(env, jobj);
   2704     return (jweak) addWeakGlobalReference(obj);
   2705 }
   2706 
   2707 /*
   2708  * Delete the specified weak global reference.
   2709  */
   2710 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
   2711     ScopedJniThreadState ts(env);
   2712     deleteWeakGlobalReference(wref);
   2713 }
   2714 
   2715 /*
   2716  * Quick check for pending exceptions.
   2717  *
   2718  * TODO: we should be able to skip the enter/exit macros here.
   2719  */
   2720 static jboolean ExceptionCheck(JNIEnv* env) {
   2721     ScopedJniThreadState ts(env);
   2722     return dvmCheckException(ts.self());
   2723 }
   2724 
   2725 /*
   2726  * Returns the type of the object referred to by "obj".  It can be local,
   2727  * global, or weak global.
   2728  *
   2729  * In the current implementation, references can be global and local at
   2730  * the same time, so while the return value is accurate it may not tell
   2731  * the whole story.
   2732  */
   2733 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
   2734     ScopedJniThreadState ts(env);
   2735     return dvmGetJNIRefType(env, jobj);
   2736 }
   2737 
   2738 /*
   2739  * Allocate and return a new java.nio.ByteBuffer for this block of memory.
   2740  *
   2741  * "address" may not be NULL, and "capacity" must be > 0.  (These are only
   2742  * verified when CheckJNI is enabled.)
   2743  */
   2744 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
   2745     ScopedJniThreadState ts(env);
   2746 
   2747     /* create an instance of java.nio.ReadWriteDirectByteBuffer */
   2748     ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
   2749     if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
   2750         return NULL;
   2751     }
   2752     Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
   2753     if (newObj == NULL) {
   2754         return NULL;
   2755     }
   2756     /* call the constructor */
   2757     jobject result = addLocalReference(env, newObj);
   2758     JValue unused;
   2759     dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init,
   2760             newObj, &unused, (jint) address, (jint) capacity);
   2761     if (dvmGetException(ts.self()) != NULL) {
   2762         deleteLocalReference(env, result);
   2763         return NULL;
   2764     }
   2765     return result;
   2766 }
   2767 
   2768 /*
   2769  * Get the starting address of the buffer for the specified java.nio.Buffer.
   2770  *
   2771  * If this is not a "direct" buffer, we return NULL.
   2772  */
   2773 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
   2774     ScopedJniThreadState ts(env);
   2775 
   2776     // All Buffer objects have an effectiveDirectAddress field.
   2777     Object* bufObj = dvmDecodeIndirectRef(env, jbuf);
   2778     return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
   2779 }
   2780 
   2781 /*
   2782  * Get the capacity of the buffer for the specified java.nio.Buffer.
   2783  *
   2784  * Returns -1 if the object is not a direct buffer.  (We actually skip
   2785  * this check, since it's expensive to determine, and just return the
   2786  * capacity regardless.)
   2787  */
   2788 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
   2789     ScopedJniThreadState ts(env);
   2790 
   2791     /*
   2792      * The capacity is always in the Buffer.capacity field.
   2793      *
   2794      * (The "check" version should verify that this is actually a Buffer,
   2795      * but we're not required to do so here.)
   2796      */
   2797     Object* buf = dvmDecodeIndirectRef(env, jbuf);
   2798     return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
   2799 }
   2800 
   2801 
   2802 /*
   2803  * ===========================================================================
   2804  *      JNI invocation functions
   2805  * ===========================================================================
   2806  */
   2807 
   2808 /*
   2809  * Handle AttachCurrentThread{AsDaemon}.
   2810  *
   2811  * We need to make sure the VM is actually running.  For example, if we start
   2812  * up, issue an Attach, and the VM exits almost immediately, by the time the
   2813  * attaching happens the VM could already be shutting down.
   2814  *
   2815  * It's hard to avoid a race condition here because we don't want to hold
   2816  * a lock across the entire operation.  What we can do is temporarily
   2817  * increment the thread count to prevent a VM exit.
   2818  *
   2819  * This could potentially still have problems if a daemon thread calls here
   2820  * while the VM is shutting down.  dvmThreadSelf() will work, since it just
   2821  * uses pthread TLS, but dereferencing "vm" could fail.  Such is life when
   2822  * you shut down a VM while threads are still running inside it.
   2823  *
   2824  * Remember that some code may call this as a way to find the per-thread
   2825  * JNIEnv pointer.  Don't do excess work for that case.
   2826  */
   2827 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
   2828     JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
   2829 
   2830     /*
   2831      * Return immediately if we're already one with the VM.
   2832      */
   2833     Thread* self = dvmThreadSelf();
   2834     if (self != NULL) {
   2835         *p_env = self->jniEnv;
   2836         return JNI_OK;
   2837     }
   2838 
   2839     /*
   2840      * No threads allowed in zygote mode.
   2841      */
   2842     if (gDvm.zygote) {
   2843         return JNI_ERR;
   2844     }
   2845 
   2846     /* increment the count to keep the VM from bailing while we run */
   2847     dvmLockThreadList(NULL);
   2848     if (gDvm.nonDaemonThreadCount == 0) {
   2849         // dead or dying
   2850         LOGV("Refusing to attach thread '%s' -- VM is shutting down",
   2851             (thr_args == NULL) ? "(unknown)" : args->name);
   2852         dvmUnlockThreadList();
   2853         return JNI_ERR;
   2854     }
   2855     gDvm.nonDaemonThreadCount++;
   2856     dvmUnlockThreadList();
   2857 
   2858     /* tweak the JavaVMAttachArgs as needed */
   2859     JavaVMAttachArgs argsCopy;
   2860     if (args == NULL) {
   2861         /* allow the v1.1 calling convention */
   2862         argsCopy.version = JNI_VERSION_1_2;
   2863         argsCopy.name = NULL;
   2864         argsCopy.group = (jobject) dvmGetMainThreadGroup();
   2865     } else {
   2866         assert(args->version >= JNI_VERSION_1_2);
   2867 
   2868         argsCopy.version = args->version;
   2869         argsCopy.name = args->name;
   2870         if (args->group != NULL) {
   2871             argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
   2872         } else {
   2873             argsCopy.group = (jobject) dvmGetMainThreadGroup();
   2874         }
   2875     }
   2876 
   2877     bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
   2878 
   2879     /* restore the count */
   2880     dvmLockThreadList(NULL);
   2881     gDvm.nonDaemonThreadCount--;
   2882     dvmUnlockThreadList();
   2883 
   2884     /*
   2885      * Change the status to indicate that we're out in native code.  This
   2886      * call is not guarded with state-change macros, so we have to do it
   2887      * by hand.
   2888      */
   2889     if (result) {
   2890         self = dvmThreadSelf();
   2891         assert(self != NULL);
   2892         dvmChangeStatus(self, THREAD_NATIVE);
   2893         *p_env = self->jniEnv;
   2894         return JNI_OK;
   2895     } else {
   2896         return JNI_ERR;
   2897     }
   2898 }
   2899 
   2900 /*
   2901  * Attach the current thread to the VM.  If the thread is already attached,
   2902  * this is a no-op.
   2903  */
   2904 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
   2905     return attachThread(vm, p_env, thr_args, false);
   2906 }
   2907 
   2908 /*
   2909  * Like AttachCurrentThread, but set the "daemon" flag.
   2910  */
   2911 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
   2912 {
   2913     return attachThread(vm, p_env, thr_args, true);
   2914 }
   2915 
   2916 /*
   2917  * Dissociate the current thread from the VM.
   2918  */
   2919 static jint DetachCurrentThread(JavaVM* vm) {
   2920     Thread* self = dvmThreadSelf();
   2921     if (self == NULL) {
   2922         /* not attached, can't do anything */
   2923         return JNI_ERR;
   2924     }
   2925 
   2926     /* switch to "running" to check for suspension */
   2927     dvmChangeStatus(self, THREAD_RUNNING);
   2928 
   2929     /* detach the thread */
   2930     dvmDetachCurrentThread();
   2931 
   2932     /* (no need to change status back -- we have no status) */
   2933     return JNI_OK;
   2934 }
   2935 
   2936 /*
   2937  * If current thread is attached to VM, return the associated JNIEnv.
   2938  * Otherwise, stuff NULL in and return JNI_EDETACHED.
   2939  *
   2940  * JVMTI overloads this by specifying a magic value for "version", so we
   2941  * do want to check that here.
   2942  */
   2943 static jint GetEnv(JavaVM* vm, void** env, jint version) {
   2944     Thread* self = dvmThreadSelf();
   2945 
   2946     if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
   2947         return JNI_EVERSION;
   2948     }
   2949 
   2950     if (self == NULL) {
   2951         *env = NULL;
   2952     } else {
   2953         /* TODO: status change is probably unnecessary */
   2954         dvmChangeStatus(self, THREAD_RUNNING);
   2955         *env = (void*) dvmGetThreadJNIEnv(self);
   2956         dvmChangeStatus(self, THREAD_NATIVE);
   2957     }
   2958     return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
   2959 }
   2960 
   2961 /*
   2962  * Destroy the VM.  This may be called from any thread.
   2963  *
   2964  * If the current thread is attached, wait until the current thread is
   2965  * the only non-daemon user-level thread.  If the current thread is not
   2966  * attached, we attach it and do the processing as usual.  (If the attach
   2967  * fails, it's probably because all the non-daemon threads have already
   2968  * exited and the VM doesn't want to let us back in.)
   2969  *
   2970  * TODO: we don't really deal with the situation where more than one thread
   2971  * has called here.  One thread wins, the other stays trapped waiting on
   2972  * the condition variable forever.  Not sure this situation is interesting
   2973  * in real life.
   2974  */
   2975 static jint DestroyJavaVM(JavaVM* vm) {
   2976     JavaVMExt* ext = (JavaVMExt*) vm;
   2977     if (ext == NULL) {
   2978         return JNI_ERR;
   2979     }
   2980 
   2981     if (gDvm.verboseShutdown) {
   2982         LOGD("DestroyJavaVM waiting for non-daemon threads to exit");
   2983     }
   2984 
   2985     /*
   2986      * Sleep on a condition variable until it's okay to exit.
   2987      */
   2988     Thread* self = dvmThreadSelf();
   2989     if (self == NULL) {
   2990         JNIEnv* tmpEnv;
   2991         if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
   2992             LOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
   2993                 gDvm.nonDaemonThreadCount);
   2994             goto shutdown;
   2995         } else {
   2996             LOGV("Attached to wait for shutdown in Destroy");
   2997         }
   2998     }
   2999     dvmChangeStatus(self, THREAD_VMWAIT);
   3000 
   3001     dvmLockThreadList(self);
   3002     gDvm.nonDaemonThreadCount--;    // remove current thread from count
   3003 
   3004     while (gDvm.nonDaemonThreadCount > 0) {
   3005         pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
   3006     }
   3007 
   3008     dvmUnlockThreadList();
   3009     self = NULL;
   3010 
   3011 shutdown:
   3012     // TODO: call System.exit() to run any registered shutdown hooks
   3013     // (this may not return -- figure out how this should work)
   3014 
   3015     if (gDvm.verboseShutdown) {
   3016         LOGD("DestroyJavaVM shutting VM down");
   3017     }
   3018     dvmShutdown();
   3019 
   3020     // TODO - free resources associated with JNI-attached daemon threads
   3021     free(ext->envList);
   3022     free(ext);
   3023 
   3024     return JNI_OK;
   3025 }
   3026 
   3027 
   3028 /*
   3029  * ===========================================================================
   3030  *      Function tables
   3031  * ===========================================================================
   3032  */
   3033 
   3034 static const struct JNINativeInterface gNativeInterface = {
   3035     NULL,
   3036     NULL,
   3037     NULL,
   3038     NULL,
   3039 
   3040     GetVersion,
   3041 
   3042     DefineClass,
   3043     FindClass,
   3044 
   3045     FromReflectedMethod,
   3046     FromReflectedField,
   3047     ToReflectedMethod,
   3048 
   3049     GetSuperclass,
   3050     IsAssignableFrom,
   3051 
   3052     ToReflectedField,
   3053 
   3054     Throw,
   3055     ThrowNew,
   3056     ExceptionOccurred,
   3057     ExceptionDescribe,
   3058     ExceptionClear,
   3059     FatalError,
   3060 
   3061     PushLocalFrame,
   3062     PopLocalFrame,
   3063 
   3064     NewGlobalRef,
   3065     DeleteGlobalRef,
   3066     DeleteLocalRef,
   3067     IsSameObject,
   3068     NewLocalRef,
   3069     EnsureLocalCapacity,
   3070 
   3071     AllocObject,
   3072     NewObject,
   3073     NewObjectV,
   3074     NewObjectA,
   3075 
   3076     GetObjectClass,
   3077     IsInstanceOf,
   3078 
   3079     GetMethodID,
   3080 
   3081     CallObjectMethod,
   3082     CallObjectMethodV,
   3083     CallObjectMethodA,
   3084     CallBooleanMethod,
   3085     CallBooleanMethodV,
   3086     CallBooleanMethodA,
   3087     CallByteMethod,
   3088     CallByteMethodV,
   3089     CallByteMethodA,
   3090     CallCharMethod,
   3091     CallCharMethodV,
   3092     CallCharMethodA,
   3093     CallShortMethod,
   3094     CallShortMethodV,
   3095     CallShortMethodA,
   3096     CallIntMethod,
   3097     CallIntMethodV,
   3098     CallIntMethodA,
   3099     CallLongMethod,
   3100     CallLongMethodV,
   3101     CallLongMethodA,
   3102     CallFloatMethod,
   3103     CallFloatMethodV,
   3104     CallFloatMethodA,
   3105     CallDoubleMethod,
   3106     CallDoubleMethodV,
   3107     CallDoubleMethodA,
   3108     CallVoidMethod,
   3109     CallVoidMethodV,
   3110     CallVoidMethodA,
   3111 
   3112     CallNonvirtualObjectMethod,
   3113     CallNonvirtualObjectMethodV,
   3114     CallNonvirtualObjectMethodA,
   3115     CallNonvirtualBooleanMethod,
   3116     CallNonvirtualBooleanMethodV,
   3117     CallNonvirtualBooleanMethodA,
   3118     CallNonvirtualByteMethod,
   3119     CallNonvirtualByteMethodV,
   3120     CallNonvirtualByteMethodA,
   3121     CallNonvirtualCharMethod,
   3122     CallNonvirtualCharMethodV,
   3123     CallNonvirtualCharMethodA,
   3124     CallNonvirtualShortMethod,
   3125     CallNonvirtualShortMethodV,
   3126     CallNonvirtualShortMethodA,
   3127     CallNonvirtualIntMethod,
   3128     CallNonvirtualIntMethodV,
   3129     CallNonvirtualIntMethodA,
   3130     CallNonvirtualLongMethod,
   3131     CallNonvirtualLongMethodV,
   3132     CallNonvirtualLongMethodA,
   3133     CallNonvirtualFloatMethod,
   3134     CallNonvirtualFloatMethodV,
   3135     CallNonvirtualFloatMethodA,
   3136     CallNonvirtualDoubleMethod,
   3137     CallNonvirtualDoubleMethodV,
   3138     CallNonvirtualDoubleMethodA,
   3139     CallNonvirtualVoidMethod,
   3140     CallNonvirtualVoidMethodV,
   3141     CallNonvirtualVoidMethodA,
   3142 
   3143     GetFieldID,
   3144 
   3145     GetObjectField,
   3146     GetBooleanField,
   3147     GetByteField,
   3148     GetCharField,
   3149     GetShortField,
   3150     GetIntField,
   3151     GetLongField,
   3152     GetFloatField,
   3153     GetDoubleField,
   3154     SetObjectField,
   3155     SetBooleanField,
   3156     SetByteField,
   3157     SetCharField,
   3158     SetShortField,
   3159     SetIntField,
   3160     SetLongField,
   3161     SetFloatField,
   3162     SetDoubleField,
   3163 
   3164     GetStaticMethodID,
   3165 
   3166     CallStaticObjectMethod,
   3167     CallStaticObjectMethodV,
   3168     CallStaticObjectMethodA,
   3169     CallStaticBooleanMethod,
   3170     CallStaticBooleanMethodV,
   3171     CallStaticBooleanMethodA,
   3172     CallStaticByteMethod,
   3173     CallStaticByteMethodV,
   3174     CallStaticByteMethodA,
   3175     CallStaticCharMethod,
   3176     CallStaticCharMethodV,
   3177     CallStaticCharMethodA,
   3178     CallStaticShortMethod,
   3179     CallStaticShortMethodV,
   3180     CallStaticShortMethodA,
   3181     CallStaticIntMethod,
   3182     CallStaticIntMethodV,
   3183     CallStaticIntMethodA,
   3184     CallStaticLongMethod,
   3185     CallStaticLongMethodV,
   3186     CallStaticLongMethodA,
   3187     CallStaticFloatMethod,
   3188     CallStaticFloatMethodV,
   3189     CallStaticFloatMethodA,
   3190     CallStaticDoubleMethod,
   3191     CallStaticDoubleMethodV,
   3192     CallStaticDoubleMethodA,
   3193     CallStaticVoidMethod,
   3194     CallStaticVoidMethodV,
   3195     CallStaticVoidMethodA,
   3196 
   3197     GetStaticFieldID,
   3198 
   3199     GetStaticObjectField,
   3200     GetStaticBooleanField,
   3201     GetStaticByteField,
   3202     GetStaticCharField,
   3203     GetStaticShortField,
   3204     GetStaticIntField,
   3205     GetStaticLongField,
   3206     GetStaticFloatField,
   3207     GetStaticDoubleField,
   3208 
   3209     SetStaticObjectField,
   3210     SetStaticBooleanField,
   3211     SetStaticByteField,
   3212     SetStaticCharField,
   3213     SetStaticShortField,
   3214     SetStaticIntField,
   3215     SetStaticLongField,
   3216     SetStaticFloatField,
   3217     SetStaticDoubleField,
   3218 
   3219     NewString,
   3220 
   3221     GetStringLength,
   3222     GetStringChars,
   3223     ReleaseStringChars,
   3224 
   3225     NewStringUTF,
   3226     GetStringUTFLength,
   3227     GetStringUTFChars,
   3228     ReleaseStringUTFChars,
   3229 
   3230     GetArrayLength,
   3231     NewObjectArray,
   3232     GetObjectArrayElement,
   3233     SetObjectArrayElement,
   3234 
   3235     NewBooleanArray,
   3236     NewByteArray,
   3237     NewCharArray,
   3238     NewShortArray,
   3239     NewIntArray,
   3240     NewLongArray,
   3241     NewFloatArray,
   3242     NewDoubleArray,
   3243 
   3244     GetBooleanArrayElements,
   3245     GetByteArrayElements,
   3246     GetCharArrayElements,
   3247     GetShortArrayElements,
   3248     GetIntArrayElements,
   3249     GetLongArrayElements,
   3250     GetFloatArrayElements,
   3251     GetDoubleArrayElements,
   3252 
   3253     ReleaseBooleanArrayElements,
   3254     ReleaseByteArrayElements,
   3255     ReleaseCharArrayElements,
   3256     ReleaseShortArrayElements,
   3257     ReleaseIntArrayElements,
   3258     ReleaseLongArrayElements,
   3259     ReleaseFloatArrayElements,
   3260     ReleaseDoubleArrayElements,
   3261 
   3262     GetBooleanArrayRegion,
   3263     GetByteArrayRegion,
   3264     GetCharArrayRegion,
   3265     GetShortArrayRegion,
   3266     GetIntArrayRegion,
   3267     GetLongArrayRegion,
   3268     GetFloatArrayRegion,
   3269     GetDoubleArrayRegion,
   3270     SetBooleanArrayRegion,
   3271     SetByteArrayRegion,
   3272     SetCharArrayRegion,
   3273     SetShortArrayRegion,
   3274     SetIntArrayRegion,
   3275     SetLongArrayRegion,
   3276     SetFloatArrayRegion,
   3277     SetDoubleArrayRegion,
   3278 
   3279     RegisterNatives,
   3280     UnregisterNatives,
   3281 
   3282     MonitorEnter,
   3283     MonitorExit,
   3284 
   3285     GetJavaVM,
   3286 
   3287     GetStringRegion,
   3288     GetStringUTFRegion,
   3289 
   3290     GetPrimitiveArrayCritical,
   3291     ReleasePrimitiveArrayCritical,
   3292 
   3293     GetStringCritical,
   3294     ReleaseStringCritical,
   3295 
   3296     NewWeakGlobalRef,
   3297     DeleteWeakGlobalRef,
   3298 
   3299     ExceptionCheck,
   3300 
   3301     NewDirectByteBuffer,
   3302     GetDirectBufferAddress,
   3303     GetDirectBufferCapacity,
   3304 
   3305     GetObjectRefType
   3306 };
   3307 
   3308 static const struct JNIInvokeInterface gInvokeInterface = {
   3309     NULL,
   3310     NULL,
   3311     NULL,
   3312 
   3313     DestroyJavaVM,
   3314     AttachCurrentThread,
   3315     DetachCurrentThread,
   3316 
   3317     GetEnv,
   3318 
   3319     AttachCurrentThreadAsDaemon,
   3320 };
   3321 
   3322 /*
   3323  * ===========================================================================
   3324  *      VM/Env creation
   3325  * ===========================================================================
   3326  */
   3327 
   3328 /*
   3329  * Create a new JNIEnv struct and add it to the VM's list.
   3330  *
   3331  * "self" will be NULL for the main thread, since the VM hasn't started
   3332  * yet; the value will be filled in later.
   3333  */
   3334 JNIEnv* dvmCreateJNIEnv(Thread* self) {
   3335     JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
   3336 
   3337     //if (self != NULL)
   3338     //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
   3339 
   3340     assert(vm != NULL);
   3341 
   3342     JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
   3343     newEnv->funcTable = &gNativeInterface;
   3344     if (self != NULL) {
   3345         dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
   3346         assert(newEnv->envThreadId != 0);
   3347     } else {
   3348         /* make it obvious if we fail to initialize these later */
   3349         newEnv->envThreadId = 0x77777775;
   3350         newEnv->self = (Thread*) 0x77777779;
   3351     }
   3352     if (gDvmJni.useCheckJni) {
   3353         dvmUseCheckedJniEnv(newEnv);
   3354     }
   3355 
   3356     ScopedPthreadMutexLock lock(&vm->envListLock);
   3357 
   3358     /* insert at head of list */
   3359     newEnv->next = vm->envList;
   3360     assert(newEnv->prev == NULL);
   3361     if (vm->envList == NULL) {
   3362         // rare, but possible
   3363         vm->envList = newEnv;
   3364     } else {
   3365         vm->envList->prev = newEnv;
   3366     }
   3367     vm->envList = newEnv;
   3368 
   3369     //if (self != NULL)
   3370     //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
   3371     return (JNIEnv*) newEnv;
   3372 }
   3373 
   3374 /*
   3375  * Remove a JNIEnv struct from the list and free it.
   3376  */
   3377 void dvmDestroyJNIEnv(JNIEnv* env) {
   3378     if (env == NULL) {
   3379         return;
   3380     }
   3381 
   3382     //LOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
   3383 
   3384     JNIEnvExt* extEnv = (JNIEnvExt*) env;
   3385     JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
   3386 
   3387     ScopedPthreadMutexLock lock(&vm->envListLock);
   3388 
   3389     if (extEnv == vm->envList) {
   3390         assert(extEnv->prev == NULL);
   3391         vm->envList = extEnv->next;
   3392     } else {
   3393         assert(extEnv->prev != NULL);
   3394         extEnv->prev->next = extEnv->next;
   3395     }
   3396     if (extEnv->next != NULL) {
   3397         extEnv->next->prev = extEnv->prev;
   3398     }
   3399 
   3400     free(env);
   3401     //LOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
   3402 }
   3403 
   3404 /*
   3405  * Enable "checked JNI" after the VM has partially started.  This must
   3406  * only be called in "zygote" mode, when we have one thread running.
   3407  *
   3408  * This doesn't attempt to rewrite the JNI call bridge associated with
   3409  * native methods, so we won't get those checks for any methods that have
   3410  * already been resolved.
   3411  */
   3412 void dvmLateEnableCheckedJni() {
   3413     JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
   3414     if (extEnv == NULL) {
   3415         LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
   3416         return;
   3417     }
   3418     JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
   3419     assert(extVm != NULL);
   3420 
   3421     if (!gDvmJni.useCheckJni) {
   3422         LOGD("Late-enabling CheckJNI");
   3423         dvmUseCheckedJniVm(extVm);
   3424         dvmUseCheckedJniEnv(extEnv);
   3425     } else {
   3426         LOGD("Not late-enabling CheckJNI (already on)");
   3427     }
   3428 }
   3429 
   3430 /*
   3431  * Not supported.
   3432  */
   3433 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
   3434     return JNI_ERR;
   3435 }
   3436 
   3437 /*
   3438  * Return a buffer full of created VMs.
   3439  *
   3440  * We always have zero or one.
   3441  */
   3442 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
   3443     if (gDvmJni.jniVm != NULL) {
   3444         *nVMs = 1;
   3445         if (bufLen > 0) {
   3446             *vmBuf++ = gDvmJni.jniVm;
   3447         }
   3448     } else {
   3449         *nVMs = 0;
   3450     }
   3451     return JNI_OK;
   3452 }
   3453 
   3454 /*
   3455  * Create a new VM instance.
   3456  *
   3457  * The current thread becomes the main VM thread.  We return immediately,
   3458  * which effectively means the caller is executing in a native method.
   3459  */
   3460 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
   3461     const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
   3462     if (args->version < JNI_VERSION_1_2) {
   3463         return JNI_EVERSION;
   3464     }
   3465 
   3466     // TODO: don't allow creation of multiple VMs -- one per customer for now
   3467 
   3468     /* zero globals; not strictly necessary the first time a VM is started */
   3469     memset(&gDvm, 0, sizeof(gDvm));
   3470 
   3471     /*
   3472      * Set up structures for JNIEnv and VM.
   3473      */
   3474     JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
   3475     memset(pVM, 0, sizeof(JavaVMExt));
   3476     pVM->funcTable = &gInvokeInterface;
   3477     pVM->envList = NULL;
   3478     dvmInitMutex(&pVM->envListLock);
   3479 
   3480     UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
   3481     memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
   3482 
   3483     /*
   3484      * Convert JNI args to argv.
   3485      *
   3486      * We have to pull out vfprintf/exit/abort, because they use the
   3487      * "extraInfo" field to pass function pointer "hooks" in.  We also
   3488      * look for the -Xcheck:jni stuff here.
   3489      */
   3490     int argc = 0;
   3491     for (int i = 0; i < args->nOptions; i++) {
   3492         const char* optStr = args->options[i].optionString;
   3493         if (optStr == NULL) {
   3494             dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
   3495             return JNI_ERR;
   3496         } else if (strcmp(optStr, "vfprintf") == 0) {
   3497             gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
   3498         } else if (strcmp(optStr, "exit") == 0) {
   3499             gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
   3500         } else if (strcmp(optStr, "abort") == 0) {
   3501             gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
   3502         } else if (strcmp(optStr, "sensitiveThread") == 0) {
   3503             gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
   3504         } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
   3505             gDvmJni.useCheckJni = true;
   3506         } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
   3507             char* jniOpts = strdup(optStr + 10);
   3508             size_t jniOptCount = 1;
   3509             for (char* p = jniOpts; *p != 0; ++p) {
   3510                 if (*p == ',') {
   3511                     ++jniOptCount;
   3512                     *p = 0;
   3513                 }
   3514             }
   3515             char* jniOpt = jniOpts;
   3516             for (size_t i = 0; i < jniOptCount; ++i) {
   3517                 if (strcmp(jniOpt, "warnonly") == 0) {
   3518                     gDvmJni.warnOnly = true;
   3519                 } else if (strcmp(jniOpt, "forcecopy") == 0) {
   3520                     gDvmJni.forceCopy = true;
   3521                 } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
   3522                     gDvmJni.logThirdPartyJni = true;
   3523                 } else {
   3524                     dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
   3525                             jniOpt);
   3526                     return JNI_ERR;
   3527                 }
   3528                 jniOpt += strlen(jniOpt) + 1;
   3529             }
   3530             free(jniOpts);
   3531         } else {
   3532             /* regular option */
   3533             argv[argc++] = optStr;
   3534         }
   3535     }
   3536 
   3537     if (gDvmJni.useCheckJni) {
   3538         dvmUseCheckedJniVm(pVM);
   3539     }
   3540 
   3541     if (gDvmJni.jniVm != NULL) {
   3542         dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
   3543         return JNI_ERR;
   3544     }
   3545     gDvmJni.jniVm = (JavaVM*) pVM;
   3546 
   3547     /*
   3548      * Create a JNIEnv for the main thread.  We need to have something set up
   3549      * here because some of the class initialization we do when starting
   3550      * up the VM will call into native code.
   3551      */
   3552     JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
   3553 
   3554     /* Initialize VM. */
   3555     gDvm.initializing = true;
   3556     std::string status =
   3557             dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
   3558     gDvm.initializing = false;
   3559 
   3560     if (!status.empty()) {
   3561         free(pEnv);
   3562         free(pVM);
   3563         LOGW("CreateJavaVM failed: %s", status.c_str());
   3564         return JNI_ERR;
   3565     }
   3566 
   3567     /*
   3568      * Success!  Return stuff to caller.
   3569      */
   3570     dvmChangeStatus(NULL, THREAD_NATIVE);
   3571     *p_env = (JNIEnv*) pEnv;
   3572     *p_vm = (JavaVM*) pVM;
   3573     LOGV("CreateJavaVM succeeded");
   3574     return JNI_OK;
   3575 }
   3576