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