OSDN Git Service

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