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