OSDN Git Service

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