Jni.cpp revision 259a8a5154c63a793ea0ee438d146acda7d990b6
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, dvmIsValidObject((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        LOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
753    }
754
755    Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
756    if (method == NULL) {
757        method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
758    }
759    if (method == NULL) {
760        dumpCandidateMethods(clazz, methodName, signature);
761        return false;
762    }
763
764    if (!dvmIsNativeMethod(method)) {
765        LOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
766        return false;
767    }
768
769    if (fastJni) {
770        // In this case, we have extra constraints to check...
771        if (dvmIsSynchronizedMethod(method)) {
772            // Synchronization is usually provided by the JNI bridge,
773            // but we won't have one.
774            LOGE("fast JNI method %s.%s:%s cannot be synchronized",
775                    clazz->descriptor, methodName, signature);
776            return false;
777        }
778        if (!dvmIsStaticMethod(method)) {
779            // There's no real reason for this constraint, but since we won't
780            // be supplying a JNIEnv* or a jobject 'this', you're effectively
781            // static anyway, so it seems clearer to say so.
782            LOGE("fast JNI method %s.%s:%s cannot be non-static",
783                    clazz->descriptor, methodName, signature);
784            return false;
785        }
786    }
787
788    if (method->nativeFunc != dvmResolveNativeMethod) {
789        /* this is allowed, but unusual */
790        LOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
791    }
792
793    method->fastJni = fastJni;
794    dvmUseJNIBridge(method, fnPtr);
795
796    LOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
797    return true;
798}
799
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                    //if (!dvmIsValidObject((Object*) modArgs[idx]))
1168                    //    dvmAbort();
1169                    jobject argObj = addLocalReference(env, (Object*) modArgs[idx]);
1170                    if (argObj == NULL) {
1171                        assert(dvmCheckException(self));
1172                        return;
1173                    }
1174                    modArgs[idx] = (u4) argObj;
1175                }
1176                break;
1177            case 'D':
1178            case 'J':
1179                idx++;
1180                break;
1181            default:
1182                /* Z B C S I -- do nothing */
1183                break;
1184            }
1185            idx++;
1186        }
1187    }
1188
1189    if (method->shouldTrace) {
1190        logNativeMethodEntry(method, args);
1191    }
1192    if (isSynchronized) {
1193        dvmLockObject(self, lockObj);
1194    }
1195
1196    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1197
1198    ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
1199    assert(method->insns != NULL);
1200
1201    COMPUTE_STACK_SUM(self);
1202    dvmPlatformInvoke(method->fastJni ? NULL : env,
1203            (ClassObject*) staticMethodClass,
1204            method->jniArgInfo, method->insSize, modArgs, method->shorty,
1205            (void*) method->insns, pResult);
1206    CHECK_STACK_SUM(self);
1207
1208    dvmChangeStatus(self, oldStatus);
1209
1210    convertReferenceResult(env, pResult, method, self);
1211
1212    if (isSynchronized) {
1213        dvmUnlockObject(self, lockObj);
1214    }
1215    if (method->shouldTrace) {
1216        logNativeMethodExit(method, self, *pResult);
1217    }
1218}
1219
1220/*
1221 * Extract the return type enum from the "jniArgInfo" field.
1222 */
1223DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo) {
1224    return static_cast<DalvikJniReturnType>((jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT);
1225}
1226
1227/*
1228 * ===========================================================================
1229 *      JNI implementation
1230 * ===========================================================================
1231 */
1232
1233/*
1234 * Return the version of the native method interface.
1235 */
1236static jint GetVersion(JNIEnv* env) {
1237    /*
1238     * There is absolutely no need to toggle the mode for correct behavior.
1239     * However, it does provide native code with a simple "suspend self
1240     * if necessary" call.
1241     */
1242    ScopedJniThreadState ts(env);
1243    return JNI_VERSION_1_6;
1244}
1245
1246/*
1247 * Create a new class from a bag of bytes.
1248 *
1249 * This is not currently supported within Dalvik.
1250 */
1251static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1252    const jbyte* buf, jsize bufLen)
1253{
1254    UNUSED_PARAMETER(name);
1255    UNUSED_PARAMETER(loader);
1256    UNUSED_PARAMETER(buf);
1257    UNUSED_PARAMETER(bufLen);
1258
1259    ScopedJniThreadState ts(env);
1260    LOGW("JNI DefineClass is not supported");
1261    return NULL;
1262}
1263
1264/*
1265 * Find a class by name.
1266 *
1267 * We have to use the "no init" version of FindClass here, because we might
1268 * be getting the class prior to registering native methods that will be
1269 * used in <clinit>.
1270 *
1271 * We need to get the class loader associated with the current native
1272 * method.  If there is no native method, e.g. we're calling this from native
1273 * code right after creating the VM, the spec says we need to use the class
1274 * loader returned by "ClassLoader.getBaseClassLoader".  There is no such
1275 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1276 * We can't get that until after the VM has initialized though.
1277 */
1278static jclass FindClass(JNIEnv* env, const char* name) {
1279    ScopedJniThreadState ts(env);
1280
1281    const Method* thisMethod = dvmGetCurrentJNIMethod();
1282    assert(thisMethod != NULL);
1283
1284    Object* loader;
1285    Object* trackedLoader = NULL;
1286    if (ts.self()->classLoaderOverride != NULL) {
1287        /* hack for JNI_OnLoad */
1288        assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1289        loader = ts.self()->classLoaderOverride;
1290    } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
1291               thisMethod == gDvm.methDalvikSystemNativeStart_run) {
1292        /* start point of invocation interface */
1293        if (!gDvm.initializing) {
1294            loader = trackedLoader = dvmGetSystemClassLoader();
1295        } else {
1296            loader = NULL;
1297        }
1298    } else {
1299        loader = thisMethod->clazz->classLoader;
1300    }
1301
1302    char* descriptor = dvmNameToDescriptor(name);
1303    if (descriptor == NULL) {
1304        return NULL;
1305    }
1306    ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
1307    free(descriptor);
1308
1309    jclass jclazz = (jclass) addLocalReference(env, (Object*) clazz);
1310    dvmReleaseTrackedAlloc(trackedLoader, ts.self());
1311    return jclazz;
1312}
1313
1314/*
1315 * Return the superclass of a class.
1316 */
1317static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
1318    ScopedJniThreadState ts(env);
1319    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1320    return (jclass) addLocalReference(env, (Object*)clazz->super);
1321}
1322
1323/*
1324 * Determine whether an object of clazz1 can be safely cast to clazz2.
1325 *
1326 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1327 */
1328static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
1329    ScopedJniThreadState ts(env);
1330    ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1);
1331    ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2);
1332    return dvmInstanceof(clazz1, clazz2);
1333}
1334
1335/*
1336 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1337 */
1338static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
1339    ScopedJniThreadState ts(env);
1340    Object* method = dvmDecodeIndirectRef(env, jmethod);
1341    return (jmethodID) dvmGetMethodFromReflectObj(method);
1342}
1343
1344/*
1345 * Given a java.lang.reflect.Field, return a fieldID.
1346 */
1347static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
1348    ScopedJniThreadState ts(env);
1349    Object* field = dvmDecodeIndirectRef(env, jfield);
1350    return (jfieldID) dvmGetFieldFromReflectObj(field);
1351}
1352
1353/*
1354 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1355 *
1356 * (The "isStatic" field does not appear in the spec.)
1357 *
1358 * Throws OutOfMemory and returns NULL on failure.
1359 */
1360static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
1361    ScopedJniThreadState ts(env);
1362    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
1363    Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1364    dvmReleaseTrackedAlloc(obj, NULL);
1365    return addLocalReference(env, obj);
1366}
1367
1368/*
1369 * Convert a fieldID to a java.lang.reflect.Field.
1370 *
1371 * (The "isStatic" field does not appear in the spec.)
1372 *
1373 * Throws OutOfMemory and returns NULL on failure.
1374 */
1375static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
1376    ScopedJniThreadState ts(env);
1377    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
1378    Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
1379    dvmReleaseTrackedAlloc(obj, NULL);
1380    return addLocalReference(env, obj);
1381}
1382
1383/*
1384 * Take this exception and throw it.
1385 */
1386static jint Throw(JNIEnv* env, jthrowable jobj) {
1387    ScopedJniThreadState ts(env);
1388    if (jobj != NULL) {
1389        Object* obj = dvmDecodeIndirectRef(env, jobj);
1390        dvmSetException(ts.self(), obj);
1391        return JNI_OK;
1392    }
1393    return JNI_ERR;
1394}
1395
1396/*
1397 * Constructs an exception object from the specified class with the message
1398 * specified by "message", and throws it.
1399 */
1400static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
1401    ScopedJniThreadState ts(env);
1402    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1403    dvmThrowException(clazz, message);
1404    // TODO: should return failure if this didn't work (e.g. OOM)
1405    return JNI_OK;
1406}
1407
1408/*
1409 * If an exception is being thrown, return the exception object.  Otherwise,
1410 * return NULL.
1411 *
1412 * TODO: if there is no pending exception, we should be able to skip the
1413 * enter/exit checks.  If we find one, we need to enter and then re-fetch
1414 * the exception (in case it got moved by a compacting GC).
1415 */
1416static jthrowable ExceptionOccurred(JNIEnv* env) {
1417    ScopedJniThreadState ts(env);
1418    Object* exception = dvmGetException(ts.self());
1419    jthrowable localException = (jthrowable) addLocalReference(env, exception);
1420    if (localException == NULL && exception != NULL) {
1421        /*
1422         * We were unable to add a new local reference, and threw a new
1423         * exception.  We can't return "exception", because it's not a
1424         * local reference.  So we have to return NULL, indicating that
1425         * there was no exception, even though it's pretty much raining
1426         * exceptions in here.
1427         */
1428        LOGW("JNI WARNING: addLocal/exception combo");
1429    }
1430    return localException;
1431}
1432
1433/*
1434 * Print an exception and stack trace to stderr.
1435 */
1436static void ExceptionDescribe(JNIEnv* env) {
1437    ScopedJniThreadState ts(env);
1438    Object* exception = dvmGetException(ts.self());
1439    if (exception != NULL) {
1440        dvmPrintExceptionStackTrace();
1441    } else {
1442        LOGI("Odd: ExceptionDescribe called, but no exception pending");
1443    }
1444}
1445
1446/*
1447 * Clear the exception currently being thrown.
1448 *
1449 * TODO: we should be able to skip the enter/exit stuff.
1450 */
1451static void ExceptionClear(JNIEnv* env) {
1452    ScopedJniThreadState ts(env);
1453    dvmClearException(ts.self());
1454}
1455
1456/*
1457 * Kill the VM.  This function does not return.
1458 */
1459static void FatalError(JNIEnv* env, const char* msg) {
1460    //dvmChangeStatus(NULL, THREAD_RUNNING);
1461    LOGE("JNI posting fatal error: %s", msg);
1462    dvmAbort();
1463}
1464
1465/*
1466 * Push a new JNI frame on the stack, with a new set of locals.
1467 *
1468 * The new frame must have the same method pointer.  (If for no other
1469 * reason than FindClass needs it to get the appropriate class loader.)
1470 */
1471static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1472    ScopedJniThreadState ts(env);
1473    if (!ensureLocalCapacity(env, capacity) ||
1474            !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
1475    {
1476        /* yes, OutOfMemoryError, not StackOverflowError */
1477        dvmClearException(ts.self());
1478        dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
1479        return JNI_ERR;
1480    }
1481    return JNI_OK;
1482}
1483
1484/*
1485 * Pop the local frame off.  If "jresult" is not null, add it as a
1486 * local reference on the now-current frame.
1487 */
1488static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
1489    ScopedJniThreadState ts(env);
1490    Object* result = dvmDecodeIndirectRef(env, jresult);
1491    if (!dvmPopLocalFrame(ts.self())) {
1492        LOGW("JNI WARNING: too many PopLocalFrame calls");
1493        dvmClearException(ts.self());
1494        dvmThrowRuntimeException("too many PopLocalFrame calls");
1495    }
1496    return addLocalReference(env, result);
1497}
1498
1499/*
1500 * Add a reference to the global list.
1501 */
1502static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
1503    ScopedJniThreadState ts(env);
1504    Object* obj = dvmDecodeIndirectRef(env, jobj);
1505    return addGlobalReference(obj);
1506}
1507
1508/*
1509 * Delete a reference from the global list.
1510 */
1511static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
1512    ScopedJniThreadState ts(env);
1513    deleteGlobalReference(jglobalRef);
1514}
1515
1516
1517/*
1518 * Add a reference to the local list.
1519 */
1520static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
1521    ScopedJniThreadState ts(env);
1522    Object* obj = dvmDecodeIndirectRef(env, jobj);
1523    return addLocalReference(env, obj);
1524}
1525
1526/*
1527 * Delete a reference from the local list.
1528 */
1529static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
1530    ScopedJniThreadState ts(env);
1531    deleteLocalReference(env, jlocalRef);
1532}
1533
1534/*
1535 * Ensure that the local references table can hold at least this many
1536 * references.
1537 */
1538static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
1539    ScopedJniThreadState ts(env);
1540    bool okay = ensureLocalCapacity(env, capacity);
1541    if (!okay) {
1542        dvmThrowOutOfMemoryError("can't ensure local reference capacity");
1543    }
1544    return okay ? 0 : -1;
1545}
1546
1547
1548/*
1549 * Determine whether two Object references refer to the same underlying object.
1550 */
1551static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
1552    ScopedJniThreadState ts(env);
1553    Object* obj1 = dvmDecodeIndirectRef(env, jref1);
1554    Object* obj2 = dvmDecodeIndirectRef(env, jref2);
1555    return (obj1 == obj2);
1556}
1557
1558/*
1559 * Allocate a new object without invoking any constructors.
1560 */
1561static jobject AllocObject(JNIEnv* env, jclass jclazz) {
1562    ScopedJniThreadState ts(env);
1563
1564    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1565    if (!canAllocClass(clazz) ||
1566        (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
1567    {
1568        assert(dvmCheckException(ts.self()));
1569        return NULL;
1570    }
1571
1572    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1573    return addLocalReference(env, newObj);
1574}
1575
1576/*
1577 * Allocate a new object and invoke the supplied constructor.
1578 */
1579static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
1580    ScopedJniThreadState ts(env);
1581    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1582
1583    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1584        assert(dvmCheckException(ts.self()));
1585        return NULL;
1586    }
1587
1588    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1589    jobject result = addLocalReference(env, newObj);
1590    if (newObj != NULL) {
1591        JValue unused;
1592        va_list args;
1593        va_start(args, methodID);
1594        dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1595        va_end(args);
1596    }
1597    return result;
1598}
1599
1600static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
1601    ScopedJniThreadState ts(env);
1602    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1603
1604    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1605        assert(dvmCheckException(ts.self()));
1606        return NULL;
1607    }
1608
1609    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1610    jobject result = addLocalReference(env, newObj);
1611    if (newObj != NULL) {
1612        JValue unused;
1613        dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1614    }
1615    return result;
1616}
1617
1618static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
1619    ScopedJniThreadState ts(env);
1620    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1621
1622    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1623        assert(dvmCheckException(ts.self()));
1624        return NULL;
1625    }
1626
1627    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1628    jobject result = addLocalReference(env, newObj);
1629    if (newObj != NULL) {
1630        JValue unused;
1631        dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1632    }
1633    return result;
1634}
1635
1636/*
1637 * Returns the class of an object.
1638 *
1639 * JNI spec says: obj must not be NULL.
1640 */
1641static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
1642    ScopedJniThreadState ts(env);
1643
1644    assert(jobj != NULL);
1645
1646    Object* obj = dvmDecodeIndirectRef(env, jobj);
1647    return (jclass) addLocalReference(env, (Object*) obj->clazz);
1648}
1649
1650/*
1651 * Determine whether "obj" is an instance of "clazz".
1652 */
1653static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
1654    ScopedJniThreadState ts(env);
1655
1656    assert(jclazz != NULL);
1657    if (jobj == NULL) {
1658        return true;
1659    }
1660
1661    Object* obj = dvmDecodeIndirectRef(env, jobj);
1662    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1663    return dvmInstanceof(obj->clazz, clazz);
1664}
1665
1666/*
1667 * Get a method ID for an instance method.
1668 *
1669 * While Dalvik bytecode has distinct instructions for virtual, super,
1670 * static, direct, and interface method invocation, JNI only provides
1671 * two functions for acquiring a method ID.  This call handles everything
1672 * but static methods.
1673 *
1674 * JNI defines <init> as an instance method, but Dalvik considers it a
1675 * "direct" method, so we have to special-case it here.
1676 *
1677 * Dalvik also puts all private methods into the "direct" list, so we
1678 * really need to just search both lists.
1679 */
1680static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1681    ScopedJniThreadState ts(env);
1682
1683    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1684    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1685        assert(dvmCheckException(ts.self()));
1686    } else if (dvmIsInterfaceClass(clazz)) {
1687        Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
1688        if (meth == NULL) {
1689            dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1690                "no method with name='%s' signature='%s' in interface %s",
1691                name, sig, clazz->descriptor);
1692        }
1693        return (jmethodID) meth;
1694    }
1695    Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1696    if (meth == NULL) {
1697        /* search private methods and constructors; non-hierarchical */
1698        meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1699    }
1700    if (meth != NULL && dvmIsStaticMethod(meth)) {
1701        IF_LOGD() {
1702            char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1703            LOGD("GetMethodID: not returning static method %s.%s %s",
1704                    clazz->descriptor, meth->name, desc);
1705            free(desc);
1706        }
1707        meth = NULL;
1708    }
1709    if (meth == NULL) {
1710        dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1711                "no method with name='%s' signature='%s' in class %s",
1712                name, sig, clazz->descriptor);
1713    } else {
1714        /*
1715         * The method's class may not be the same as clazz, but if
1716         * it isn't this must be a virtual method and the class must
1717         * be a superclass (and, hence, already initialized).
1718         */
1719        assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
1720    }
1721    return (jmethodID) meth;
1722}
1723
1724/*
1725 * Get a field ID (instance fields).
1726 */
1727static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1728    ScopedJniThreadState ts(env);
1729
1730    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1731
1732    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1733        assert(dvmCheckException(ts.self()));
1734        return NULL;
1735    }
1736
1737    jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1738    if (id == NULL) {
1739        dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1740                "no field with name='%s' signature='%s' in class %s",
1741                name, sig, clazz->descriptor);
1742    }
1743    return id;
1744}
1745
1746/*
1747 * Get the method ID for a static method in a class.
1748 */
1749static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1750    ScopedJniThreadState ts(env);
1751
1752    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1753    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1754        assert(dvmCheckException(ts.self()));
1755        return NULL;
1756    }
1757
1758    Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1759
1760    /* make sure it's static, not virtual+private */
1761    if (meth != NULL && !dvmIsStaticMethod(meth)) {
1762        IF_LOGD() {
1763            char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1764            LOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
1765                    clazz->descriptor, meth->name, desc);
1766            free(desc);
1767        }
1768        meth = NULL;
1769    }
1770
1771    jmethodID id = (jmethodID) meth;
1772    if (id == NULL) {
1773        dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1774                "no static method with name='%s' signature='%s' in class %s",
1775                name, sig, clazz->descriptor);
1776    }
1777    return id;
1778}
1779
1780/*
1781 * Get a field ID (static fields).
1782 */
1783static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1784    ScopedJniThreadState ts(env);
1785
1786    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1787    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1788        assert(dvmCheckException(ts.self()));
1789        return NULL;
1790    }
1791
1792    jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
1793    if (id == NULL) {
1794        dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1795                "no static field with name='%s' signature='%s' in class %s",
1796                name, sig, clazz->descriptor);
1797    }
1798    return id;
1799}
1800
1801/*
1802 * Get a static field.
1803 *
1804 * If we get an object reference, add it to the local refs list.
1805 */
1806#define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref)                       \
1807    static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz,      \
1808        jfieldID fieldID)                                                   \
1809    {                                                                       \
1810        UNUSED_PARAMETER(jclazz);                                           \
1811        ScopedJniThreadState ts(env);                                       \
1812        StaticField* sfield = (StaticField*) fieldID;                       \
1813        _ctype value;                                                       \
1814        if (dvmIsVolatileField(sfield)) {                                   \
1815            if (_isref) {   /* only when _ctype==jobject */                 \
1816                Object* obj = dvmGetStaticFieldObjectVolatile(sfield);      \
1817                value = (_ctype)(u4)addLocalReference(env, obj);            \
1818            } else {                                                        \
1819                value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
1820            }                                                               \
1821        } else {                                                            \
1822            if (_isref) {                                                   \
1823                Object* obj = dvmGetStaticFieldObject(sfield);              \
1824                value = (_ctype)(u4)addLocalReference(env, obj);            \
1825            } else {                                                        \
1826                value = (_ctype) dvmGetStaticField##_jname(sfield);         \
1827            }                                                               \
1828        }                                                                   \
1829        return value;                                                       \
1830    }
1831GET_STATIC_TYPE_FIELD(jobject, Object, true);
1832GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1833GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1834GET_STATIC_TYPE_FIELD(jchar, Char, false);
1835GET_STATIC_TYPE_FIELD(jshort, Short, false);
1836GET_STATIC_TYPE_FIELD(jint, Int, false);
1837GET_STATIC_TYPE_FIELD(jlong, Long, false);
1838GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1839GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1840
1841/*
1842 * Set a static field.
1843 */
1844#define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref)              \
1845    static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz,        \
1846        jfieldID fieldID, _ctype value)                                     \
1847    {                                                                       \
1848        UNUSED_PARAMETER(jclazz);                                           \
1849        ScopedJniThreadState ts(env);                                       \
1850        StaticField* sfield = (StaticField*) fieldID;                       \
1851        if (dvmIsVolatileField(sfield)) {                                   \
1852            if (_isref) {   /* only when _ctype==jobject */                 \
1853                Object* valObj =                                            \
1854                    dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
1855                dvmSetStaticFieldObjectVolatile(sfield, valObj);            \
1856            } else {                                                        \
1857                dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
1858            }                                                               \
1859        } else {                                                            \
1860            if (_isref) {                                                   \
1861                Object* valObj =                                            \
1862                    dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
1863                dvmSetStaticFieldObject(sfield, valObj);                    \
1864            } else {                                                        \
1865                dvmSetStaticField##_jname(sfield, (_ctype2)value);          \
1866            }                                                               \
1867        }                                                                   \
1868    }
1869SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
1870SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
1871SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
1872SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
1873SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
1874SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
1875SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
1876SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
1877SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
1878
1879/*
1880 * Get an instance field.
1881 *
1882 * If we get an object reference, add it to the local refs list.
1883 */
1884#define GET_TYPE_FIELD(_ctype, _jname, _isref)                              \
1885    static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj,             \
1886        jfieldID fieldID)                                                   \
1887    {                                                                       \
1888        ScopedJniThreadState ts(env);                                       \
1889        Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
1890        InstField* field = (InstField*) fieldID;                            \
1891        _ctype value;                                                       \
1892        if (dvmIsVolatileField(field)) {                            \
1893            if (_isref) {   /* only when _ctype==jobject */                 \
1894                Object* valObj =                                            \
1895                    dvmGetFieldObjectVolatile(obj, field->byteOffset);      \
1896                value = (_ctype)(u4)addLocalReference(env, valObj);         \
1897            } else {                                                        \
1898                value = (_ctype)                                            \
1899                    dvmGetField##_jname##Volatile(obj, field->byteOffset);  \
1900            }                                                               \
1901        } else {                                                            \
1902            if (_isref) {                                                   \
1903                Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
1904                value = (_ctype)(u4)addLocalReference(env, valObj);         \
1905            } else {                                                        \
1906                value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
1907            }                                                               \
1908        }                                                                   \
1909        return value;                                                       \
1910    }
1911GET_TYPE_FIELD(jobject, Object, true);
1912GET_TYPE_FIELD(jboolean, Boolean, false);
1913GET_TYPE_FIELD(jbyte, Byte, false);
1914GET_TYPE_FIELD(jchar, Char, false);
1915GET_TYPE_FIELD(jshort, Short, false);
1916GET_TYPE_FIELD(jint, Int, false);
1917GET_TYPE_FIELD(jlong, Long, false);
1918GET_TYPE_FIELD(jfloat, Float, false);
1919GET_TYPE_FIELD(jdouble, Double, false);
1920
1921/*
1922 * Set an instance field.
1923 */
1924#define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref)                     \
1925    static void Set##_jname##Field(JNIEnv* env, jobject jobj,               \
1926        jfieldID fieldID, _ctype value)                                     \
1927    {                                                                       \
1928        ScopedJniThreadState ts(env);                                       \
1929        Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
1930        InstField* field = (InstField*) fieldID;                            \
1931        if (dvmIsVolatileField(field)) {                                    \
1932            if (_isref) {   /* only when _ctype==jobject */                 \
1933                Object* valObj =                                            \
1934                    dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
1935                dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj);  \
1936            } else {                                                        \
1937                dvmSetField##_jname##Volatile(obj,                          \
1938                    field->byteOffset, (_ctype2)value);                     \
1939            }                                                               \
1940        } else {                                                            \
1941            if (_isref) {                                                   \
1942                Object* valObj =                                            \
1943                    dvmDecodeIndirectRef(env, (jobject)(u4)value);          \
1944                dvmSetFieldObject(obj, field->byteOffset, valObj);          \
1945            } else {                                                        \
1946                dvmSetField##_jname(obj,                                    \
1947                    field->byteOffset, (_ctype2)value);                     \
1948            }                                                               \
1949        }                                                                   \
1950    }
1951SET_TYPE_FIELD(jobject, Object*, Object, true);
1952SET_TYPE_FIELD(jboolean, bool, Boolean, false);
1953SET_TYPE_FIELD(jbyte, s1, Byte, false);
1954SET_TYPE_FIELD(jchar, u2, Char, false);
1955SET_TYPE_FIELD(jshort, s2, Short, false);
1956SET_TYPE_FIELD(jint, s4, Int, false);
1957SET_TYPE_FIELD(jlong, s8, Long, false);
1958SET_TYPE_FIELD(jfloat, float, Float, false);
1959SET_TYPE_FIELD(jdouble, double, Double, false);
1960
1961/*
1962 * Make a virtual method call.
1963 *
1964 * Three versions (..., va_list, jvalue[]) for each return type.  If we're
1965 * returning an Object, we have to add it to the local references table.
1966 */
1967#define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref)              \
1968    static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj,           \
1969        jmethodID methodID, ...)                                            \
1970    {                                                                       \
1971        ScopedJniThreadState ts(env);                                       \
1972        Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
1973        const Method* meth;                                                 \
1974        va_list args;                                                       \
1975        JValue result;                                                      \
1976        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
1977        if (meth == NULL) {                                                 \
1978            return _retfail;                                                \
1979        }                                                                   \
1980        va_start(args, methodID);                                           \
1981        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
1982        va_end(args);                                                       \
1983        if (_isref && !dvmCheckException(ts.self()))                        \
1984            result.l = (Object*)addLocalReference(env, result.l);           \
1985        return _retok;                                                      \
1986    }                                                                       \
1987    static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj,          \
1988        jmethodID methodID, va_list args)                                   \
1989    {                                                                       \
1990        ScopedJniThreadState ts(env);                                       \
1991        Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
1992        const Method* meth;                                                 \
1993        JValue result;                                                      \
1994        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
1995        if (meth == NULL) {                                                 \
1996            return _retfail;                                                \
1997        }                                                                   \
1998        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
1999        if (_isref && !dvmCheckException(ts.self()))                        \
2000            result.l = (Object*)addLocalReference(env, result.l);           \
2001        return _retok;                                                      \
2002    }                                                                       \
2003    static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj,          \
2004        jmethodID methodID, jvalue* args)                                   \
2005    {                                                                       \
2006        ScopedJniThreadState ts(env);                                       \
2007        Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
2008        const Method* meth;                                                 \
2009        JValue result;                                                      \
2010        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
2011        if (meth == NULL) {                                                 \
2012            return _retfail;                                                \
2013        }                                                                   \
2014        dvmCallMethodA(ts.self(), meth, obj, true, &result, args);          \
2015        if (_isref && !dvmCheckException(ts.self()))                        \
2016            result.l = (Object*)addLocalReference(env, result.l);           \
2017        return _retok;                                                      \
2018    }
2019CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
2020CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
2021CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
2022CALL_VIRTUAL(jchar, Char, 0, result.c, false);
2023CALL_VIRTUAL(jshort, Short, 0, result.s, false);
2024CALL_VIRTUAL(jint, Int, 0, result.i, false);
2025CALL_VIRTUAL(jlong, Long, 0, result.j, false);
2026CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
2027CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
2028CALL_VIRTUAL(void, Void, , , false);
2029
2030/*
2031 * Make a "non-virtual" method call.  We're still calling a virtual method,
2032 * but this time we're not doing an indirection through the object's vtable.
2033 * The "clazz" parameter defines which implementation of a method we want.
2034 *
2035 * Three versions (..., va_list, jvalue[]) for each return type.
2036 */
2037#define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref)           \
2038    static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
2039        jclass jclazz, jmethodID methodID, ...)                             \
2040    {                                                                       \
2041        ScopedJniThreadState ts(env);                                       \
2042        Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
2043        ClassObject* clazz =                                                \
2044            (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
2045        const Method* meth;                                                 \
2046        va_list args;                                                       \
2047        JValue result;                                                      \
2048        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
2049        if (meth == NULL) {                                                 \
2050            return _retfail;                                                \
2051        }                                                                   \
2052        va_start(args, methodID);                                           \
2053        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
2054        if (_isref && !dvmCheckException(ts.self()))                        \
2055            result.l = (Object*)addLocalReference(env, result.l);           \
2056        va_end(args);                                                       \
2057        return _retok;                                                      \
2058    }                                                                       \
2059    static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
2060        jclass jclazz, jmethodID methodID, va_list args)                    \
2061    {                                                                       \
2062        ScopedJniThreadState ts(env);                                       \
2063        Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
2064        ClassObject* clazz =                                                \
2065            (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
2066        const Method* meth;                                                 \
2067        JValue result;                                                      \
2068        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
2069        if (meth == NULL) {                                                 \
2070            return _retfail;                                                \
2071        }                                                                   \
2072        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
2073        if (_isref && !dvmCheckException(ts.self()))                        \
2074            result.l = (Object*)addLocalReference(env, result.l);           \
2075        return _retok;                                                      \
2076    }                                                                       \
2077    static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2078        jclass jclazz, jmethodID methodID, jvalue* args)                    \
2079    {                                                                       \
2080        ScopedJniThreadState ts(env);                                       \
2081        Object* obj = dvmDecodeIndirectRef(env, jobj);                      \
2082        ClassObject* clazz =                                                \
2083            (ClassObject*) dvmDecodeIndirectRef(env, jclazz);               \
2084        const Method* meth;                                                 \
2085        JValue result;                                                      \
2086        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
2087        if (meth == NULL) {                                                 \
2088            return _retfail;                                                \
2089        }                                                                   \
2090        dvmCallMethodA(ts.self(), meth, obj, true, &result, args);          \
2091        if (_isref && !dvmCheckException(ts.self()))                        \
2092            result.l = (Object*)addLocalReference(env, result.l);           \
2093        return _retok;                                                      \
2094    }
2095CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
2096CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2097CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2098CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2099CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2100CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2101CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2102CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2103CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2104CALL_NONVIRTUAL(void, Void, , , false);
2105
2106
2107/*
2108 * Call a static method.
2109 */
2110#define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref)               \
2111    static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,    \
2112        jmethodID methodID, ...)                                            \
2113    {                                                                       \
2114        UNUSED_PARAMETER(jclazz);                                           \
2115        ScopedJniThreadState ts(env);                                       \
2116        JValue result;                                                      \
2117        va_list args;                                                       \
2118        va_start(args, methodID);                                           \
2119        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2120        va_end(args);                                                       \
2121        if (_isref && !dvmCheckException(ts.self()))                        \
2122            result.l = (Object*)addLocalReference(env, result.l);           \
2123        return _retok;                                                      \
2124    }                                                                       \
2125    static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,   \
2126        jmethodID methodID, va_list args)                                   \
2127    {                                                                       \
2128        UNUSED_PARAMETER(jclazz);                                           \
2129        ScopedJniThreadState ts(env);                                       \
2130        JValue result;                                                      \
2131        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2132        if (_isref && !dvmCheckException(ts.self()))                        \
2133            result.l = (Object*)addLocalReference(env, result.l);           \
2134        return _retok;                                                      \
2135    }                                                                       \
2136    static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,   \
2137        jmethodID methodID, jvalue* args)                                   \
2138    {                                                                       \
2139        UNUSED_PARAMETER(jclazz);                                           \
2140        ScopedJniThreadState ts(env);                                       \
2141        JValue result;                                                      \
2142        dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2143        if (_isref && !dvmCheckException(ts.self()))                        \
2144            result.l = (Object*)addLocalReference(env, result.l);           \
2145        return _retok;                                                      \
2146    }
2147CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
2148CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2149CALL_STATIC(jbyte, Byte, 0, result.b, false);
2150CALL_STATIC(jchar, Char, 0, result.c, false);
2151CALL_STATIC(jshort, Short, 0, result.s, false);
2152CALL_STATIC(jint, Int, 0, result.i, false);
2153CALL_STATIC(jlong, Long, 0, result.j, false);
2154CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2155CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2156CALL_STATIC(void, Void, , , false);
2157
2158/*
2159 * Create a new String from Unicode data.
2160 *
2161 * If "len" is zero, we will return an empty string even if "unicodeChars"
2162 * is NULL.  (The JNI spec is vague here.)
2163 */
2164static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
2165    ScopedJniThreadState ts(env);
2166    StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2167    if (jstr == NULL) {
2168        return NULL;
2169    }
2170    dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2171    return (jstring) addLocalReference(env, (Object*) jstr);
2172}
2173
2174/*
2175 * Return the length of a String in Unicode character units.
2176 */
2177static jsize GetStringLength(JNIEnv* env, jstring jstr) {
2178    ScopedJniThreadState ts(env);
2179    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2180    return strObj->length();
2181}
2182
2183
2184/*
2185 * Get a string's character data.
2186 *
2187 * The result is guaranteed to be valid until ReleaseStringChars is
2188 * called, which means we have to pin it or return a copy.
2189 */
2190static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2191    ScopedJniThreadState ts(env);
2192
2193    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2194    ArrayObject* strChars = strObj->array();
2195
2196    pinPrimitiveArray(strChars);
2197
2198    const u2* data = strObj->chars();
2199    if (isCopy != NULL) {
2200        *isCopy = JNI_FALSE;
2201    }
2202    return (jchar*) data;
2203}
2204
2205/*
2206 * Release our grip on some characters from a string.
2207 */
2208static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
2209    ScopedJniThreadState ts(env);
2210    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2211    ArrayObject* strChars = strObj->array();
2212    unpinPrimitiveArray(strChars);
2213}
2214
2215/*
2216 * Create a new java.lang.String object from chars in modified UTF-8 form.
2217 *
2218 * The spec doesn't say how to handle a NULL string.  Popular desktop VMs
2219 * accept it and return a NULL pointer in response.
2220 */
2221static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
2222    ScopedJniThreadState ts(env);
2223    if (bytes == NULL) {
2224        return NULL;
2225    }
2226    /* note newStr could come back NULL on OOM */
2227    StringObject* newStr = dvmCreateStringFromCstr(bytes);
2228    jstring result = (jstring) addLocalReference(env, (Object*) newStr);
2229    dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2230    return result;
2231}
2232
2233/*
2234 * Return the length in bytes of the modified UTF-8 form of the string.
2235 */
2236static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
2237    ScopedJniThreadState ts(env);
2238    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2239    if (strObj == NULL) {
2240        return 0; // Should we throw something or assert?
2241    }
2242    return strObj->utfLength();
2243}
2244
2245/*
2246 * Convert "string" to modified UTF-8 and return a pointer.  The returned
2247 * value must be released with ReleaseStringUTFChars.
2248 *
2249 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2250 * or NULL if the operation fails. Returns NULL if and only if an invocation
2251 * of this function has thrown an exception."
2252 *
2253 * The behavior here currently follows that of other open-source VMs, which
2254 * quietly return NULL if "string" is NULL.  We should consider throwing an
2255 * NPE.  (The CheckJNI code blows up if you try to pass in a NULL string,
2256 * which should catch this sort of thing during development.)  Certain other
2257 * VMs will crash with a segmentation fault.
2258 */
2259static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2260    ScopedJniThreadState ts(env);
2261    if (jstr == NULL) {
2262        /* this shouldn't happen; throw NPE? */
2263        return NULL;
2264    }
2265    if (isCopy != NULL) {
2266        *isCopy = JNI_TRUE;
2267    }
2268    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2269    char* newStr = dvmCreateCstrFromString(strObj);
2270    if (newStr == NULL) {
2271        /* assume memory failure */
2272        dvmThrowOutOfMemoryError("native heap string alloc failed");
2273    }
2274    return newStr;
2275}
2276
2277/*
2278 * Release a string created by GetStringUTFChars().
2279 */
2280static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
2281    ScopedJniThreadState ts(env);
2282    free((char*) utf);
2283}
2284
2285/*
2286 * Return the capacity of the array.
2287 */
2288static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
2289    ScopedJniThreadState ts(env);
2290    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2291    return arrObj->length;
2292}
2293
2294/*
2295 * Construct a new array that holds objects from class "elementClass".
2296 */
2297static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2298    jclass jelementClass, jobject jinitialElement)
2299{
2300    ScopedJniThreadState ts(env);
2301
2302    if (jelementClass == NULL) {
2303        dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
2304        return NULL;
2305    }
2306
2307    ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(env, jelementClass);
2308    ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
2309    ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
2310    if (newObj == NULL) {
2311        assert(dvmCheckException(ts.self()));
2312        return NULL;
2313    }
2314    jobjectArray newArray = (jobjectArray) addLocalReference(env, (Object*) newObj);
2315    dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2316
2317    /*
2318     * Initialize the array.
2319     */
2320    if (jinitialElement != NULL) {
2321        Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement);
2322        Object** arrayData = (Object**) (void*) newObj->contents;
2323        for (jsize i = 0; i < length; ++i) {
2324            arrayData[i] = initialElement;
2325        }
2326    }
2327
2328    return newArray;
2329}
2330
2331static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
2332    assert(arrayObj != NULL);
2333    if (index < 0 || index >= (int) arrayObj->length) {
2334        dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
2335        return false;
2336    }
2337    return true;
2338}
2339
2340/*
2341 * Get one element of an Object array.
2342 *
2343 * Add the object to the local references table in case the array goes away.
2344 */
2345static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
2346    ScopedJniThreadState ts(env);
2347
2348    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2349    if (!checkArrayElementBounds(arrayObj, index)) {
2350        return NULL;
2351    }
2352
2353    Object* value = ((Object**) (void*) arrayObj->contents)[index];
2354    return addLocalReference(env, value);
2355}
2356
2357/*
2358 * Set one element of an Object array.
2359 */
2360static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
2361    ScopedJniThreadState ts(env);
2362
2363    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2364    if (!checkArrayElementBounds(arrayObj, index)) {
2365        return;
2366    }
2367
2368    //LOGV("JNI: set element %d in array %p to %p", index, array, value);
2369
2370    Object* obj = dvmDecodeIndirectRef(env, jobj);
2371    dvmSetObjectArrayElement(arrayObj, index, obj);
2372}
2373
2374/*
2375 * Create a new array of primitive elements.
2376 */
2377#define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2378    static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
2379        ScopedJniThreadState ts(env); \
2380        ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
2381        if (arrayObj == NULL) { \
2382            return NULL; \
2383        } \
2384        _artype result = (_artype) addLocalReference(env, (Object*) arrayObj); \
2385        dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2386        return result; \
2387    }
2388NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2389NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2390NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2391NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2392NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2393NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2394NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2395NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2396
2397/*
2398 * Get a pointer to a C array of primitive elements from an array object
2399 * of the matching type.
2400 *
2401 * In a compacting GC, we either need to return a copy of the elements or
2402 * "pin" the memory.  Otherwise we run the risk of native code using the
2403 * buffer as the destination of e.g. a blocking read() call that wakes up
2404 * during a GC.
2405 */
2406#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2407    static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2408        _ctype##Array jarr, jboolean* isCopy) \
2409    { \
2410        ScopedJniThreadState ts(env); \
2411        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
2412        pinPrimitiveArray(arrayObj); \
2413        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2414        if (isCopy != NULL) { \
2415            *isCopy = JNI_FALSE; \
2416        } \
2417        return data; \
2418    }
2419
2420/*
2421 * Release the storage locked down by the "get" function.
2422 *
2423 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2424 * elements in 'array'."  They apparently did not anticipate the need to
2425 * un-pin memory.
2426 */
2427#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                    \
2428    static void Release##_jname##ArrayElements(JNIEnv* env,                 \
2429        _ctype##Array jarr, _ctype* elems, jint mode)                       \
2430    {                                                                       \
2431        UNUSED_PARAMETER(elems);                                            \
2432        if (mode != JNI_COMMIT) {                                           \
2433            ScopedJniThreadState ts(env);                                   \
2434            ArrayObject* arrayObj =                                         \
2435                (ArrayObject*) dvmDecodeIndirectRef(env, jarr);             \
2436            unpinPrimitiveArray(arrayObj);                                  \
2437        }                                                                   \
2438    }
2439
2440static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
2441    jsize len, const char* arrayIdentifier)
2442{
2443    dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
2444        "%s offset=%d length=%d %s.length=%d",
2445        arrayObj->clazz->descriptor, start, len, arrayIdentifier,
2446        arrayObj->length);
2447}
2448
2449/*
2450 * Copy a section of a primitive array to a buffer.
2451 */
2452#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2453    static void Get##_jname##ArrayRegion(JNIEnv* env, \
2454        _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2455    { \
2456        ScopedJniThreadState ts(env); \
2457        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
2458        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2459        if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2460            throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
2461        } else { \
2462            memcpy(buf, data + start, len * sizeof(_ctype)); \
2463        } \
2464    }
2465
2466/*
2467 * Copy a section of a primitive array from a buffer.
2468 */
2469#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2470    static void Set##_jname##ArrayRegion(JNIEnv* env, \
2471        _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2472    { \
2473        ScopedJniThreadState ts(env); \
2474        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
2475        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2476        if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2477            throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
2478        } else { \
2479            memcpy(data + start, buf, len * sizeof(_ctype)); \
2480        } \
2481    }
2482
2483/*
2484 * 4-in-1:
2485 *  Get<Type>ArrayElements
2486 *  Release<Type>ArrayElements
2487 *  Get<Type>ArrayRegion
2488 *  Set<Type>ArrayRegion
2489 */
2490#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname)                           \
2491    GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                           \
2492    RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                       \
2493    GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);                             \
2494    SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2495
2496PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2497PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2498PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2499PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2500PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2501PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2502PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2503PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2504
2505/*
2506 * Register one or more native functions in one class.
2507 *
2508 * This can be called multiple times on the same method, allowing the
2509 * caller to redefine the method implementation at will.
2510 */
2511static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2512    const JNINativeMethod* methods, jint nMethods)
2513{
2514    ScopedJniThreadState ts(env);
2515
2516    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2517
2518    if (gDvm.verboseJni) {
2519        LOGI("[Registering JNI native methods for class %s]",
2520            clazz->descriptor);
2521    }
2522
2523    for (int i = 0; i < nMethods; i++) {
2524        if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2525                methods[i].signature, methods[i].fnPtr))
2526        {
2527            return JNI_ERR;
2528        }
2529    }
2530    return JNI_OK;
2531}
2532
2533/*
2534 * Un-register all native methods associated with the class.
2535 *
2536 * The JNI docs refer to this as a way to reload/relink native libraries,
2537 * and say it "should not be used in normal native code".  In particular,
2538 * there is no need to do this during shutdown, and you do not need to do
2539 * this before redefining a method implementation with RegisterNatives.
2540 *
2541 * It's chiefly useful for a native "plugin"-style library that wasn't
2542 * loaded with System.loadLibrary() (since there's no way to unload those).
2543 * For example, the library could upgrade itself by:
2544 *
2545 *  1. call UnregisterNatives to unbind the old methods
2546 *  2. ensure that no code is still executing inside it (somehow)
2547 *  3. dlclose() the library
2548 *  4. dlopen() the new library
2549 *  5. use RegisterNatives to bind the methods from the new library
2550 *
2551 * The above can work correctly without the UnregisterNatives call, but
2552 * creates a window of opportunity in which somebody might try to call a
2553 * method that is pointing at unmapped memory, crashing the VM.  In theory
2554 * the same guards that prevent dlclose() from unmapping executing code could
2555 * prevent that anyway, but with this we can be more thorough and also deal
2556 * with methods that only exist in the old or new form of the library (maybe
2557 * the lib wants to try the call and catch the UnsatisfiedLinkError).
2558 */
2559static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
2560    ScopedJniThreadState ts(env);
2561
2562    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2563    if (gDvm.verboseJni) {
2564        LOGI("[Unregistering JNI native methods for class %s]",
2565            clazz->descriptor);
2566    }
2567    dvmUnregisterJNINativeMethods(clazz);
2568    return JNI_OK;
2569}
2570
2571/*
2572 * Lock the monitor.
2573 *
2574 * We have to track all monitor enters and exits, so that we can undo any
2575 * outstanding synchronization before the thread exits.
2576 */
2577static jint MonitorEnter(JNIEnv* env, jobject jobj) {
2578    ScopedJniThreadState ts(env);
2579    Object* obj = dvmDecodeIndirectRef(env, jobj);
2580    dvmLockObject(ts.self(), obj);
2581    trackMonitorEnter(ts.self(), obj);
2582    return JNI_OK;
2583}
2584
2585/*
2586 * Unlock the monitor.
2587 *
2588 * Throws an IllegalMonitorStateException if the current thread
2589 * doesn't own the monitor.  (dvmUnlockObject() takes care of the throw.)
2590 *
2591 * According to the 1.6 spec, it's legal to call here with an exception
2592 * pending.  If this fails, we'll stomp the original exception.
2593 */
2594static jint MonitorExit(JNIEnv* env, jobject jobj) {
2595    ScopedJniThreadState ts(env);
2596    Object* obj = dvmDecodeIndirectRef(env, jobj);
2597    bool success = dvmUnlockObject(ts.self(), obj);
2598    if (success) {
2599        trackMonitorExit(ts.self(), obj);
2600    }
2601    return success ? JNI_OK : JNI_ERR;
2602}
2603
2604/*
2605 * Return the JavaVM interface associated with the current thread.
2606 */
2607static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
2608    ScopedJniThreadState ts(env);
2609    *vm = gDvmJni.jniVm;
2610    return (*vm == NULL) ? JNI_ERR : JNI_OK;
2611}
2612
2613/*
2614 * Copies "len" Unicode characters, from offset "start".
2615 */
2616static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
2617    ScopedJniThreadState ts(env);
2618    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2619    int strLen = strObj->length();
2620    if (((start|len) < 0) || (start + len > strLen)) {
2621        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2622        return;
2623    }
2624    memcpy(buf, strObj->chars() + start, len * sizeof(u2));
2625}
2626
2627/*
2628 * Translates "len" Unicode characters, from offset "start", into
2629 * modified UTF-8 encoding.
2630 */
2631static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
2632    ScopedJniThreadState ts(env);
2633    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2634    int strLen = strObj->length();
2635    if (((start|len) < 0) || (start + len > strLen)) {
2636        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2637        return;
2638    }
2639    dvmGetStringUtfRegion(strObj, start, len, buf);
2640}
2641
2642/*
2643 * Get a raw pointer to array data.
2644 *
2645 * The caller is expected to call "release" before doing any JNI calls
2646 * or blocking I/O operations.
2647 *
2648 * We need to pin the memory or block GC.
2649 */
2650static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
2651    ScopedJniThreadState ts(env);
2652    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2653    pinPrimitiveArray(arrayObj);
2654    void* data = arrayObj->contents;
2655    if (isCopy != NULL) {
2656        *isCopy = JNI_FALSE;
2657    }
2658    return data;
2659}
2660
2661/*
2662 * Release an array obtained with GetPrimitiveArrayCritical.
2663 */
2664static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
2665    if (mode != JNI_COMMIT) {
2666        ScopedJniThreadState ts(env);
2667        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2668        unpinPrimitiveArray(arrayObj);
2669    }
2670}
2671
2672/*
2673 * Like GetStringChars, but with restricted use.
2674 */
2675static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2676    ScopedJniThreadState ts(env);
2677
2678    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2679    ArrayObject* strChars = strObj->array();
2680
2681    pinPrimitiveArray(strChars);
2682
2683    const u2* data = strObj->chars();
2684    if (isCopy != NULL) {
2685        *isCopy = JNI_FALSE;
2686    }
2687    return (jchar*) data;
2688}
2689
2690/*
2691 * Like ReleaseStringChars, but with restricted use.
2692 */
2693static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
2694    ScopedJniThreadState ts(env);
2695    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2696    ArrayObject* strChars = strObj->array();
2697    unpinPrimitiveArray(strChars);
2698}
2699
2700/*
2701 * Create a new weak global reference.
2702 */
2703static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
2704    ScopedJniThreadState ts(env);
2705    Object *obj = dvmDecodeIndirectRef(env, jobj);
2706    return (jweak) addWeakGlobalReference(obj);
2707}
2708
2709/*
2710 * Delete the specified weak global reference.
2711 */
2712static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
2713    ScopedJniThreadState ts(env);
2714    deleteWeakGlobalReference(wref);
2715}
2716
2717/*
2718 * Quick check for pending exceptions.
2719 *
2720 * TODO: we should be able to skip the enter/exit macros here.
2721 */
2722static jboolean ExceptionCheck(JNIEnv* env) {
2723    ScopedJniThreadState ts(env);
2724    return dvmCheckException(ts.self());
2725}
2726
2727/*
2728 * Returns the type of the object referred to by "obj".  It can be local,
2729 * global, or weak global.
2730 *
2731 * In the current implementation, references can be global and local at
2732 * the same time, so while the return value is accurate it may not tell
2733 * the whole story.
2734 */
2735static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
2736    ScopedJniThreadState ts(env);
2737    return dvmGetJNIRefType(env, jobj);
2738}
2739
2740/*
2741 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2742 *
2743 * "address" may not be NULL, and "capacity" must be > 0.  (These are only
2744 * verified when CheckJNI is enabled.)
2745 */
2746static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2747    ScopedJniThreadState ts(env);
2748
2749    /* create an instance of java.nio.ReadWriteDirectByteBuffer */
2750    ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
2751    if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
2752        return NULL;
2753    }
2754    Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
2755    if (newObj == NULL) {
2756        return NULL;
2757    }
2758    /* call the constructor */
2759    jobject result = addLocalReference(env, newObj);
2760    JValue unused;
2761    dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init,
2762            newObj, &unused, (jint) address, (jint) capacity);
2763    if (dvmGetException(ts.self()) != NULL) {
2764        deleteLocalReference(env, result);
2765        return NULL;
2766    }
2767    return result;
2768}
2769
2770/*
2771 * Get the starting address of the buffer for the specified java.nio.Buffer.
2772 *
2773 * If this is not a "direct" buffer, we return NULL.
2774 */
2775static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
2776    ScopedJniThreadState ts(env);
2777
2778    // All Buffer objects have an effectiveDirectAddress field.
2779    Object* bufObj = dvmDecodeIndirectRef(env, jbuf);
2780    return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
2781}
2782
2783/*
2784 * Get the capacity of the buffer for the specified java.nio.Buffer.
2785 *
2786 * Returns -1 if the object is not a direct buffer.  (We actually skip
2787 * this check, since it's expensive to determine, and just return the
2788 * capacity regardless.)
2789 */
2790static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
2791    ScopedJniThreadState ts(env);
2792
2793    /*
2794     * The capacity is always in the Buffer.capacity field.
2795     *
2796     * (The "check" version should verify that this is actually a Buffer,
2797     * but we're not required to do so here.)
2798     */
2799    Object* buf = dvmDecodeIndirectRef(env, jbuf);
2800    return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
2801}
2802
2803
2804/*
2805 * ===========================================================================
2806 *      JNI invocation functions
2807 * ===========================================================================
2808 */
2809
2810/*
2811 * Handle AttachCurrentThread{AsDaemon}.
2812 *
2813 * We need to make sure the VM is actually running.  For example, if we start
2814 * up, issue an Attach, and the VM exits almost immediately, by the time the
2815 * attaching happens the VM could already be shutting down.
2816 *
2817 * It's hard to avoid a race condition here because we don't want to hold
2818 * a lock across the entire operation.  What we can do is temporarily
2819 * increment the thread count to prevent a VM exit.
2820 *
2821 * This could potentially still have problems if a daemon thread calls here
2822 * while the VM is shutting down.  dvmThreadSelf() will work, since it just
2823 * uses pthread TLS, but dereferencing "vm" could fail.  Such is life when
2824 * you shut down a VM while threads are still running inside it.
2825 *
2826 * Remember that some code may call this as a way to find the per-thread
2827 * JNIEnv pointer.  Don't do excess work for that case.
2828 */
2829static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
2830    JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2831
2832    /*
2833     * Return immediately if we're already one with the VM.
2834     */
2835    Thread* self = dvmThreadSelf();
2836    if (self != NULL) {
2837        *p_env = self->jniEnv;
2838        return JNI_OK;
2839    }
2840
2841    /*
2842     * No threads allowed in zygote mode.
2843     */
2844    if (gDvm.zygote) {
2845        return JNI_ERR;
2846    }
2847
2848    /* increment the count to keep the VM from bailing while we run */
2849    dvmLockThreadList(NULL);
2850    if (gDvm.nonDaemonThreadCount == 0) {
2851        // dead or dying
2852        LOGV("Refusing to attach thread '%s' -- VM is shutting down",
2853            (thr_args == NULL) ? "(unknown)" : args->name);
2854        dvmUnlockThreadList();
2855        return JNI_ERR;
2856    }
2857    gDvm.nonDaemonThreadCount++;
2858    dvmUnlockThreadList();
2859
2860    /* tweak the JavaVMAttachArgs as needed */
2861    JavaVMAttachArgs argsCopy;
2862    if (args == NULL) {
2863        /* allow the v1.1 calling convention */
2864        argsCopy.version = JNI_VERSION_1_2;
2865        argsCopy.name = NULL;
2866        argsCopy.group = (jobject) dvmGetMainThreadGroup();
2867    } else {
2868        assert(args->version >= JNI_VERSION_1_2);
2869
2870        argsCopy.version = args->version;
2871        argsCopy.name = args->name;
2872        if (args->group != NULL) {
2873            argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
2874        } else {
2875            argsCopy.group = (jobject) dvmGetMainThreadGroup();
2876        }
2877    }
2878
2879    bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2880
2881    /* restore the count */
2882    dvmLockThreadList(NULL);
2883    gDvm.nonDaemonThreadCount--;
2884    dvmUnlockThreadList();
2885
2886    /*
2887     * Change the status to indicate that we're out in native code.  This
2888     * call is not guarded with state-change macros, so we have to do it
2889     * by hand.
2890     */
2891    if (result) {
2892        self = dvmThreadSelf();
2893        assert(self != NULL);
2894        dvmChangeStatus(self, THREAD_NATIVE);
2895        *p_env = self->jniEnv;
2896        return JNI_OK;
2897    } else {
2898        return JNI_ERR;
2899    }
2900}
2901
2902/*
2903 * Attach the current thread to the VM.  If the thread is already attached,
2904 * this is a no-op.
2905 */
2906static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
2907    return attachThread(vm, p_env, thr_args, false);
2908}
2909
2910/*
2911 * Like AttachCurrentThread, but set the "daemon" flag.
2912 */
2913static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2914{
2915    return attachThread(vm, p_env, thr_args, true);
2916}
2917
2918/*
2919 * Dissociate the current thread from the VM.
2920 */
2921static jint DetachCurrentThread(JavaVM* vm) {
2922    Thread* self = dvmThreadSelf();
2923    if (self == NULL) {
2924        /* not attached, can't do anything */
2925        return JNI_ERR;
2926    }
2927
2928    /* switch to "running" to check for suspension */
2929    dvmChangeStatus(self, THREAD_RUNNING);
2930
2931    /* detach the thread */
2932    dvmDetachCurrentThread();
2933
2934    /* (no need to change status back -- we have no status) */
2935    return JNI_OK;
2936}
2937
2938/*
2939 * If current thread is attached to VM, return the associated JNIEnv.
2940 * Otherwise, stuff NULL in and return JNI_EDETACHED.
2941 *
2942 * JVMTI overloads this by specifying a magic value for "version", so we
2943 * do want to check that here.
2944 */
2945static jint GetEnv(JavaVM* vm, void** env, jint version) {
2946    Thread* self = dvmThreadSelf();
2947
2948    if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
2949        return JNI_EVERSION;
2950    }
2951
2952    if (self == NULL) {
2953        *env = NULL;
2954    } else {
2955        /* TODO: status change is probably unnecessary */
2956        dvmChangeStatus(self, THREAD_RUNNING);
2957        *env = (void*) dvmGetThreadJNIEnv(self);
2958        dvmChangeStatus(self, THREAD_NATIVE);
2959    }
2960    return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
2961}
2962
2963/*
2964 * Destroy the VM.  This may be called from any thread.
2965 *
2966 * If the current thread is attached, wait until the current thread is
2967 * the only non-daemon user-level thread.  If the current thread is not
2968 * attached, we attach it and do the processing as usual.  (If the attach
2969 * fails, it's probably because all the non-daemon threads have already
2970 * exited and the VM doesn't want to let us back in.)
2971 *
2972 * TODO: we don't really deal with the situation where more than one thread
2973 * has called here.  One thread wins, the other stays trapped waiting on
2974 * the condition variable forever.  Not sure this situation is interesting
2975 * in real life.
2976 */
2977static jint DestroyJavaVM(JavaVM* vm) {
2978    JavaVMExt* ext = (JavaVMExt*) vm;
2979    if (ext == NULL) {
2980        return JNI_ERR;
2981    }
2982
2983    if (gDvm.verboseShutdown) {
2984        LOGD("DestroyJavaVM waiting for non-daemon threads to exit");
2985    }
2986
2987    /*
2988     * Sleep on a condition variable until it's okay to exit.
2989     */
2990    Thread* self = dvmThreadSelf();
2991    if (self == NULL) {
2992        JNIEnv* tmpEnv;
2993        if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
2994            LOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
2995                gDvm.nonDaemonThreadCount);
2996            goto shutdown;
2997        } else {
2998            LOGV("Attached to wait for shutdown in Destroy");
2999        }
3000    }
3001    dvmChangeStatus(self, THREAD_VMWAIT);
3002
3003    dvmLockThreadList(self);
3004    gDvm.nonDaemonThreadCount--;    // remove current thread from count
3005
3006    while (gDvm.nonDaemonThreadCount > 0) {
3007        pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
3008    }
3009
3010    dvmUnlockThreadList();
3011    self = NULL;
3012
3013shutdown:
3014    // TODO: call System.exit() to run any registered shutdown hooks
3015    // (this may not return -- figure out how this should work)
3016
3017    if (gDvm.verboseShutdown) {
3018        LOGD("DestroyJavaVM shutting VM down");
3019    }
3020    dvmShutdown();
3021
3022    // TODO - free resources associated with JNI-attached daemon threads
3023    free(ext->envList);
3024    free(ext);
3025
3026    return JNI_OK;
3027}
3028
3029
3030/*
3031 * ===========================================================================
3032 *      Function tables
3033 * ===========================================================================
3034 */
3035
3036static const struct JNINativeInterface gNativeInterface = {
3037    NULL,
3038    NULL,
3039    NULL,
3040    NULL,
3041
3042    GetVersion,
3043
3044    DefineClass,
3045    FindClass,
3046
3047    FromReflectedMethod,
3048    FromReflectedField,
3049    ToReflectedMethod,
3050
3051    GetSuperclass,
3052    IsAssignableFrom,
3053
3054    ToReflectedField,
3055
3056    Throw,
3057    ThrowNew,
3058    ExceptionOccurred,
3059    ExceptionDescribe,
3060    ExceptionClear,
3061    FatalError,
3062
3063    PushLocalFrame,
3064    PopLocalFrame,
3065
3066    NewGlobalRef,
3067    DeleteGlobalRef,
3068    DeleteLocalRef,
3069    IsSameObject,
3070    NewLocalRef,
3071    EnsureLocalCapacity,
3072
3073    AllocObject,
3074    NewObject,
3075    NewObjectV,
3076    NewObjectA,
3077
3078    GetObjectClass,
3079    IsInstanceOf,
3080
3081    GetMethodID,
3082
3083    CallObjectMethod,
3084    CallObjectMethodV,
3085    CallObjectMethodA,
3086    CallBooleanMethod,
3087    CallBooleanMethodV,
3088    CallBooleanMethodA,
3089    CallByteMethod,
3090    CallByteMethodV,
3091    CallByteMethodA,
3092    CallCharMethod,
3093    CallCharMethodV,
3094    CallCharMethodA,
3095    CallShortMethod,
3096    CallShortMethodV,
3097    CallShortMethodA,
3098    CallIntMethod,
3099    CallIntMethodV,
3100    CallIntMethodA,
3101    CallLongMethod,
3102    CallLongMethodV,
3103    CallLongMethodA,
3104    CallFloatMethod,
3105    CallFloatMethodV,
3106    CallFloatMethodA,
3107    CallDoubleMethod,
3108    CallDoubleMethodV,
3109    CallDoubleMethodA,
3110    CallVoidMethod,
3111    CallVoidMethodV,
3112    CallVoidMethodA,
3113
3114    CallNonvirtualObjectMethod,
3115    CallNonvirtualObjectMethodV,
3116    CallNonvirtualObjectMethodA,
3117    CallNonvirtualBooleanMethod,
3118    CallNonvirtualBooleanMethodV,
3119    CallNonvirtualBooleanMethodA,
3120    CallNonvirtualByteMethod,
3121    CallNonvirtualByteMethodV,
3122    CallNonvirtualByteMethodA,
3123    CallNonvirtualCharMethod,
3124    CallNonvirtualCharMethodV,
3125    CallNonvirtualCharMethodA,
3126    CallNonvirtualShortMethod,
3127    CallNonvirtualShortMethodV,
3128    CallNonvirtualShortMethodA,
3129    CallNonvirtualIntMethod,
3130    CallNonvirtualIntMethodV,
3131    CallNonvirtualIntMethodA,
3132    CallNonvirtualLongMethod,
3133    CallNonvirtualLongMethodV,
3134    CallNonvirtualLongMethodA,
3135    CallNonvirtualFloatMethod,
3136    CallNonvirtualFloatMethodV,
3137    CallNonvirtualFloatMethodA,
3138    CallNonvirtualDoubleMethod,
3139    CallNonvirtualDoubleMethodV,
3140    CallNonvirtualDoubleMethodA,
3141    CallNonvirtualVoidMethod,
3142    CallNonvirtualVoidMethodV,
3143    CallNonvirtualVoidMethodA,
3144
3145    GetFieldID,
3146
3147    GetObjectField,
3148    GetBooleanField,
3149    GetByteField,
3150    GetCharField,
3151    GetShortField,
3152    GetIntField,
3153    GetLongField,
3154    GetFloatField,
3155    GetDoubleField,
3156    SetObjectField,
3157    SetBooleanField,
3158    SetByteField,
3159    SetCharField,
3160    SetShortField,
3161    SetIntField,
3162    SetLongField,
3163    SetFloatField,
3164    SetDoubleField,
3165
3166    GetStaticMethodID,
3167
3168    CallStaticObjectMethod,
3169    CallStaticObjectMethodV,
3170    CallStaticObjectMethodA,
3171    CallStaticBooleanMethod,
3172    CallStaticBooleanMethodV,
3173    CallStaticBooleanMethodA,
3174    CallStaticByteMethod,
3175    CallStaticByteMethodV,
3176    CallStaticByteMethodA,
3177    CallStaticCharMethod,
3178    CallStaticCharMethodV,
3179    CallStaticCharMethodA,
3180    CallStaticShortMethod,
3181    CallStaticShortMethodV,
3182    CallStaticShortMethodA,
3183    CallStaticIntMethod,
3184    CallStaticIntMethodV,
3185    CallStaticIntMethodA,
3186    CallStaticLongMethod,
3187    CallStaticLongMethodV,
3188    CallStaticLongMethodA,
3189    CallStaticFloatMethod,
3190    CallStaticFloatMethodV,
3191    CallStaticFloatMethodA,
3192    CallStaticDoubleMethod,
3193    CallStaticDoubleMethodV,
3194    CallStaticDoubleMethodA,
3195    CallStaticVoidMethod,
3196    CallStaticVoidMethodV,
3197    CallStaticVoidMethodA,
3198
3199    GetStaticFieldID,
3200
3201    GetStaticObjectField,
3202    GetStaticBooleanField,
3203    GetStaticByteField,
3204    GetStaticCharField,
3205    GetStaticShortField,
3206    GetStaticIntField,
3207    GetStaticLongField,
3208    GetStaticFloatField,
3209    GetStaticDoubleField,
3210
3211    SetStaticObjectField,
3212    SetStaticBooleanField,
3213    SetStaticByteField,
3214    SetStaticCharField,
3215    SetStaticShortField,
3216    SetStaticIntField,
3217    SetStaticLongField,
3218    SetStaticFloatField,
3219    SetStaticDoubleField,
3220
3221    NewString,
3222
3223    GetStringLength,
3224    GetStringChars,
3225    ReleaseStringChars,
3226
3227    NewStringUTF,
3228    GetStringUTFLength,
3229    GetStringUTFChars,
3230    ReleaseStringUTFChars,
3231
3232    GetArrayLength,
3233    NewObjectArray,
3234    GetObjectArrayElement,
3235    SetObjectArrayElement,
3236
3237    NewBooleanArray,
3238    NewByteArray,
3239    NewCharArray,
3240    NewShortArray,
3241    NewIntArray,
3242    NewLongArray,
3243    NewFloatArray,
3244    NewDoubleArray,
3245
3246    GetBooleanArrayElements,
3247    GetByteArrayElements,
3248    GetCharArrayElements,
3249    GetShortArrayElements,
3250    GetIntArrayElements,
3251    GetLongArrayElements,
3252    GetFloatArrayElements,
3253    GetDoubleArrayElements,
3254
3255    ReleaseBooleanArrayElements,
3256    ReleaseByteArrayElements,
3257    ReleaseCharArrayElements,
3258    ReleaseShortArrayElements,
3259    ReleaseIntArrayElements,
3260    ReleaseLongArrayElements,
3261    ReleaseFloatArrayElements,
3262    ReleaseDoubleArrayElements,
3263
3264    GetBooleanArrayRegion,
3265    GetByteArrayRegion,
3266    GetCharArrayRegion,
3267    GetShortArrayRegion,
3268    GetIntArrayRegion,
3269    GetLongArrayRegion,
3270    GetFloatArrayRegion,
3271    GetDoubleArrayRegion,
3272    SetBooleanArrayRegion,
3273    SetByteArrayRegion,
3274    SetCharArrayRegion,
3275    SetShortArrayRegion,
3276    SetIntArrayRegion,
3277    SetLongArrayRegion,
3278    SetFloatArrayRegion,
3279    SetDoubleArrayRegion,
3280
3281    RegisterNatives,
3282    UnregisterNatives,
3283
3284    MonitorEnter,
3285    MonitorExit,
3286
3287    GetJavaVM,
3288
3289    GetStringRegion,
3290    GetStringUTFRegion,
3291
3292    GetPrimitiveArrayCritical,
3293    ReleasePrimitiveArrayCritical,
3294
3295    GetStringCritical,
3296    ReleaseStringCritical,
3297
3298    NewWeakGlobalRef,
3299    DeleteWeakGlobalRef,
3300
3301    ExceptionCheck,
3302
3303    NewDirectByteBuffer,
3304    GetDirectBufferAddress,
3305    GetDirectBufferCapacity,
3306
3307    GetObjectRefType
3308};
3309
3310static const struct JNIInvokeInterface gInvokeInterface = {
3311    NULL,
3312    NULL,
3313    NULL,
3314
3315    DestroyJavaVM,
3316    AttachCurrentThread,
3317    DetachCurrentThread,
3318
3319    GetEnv,
3320
3321    AttachCurrentThreadAsDaemon,
3322};
3323
3324/*
3325 * ===========================================================================
3326 *      VM/Env creation
3327 * ===========================================================================
3328 */
3329
3330/*
3331 * Create a new JNIEnv struct and add it to the VM's list.
3332 *
3333 * "self" will be NULL for the main thread, since the VM hasn't started
3334 * yet; the value will be filled in later.
3335 */
3336JNIEnv* dvmCreateJNIEnv(Thread* self) {
3337    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3338
3339    //if (self != NULL)
3340    //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
3341
3342    assert(vm != NULL);
3343
3344    JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
3345    newEnv->funcTable = &gNativeInterface;
3346    if (self != NULL) {
3347        dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
3348        assert(newEnv->envThreadId != 0);
3349    } else {
3350        /* make it obvious if we fail to initialize these later */
3351        newEnv->envThreadId = 0x77777775;
3352        newEnv->self = (Thread*) 0x77777779;
3353    }
3354    if (gDvmJni.useCheckJni) {
3355        dvmUseCheckedJniEnv(newEnv);
3356    }
3357
3358    ScopedPthreadMutexLock lock(&vm->envListLock);
3359
3360    /* insert at head of list */
3361    newEnv->next = vm->envList;
3362    assert(newEnv->prev == NULL);
3363    if (vm->envList == NULL) {
3364        // rare, but possible
3365        vm->envList = newEnv;
3366    } else {
3367        vm->envList->prev = newEnv;
3368    }
3369    vm->envList = newEnv;
3370
3371    //if (self != NULL)
3372    //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
3373    return (JNIEnv*) newEnv;
3374}
3375
3376/*
3377 * Remove a JNIEnv struct from the list and free it.
3378 */
3379void dvmDestroyJNIEnv(JNIEnv* env) {
3380    if (env == NULL) {
3381        return;
3382    }
3383
3384    //LOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3385
3386    JNIEnvExt* extEnv = (JNIEnvExt*) env;
3387    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3388
3389    ScopedPthreadMutexLock lock(&vm->envListLock);
3390
3391    if (extEnv == vm->envList) {
3392        assert(extEnv->prev == NULL);
3393        vm->envList = extEnv->next;
3394    } else {
3395        assert(extEnv->prev != NULL);
3396        extEnv->prev->next = extEnv->next;
3397    }
3398    if (extEnv->next != NULL) {
3399        extEnv->next->prev = extEnv->prev;
3400    }
3401
3402    free(env);
3403    //LOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3404}
3405
3406/*
3407 * Enable "checked JNI" after the VM has partially started.  This must
3408 * only be called in "zygote" mode, when we have one thread running.
3409 *
3410 * This doesn't attempt to rewrite the JNI call bridge associated with
3411 * native methods, so we won't get those checks for any methods that have
3412 * already been resolved.
3413 */
3414void dvmLateEnableCheckedJni() {
3415    JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
3416    if (extEnv == NULL) {
3417        LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
3418        return;
3419    }
3420    JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
3421    assert(extVm != NULL);
3422
3423    if (!gDvmJni.useCheckJni) {
3424        LOGD("Late-enabling CheckJNI");
3425        dvmUseCheckedJniVm(extVm);
3426        dvmUseCheckedJniEnv(extEnv);
3427    } else {
3428        LOGD("Not late-enabling CheckJNI (already on)");
3429    }
3430}
3431
3432/*
3433 * Not supported.
3434 */
3435jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
3436    return JNI_ERR;
3437}
3438
3439/*
3440 * Return a buffer full of created VMs.
3441 *
3442 * We always have zero or one.
3443 */
3444jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
3445    if (gDvmJni.jniVm != NULL) {
3446        *nVMs = 1;
3447        if (bufLen > 0) {
3448            *vmBuf++ = gDvmJni.jniVm;
3449        }
3450    } else {
3451        *nVMs = 0;
3452    }
3453    return JNI_OK;
3454}
3455
3456/*
3457 * Create a new VM instance.
3458 *
3459 * The current thread becomes the main VM thread.  We return immediately,
3460 * which effectively means the caller is executing in a native method.
3461 */
3462jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
3463    const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3464    if (args->version < JNI_VERSION_1_2) {
3465        return JNI_EVERSION;
3466    }
3467
3468    // TODO: don't allow creation of multiple VMs -- one per customer for now
3469
3470    /* zero globals; not strictly necessary the first time a VM is started */
3471    memset(&gDvm, 0, sizeof(gDvm));
3472
3473    /*
3474     * Set up structures for JNIEnv and VM.
3475     */
3476    JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
3477    memset(pVM, 0, sizeof(JavaVMExt));
3478    pVM->funcTable = &gInvokeInterface;
3479    pVM->envList = NULL;
3480    dvmInitMutex(&pVM->envListLock);
3481
3482    UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
3483    memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
3484
3485    /*
3486     * Convert JNI args to argv.
3487     *
3488     * We have to pull out vfprintf/exit/abort, because they use the
3489     * "extraInfo" field to pass function pointer "hooks" in.  We also
3490     * look for the -Xcheck:jni stuff here.
3491     */
3492    int argc = 0;
3493    for (int i = 0; i < args->nOptions; i++) {
3494        const char* optStr = args->options[i].optionString;
3495        if (optStr == NULL) {
3496            dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
3497            return JNI_ERR;
3498        } else if (strcmp(optStr, "vfprintf") == 0) {
3499            gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
3500        } else if (strcmp(optStr, "exit") == 0) {
3501            gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
3502        } else if (strcmp(optStr, "abort") == 0) {
3503            gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
3504        } else if (strcmp(optStr, "sensitiveThread") == 0) {
3505            gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
3506        } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3507            gDvmJni.useCheckJni = true;
3508        } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3509            char* jniOpts = strdup(optStr + 10);
3510            size_t jniOptCount = 1;
3511            for (char* p = jniOpts; *p != 0; ++p) {
3512                if (*p == ',') {
3513                    ++jniOptCount;
3514                    *p = 0;
3515                }
3516            }
3517            char* jniOpt = jniOpts;
3518            for (size_t i = 0; i < jniOptCount; ++i) {
3519                if (strcmp(jniOpt, "warnonly") == 0) {
3520                    gDvmJni.warnOnly = true;
3521                } else if (strcmp(jniOpt, "forcecopy") == 0) {
3522                    gDvmJni.forceCopy = true;
3523                } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
3524                    gDvmJni.logThirdPartyJni = true;
3525                } else {
3526                    dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
3527                            jniOpt);
3528                    return JNI_ERR;
3529                }
3530                jniOpt += strlen(jniOpt) + 1;
3531            }
3532            free(jniOpts);
3533        } else {
3534            /* regular option */
3535            argv[argc++] = optStr;
3536        }
3537    }
3538
3539    if (gDvmJni.useCheckJni) {
3540        dvmUseCheckedJniVm(pVM);
3541    }
3542
3543    if (gDvmJni.jniVm != NULL) {
3544        dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
3545        return JNI_ERR;
3546    }
3547    gDvmJni.jniVm = (JavaVM*) pVM;
3548
3549    /*
3550     * Create a JNIEnv for the main thread.  We need to have something set up
3551     * here because some of the class initialization we do when starting
3552     * up the VM will call into native code.
3553     */
3554    JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3555
3556    /* Initialize VM. */
3557    gDvm.initializing = true;
3558    std::string status =
3559            dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
3560    gDvm.initializing = false;
3561
3562    if (!status.empty()) {
3563        free(pEnv);
3564        free(pVM);
3565        LOGW("CreateJavaVM failed: %s", status.c_str());
3566        return JNI_ERR;
3567    }
3568
3569    /*
3570     * Success!  Return stuff to caller.
3571     */
3572    dvmChangeStatus(NULL, THREAD_NATIVE);
3573    *p_env = (JNIEnv*) pEnv;
3574    *p_vm = (JavaVM*) pVM;
3575    LOGV("CreateJavaVM succeeded");
3576    return JNI_OK;
3577}
3578