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