OSDN Git Service

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