2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Dalvik implementation of JNI interfaces.
21 #include "JniInternal.h"
28 Native methods and interaction with the GC
30 All JNI methods must start by changing their thread status to
31 THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
32 returning to native code. The switch to "running" triggers a thread
35 With a rudimentary GC we should be able to skip the status change for
36 simple functions, e.g. IsSameObject, GetJavaVM, GetStringLength, maybe
37 even access to fields with primitive types. Our options are more limited
38 with a compacting GC, so we should replace JNI_ENTER with JNI_ENTER_NCGC
39 or somesuch on the "lite" functions if we want to try this optimization.
41 For performance reasons we do as little error-checking as possible here.
42 For example, we don't check to make sure the correct type of Object is
43 passed in when setting a field, and we don't prevent you from storing
44 new values in a "final" field. Such things are best handled in the
45 "check" version. For actions that are common, dangerous, and must be
46 checked at runtime, such as array bounds checks, we do the tests here.
49 General notes on local/global reference tracking
51 JNI provides explicit control over natively-held references that the VM GC
52 needs to know about. These can be local, in which case they're released
53 when the native method returns, or global, which are held until explicitly
56 The references can be created and deleted with JNI NewLocalRef /
57 NewGlobalRef calls, but this is unusual except perhaps for holding on
58 to a Class reference. Most often they are created transparently by the
59 JNI functions. For example, the paired Get/Release calls guarantee that
60 objects survive until explicitly released, so a simple way to implement
61 this is to create a global reference on "Get" and delete it on "Release".
62 The AllocObject/NewObject functions must create local references, because
63 nothing else in the GC root set has a reference to the new objects.
65 The most common mode of operation is for a method to create zero or
66 more local references and return. Explicit "local delete" operations
67 are expected to be exceedingly rare, except when walking through an
68 object array, and the Push/PopLocalFrame calls are expected to be used
69 infrequently. For efficient operation, we want to add new local refs
70 with a simple store/increment operation; to avoid infinite growth in
71 pathological situations, we need to reclaim the space used by deleted
74 The simplest implementation is an expanding append-only array that compacts
75 when objects are deleted. In typical situations, e.g. running through
76 an array of objects, we will be deleting one of the most recently added
77 entries, so we can minimize the number of elements moved (or avoid having
80 The spec says, "Local references are only valid in the thread in which
81 they are created. The native code must not pass local references from
82 one thread to another." It should also be noted that, while some calls
83 will *create* global references as a side-effect, only the NewGlobalRef
84 and NewWeakGlobalRef calls actually *return* global references.
87 Global reference tracking
89 There should be a small "active" set centered around the most-recently
90 added items. We can use an append-only, compacting array like we do for
93 Because it's global, access to it has to be synchronized.
95 The JNI spec does not define any sort of limit, so the list must be able
96 to expand. It may be useful to log significant increases in usage to
97 help identify resource leaks.
99 TODO: we currently use global references on strings and primitive array
100 data, because they have the property we need (i.e. the pointer we return
101 is guaranteed valid until we explicitly release it). However, if we have
102 a compacting GC and don't want to pin all memory held by all global refs,
103 we actually want to treat these differently. Either we need a way to
104 tell the GC that specific global references are pinned, or we have to
105 make a copy of the data and return that instead (something JNI supports).
108 Local reference tracking
110 The table of local references can be stored on the interpreted stack or
111 in a parallel data structure (one per thread).
113 *** Approach #1: use the interpreted stack
115 The easiest place to tuck it is between the frame ptr and the first saved
116 register, which is always in0. (See the ASCII art in Stack.h.) We can
117 shift the "VM-specific goop" and frame ptr down, effectively inserting
118 the JNI local refs in the space normally occupied by local variables.
120 (Three things are accessed from the frame pointer:
121 (1) framePtr[N] is register vN, used to get at "ins" and "locals".
122 (2) framePtr - sizeof(StackSaveArea) is the VM frame goop.
123 (3) framePtr - sizeof(StackSaveArea) - numOuts is where the "outs" go.
124 The only thing that isn't determined by an offset from the current FP
125 is the previous frame. However, tucking things below the previous frame
126 can be problematic because the "outs" of the previous frame overlap with
127 the "ins" of the current frame. If the "ins" are altered they must be
128 restored before we return. For a native method call, the easiest and
129 safest thing to disrupt is #1, because there are no locals and the "ins"
130 are all copied to the native stack.)
132 We can implement Push/PopLocalFrame with the existing stack frame calls,
133 making sure we copy some goop from the previous frame (notably the method
134 ptr, so that dvmGetCurrentJNIMethod() doesn't require extra effort).
136 We can pre-allocate the storage at the time the stack frame is first
137 set up, but we have to be careful. When calling from interpreted code
138 the frame ptr points directly at the arguments we're passing, but we can
139 offset the args pointer when calling the native bridge.
141 To manage the local ref collection, we need to be able to find three
142 things: (1) the start of the region, (2) the end of the region, and (3)
143 the next available entry. The last is only required for quick adds.
144 We currently have two easily-accessible pointers, the current FP and the
145 previous frame's FP. (The "stack pointer" shown in the ASCII art doesn't
146 actually exist in the interpreted world.)
148 We can't use the current FP to find the first "in", because we want to
149 insert the variable-sized local refs table between them. It's awkward
150 to use the previous frame's FP because native methods invoked via
151 dvmCallMethod() or dvmInvokeMethod() don't have "ins", but native methods
152 invoked from interpreted code do. We can either track the local refs
153 table size with a field in the stack frame, or insert unnecessary items
154 so that all native stack frames have "ins".
156 Assuming we can find the region bounds, we still need pointer #3
157 for an efficient implementation. This can be stored in an otherwise
158 unused-for-native field in the frame goop.
160 When we run out of room we have to make more space. If we start allocating
161 locals immediately below in0 and grow downward, we will detect end-of-space
162 by running into the current frame's FP. We then memmove() the goop down
163 (memcpy if we guarantee the additional size is larger than the frame).
164 This is nice because we only have to move sizeof(StackSaveArea) bytes
167 Stack walking should be okay so long as nothing tries to access the
168 "ins" by an offset from the FP. In theory the "ins" could be read by
169 the debugger or SIGQUIT handler looking for "this" or other arguments,
170 but in practice this behavior isn't expected to work for native methods,
171 so we can simply disallow it.
173 A conservative GC can just scan the entire stack from top to bottom to find
174 all references. An exact GC will need to understand the actual layout.
176 *** Approach #2: use a parallel stack
178 Each Thread/JNIEnv points to a ReferenceTable struct. The struct
179 has a system-heap-allocated array of references and a pointer to the
180 next-available entry ("nextEntry").
182 Each stack frame has a pointer to what it sees as the "top" element in the
183 array (we can double-up the "currentPc" field). This is set to "nextEntry"
184 when the frame is pushed on. As local references are added or removed,
185 "nextEntry" is updated.
187 We implement Push/PopLocalFrame with actual stack frames. Before a JNI
188 frame gets popped, we set "nextEntry" to the "top" pointer of the current
189 frame, effectively releasing the references.
191 The GC will scan all references from the start of the table to the
196 All approaches will return a failure result when they run out of local
197 reference space. For #1 that means blowing out the stack, for #2 it's
198 running out of room in the array.
200 Compared to #1, approach #2:
201 - Needs only one pointer in the stack frame goop.
202 - Makes pre-allocating storage unnecessary.
203 - Doesn't contend with interpreted stack depth for space. In most
204 cases, if something blows out the local ref storage, it's because the
205 JNI code was misbehaving rather than called from way down.
206 - Allows the GC to do a linear scan per thread in a buffer that is 100%
207 references. The GC can be slightly less smart when scanning the stack.
208 - Will be easier to work with if we combine native and interpeted stacks.
210 - Isn't as clean, especially when popping frames, since we have to do
211 explicit work. Fortunately we only have to do it when popping native
212 method calls off, so it doesn't add overhead to interpreted code paths.
213 - Is awkward to expand dynamically. We'll want to pre-allocate the full
214 amount of space; this is fine, since something on the order of 1KB should
215 be plenty. The JNI spec allows us to limit this.
216 - Requires the GC to scan even more memory. With the references embedded
217 in the stack we get better locality of reference.
222 static const struct JNINativeInterface gNativeInterface;
223 static jobject addGlobalReference(Object* obj);
226 #ifdef WITH_JNI_STACK_CHECK
227 # define COMPUTE_STACK_SUM(_self) computeStackSum(_self);
228 # define CHECK_STACK_SUM(_self) checkStackSum(_self);
229 static void computeStackSum(Thread* self);
230 static void checkStackSum(Thread* self);
232 # define COMPUTE_STACK_SUM(_self) ((void)0)
233 # define CHECK_STACK_SUM(_self) ((void)0)
238 * ===========================================================================
240 * ===========================================================================
244 * Bridge to calling a JNI function. This ideally gets some help from
245 * assembly language code in dvmPlatformInvoke, because the arguments
246 * must be pushed into the native stack as if we were calling a <stdarg.h>
249 * The number of values in "args" must match method->insSize.
251 * This is generally just set up by the resolver and then called through.
252 * We don't call here explicitly. This takes the same arguments as all
253 * of the "internal native" methods.
255 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method,
260 assert(method->insns != NULL);
263 //LOGI("JNI calling %p (%s.%s %s):\n", method->insns,
264 // method->clazz->descriptor, method->name, method->signature);
265 //for (i = 0; i < method->insSize; i++)
266 // LOGI(" %d: 0x%08x\n", i, args[i]);
268 oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
270 COMPUTE_STACK_SUM(self);
271 // TODO: should we be converting 'this' to a local ref?
272 dvmPlatformInvoke(self->jniEnv,
273 dvmIsStaticMethod(method) ? method->clazz : NULL,
274 method->jniArgInfo, method->insSize, args, method->shorty,
275 (void*)method->insns, pResult);
276 CHECK_STACK_SUM(self);
278 dvmChangeStatus(self, oldStatus);
282 * Alternate call bridge for the unusual case of a synchronized native method.
284 * Lock the object, then call through the usual function.
286 void dvmCallSynchronizedJNIMethod(const u4* args, JValue* pResult,
287 const Method* method, Thread* self)
291 assert(dvmIsSynchronizedMethod(method));
293 if (dvmIsStaticMethod(method))
294 lockObj = (Object*) method->clazz;
296 lockObj = (Object*) args[0];
298 LOGVV("Calling %s.%s: locking %p (%s)\n",
299 method->clazz->descriptor, method->name,
300 lockObj, lockObj->clazz->descriptor);
302 dvmLockObject(self, lockObj);
303 dvmCallJNIMethod(args, pResult, method, self);
304 dvmUnlockObject(self, lockObj);
308 * Extract the return type enum from the "jniArgInfo" field.
310 DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
312 return (jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT;
317 * ===========================================================================
319 * ===========================================================================
323 * Entry/exit processing for all JNI calls.
325 * If TRUSTED_JNIENV is set, we get to skip the (curiously expensive)
326 * thread-local storage lookup on our Thread*. If the caller has passed
327 * the wrong JNIEnv in, we're going to be accessing unsynchronized
328 * structures from more than one thread, and things are going to fail
329 * in bizarre ways. This is only sensible if the native code has been
330 * fully exercised with CheckJNI enabled.
332 #define TRUSTED_JNIENV
333 #ifdef TRUSTED_JNIENV
334 # define JNI_ENTER() \
335 Thread* _self = ((JNIEnvExt*)env)->self; \
336 CHECK_STACK_SUM(_self); \
337 dvmChangeStatus(_self, THREAD_RUNNING)
339 # define JNI_ENTER() \
340 Thread* _self = dvmThreadSelf(); \
341 UNUSED_PARAMETER(env); \
342 CHECK_STACK_SUM(_self); \
343 dvmChangeStatus(_self, THREAD_RUNNING)
346 dvmChangeStatus(_self, THREAD_NATIVE); \
347 COMPUTE_STACK_SUM(_self)
349 #define kGlobalRefsTableInitialSize 512
350 #define kGlobalRefsTableMaxSize 51200 /* arbitrary, must be < 64K */
351 #define kGrefWaterInterval 100
352 #define kTrackGrefUsage true
354 #define kPinTableInitialSize 16
355 #define kPinTableMaxSize 1024
356 #define kPinComplainThreshold 10
359 * Allocate the global references table, and look up some classes for
360 * the benefit of direct buffer access.
362 bool dvmJniStartup(void)
364 if (!dvmInitReferenceTable(&gDvm.jniGlobalRefTable,
365 kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize))
368 dvmInitMutex(&gDvm.jniGlobalRefLock);
369 gDvm.jniGlobalRefLoMark = 0;
370 gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
372 if (!dvmInitReferenceTable(&gDvm.jniPinRefTable,
373 kPinTableInitialSize, kPinTableMaxSize))
376 dvmInitMutex(&gDvm.jniPinRefLock);
379 * Look up and cache pointers to some direct buffer classes, fields,
384 ClassObject* platformAddressClass =
385 dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddress;");
386 ClassObject* platformAddressFactoryClass =
387 dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddressFactory;");
388 ClassObject* directBufferClass =
389 dvmFindSystemClassNoInit("Lorg/apache/harmony/nio/internal/DirectBuffer;");
390 ClassObject* readWriteBufferClass =
391 dvmFindSystemClassNoInit("Ljava/nio/ReadWriteDirectByteBuffer;");
392 ClassObject* bufferClass =
393 dvmFindSystemClassNoInit("Ljava/nio/Buffer;");
395 if (platformAddressClass == NULL || platformAddressFactoryClass == NULL ||
396 directBufferClass == NULL || readWriteBufferClass == NULL ||
399 LOGE("Unable to find internal direct buffer classes\n");
402 /* needs to be a global ref so CheckJNI thinks we're allowed to see it */
403 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer =
404 addGlobalReference((Object*) directBufferClass);
405 gDvm.classJavaNioReadWriteDirectByteBuffer = readWriteBufferClass;
408 * We need a Method* here rather than a vtable offset, because
409 * DirectBuffer is an interface class.
411 meth = dvmFindVirtualMethodByDescriptor(
412 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer,
413 "getEffectiveAddress",
414 "()Lorg/apache/harmony/luni/platform/PlatformAddress;");
416 LOGE("Unable to find PlatformAddress.getEffectiveAddress\n");
419 gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress = meth;
421 meth = dvmFindVirtualMethodByDescriptor(platformAddressClass,
424 LOGE("Unable to find PlatformAddress.toLong\n");
427 gDvm.voffOrgApacheHarmonyLuniPlatformPlatformAddress_toLong =
430 meth = dvmFindDirectMethodByDescriptor(platformAddressFactoryClass,
432 "(I)Lorg/apache/harmony/luni/platform/PlatformAddress;");
434 LOGE("Unable to find PlatformAddressFactory.on\n");
437 gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on = meth;
439 meth = dvmFindDirectMethodByDescriptor(readWriteBufferClass,
441 "(Lorg/apache/harmony/luni/platform/PlatformAddress;II)V");
443 LOGE("Unable to find ReadWriteDirectByteBuffer.<init>\n");
446 gDvm.methJavaNioReadWriteDirectByteBuffer_init = meth;
448 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr =
449 dvmFindFieldOffset(platformAddressClass, "osaddr", "I");
450 if (gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr < 0) {
451 LOGE("Unable to find PlatformAddress.osaddr\n");
455 gDvm.offJavaNioBuffer_capacity =
456 dvmFindFieldOffset(bufferClass, "capacity", "I");
457 if (gDvm.offJavaNioBuffer_capacity < 0) {
458 LOGE("Unable to find Buffer.capacity\n");
462 gDvm.offJavaNioBuffer_effectiveDirectAddress =
463 dvmFindFieldOffset(bufferClass, "effectiveDirectAddress", "I");
464 if (gDvm.offJavaNioBuffer_effectiveDirectAddress < 0) {
465 LOGE("Unable to find Buffer.effectiveDirectAddress\n");
473 * Free the global references table.
475 void dvmJniShutdown(void)
477 dvmClearReferenceTable(&gDvm.jniGlobalRefTable);
482 * Find the JNIEnv associated with the current thread.
484 * Currently stored in the Thread struct. Could also just drop this into
485 * thread-local storage.
487 JNIEnvExt* dvmGetJNIEnvForThread(void)
489 Thread* self = dvmThreadSelf();
492 return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
496 * Create a new JNIEnv struct and add it to the VM's list.
498 * "self" will be NULL for the main thread, since the VM hasn't started
499 * yet; the value will be filled in later.
501 JNIEnv* dvmCreateJNIEnv(Thread* self)
503 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
507 // LOGI("Ent CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
511 newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
512 newEnv->funcTable = &gNativeInterface;
514 newEnv->forceDataCopy = vm->forceDataCopy;
516 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
517 assert(newEnv->envThreadId != 0);
519 /* make it obvious if we fail to initialize these later */
520 newEnv->envThreadId = 0x77777775;
521 newEnv->self = (Thread*) 0x77777779;
524 dvmUseCheckedJniEnv(newEnv);
526 dvmLockMutex(&vm->envListLock);
528 /* insert at head of list */
529 newEnv->next = vm->envList;
530 assert(newEnv->prev == NULL);
531 if (vm->envList == NULL) // rare, but possible
532 vm->envList = newEnv;
534 vm->envList->prev = newEnv;
535 vm->envList = newEnv;
537 dvmUnlockMutex(&vm->envListLock);
540 // LOGI("Xit CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
541 return (JNIEnv*) newEnv;
545 * Remove a JNIEnv struct from the list and free it.
547 void dvmDestroyJNIEnv(JNIEnv* env)
549 JNIEnvExt* extEnv = (JNIEnvExt*) env;
550 JavaVMExt* vm = extEnv->vm;
556 self = dvmThreadSelf();
557 assert(self != NULL);
559 //LOGI("Ent DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
561 dvmLockMutex(&vm->envListLock);
563 if (extEnv == vm->envList) {
564 assert(extEnv->prev == NULL);
565 vm->envList = extEnv->next;
567 assert(extEnv->prev != NULL);
568 extEnv->prev->next = extEnv->next;
570 if (extEnv->next != NULL)
571 extEnv->next->prev = extEnv->prev;
573 dvmUnlockMutex(&extEnv->vm->envListLock);
576 //LOGI("Xit DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
581 * Retrieve the ReferenceTable struct for the current thread.
583 * Going through "env" rather than dvmThreadSelf() is faster but will
584 * get weird if the JNI code is passing the wrong JNIEnv around.
586 static inline ReferenceTable* getLocalRefTable(JNIEnv* env)
588 //return &dvmThreadSelf()->jniLocalRefTable;
589 return &((JNIEnvExt*)env)->self->jniLocalRefTable;
593 * Add a local reference for an object to the current stack frame. When
594 * the native function returns, the reference will be discarded.
596 * We need to allow the same reference to be added multiple times.
598 * This will be called on otherwise unreferenced objects. We cannot do
599 * GC allocations here, and it's best if we don't grab a mutex.
601 * Returns the local reference (currently just the same pointer that was
602 * passed in), or NULL on failure.
604 static jobject addLocalReference(JNIEnv* env, Object* obj)
609 ReferenceTable* pRefTable = getLocalRefTable(env);
611 if (!dvmAddToReferenceTable(pRefTable, obj)) {
612 dvmDumpReferenceTable(pRefTable, "JNI local");
613 LOGE("Failed adding to JNI local ref table (has %d entries)\n",
614 (int) dvmReferenceTableEntries(pRefTable));
615 dvmDumpThread(dvmThreadSelf(), false);
616 dvmAbort(); // spec says call FatalError; this is equivalent
618 LOGVV("LREF add %p (%s.%s)\n", obj,
619 dvmGetCurrentJNIMethod()->clazz->descriptor,
620 dvmGetCurrentJNIMethod()->name);
627 * Convert an indirect reference to an Object reference. The indirect
628 * reference may be local, global, or weak-global.
630 * If "jobj" is NULL or an invalid indirect reference, this returns NULL.
632 * [ this is currently a no-op ]
634 Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj)
636 return (Object*) jobj;
640 * Ensure that at least "capacity" references can be held in the local
641 * refs table of the current thread.
643 static bool ensureLocalCapacity(JNIEnv* env, int capacity)
645 ReferenceTable* pRefTable = getLocalRefTable(env);
647 return (kJniLocalRefMax - (pRefTable->nextEntry - pRefTable->table) >= capacity);
651 * Explicitly delete a reference from the local list.
653 static void deleteLocalReference(JNIEnv* env, jobject jobj)
658 ReferenceTable* pRefTable = getLocalRefTable(env);
659 Thread* self = dvmThreadSelf();
660 Object** top = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefTop;
662 if (!dvmRemoveFromReferenceTable(pRefTable, top, (Object*) jobj)) {
664 * Attempting to delete a local reference that is not in the
665 * topmost local reference frame is a no-op. DeleteLocalRef returns
666 * void and doesn't throw any exceptions, but we should probably
667 * complain about it so the user will notice that things aren't
668 * going quite the way they expect.
670 LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry (valid=%d)\n",
671 jobj, dvmIsValidObject((Object*) jobj));
676 * Add a global reference for an object.
678 * We may add the same object more than once. Add/remove calls are paired,
679 * so it needs to appear on the list multiple times.
681 static jobject addGlobalReference(Object* obj)
686 //LOGI("adding obj=%p\n", obj);
687 //dvmDumpThread(dvmThreadSelf(), false);
689 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangClass) {
690 ClassObject* clazz = (ClassObject*) obj;
692 LOGI("Adding global ref on class %s\n", clazz->descriptor);
693 dvmDumpThread(dvmThreadSelf(), false);
695 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
696 StringObject* strObj = (StringObject*) obj;
697 char* str = dvmCreateCstrFromString(strObj);
698 if (strcmp(str, "sync-response") == 0) {
700 LOGI("Adding global ref on string '%s'\n", str);
701 dvmDumpThread(dvmThreadSelf(), false);
706 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
707 ArrayObject* arrayObj = (ArrayObject*) obj;
708 if (arrayObj->length == 8192 &&
709 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400)
711 LOGI("Adding global ref on byte array %p (len=%d)\n",
712 arrayObj, arrayObj->length);
713 dvmDumpThread(dvmThreadSelf(), false);
717 dvmLockMutex(&gDvm.jniGlobalRefLock);
720 * Expanding the table should happen rarely, so I'm not overly
721 * concerned about the performance impact of copying the old list
722 * over. We shouldn't see one-time activity spikes, so freeing
723 * up storage shouldn't be required.
725 * Throwing an exception on failure is problematic, because JNI code
726 * may not be expecting an exception, and things sort of cascade. We
727 * want to have a hard limit to catch leaks during debugging, but this
728 * otherwise needs to expand until memory is consumed. As a practical
729 * matter, if we have many thousands of global references, chances are
730 * we're either leaking global ref table entries or we're going to
731 * run out of space in the GC heap.
733 if (!dvmAddToReferenceTable(&gDvm.jniGlobalRefTable, (Object*)obj)) {
734 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
735 LOGE("Failed adding to JNI global ref table (%d entries)\n",
736 (int) dvmReferenceTableEntries(&gDvm.jniGlobalRefTable));
740 LOGVV("GREF add %p (%s.%s)\n", obj,
741 dvmGetCurrentJNIMethod()->clazz->descriptor,
742 dvmGetCurrentJNIMethod()->name);
744 /* GREF usage tracking; should probably be disabled for production env */
745 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
746 int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
747 if (count > gDvm.jniGlobalRefHiMark) {
748 LOGD("GREF has increased to %d\n", count);
749 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
750 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
752 /* watch for "excessive" use; not generally appropriate */
753 if (count >= gDvm.jniGrefLimit) {
754 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
756 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable,"JNI global");
757 LOGE("Excessive JNI global references (%d)\n", count);
760 LOGW("Excessive JNI global references (%d)\n", count);
767 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
768 return (jobject) obj;
772 * Remove a global reference. In most cases it's the entry most recently
773 * added, which makes this pretty quick.
775 * Thought: if it's not the most recent entry, just null it out. When we
776 * fill up, do a compaction pass before we expand the list.
778 static void deleteGlobalReference(jobject jobj)
783 dvmLockMutex(&gDvm.jniGlobalRefLock);
785 if (!dvmRemoveFromReferenceTable(&gDvm.jniGlobalRefTable,
786 gDvm.jniGlobalRefTable.table, jobj))
788 LOGW("JNI: DeleteGlobalRef(%p) failed to find entry (valid=%d)\n",
789 jobj, dvmIsValidObject((Object*) jobj));
793 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
794 int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
795 if (count < gDvm.jniGlobalRefLoMark) {
796 LOGD("GREF has decreased to %d\n", count);
797 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
798 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
803 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
807 * Objects don't currently move, so we just need to create a reference
808 * that will ensure the array object isn't collected.
810 * We use a separate reference table, which is part of the GC root set.
812 static void pinPrimitiveArray(ArrayObject* arrayObj)
814 if (arrayObj == NULL)
817 dvmLockMutex(&gDvm.jniPinRefLock);
818 if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
819 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
820 LOGE("Failed adding to JNI pinned array ref table (%d entries)\n",
821 (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
822 dvmDumpThread(dvmThreadSelf(), false);
827 * If we're watching global ref usage, also keep an eye on these.
829 * The total number of pinned primitive arrays should be pretty small.
830 * A single array should not be pinned more than once or twice; any
831 * more than that is a strong indicator that a Release function is
834 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
836 Object** ppObj = gDvm.jniPinRefTable.table;
837 while (ppObj < gDvm.jniPinRefTable.nextEntry) {
838 if (*ppObj++ == (Object*) arrayObj)
842 if (count > kPinComplainThreshold) {
843 LOGW("JNI: pin count on array %p (%s) is now %d\n",
844 arrayObj, arrayObj->obj.clazz->descriptor, count);
849 dvmUnlockMutex(&gDvm.jniPinRefLock);
853 * Un-pin the array object. If an object was pinned twice, it must be
854 * unpinned twice before it's free to move.
856 static void unpinPrimitiveArray(ArrayObject* arrayObj)
858 if (arrayObj == NULL)
861 dvmLockMutex(&gDvm.jniPinRefLock);
862 if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
863 gDvm.jniPinRefTable.table, (Object*) arrayObj))
865 LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)\n",
866 arrayObj, dvmIsValidObject((Object*) arrayObj));
871 dvmUnlockMutex(&gDvm.jniPinRefLock);
875 * GC helper function to mark all JNI global references.
877 * We're currently handling the "pin" table here too.
879 void dvmGcMarkJniGlobalRefs()
883 dvmLockMutex(&gDvm.jniGlobalRefLock);
885 op = gDvm.jniGlobalRefTable.table;
886 while ((uintptr_t)op < (uintptr_t)gDvm.jniGlobalRefTable.nextEntry) {
887 dvmMarkObjectNonNull(*(op++));
890 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
893 dvmLockMutex(&gDvm.jniPinRefLock);
895 op = gDvm.jniPinRefTable.table;
896 while ((uintptr_t)op < (uintptr_t)gDvm.jniPinRefTable.nextEntry) {
897 dvmMarkObjectNonNull(*(op++));
900 dvmUnlockMutex(&gDvm.jniPinRefLock);
905 * Determine if "obj" appears in the argument list for the native method.
907 * We use the "shorty" signature to determine which argument slots hold
910 static bool findInArgList(Thread* self, Object* obj)
919 * Back up over JNI PushLocalFrame frames. This works because the
920 * previous frame on the interpreted stack is either a break frame
921 * (if we called here via native code) or an interpreted method (if
922 * we called here via the interpreter). In both cases the method
923 * pointer won't match.
925 StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
926 meth = saveArea->method;
927 if (meth != SAVEAREA_FROM_FP(saveArea->prevFrame)->method)
929 fp = saveArea->prevFrame;
932 LOGVV("+++ scanning %d args in %s (%s)\n",
933 meth->insSize, meth->name, meth->shorty);
934 const char* shorty = meth->shorty +1; /* skip return type char */
935 for (i = 0; i < meth->insSize; i++) {
936 if (i == 0 && !dvmIsStaticMethod(meth)) {
937 /* first arg is "this" ref, not represented in "shorty" */
938 if (fp[i] == (u4) obj)
941 /* if this is a reference type, see if it matches */
944 if (fp[i] == (u4) obj)
952 LOGE("Whoops! ran off the end of %s (%d)\n",
953 meth->shorty, meth->insSize);
956 if (fp[i] == (u4) obj)
957 LOGI("NOTE: ref %p match on arg type %c\n", obj, *shorty);
965 * For static methods, we also pass a class pointer in.
967 if (dvmIsStaticMethod(meth)) {
968 //LOGI("+++ checking class pointer in %s\n", meth->name);
969 if ((void*)obj == (void*)meth->clazz)
976 * Verify that a reference passed in from native code is one that the
977 * code is allowed to have.
979 * It's okay for native code to pass us a reference that:
980 * - was just passed in as an argument when invoked by native code
981 * - was returned to it from JNI (and is now in the JNI local refs table)
982 * - is present in the JNI global refs table
983 * The first one is a little awkward. The latter two are just table lookups.
985 * Used by -Xcheck:jni and GetObjectRefType.
987 * NOTE: in the current VM, global and local references are identical. If
988 * something is both global and local, we can't tell them apart, and always
991 jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj)
993 ReferenceTable* pRefTable = getLocalRefTable(env);
994 Thread* self = dvmThreadSelf();
999 if (findInArgList(self, jobj)) {
1000 //LOGI("--- REF found %p on stack\n", jobj);
1001 return JNILocalRefType;
1005 //top = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefTop;
1006 if (dvmFindInReferenceTable(pRefTable, pRefTable->table, jobj) != NULL) {
1007 //LOGI("--- REF found %p in locals\n", jobj);
1008 return JNILocalRefType;
1012 dvmLockMutex(&gDvm.jniGlobalRefLock);
1013 if (dvmFindInReferenceTable(&gDvm.jniGlobalRefTable,
1014 gDvm.jniGlobalRefTable.table, jobj))
1016 //LOGI("--- REF found %p in globals\n", jobj);
1017 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
1018 return JNIGlobalRefType;
1020 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
1023 return JNIInvalidRefType;
1027 * Register a method that uses JNI calling conventions.
1029 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
1030 const char* signature, void* fnPtr)
1033 bool result = false;
1038 method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
1040 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
1041 if (method == NULL) {
1042 LOGW("ERROR: Unable to find decl for native %s.%s %s\n",
1043 clazz->descriptor, methodName, signature);
1047 if (!dvmIsNativeMethod(method)) {
1048 LOGW("Unable to register: not native: %s.%s %s\n",
1049 clazz->descriptor, methodName, signature);
1053 if (method->nativeFunc != dvmResolveNativeMethod) {
1054 LOGW("Warning: %s.%s %s was already registered/resolved?\n",
1055 clazz->descriptor, methodName, signature);
1056 /* keep going, I guess */
1059 dvmUseJNIBridge(method, fnPtr);
1061 LOGV("JNI-registered %s.%s %s\n", clazz->descriptor, methodName,
1070 * Returns "true" if CheckJNI is enabled in the VM.
1072 static bool dvmIsCheckJNIEnabled(void)
1074 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
1075 return vm->useChecked;
1079 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
1080 * to point at the actual function.
1082 void dvmUseJNIBridge(Method* method, void* func)
1084 if (dvmIsCheckJNIEnabled()) {
1085 if (dvmIsSynchronizedMethod(method))
1086 dvmSetNativeFunc(method, dvmCheckCallSynchronizedJNIMethod, func);
1088 dvmSetNativeFunc(method, dvmCheckCallJNIMethod, func);
1090 if (dvmIsSynchronizedMethod(method))
1091 dvmSetNativeFunc(method, dvmCallSynchronizedJNIMethod, func);
1093 dvmSetNativeFunc(method, dvmCallJNIMethod, func);
1098 * Get the method currently being executed by examining the interp stack.
1100 const Method* dvmGetCurrentJNIMethod(void)
1102 assert(dvmThreadSelf() != NULL);
1104 void* fp = dvmThreadSelf()->curFrame;
1105 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
1107 assert(meth != NULL);
1108 assert(dvmIsNativeMethod(meth));
1114 * Track a JNI MonitorEnter in the current thread.
1116 * The goal is to be able to "implicitly" release all JNI-held monitors
1117 * when the thread detaches.
1119 * Monitors may be entered multiple times, so we add a new entry for each
1120 * enter call. It would be more efficient to keep a counter. At present
1121 * there's no real motivation to improve this however.
1123 static void trackMonitorEnter(Thread* self, Object* obj)
1125 static const int kInitialSize = 16;
1126 ReferenceTable* refTable = &self->jniMonitorRefTable;
1128 /* init table on first use */
1129 if (refTable->table == NULL) {
1130 assert(refTable->maxEntries == 0);
1132 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
1133 LOGE("Unable to initialize monitor tracking table\n");
1138 if (!dvmAddToReferenceTable(refTable, obj)) {
1139 /* ran out of memory? could throw exception instead */
1140 LOGE("Unable to add entry to monitor tracking table\n");
1143 LOGVV("--- added monitor %p\n", obj);
1149 * Track a JNI MonitorExit in the current thread.
1151 static void trackMonitorExit(Thread* self, Object* obj)
1153 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
1155 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
1156 LOGE("JNI monitor %p not found in tracking list\n", obj);
1159 LOGVV("--- removed monitor %p\n", obj);
1164 * Release all monitors held by the jniMonitorRefTable list.
1166 void dvmReleaseJniMonitors(Thread* self)
1168 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
1169 Object** top = pRefTable->table;
1174 Object** ptr = pRefTable->nextEntry;
1175 while (--ptr >= top) {
1176 if (!dvmUnlockObject(self, *ptr)) {
1177 LOGW("Unable to unlock monitor %p at thread detach\n", *ptr);
1179 LOGVV("--- detach-releasing monitor %p\n", *ptr);
1184 pRefTable->nextEntry = pRefTable->table;
1187 #ifdef WITH_JNI_STACK_CHECK
1189 * Compute a CRC on the entire interpreted stack.
1191 * Would be nice to compute it on "self" as well, but there are parts of
1192 * the Thread that can be altered by other threads (e.g. prev/next pointers).
1194 static void computeStackSum(Thread* self)
1196 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
1197 u4 crc = dvmInitCrc32();
1199 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
1200 self->stackCrc = crc;
1204 * Compute a CRC on the entire interpreted stack, and compare it to what
1205 * we previously computed.
1207 * We can execute JNI directly from native code without calling in from
1208 * interpreted code during VM initialization and immediately after JNI
1209 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather
1210 * than catching these cases we just ignore them here, which is marginally
1211 * less accurate but reduces the amount of code we have to touch with #ifdefs.
1213 static void checkStackSum(Thread* self)
1215 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
1218 stackCrc = self->stackCrc;
1220 crc = dvmInitCrc32();
1221 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
1222 if (crc != stackCrc) {
1223 const Method* meth = dvmGetCurrentJNIMethod();
1224 if (dvmComputeExactFrameDepth(self->curFrame) == 1) {
1225 LOGD("JNI: bad stack CRC (0x%08x) -- okay during init\n",
1227 } else if (strcmp(meth->name, "nativeLoad") == 0 &&
1228 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0))
1230 LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad\n",
1233 LOGW("JNI: bad stack CRC (%08x vs %08x)\n", crc, stackCrc);
1237 self->stackCrc = (u4) -1; /* make logic errors more noticeable */
1243 * ===========================================================================
1244 * JNI implementation
1245 * ===========================================================================
1249 * Return the version of the native method interface.
1251 static jint GetVersion(JNIEnv* env)
1255 * There is absolutely no need to toggle the mode for correct behavior.
1256 * However, it does provide native code with a simple "suspend self
1257 * if necessary" call.
1260 return JNI_VERSION_1_6;
1264 * Create a new class from a bag of bytes.
1266 * This is not currently supported within Dalvik.
1268 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1269 const jbyte* buf, jsize bufLen)
1271 UNUSED_PARAMETER(name);
1272 UNUSED_PARAMETER(loader);
1273 UNUSED_PARAMETER(buf);
1274 UNUSED_PARAMETER(bufLen);
1277 LOGW("JNI DefineClass is not supported\n");
1283 * Find a class by name.
1285 * We have to use the "no init" version of FindClass here, because we might
1286 * be getting the class prior to registering native methods that will be
1289 * We need to get the class loader associated with the current native
1290 * method. If there is no native method, e.g. we're calling this from native
1291 * code right after creating the VM, the spec says we need to use the class
1292 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1293 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1294 * We can't get that until after the VM has initialized though.
1296 static jclass FindClass(JNIEnv* env, const char* name)
1300 const Method* thisMethod;
1302 jclass jclazz = NULL;
1304 char* descriptor = NULL;
1306 thisMethod = dvmGetCurrentJNIMethod();
1307 assert(thisMethod != NULL);
1309 descriptor = dvmNameToDescriptor(name);
1310 if (descriptor == NULL) {
1315 //Thread* self = dvmThreadSelf();
1316 if (_self->classLoaderOverride != NULL) {
1317 /* hack for JNI_OnLoad */
1318 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1319 loader = _self->classLoaderOverride;
1320 } else if (thisMethod == gDvm.methFakeNativeEntry) {
1321 /* start point of invocation interface */
1322 if (!gDvm.initializing)
1323 loader = dvmGetSystemClassLoader();
1327 loader = thisMethod->clazz->classLoader;
1330 clazz = dvmFindClassNoInit(descriptor, loader);
1331 jclazz = addLocalReference(env, (Object*) clazz);
1341 * Return the superclass of a class.
1343 static jclass GetSuperclass(JNIEnv* env, jclass jclazz)
1348 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1352 jsuper = addLocalReference(env, (Object*)clazz->super);
1358 * Determine whether an object of clazz1 can be safely cast to clazz2.
1360 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1362 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2)
1366 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1);
1367 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2);
1369 jboolean result = dvmInstanceof(clazz1, clazz2);
1376 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1378 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod)
1382 Object* method = dvmDecodeIndirectRef(env, jmethod);
1383 methodID = (jmethodID) dvmGetMethodFromReflectObj(method);
1389 * Given a java.lang.reflect.Field, return a fieldID.
1391 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield)
1395 Object* field = dvmDecodeIndirectRef(env, jfield);
1396 fieldID = (jfieldID) dvmGetFieldFromReflectObj(field);
1402 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1404 * (The "isStatic" field does not appear in the spec.)
1406 * Throws OutOfMemory and returns NULL on failure.
1408 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID,
1412 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
1413 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1414 dvmReleaseTrackedAlloc(obj, NULL);
1415 jobject jobj = addLocalReference(env, obj);
1421 * Convert a fieldID to a java.lang.reflect.Field.
1423 * (The "isStatic" field does not appear in the spec.)
1425 * Throws OutOfMemory and returns NULL on failure.
1427 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID,
1431 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
1432 Object* obj = dvmCreateReflectObjForField(jcls, (Field*) fieldID);
1433 dvmReleaseTrackedAlloc(obj, NULL);
1434 jobject jobj = addLocalReference(env, obj);
1440 * Take this exception and throw it.
1442 static jint Throw(JNIEnv* env, jthrowable jobj)
1449 Object* obj = dvmDecodeIndirectRef(env, jobj);
1450 dvmSetException(_self, obj);
1461 * Constructs an exception object from the specified class with the message
1462 * specified by "message", and throws it.
1464 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message)
1468 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1469 dvmThrowExceptionByClass(clazz, message);
1470 // TODO: should return failure if this didn't work (e.g. OOM)
1477 * If an exception is being thrown, return the exception object. Otherwise,
1480 * TODO: if there is no pending exception, we should be able to skip the
1481 * enter/exit checks. If we find one, we need to enter and then re-fetch
1482 * the exception (in case it got moved by a compacting GC).
1484 static jthrowable ExceptionOccurred(JNIEnv* env)
1489 jobject localException;
1491 exception = dvmGetException(_self);
1492 localException = addLocalReference(env, exception);
1493 if (localException == NULL && exception != NULL) {
1495 * We were unable to add a new local reference, and threw a new
1496 * exception. We can't return "exception", because it's not a
1497 * local reference. So we have to return NULL, indicating that
1498 * there was no exception, even though it's pretty much raining
1499 * exceptions in here.
1501 LOGW("JNI WARNING: addLocal/exception combo\n");
1505 return localException;
1509 * Print an exception and stack trace to stderr.
1511 static void ExceptionDescribe(JNIEnv* env)
1515 Object* exception = dvmGetException(_self);
1516 if (exception != NULL) {
1517 dvmPrintExceptionStackTrace();
1519 LOGI("Odd: ExceptionDescribe called, but no exception pending\n");
1526 * Clear the exception currently being thrown.
1528 * TODO: we should be able to skip the enter/exit stuff.
1530 static void ExceptionClear(JNIEnv* env)
1533 dvmClearException(_self);
1538 * Kill the VM. This function does not return.
1540 static void FatalError(JNIEnv* env, const char* msg)
1542 //dvmChangeStatus(NULL, THREAD_RUNNING);
1543 LOGE("JNI posting fatal error: %s\n", msg);
1548 * Push a new JNI frame on the stack, with a new set of locals.
1550 * The new frame must have the same method pointer. (If for no other
1551 * reason than FindClass needs it to get the appropriate class loader.)
1553 static jint PushLocalFrame(JNIEnv* env, jint capacity)
1556 int result = JNI_OK;
1557 if (!ensureLocalCapacity(env, capacity) ||
1558 !dvmPushLocalFrame(_self /*dvmThreadSelf()*/, dvmGetCurrentJNIMethod()))
1560 /* yes, OutOfMemoryError, not StackOverflowError */
1561 dvmClearException(_self);
1562 dvmThrowException("Ljava/lang/OutOfMemoryError;",
1563 "out of stack in JNI PushLocalFrame");
1571 * Pop the local frame off. If "result" is not null, add it as a
1572 * local reference on the now-current frame.
1574 static jobject PopLocalFrame(JNIEnv* env, jobject jresult)
1577 Object* result = dvmDecodeIndirectRef(env, jresult);
1578 if (!dvmPopLocalFrame(_self /*dvmThreadSelf()*/)) {
1579 LOGW("JNI WARNING: too many PopLocalFrame calls\n");
1580 dvmClearException(_self);
1581 dvmThrowException("Ljava/lang/RuntimeException;",
1582 "too many PopLocalFrame calls");
1584 jresult = addLocalReference(env, result);
1590 * Add a reference to the global list.
1592 static jobject NewGlobalRef(JNIEnv* env, jobject jobj)
1595 Object* obj = dvmDecodeIndirectRef(env, jobj);
1596 jobject retval = addGlobalReference(obj);
1602 * Delete a reference from the global list.
1604 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef)
1607 deleteGlobalReference(jglobalRef);
1613 * Add a reference to the local list.
1615 static jobject NewLocalRef(JNIEnv* env, jobject jref)
1618 Object* obj = dvmDecodeIndirectRef(env, jref);
1619 jobject retval = addLocalReference(env, obj);
1625 * Delete a reference from the local list.
1627 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef)
1630 deleteLocalReference(env, jlocalRef);
1635 * Ensure that the local references table can hold at least this many
1638 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity)
1641 bool okay = ensureLocalCapacity(env, capacity);
1643 dvmThrowException("Ljava/lang/OutOfMemoryError;",
1644 "can't ensure local reference capacity");
1655 * Determine whether two Object references refer to the same underlying object.
1657 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2)
1660 Object* obj1 = dvmDecodeIndirectRef(env, jref1);
1661 Object* obj2 = dvmDecodeIndirectRef(env, jref2);
1662 jboolean result = (obj1 == obj2);
1668 * Allocate a new object without invoking any constructors.
1670 static jobject AllocObject(JNIEnv* env, jclass jclazz)
1674 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1677 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1678 assert(dvmCheckException(_self));
1681 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1682 result = addLocalReference(env, newObj);
1690 * Allocate a new object and invoke the supplied constructor.
1692 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...)
1695 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1698 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1699 assert(dvmCheckException(_self));
1702 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1703 result = addLocalReference(env, newObj);
1704 if (newObj != NULL) {
1707 va_start(args, methodID);
1708 dvmCallMethodV(_self, (Method*) methodID, newObj, &unused, args);
1716 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID,
1720 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1723 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1724 result = addLocalReference(env, newObj);
1725 if (newObj != NULL) {
1727 dvmCallMethodV(_self, (Method*) methodID, newObj, &unused, args);
1733 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID,
1737 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1740 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1741 result = addLocalReference(env, newObj);
1742 if (newObj != NULL) {
1744 dvmCallMethodA(_self, (Method*) methodID, newObj, &unused, args);
1752 * Returns the class of an object.
1754 * JNI spec says: obj must not be NULL.
1756 static jclass GetObjectClass(JNIEnv* env, jobject jobj)
1760 assert(jobj != NULL);
1762 Object* obj = dvmDecodeIndirectRef(env, jobj);
1763 jclass jclazz = addLocalReference(env, (Object*) obj->clazz);
1770 * Determine whether "obj" is an instance of "clazz".
1772 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz)
1776 assert(jclazz != NULL);
1783 Object* obj = dvmDecodeIndirectRef(env, jobj);
1784 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1785 result = dvmInstanceof(obj->clazz, clazz);
1793 * Get a method ID for an instance method.
1795 * JNI defines <init> as an instance method, but Dalvik considers it a
1796 * "direct" method, so we have to special-case it here.
1798 * Dalvik also puts all private methods into the "direct" list, so we
1799 * really need to just search both lists.
1801 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,
1806 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1807 jmethodID id = NULL;
1809 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1810 assert(dvmCheckException(_self));
1814 meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1816 /* search private methods and constructors; non-hierarchical */
1817 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1819 if (meth != NULL && dvmIsStaticMethod(meth)) {
1821 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1822 LOGD("GetMethodID: not returning static method %s.%s %s\n",
1823 clazz->descriptor, meth->name, desc);
1829 LOGD("GetMethodID: method not found: %s.%s:%s\n",
1830 clazz->descriptor, name, sig);
1831 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
1835 * The method's class may not be the same as clazz, but if
1836 * it isn't this must be a virtual method and the class must
1837 * be a superclass (and, hence, already initialized).
1840 assert(dvmIsClassInitialized(meth->clazz) ||
1841 dvmIsClassInitializing(meth->clazz));
1843 id = (jmethodID) meth;
1850 * Get a field ID (instance fields).
1852 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,
1853 const char* name, const char* sig)
1857 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1860 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1861 assert(dvmCheckException(_self));
1864 id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1866 LOGD("GetFieldID: unable to find field %s.%s:%s\n",
1867 clazz->descriptor, name, sig);
1868 dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
1876 * Get the method ID for a static method in a class.
1878 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz,
1879 const char* name, const char* sig)
1883 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1886 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1887 assert(dvmCheckException(_self));
1892 meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1894 /* make sure it's static, not virtual+private */
1895 if (meth != NULL && !dvmIsStaticMethod(meth)) {
1897 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1898 LOGD("GetStaticMethodID: "
1899 "not returning nonstatic method %s.%s %s\n",
1900 clazz->descriptor, meth->name, desc);
1906 id = (jmethodID) meth;
1908 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
1916 * Get a field ID (static fields).
1918 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz,
1919 const char* name, const char* sig)
1923 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1926 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1927 assert(dvmCheckException(_self));
1930 id = (jfieldID) dvmFindStaticField(clazz, name, sig);
1932 dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
1939 * Get a static field.
1941 * If we get an object reference, add it to the local refs list.
1943 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
1944 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1947 UNUSED_PARAMETER(jclazz); \
1949 StaticField* sfield = (StaticField*) fieldID; \
1951 if (_isref) { /* only when _ctype==jobject */ \
1952 Object* obj = dvmGetStaticFieldObject(sfield); \
1953 value = (_ctype)(u4)addLocalReference(env, obj); \
1955 value = dvmGetStaticField##_jname(sfield); \
1960 GET_STATIC_TYPE_FIELD(jobject, Object, true);
1961 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1962 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1963 GET_STATIC_TYPE_FIELD(jchar, Char, false);
1964 GET_STATIC_TYPE_FIELD(jshort, Short, false);
1965 GET_STATIC_TYPE_FIELD(jint, Int, false);
1966 GET_STATIC_TYPE_FIELD(jlong, Long, false);
1967 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1968 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1971 * Set a static field.
1973 #define SET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
1974 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1975 jfieldID fieldID, _ctype value) \
1977 UNUSED_PARAMETER(jclazz); \
1979 StaticField* sfield = (StaticField*) fieldID; \
1980 if (_isref) { /* only when _ctype==jobject */ \
1981 Object* valObj = dvmDecodeIndirectRef(env, (jobject)(u4)value); \
1982 dvmSetStaticFieldObject(sfield, valObj); \
1984 dvmSetStaticField##_jname(sfield, value); \
1988 SET_STATIC_TYPE_FIELD(jobject, Object, true);
1989 SET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1990 SET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1991 SET_STATIC_TYPE_FIELD(jchar, Char, false);
1992 SET_STATIC_TYPE_FIELD(jshort, Short, false);
1993 SET_STATIC_TYPE_FIELD(jint, Int, false);
1994 SET_STATIC_TYPE_FIELD(jlong, Long, false);
1995 SET_STATIC_TYPE_FIELD(jfloat, Float, false);
1996 SET_STATIC_TYPE_FIELD(jdouble, Double, false);
1999 * Get an instance field.
2001 * If we get an object reference, add it to the local refs list.
2003 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \
2004 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \
2008 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2009 InstField* field = (InstField*) fieldID; \
2011 if (_isref) { /* only when _ctype==jobject */ \
2012 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
2013 value = (_ctype)(u4)addLocalReference(env, valObj); \
2015 value = dvmGetField##_jname(obj, field->byteOffset); \
2020 GET_TYPE_FIELD(jobject, Object, true);
2021 GET_TYPE_FIELD(jboolean, Boolean, false);
2022 GET_TYPE_FIELD(jbyte, Byte, false);
2023 GET_TYPE_FIELD(jchar, Char, false);
2024 GET_TYPE_FIELD(jshort, Short, false);
2025 GET_TYPE_FIELD(jint, Int, false);
2026 GET_TYPE_FIELD(jlong, Long, false);
2027 GET_TYPE_FIELD(jfloat, Float, false);
2028 GET_TYPE_FIELD(jdouble, Double, false);
2031 * Set an instance field.
2033 #define SET_TYPE_FIELD(_ctype, _jname, _isref) \
2034 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \
2035 jfieldID fieldID, _ctype value) \
2038 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2039 InstField* field = (InstField*) fieldID; \
2040 if (_isref) { /* only when _ctype==jobject */ \
2041 Object* valObj = dvmDecodeIndirectRef(env, (jobject)(u4)value); \
2042 dvmSetFieldObject(obj, field->byteOffset, valObj); \
2044 dvmSetField##_jname(obj, field->byteOffset, value); \
2048 SET_TYPE_FIELD(jobject, Object, true);
2049 SET_TYPE_FIELD(jboolean, Boolean, false);
2050 SET_TYPE_FIELD(jbyte, Byte, false);
2051 SET_TYPE_FIELD(jchar, Char, false);
2052 SET_TYPE_FIELD(jshort, Short, false);
2053 SET_TYPE_FIELD(jint, Int, false);
2054 SET_TYPE_FIELD(jlong, Long, false);
2055 SET_TYPE_FIELD(jfloat, Float, false);
2056 SET_TYPE_FIELD(jdouble, Double, false);
2059 * Make a virtual method call.
2061 * Three versions (..., va_list, jvalue[]) for each return type. If we're
2062 * returning an Object, we have to add it to the local references table.
2064 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
2065 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \
2066 jmethodID methodID, ...) \
2069 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2070 const Method* meth; \
2073 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
2074 if (meth == NULL) { \
2078 va_start(args, methodID); \
2079 dvmCallMethodV(_self, meth, obj, &result, args); \
2082 result.l = addLocalReference(env, result.l); \
2086 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \
2087 jmethodID methodID, va_list args) \
2090 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2091 const Method* meth; \
2093 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
2094 if (meth == NULL) { \
2098 dvmCallMethodV(_self, meth, obj, &result, args); \
2100 result.l = addLocalReference(env, result.l); \
2104 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \
2105 jmethodID methodID, jvalue* args) \
2108 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2109 const Method* meth; \
2111 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
2112 if (meth == NULL) { \
2116 dvmCallMethodA(_self, meth, obj, &result, args); \
2118 result.l = addLocalReference(env, result.l); \
2122 CALL_VIRTUAL(jobject, Object, NULL, result.l, true);
2123 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
2124 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
2125 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
2126 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
2127 CALL_VIRTUAL(jint, Int, 0, result.i, false);
2128 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
2129 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
2130 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
2131 CALL_VIRTUAL(void, Void, , , false);
2134 * Make a "non-virtual" method call. We're still calling a virtual method,
2135 * but this time we're not doing an indirection through the object's vtable.
2136 * The "clazz" parameter defines which implementation of a method we want.
2138 * Three versions (..., va_list, jvalue[]) for each return type.
2140 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
2141 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
2142 jclass jclazz, jmethodID methodID, ...) \
2145 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2146 ClassObject* clazz = \
2147 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
2148 const Method* meth; \
2151 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2152 if (meth == NULL) { \
2156 va_start(args, methodID); \
2157 dvmCallMethodV(_self, meth, obj, &result, args); \
2159 result.l = addLocalReference(env, result.l); \
2164 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
2165 jclass jclazz, jmethodID methodID, va_list args) \
2168 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2169 ClassObject* clazz = \
2170 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
2171 const Method* meth; \
2173 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2174 if (meth == NULL) { \
2178 dvmCallMethodV(_self, meth, obj, &result, args); \
2180 result.l = addLocalReference(env, result.l); \
2184 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2185 jclass jclazz, jmethodID methodID, jvalue* args) \
2188 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2189 ClassObject* clazz = \
2190 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
2191 const Method* meth; \
2193 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2194 if (meth == NULL) { \
2198 dvmCallMethodA(_self, meth, obj, &result, args); \
2200 result.l = addLocalReference(env, result.l); \
2204 CALL_NONVIRTUAL(jobject, Object, NULL, result.l, true);
2205 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2206 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2207 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2208 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2209 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2210 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2211 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2212 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2213 CALL_NONVIRTUAL(void, Void, , , false);
2217 * Call a static method.
2219 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
2220 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \
2221 jmethodID methodID, ...) \
2223 UNUSED_PARAMETER(jclazz); \
2227 va_start(args, methodID); \
2228 dvmCallMethodV(_self, (Method*) methodID, NULL, &result, args); \
2231 result.l = addLocalReference(env, result.l); \
2235 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
2236 jmethodID methodID, va_list args) \
2238 UNUSED_PARAMETER(jclazz); \
2241 dvmCallMethodV(_self, (Method*) methodID, NULL, &result, args); \
2243 result.l = addLocalReference(env, result.l); \
2247 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \
2248 jmethodID methodID, jvalue* args) \
2250 UNUSED_PARAMETER(jclazz); \
2253 dvmCallMethodA(_self, (Method*) methodID, NULL, &result, args); \
2255 result.l = addLocalReference(env, result.l); \
2259 CALL_STATIC(jobject, Object, NULL, result.l, true);
2260 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2261 CALL_STATIC(jbyte, Byte, 0, result.b, false);
2262 CALL_STATIC(jchar, Char, 0, result.c, false);
2263 CALL_STATIC(jshort, Short, 0, result.s, false);
2264 CALL_STATIC(jint, Int, 0, result.i, false);
2265 CALL_STATIC(jlong, Long, 0, result.j, false);
2266 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2267 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2268 CALL_STATIC(void, Void, , , false);
2271 * Create a new String from Unicode data.
2273 * If "len" is zero, we will return an empty string even if "unicodeChars"
2274 * is NULL. (The JNI spec is vague here.)
2276 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len)
2281 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2285 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2286 retval = addLocalReference(env, (Object*) jstr);
2294 * Return the length of a String in Unicode character units.
2296 static jsize GetStringLength(JNIEnv* env, jstring jstr)
2300 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2301 jsize len = dvmStringLen(strObj);
2309 * Get a string's character data.
2311 * The result is guaranteed to be valid until ReleaseStringChars is
2312 * called, which means we have to pin it or return a copy.
2314 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy)
2318 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2319 ArrayObject* strChars = dvmStringCharArray(jstr);
2321 pinPrimitiveArray(strChars);
2323 const u2* data = dvmStringChars(strObj);
2325 *isCopy = JNI_FALSE;
2328 return (jchar*)data;
2332 * Release our grip on some characters from a string.
2334 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars)
2337 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2338 ArrayObject* strChars = dvmStringCharArray(jstr);
2339 unpinPrimitiveArray(strChars);
2344 * Create a new java.lang.String object from chars in modified UTF-8 form.
2346 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2347 * accept it and return a NULL pointer in response.
2349 static jstring NewStringUTF(JNIEnv* env, const char* bytes)
2355 if (bytes == NULL) {
2358 /* note newStr could come back NULL on OOM */
2359 StringObject* newStr = dvmCreateStringFromCstr(bytes, ALLOC_DEFAULT);
2360 result = addLocalReference(env, (Object*) newStr);
2361 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2369 * Return the length in bytes of the modified UTF-8 form of the string.
2371 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr)
2375 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2376 jsize len = dvmStringUtf8ByteLen(strObj);
2383 * Convert "string" to modified UTF-8 and return a pointer. The returned
2384 * value must be released with ReleaseStringUTFChars.
2386 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2387 * or NULL if the operation fails. Returns NULL if and only if an invocation
2388 * of this function has thrown an exception."
2390 * The behavior here currently follows that of other open-source VMs, which
2391 * quietly return NULL if "string" is NULL. We should consider throwing an
2392 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
2393 * which should catch this sort of thing during development.) Certain other
2394 * VMs will crash with a segmentation fault.
2396 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr,
2403 /* this shouldn't happen; throw NPE? */
2409 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2410 newStr = dvmCreateCstrFromString(strObj);
2411 if (newStr == NULL) {
2412 /* assume memory failure */
2413 dvmThrowException("Ljava/lang/OutOfMemoryError;",
2414 "native heap string alloc failed");
2423 * Release a string created by GetStringUTFChars().
2425 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf)
2433 * Return the capacity of the array.
2435 static jsize GetArrayLength(JNIEnv* env, jarray jarr)
2439 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2440 jsize length = arrObj->length;
2447 * Construct a new array that holds objects from class "elementClass".
2449 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2450 jclass jelementClass, jobject jinitialElement)
2454 jobjectArray newArray = NULL;
2455 ClassObject* elemClassObj =
2456 (ClassObject*) dvmDecodeIndirectRef(env, jelementClass);
2458 if (elemClassObj == NULL) {
2459 dvmThrowException("Ljava/lang/NullPointerException;",
2460 "JNI NewObjectArray");
2464 ArrayObject* newObj =
2465 dvmAllocObjectArray(elemClassObj, length, ALLOC_DEFAULT);
2466 if (newObj == NULL) {
2467 assert(dvmCheckException(_self));
2470 newArray = addLocalReference(env, (Object*) newObj);
2471 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2474 * Initialize the array. Trashes "length".
2476 if (jinitialElement != NULL) {
2477 Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement);
2478 Object** arrayData = (Object**) newObj->contents;
2481 *arrayData++ = initialElement;
2491 * Get one element of an Object array.
2493 * Add the object to the local references table in case the array goes away.
2495 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
2500 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2501 jobject retval = NULL;
2503 assert(arrayObj != NULL);
2505 /* check the array bounds */
2506 if (index < 0 || index >= (int) arrayObj->length) {
2507 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
2508 arrayObj->obj.clazz->descriptor);
2512 Object* value = ((Object**) arrayObj->contents)[index];
2513 retval = addLocalReference(env, value);
2521 * Set one element of an Object array.
2523 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
2524 jsize index, jobject jobj)
2528 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2530 assert(arrayObj != NULL);
2532 /* check the array bounds */
2533 if (index < 0 || index >= (int) arrayObj->length) {
2534 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
2535 arrayObj->obj.clazz->descriptor);
2539 //LOGV("JNI: set element %d in array %p to %p\n", index, array, value);
2545 obj = dvmDecodeIndirectRef(env, jobj);
2546 ((Object**) arrayObj->contents)[index] = obj;
2553 * Create a new array of primitive elements.
2555 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2556 static _artype New##_jname##Array(JNIEnv* env, jsize length) \
2559 ArrayObject* arrayObj; \
2560 arrayObj = dvmAllocPrimitiveArray(_typechar, length, \
2562 jarray jarr = NULL; \
2563 if (arrayObj != NULL) { \
2564 jarr = addLocalReference(env, (Object*) arrayObj); \
2565 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2568 return (_artype)jarr; \
2570 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2571 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2572 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2573 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2574 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2575 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2576 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2577 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2580 * Get a pointer to a C array of primitive elements from an array object
2581 * of the matching type.
2583 * In a compacting GC, we either need to return a copy of the elements or
2584 * "pin" the memory. Otherwise we run the risk of native code using the
2585 * buffer as the destination of e.g. a blocking read() call that wakes up
2588 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2589 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2590 _ctype##Array jarr, jboolean* isCopy) \
2594 ArrayObject* arrayObj = \
2595 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
2596 pinPrimitiveArray(arrayObj); \
2597 data = (_ctype*) arrayObj->contents; \
2598 if (isCopy != NULL) \
2599 *isCopy = JNI_FALSE; \
2605 * Release the storage locked down by the "get" function.
2607 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2608 * elements in 'array'." They apparently did not anticipate the need to
2611 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2612 static void Release##_jname##ArrayElements(JNIEnv* env, \
2613 _ctype##Array jarr, _ctype* elems, jint mode) \
2615 UNUSED_PARAMETER(elems); \
2617 if (mode != JNI_COMMIT) { \
2618 ArrayObject* arrayObj = \
2619 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
2620 unpinPrimitiveArray(arrayObj); \
2626 * Copy a section of a primitive array to a buffer.
2628 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2629 static void Get##_jname##ArrayRegion(JNIEnv* env, \
2630 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2633 ArrayObject* arrayObj = \
2634 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
2635 _ctype* data = (_ctype*) arrayObj->contents; \
2636 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2637 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
2638 arrayObj->obj.clazz->descriptor); \
2640 memcpy(buf, data + start, len * sizeof(_ctype)); \
2646 * Copy a section of a primitive array to a buffer.
2648 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2649 static void Set##_jname##ArrayRegion(JNIEnv* env, \
2650 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2653 ArrayObject* arrayObj = \
2654 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
2655 _ctype* data = (_ctype*) arrayObj->contents; \
2656 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2657 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
2658 arrayObj->obj.clazz->descriptor); \
2660 memcpy(data + start, buf, len * sizeof(_ctype)); \
2667 * Get<Type>ArrayElements
2668 * Release<Type>ArrayElements
2669 * Get<Type>ArrayRegion
2670 * Set<Type>ArrayRegion
2672 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
2673 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2674 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2675 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
2676 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2678 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2679 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2680 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2681 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2682 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2683 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2684 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2685 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2688 * Register one or more native functions in one class.
2690 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2691 const JNINativeMethod* methods, jint nMethods)
2695 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2699 if (gDvm.verboseJni) {
2700 LOGI("[Registering JNI native methods for class %s]\n",
2704 for (i = 0; i < nMethods; i++) {
2705 if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2706 methods[i].signature, methods[i].fnPtr))
2720 * Un-register a native function.
2722 static jint UnregisterNatives(JNIEnv* env, jclass jclazz)
2726 * The JNI docs refer to this as a way to reload/relink native libraries,
2727 * and say it "should not be used in normal native code".
2729 * We can implement it if we decide we need it.
2738 * We have to track all monitor enters and exits, so that we can undo any
2739 * outstanding synchronization before the thread exits.
2741 static jint MonitorEnter(JNIEnv* env, jobject jobj)
2744 Object* obj = dvmDecodeIndirectRef(env, jobj);
2745 dvmLockObject(_self, obj);
2746 trackMonitorEnter(_self, obj);
2752 * Unlock the monitor.
2754 * Throws an IllegalMonitorStateException if the current thread
2755 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
2757 * According to the 1.6 spec, it's legal to call here with an exception
2758 * pending. If this fails, we'll stomp the original exception.
2760 static jint MonitorExit(JNIEnv* env, jobject jobj)
2763 Object* obj = dvmDecodeIndirectRef(env, jobj);
2764 bool success = dvmUnlockObject(_self, obj);
2766 trackMonitorExit(_self, obj);
2768 return success ? JNI_OK : JNI_ERR;
2772 * Return the JavaVM interface associated with the current thread.
2774 static jint GetJavaVM(JNIEnv* env, JavaVM** vm)
2777 //*vm = gDvm.vmList;
2778 *vm = (JavaVM*) ((JNIEnvExt*)env)->vm;
2787 * Copies "len" Unicode characters, from offset "start".
2789 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len,
2793 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2794 if (start + len > dvmStringLen(strObj))
2795 dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
2797 memcpy(buf, dvmStringChars(strObj) + start, len * sizeof(u2));
2802 * Translates "len" Unicode characters, from offset "start", into
2803 * modified UTF-8 encoding.
2805 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start,
2806 jsize len, char* buf)
2809 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2810 if (start + len > dvmStringLen(strObj))
2811 dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
2813 dvmCreateCstrFromStringRegion(strObj, start, len, buf);
2818 * Get a raw pointer to array data.
2820 * The caller is expected to call "release" before doing any JNI calls
2821 * or blocking I/O operations.
2823 * We need to pin the memory or block GC.
2825 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr,
2830 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2831 pinPrimitiveArray(arrayObj);
2832 data = arrayObj->contents;
2834 *isCopy = JNI_FALSE;
2840 * Release an array obtained with GetPrimitiveArrayCritical.
2842 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr,
2843 void* carray, jint mode)
2846 if (mode != JNI_COMMIT) {
2847 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2848 unpinPrimitiveArray(arrayObj);
2854 * Like GetStringChars, but with restricted use.
2856 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr,
2860 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2861 ArrayObject* strChars = dvmStringCharArray(strObj);
2863 pinPrimitiveArray(strChars);
2865 const u2* data = dvmStringChars(strObj);
2867 *isCopy = JNI_FALSE;
2870 return (jchar*)data;
2874 * Like ReleaseStringChars, but with restricted use.
2876 static void ReleaseStringCritical(JNIEnv* env, jstring jstr,
2877 const jchar* carray)
2880 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2881 ArrayObject* strChars = dvmStringCharArray(jstr);
2882 unpinPrimitiveArray(strChars);
2887 * Create a new weak global reference.
2889 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj)
2893 jobject gref = NULL;
2894 LOGE("JNI ERROR: NewWeakGlobalRef not implemented\n");
2901 * Delete the specified weak global reference.
2903 static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj)
2907 LOGE("JNI ERROR: DeleteWeakGlobalRef not implemented\n");
2913 * Quick check for pending exceptions.
2915 * TODO: we should be able to skip the enter/exit macros here.
2917 static jboolean ExceptionCheck(JNIEnv* env)
2920 bool result = dvmCheckException(_self);
2926 * Returns the type of the object referred to by "obj". It can be local,
2927 * global, or weak global.
2929 * In the current implementation, references can be global and local at
2930 * the same time, so while the return value is accurate it may not tell
2933 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj)
2936 jobjectRefType type;
2939 type = JNIInvalidRefType;
2941 type = dvmGetJNIRefType(env, jobj);
2947 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2949 * "address" may not be NULL, and "capacity" must be > 0. (These are only
2950 * verified when CheckJNI is enabled.)
2952 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)
2956 Thread* self = _self /*dvmThreadSelf()*/;
2957 Object* platformAddress = NULL;
2959 jobject result = NULL;
2961 /* get an instance of PlatformAddress that wraps the provided address */
2963 gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on,
2964 NULL, &callResult, address);
2965 if (dvmGetException(self) != NULL || callResult.l == NULL)
2968 /* don't let the GC discard it */
2969 platformAddress = (Object*) callResult.l;
2970 dvmAddTrackedAlloc(platformAddress, self);
2971 LOGV("tracking %p for address=%p\n", platformAddress, address);
2973 /* create an instance of java.nio.ReadWriteDirectByteBuffer */
2974 ClassObject* clazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
2975 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
2977 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2978 if (newObj != NULL) {
2979 /* call the (PlatformAddress, int, int) constructor */
2980 result = addLocalReference(env, newObj);
2981 dvmCallMethod(self, gDvm.methJavaNioReadWriteDirectByteBuffer_init,
2982 newObj, &callResult, platformAddress, (jint) capacity, (jint) 0);
2983 if (dvmGetException(self) != NULL) {
2984 deleteLocalReference(env, result);
2991 if (platformAddress != NULL)
2992 dvmReleaseTrackedAlloc(platformAddress, self);
2998 * Get the starting address of the buffer for the specified java.nio.Buffer.
3000 * If this is not a "direct" buffer, we return NULL.
3002 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf)
3006 Object* bufObj = dvmDecodeIndirectRef(env, jbuf);
3007 Thread* self = _self /*dvmThreadSelf()*/;
3011 * All Buffer objects have an effectiveDirectAddress field. If it's
3012 * nonzero, we can just return that value. If not, we have to call
3013 * through DirectBuffer.getEffectiveAddress(), which as a side-effect
3014 * will set the effectiveDirectAddress field for direct buffers (and
3015 * things that wrap direct buffers).
3017 result = (void*) dvmGetFieldInt(bufObj,
3018 gDvm.offJavaNioBuffer_effectiveDirectAddress);
3019 if (result != NULL) {
3020 //LOGI("fast path for %p\n", buf);
3025 * Start by determining if the object supports the DirectBuffer
3026 * interfaces. Note this does not guarantee that it's a direct buffer.
3028 if (!dvmInstanceof(bufObj->clazz,
3029 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer))
3035 * Get a PlatformAddress object with the effective address.
3037 * If this isn't a direct buffer, the result will be NULL and/or an
3038 * exception will have been thrown.
3041 const Method* meth = dvmGetVirtualizedMethod(bufObj->clazz,
3042 gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress);
3043 dvmCallMethodA(self, meth, bufObj, &callResult, NULL);
3044 if (dvmGetException(self) != NULL) {
3045 dvmClearException(self);
3046 callResult.l = NULL;
3049 Object* platformAddr = callResult.l;
3050 if (platformAddr == NULL) {
3051 LOGV("Got request for address of non-direct buffer\n");
3056 * Extract the address from the PlatformAddress object. Instead of
3057 * calling the toLong() method, just grab the field directly. This
3058 * is faster but more fragile.
3060 result = (void*) dvmGetFieldInt(platformAddr,
3061 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr);
3063 //LOGI("slow path for %p --> %p\n", buf, result);
3071 * Get the capacity of the buffer for the specified java.nio.Buffer.
3073 * Returns -1 if the object is not a direct buffer. (We actually skip
3074 * this check, since it's expensive to determine, and just return the
3075 * capacity regardless.)
3077 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf)
3082 * The capacity is always in the Buffer.capacity field.
3084 * (The "check" version should verify that this is actually a Buffer,
3085 * but we're not required to do so here.)
3087 Object* buf = dvmDecodeIndirectRef(env, jbuf);
3088 jlong result = dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
3096 * ===========================================================================
3097 * JNI invocation functions
3098 * ===========================================================================
3102 * Handle AttachCurrentThread{AsDaemon}.
3104 * We need to make sure the VM is actually running. For example, if we start
3105 * up, issue an Attach, and the VM exits almost immediately, by the time the
3106 * attaching happens the VM could already be shutting down.
3108 * It's hard to avoid a race condition here because we don't want to hold
3109 * a lock across the entire operation. What we can do is temporarily
3110 * increment the thread count to prevent a VM exit.
3112 * This could potentially still have problems if a daemon thread calls here
3113 * while the VM is shutting down. dvmThreadSelf() will work, since it just
3114 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
3115 * you shut down a VM while threads are still running inside it.
3117 * Remember that some code may call this as a way to find the per-thread
3118 * JNIEnv pointer. Don't do excess work for that case.
3120 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args,
3123 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
3125 bool result = false;
3128 * Return immediately if we're already one with the VM.
3130 self = dvmThreadSelf();
3132 *p_env = self->jniEnv;
3137 * No threads allowed in zygote mode.
3143 /* increment the count to keep the VM from bailing while we run */
3144 dvmLockThreadList(NULL);
3145 if (gDvm.nonDaemonThreadCount == 0) {
3147 LOGV("Refusing to attach thread '%s' -- VM is shutting down\n",
3148 (thr_args == NULL) ? "(unknown)" : args->name);
3149 dvmUnlockThreadList();
3152 gDvm.nonDaemonThreadCount++;
3153 dvmUnlockThreadList();
3155 /* tweak the JavaVMAttachArgs as needed */
3156 JavaVMAttachArgs argsCopy;
3158 /* allow the v1.1 calling convention */
3159 argsCopy.version = JNI_VERSION_1_2;
3160 argsCopy.name = NULL;
3161 argsCopy.group = dvmGetMainThreadGroup();
3163 assert(args->version >= JNI_VERSION_1_2);
3165 argsCopy.version = args->version;
3166 argsCopy.name = args->name;
3167 if (args->group != NULL)
3168 argsCopy.group = args->group;
3170 argsCopy.group = dvmGetMainThreadGroup();
3173 result = dvmAttachCurrentThread(&argsCopy, isDaemon);
3175 /* restore the count */
3176 dvmLockThreadList(NULL);
3177 gDvm.nonDaemonThreadCount--;
3178 dvmUnlockThreadList();
3181 * Change the status to indicate that we're out in native code. This
3182 * call is not guarded with state-change macros, so we have to do it
3186 self = dvmThreadSelf();
3187 assert(self != NULL);
3188 dvmChangeStatus(self, THREAD_NATIVE);
3189 *p_env = self->jniEnv;
3197 * Attach the current thread to the VM. If the thread is already attached,
3200 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args)
3202 return attachThread(vm, p_env, thr_args, false);
3206 * Like AttachCurrentThread, but set the "daemon" flag.
3208 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env,
3211 return attachThread(vm, p_env, thr_args, true);
3215 * Dissociate the current thread from the VM.
3217 static jint DetachCurrentThread(JavaVM* vm)
3219 Thread* self = dvmThreadSelf();
3221 if (self == NULL) /* not attached, can't do anything */
3224 /* switch to "running" to check for suspension */
3225 dvmChangeStatus(self, THREAD_RUNNING);
3227 /* detach the thread */
3228 dvmDetachCurrentThread();
3230 /* (no need to change status back -- we have no status) */
3235 * If current thread is attached to VM, return the associated JNIEnv.
3236 * Otherwise, stuff NULL in and return JNI_EDETACHED.
3238 * JVMTI overloads this by specifying a magic value for "version", so we
3239 * do want to check that here.
3241 static jint GetEnv(JavaVM* vm, void** env, jint version)
3243 Thread* self = dvmThreadSelf();
3245 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6)
3246 return JNI_EVERSION;
3251 /* TODO: status change is probably unnecessary */
3252 dvmChangeStatus(self, THREAD_RUNNING);
3253 *env = (void*) dvmGetThreadJNIEnv(self);
3254 dvmChangeStatus(self, THREAD_NATIVE);
3257 return JNI_EDETACHED;
3263 * Destroy the VM. This may be called from any thread.
3265 * If the current thread is attached, wait until the current thread is
3266 * the only non-daemon user-level thread. If the current thread is not
3267 * attached, we attach it and do the processing as usual. (If the attach
3268 * fails, it's probably because all the non-daemon threads have already
3269 * exited and the VM doesn't want to let us back in.)
3271 * TODO: we don't really deal with the situation where more than one thread
3272 * has called here. One thread wins, the other stays trapped waiting on
3273 * the condition variable forever. Not sure this situation is interesting
3276 static jint DestroyJavaVM(JavaVM* vm)
3278 JavaVMExt* ext = (JavaVMExt*) vm;
3284 LOGD("DestroyJavaVM waiting for non-daemon threads to exit\n");
3287 * Sleep on a condition variable until it's okay to exit.
3289 self = dvmThreadSelf();
3292 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
3293 LOGV("Unable to reattach main for Destroy; assuming VM is "
3294 "shutting down (count=%d)\n",
3295 gDvm.nonDaemonThreadCount);
3298 LOGV("Attached to wait for shutdown in Destroy\n");
3301 dvmChangeStatus(self, THREAD_VMWAIT);
3303 dvmLockThreadList(self);
3304 gDvm.nonDaemonThreadCount--; // remove current thread from count
3306 while (gDvm.nonDaemonThreadCount > 0)
3307 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
3309 dvmUnlockThreadList();
3313 // TODO: call System.exit() to run any registered shutdown hooks
3314 // (this may not return -- figure out how this should work)
3316 LOGD("DestroyJavaVM shutting VM down\n");
3319 // TODO - free resources associated with JNI-attached daemon threads
3328 * ===========================================================================
3330 * ===========================================================================
3333 static const struct JNINativeInterface gNativeInterface = {
3344 FromReflectedMethod,
3368 EnsureLocalCapacity,
3411 CallNonvirtualObjectMethod,
3412 CallNonvirtualObjectMethodV,
3413 CallNonvirtualObjectMethodA,
3414 CallNonvirtualBooleanMethod,
3415 CallNonvirtualBooleanMethodV,
3416 CallNonvirtualBooleanMethodA,
3417 CallNonvirtualByteMethod,
3418 CallNonvirtualByteMethodV,
3419 CallNonvirtualByteMethodA,
3420 CallNonvirtualCharMethod,
3421 CallNonvirtualCharMethodV,
3422 CallNonvirtualCharMethodA,
3423 CallNonvirtualShortMethod,
3424 CallNonvirtualShortMethodV,
3425 CallNonvirtualShortMethodA,
3426 CallNonvirtualIntMethod,
3427 CallNonvirtualIntMethodV,
3428 CallNonvirtualIntMethodA,
3429 CallNonvirtualLongMethod,
3430 CallNonvirtualLongMethodV,
3431 CallNonvirtualLongMethodA,
3432 CallNonvirtualFloatMethod,
3433 CallNonvirtualFloatMethodV,
3434 CallNonvirtualFloatMethodA,
3435 CallNonvirtualDoubleMethod,
3436 CallNonvirtualDoubleMethodV,
3437 CallNonvirtualDoubleMethodA,
3438 CallNonvirtualVoidMethod,
3439 CallNonvirtualVoidMethodV,
3440 CallNonvirtualVoidMethodA,
3465 CallStaticObjectMethod,
3466 CallStaticObjectMethodV,
3467 CallStaticObjectMethodA,
3468 CallStaticBooleanMethod,
3469 CallStaticBooleanMethodV,
3470 CallStaticBooleanMethodA,
3471 CallStaticByteMethod,
3472 CallStaticByteMethodV,
3473 CallStaticByteMethodA,
3474 CallStaticCharMethod,
3475 CallStaticCharMethodV,
3476 CallStaticCharMethodA,
3477 CallStaticShortMethod,
3478 CallStaticShortMethodV,
3479 CallStaticShortMethodA,
3480 CallStaticIntMethod,
3481 CallStaticIntMethodV,
3482 CallStaticIntMethodA,
3483 CallStaticLongMethod,
3484 CallStaticLongMethodV,
3485 CallStaticLongMethodA,
3486 CallStaticFloatMethod,
3487 CallStaticFloatMethodV,
3488 CallStaticFloatMethodA,
3489 CallStaticDoubleMethod,
3490 CallStaticDoubleMethodV,
3491 CallStaticDoubleMethodA,
3492 CallStaticVoidMethod,
3493 CallStaticVoidMethodV,
3494 CallStaticVoidMethodA,
3498 GetStaticObjectField,
3499 GetStaticBooleanField,
3502 GetStaticShortField,
3505 GetStaticFloatField,
3506 GetStaticDoubleField,
3508 SetStaticObjectField,
3509 SetStaticBooleanField,
3512 SetStaticShortField,
3515 SetStaticFloatField,
3516 SetStaticDoubleField,
3527 ReleaseStringUTFChars,
3531 GetObjectArrayElement,
3532 SetObjectArrayElement,
3543 GetBooleanArrayElements,
3544 GetByteArrayElements,
3545 GetCharArrayElements,
3546 GetShortArrayElements,
3547 GetIntArrayElements,
3548 GetLongArrayElements,
3549 GetFloatArrayElements,
3550 GetDoubleArrayElements,
3552 ReleaseBooleanArrayElements,
3553 ReleaseByteArrayElements,
3554 ReleaseCharArrayElements,
3555 ReleaseShortArrayElements,
3556 ReleaseIntArrayElements,
3557 ReleaseLongArrayElements,
3558 ReleaseFloatArrayElements,
3559 ReleaseDoubleArrayElements,
3561 GetBooleanArrayRegion,
3564 GetShortArrayRegion,
3567 GetFloatArrayRegion,
3568 GetDoubleArrayRegion,
3569 SetBooleanArrayRegion,
3572 SetShortArrayRegion,
3575 SetFloatArrayRegion,
3576 SetDoubleArrayRegion,
3589 GetPrimitiveArrayCritical,
3590 ReleasePrimitiveArrayCritical,
3593 ReleaseStringCritical,
3596 DeleteWeakGlobalRef,
3600 NewDirectByteBuffer,
3601 GetDirectBufferAddress,
3602 GetDirectBufferCapacity,
3606 static const struct JNIInvokeInterface gInvokeInterface = {
3612 AttachCurrentThread,
3613 DetachCurrentThread,
3617 AttachCurrentThreadAsDaemon,
3622 * ===========================================================================
3624 * ===========================================================================
3628 * Enable "checked JNI" after the VM has partially started. This must
3629 * only be called in "zygote" mode, when we have one thread running.
3631 * This doesn't attempt to rewrite the JNI call bridge associated with
3632 * native methods, so we won't get those checks for any methods that have
3633 * already been resolved.
3635 void dvmLateEnableCheckedJni(void)
3640 extEnv = dvmGetJNIEnvForThread();
3641 if (extEnv == NULL) {
3642 LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv\n");
3646 assert(extVm != NULL);
3648 if (!extVm->useChecked) {
3649 LOGD("Late-enabling CheckJNI\n");
3650 dvmUseCheckedJniVm(extVm);
3651 extVm->useChecked = true;
3652 dvmUseCheckedJniEnv(extEnv);
3654 /* currently no way to pick up jniopts features */
3656 LOGD("Not late-enabling CheckJNI (already on)\n");
3663 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args)
3669 * Return a buffer full of created VMs.
3671 * We always have zero or one.
3673 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
3675 if (gDvm.vmList != NULL) {
3679 *vmBuf++ = gDvm.vmList;
3689 * Create a new VM instance.
3691 * The current thread becomes the main VM thread. We return immediately,
3692 * which effectively means the caller is executing in a native method.
3694 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)
3696 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3697 JNIEnvExt* pEnv = NULL;
3698 JavaVMExt* pVM = NULL;
3702 int result = JNI_ERR;
3703 bool checkJni = false;
3704 bool warnError = true;
3705 bool forceDataCopy = false;
3707 if (args->version < JNI_VERSION_1_2)
3708 return JNI_EVERSION;
3710 // TODO: don't allow creation of multiple VMs -- one per customer for now
3712 /* zero globals; not strictly necessary the first time a VM is started */
3713 memset(&gDvm, 0, sizeof(gDvm));
3716 * Set up structures for JNIEnv and VM.
3718 //pEnv = (JNIEnvExt*) malloc(sizeof(JNIEnvExt));
3719 pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
3721 //memset(pEnv, 0, sizeof(JNIEnvExt));
3722 //pEnv->funcTable = &gNativeInterface;
3724 memset(pVM, 0, sizeof(JavaVMExt));
3725 pVM->funcTable = &gInvokeInterface;
3726 pVM->envList = pEnv;
3727 dvmInitMutex(&pVM->envListLock);
3729 argv = (const char**) malloc(sizeof(char*) * (args->nOptions));
3730 memset(argv, 0, sizeof(char*) * (args->nOptions));
3735 * Convert JNI args to argv.
3737 * We have to pull out vfprintf/exit/abort, because they use the
3738 * "extraInfo" field to pass function pointer "hooks" in. We also
3739 * look for the -Xcheck:jni stuff here.
3741 for (i = 0; i < args->nOptions; i++) {
3742 const char* optStr = args->options[i].optionString;
3744 if (optStr == NULL) {
3745 fprintf(stderr, "ERROR: arg %d string was null\n", i);
3747 } else if (strcmp(optStr, "vfprintf") == 0) {
3748 gDvm.vfprintfHook = args->options[i].extraInfo;
3749 } else if (strcmp(optStr, "exit") == 0) {
3750 gDvm.exitHook = args->options[i].extraInfo;
3751 } else if (strcmp(optStr, "abort") == 0) {
3752 gDvm.abortHook = args->options[i].extraInfo;
3753 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3755 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3756 const char* jniOpts = optStr + 9;
3757 while (jniOpts != NULL) {
3758 jniOpts++; /* skip past ':' or ',' */
3759 if (strncmp(jniOpts, "warnonly", 8) == 0) {
3761 } else if (strncmp(jniOpts, "forcecopy", 9) == 0) {
3762 forceDataCopy = true;
3764 LOGW("unknown jni opt starting at '%s'\n", jniOpts);
3766 jniOpts = strchr(jniOpts, ',');
3769 /* regular option */
3770 argv[curOpt++] = optStr;
3776 dvmUseCheckedJniVm(pVM);
3777 pVM->useChecked = true;
3779 pVM->warnError = warnError;
3780 pVM->forceDataCopy = forceDataCopy;
3782 /* set this up before initializing VM, so it can create some JNIEnvs */
3783 gDvm.vmList = (JavaVM*) pVM;
3786 * Create an env for main thread. We need to have something set up
3787 * here because some of the class initialization we do when starting
3788 * up the VM will call into native code.
3790 pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3793 gDvm.initializing = true;
3794 if (dvmStartup(argc, argv, args->ignoreUnrecognized, (JNIEnv*)pEnv) != 0) {
3801 * Success! Return stuff to caller.
3803 dvmChangeStatus(NULL, THREAD_NATIVE);
3804 *p_env = (JNIEnv*) pEnv;
3805 *p_vm = (JavaVM*) pVM;
3809 gDvm.initializing = false;
3810 if (result == JNI_OK)
3811 LOGV("JNI_CreateJavaVM succeeded\n");
3813 LOGW("JNI_CreateJavaVM failed\n");