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