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