OSDN Git Service

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