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