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