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 GC
52 needs to know about. These can be local, in which case they're released
53 when the native method returns into the VM, or global, which are held
54 until explicitly released. (There are also weak-global references,
55 which have the lifespan and visibility of global references, but the
56 object they refer to may be collected.)
58 The references can be created with explicit JNI NewLocalRef / NewGlobalRef
59 calls. The former is very unusual, the latter is reasonably common
60 (e.g. for caching references to class objects).
62 Local references are most often created as a side-effect of JNI functions.
63 For example, the AllocObject/NewObject functions must create local
64 references to the objects returned, because nothing else in the GC root
65 set has a reference to the new objects.
67 The most common mode of operation is for a method to create zero or
68 more local references and return. Explicit "local delete" operations
69 are expected to be exceedingly rare, except when walking through an
70 object array, and the Push/PopLocalFrame calls are expected to be used
71 infrequently. For efficient operation, we want to add new local refs
72 with a simple store/increment operation; to avoid infinite growth in
73 pathological situations, we need to reclaim the space used by deleted
76 If we just want to maintain a list for the GC root set, we can use an
77 expanding append-only array that compacts when objects are deleted.
78 In typical situations, e.g. running through an array of objects, we will
79 be deleting one of the most recently added entries, so we can minimize
80 the number of elements moved (or avoid having to move any).
82 If we want to conceal the pointer values from native code, which is
83 necessary to allow the GC to move JNI-referenced objects around, then we
84 have to use a more complicated indirection mechanism.
86 The spec says, "Local references are only valid in the thread in which
87 they are created. The native code must not pass local references from
88 one thread to another."
93 For some large chunks of data, notably primitive arrays and String data,
94 JNI allows the VM to choose whether it wants to pin the array object or
95 make a copy. We currently pin the memory for better execution performance.
97 TODO: we're using simple root set references to pin primitive array data,
98 because they have the property we need (i.e. the pointer we return is
99 guaranteed valid until we explicitly release it). However, if we have a
100 compacting GC and don't want to pin all memory held by all global refs,
101 we need to treat these differently.
104 Global reference tracking
106 There should be a small "active" set centered around the most-recently
109 Because it's global, access to it has to be synchronized. Additions and
110 removals require grabbing a mutex. If the table serves as an indirection
111 mechanism (i.e. it's not just a list for the benefit of the garbage
112 collector), reference lookups may also require grabbing a mutex.
114 The JNI spec does not define any sort of limit, so the list must be able
115 to expand to a reasonable size. It may be useful to log significant
116 increases in usage to help identify resource leaks.
119 Weak-global reference tracking
124 Local reference tracking
126 The table of local references can be stored on the interpreted stack or
127 in a parallel data structure (one per thread).
129 *** Approach #1: use the interpreted stack
131 The easiest place to tuck it is between the frame ptr and the first saved
132 register, which is always in0. (See the ASCII art in Stack.h.) We can
133 shift the "VM-specific goop" and frame ptr down, effectively inserting
134 the JNI local refs in the space normally occupied by local variables.
136 (Three things are accessed from the frame pointer:
137 (1) framePtr[N] is register vN, used to get at "ins" and "locals".
138 (2) framePtr - sizeof(StackSaveArea) is the VM frame goop.
139 (3) framePtr - sizeof(StackSaveArea) - numOuts is where the "outs" go.
140 The only thing that isn't determined by an offset from the current FP
141 is the previous frame. However, tucking things below the previous frame
142 can be problematic because the "outs" of the previous frame overlap with
143 the "ins" of the current frame. If the "ins" are altered they must be
144 restored before we return. For a native method call, the easiest and
145 safest thing to disrupt is #1, because there are no locals and the "ins"
146 are all copied to the native stack.)
148 We can implement Push/PopLocalFrame with the existing stack frame calls,
149 making sure we copy some goop from the previous frame (notably the method
150 ptr, so that dvmGetCurrentJNIMethod() doesn't require extra effort).
152 We can pre-allocate the storage at the time the stack frame is first
153 set up, but we have to be careful. When calling from interpreted code
154 the frame ptr points directly at the arguments we're passing, but we can
155 offset the args pointer when calling the native bridge.
157 To manage the local ref collection, we need to be able to find three
158 things: (1) the start of the region, (2) the end of the region, and (3)
159 the next available entry. The last is only required for quick adds.
160 We currently have two easily-accessible pointers, the current FP and the
161 previous frame's FP. (The "stack pointer" shown in the ASCII art doesn't
162 actually exist in the interpreted world.)
164 We can't use the current FP to find the first "in", because we want to
165 insert the variable-sized local refs table between them. It's awkward
166 to use the previous frame's FP because native methods invoked via
167 dvmCallMethod() or dvmInvokeMethod() don't have "ins", but native methods
168 invoked from interpreted code do. We can either track the local refs
169 table size with a field in the stack frame, or insert unnecessary items
170 so that all native stack frames have "ins".
172 Assuming we can find the region bounds, we still need pointer #3
173 for an efficient implementation. This can be stored in an otherwise
174 unused-for-native field in the frame goop.
176 When we run out of room we have to make more space. If we start allocating
177 locals immediately below in0 and grow downward, we will detect end-of-space
178 by running into the current frame's FP. We then memmove() the goop down
179 (memcpy if we guarantee the additional size is larger than the frame).
180 This is nice because we only have to move sizeof(StackSaveArea) bytes
183 Stack walking should be okay so long as nothing tries to access the
184 "ins" by an offset from the FP. In theory the "ins" could be read by
185 the debugger or SIGQUIT handler looking for "this" or other arguments,
186 but in practice this behavior isn't expected to work for native methods,
187 so we can simply disallow it.
189 A conservative GC can just scan the entire stack from top to bottom to find
190 all references. An exact GC will need to understand the actual layout.
192 *** Approach #2: use a parallel stack
194 Each Thread/JNIEnv points to a reference table. The struct has
195 a system-heap-allocated array of references and a pointer to the
196 next-available entry ("nextEntry").
198 Each stack frame has a pointer to what it sees as the "bottom" element
199 in the array (we can double-up the "currentPc" field). This is set to
200 "nextEntry" when the frame is pushed on. As local references are added
201 or removed, "nextEntry" is updated.
203 We implement Push/PopLocalFrame with actual stack frames. Before a JNI
204 frame gets popped, we set "nextEntry" to the "top" pointer of the current
205 frame, effectively releasing the references.
207 The GC will scan all references from the start of the table to the
212 All approaches will return a failure result when they run out of local
213 reference space. For #1 that means blowing out the stack, for #2 it's
214 running out of room in the array.
216 Compared to #1, approach #2:
217 - Needs only one pointer in the stack frame goop.
218 - Makes pre-allocating storage unnecessary.
219 - Doesn't contend with interpreted stack depth for space. In most
220 cases, if something blows out the local ref storage, it's because the
221 JNI code was misbehaving rather than called from way down.
222 - Allows the GC to do a linear scan per thread in a buffer that is 100%
223 references. The GC can be slightly less smart when scanning the stack.
224 - Will be easier to work with if we combine native and interpeted stacks.
226 - Isn't as clean, especially when popping frames, since we have to do
227 explicit work. Fortunately we only have to do it when popping native
228 method calls off, so it doesn't add overhead to interpreted code paths.
229 - Is awkward to expand dynamically. We'll want to pre-allocate the full
230 amount of space; this is fine, since something on the order of 1KB should
231 be plenty. The JNI spec allows us to limit this.
232 - Requires the GC to scan even more memory. With the references embedded
233 in the stack we get better locality of reference.
238 static const struct JNINativeInterface gNativeInterface;
239 static jobject addGlobalReference(Object* obj);
241 #ifdef WITH_JNI_STACK_CHECK
242 # define COMPUTE_STACK_SUM(_self) computeStackSum(_self);
243 # define CHECK_STACK_SUM(_self) checkStackSum(_self);
244 //static void computeStackSum(Thread* self);
245 //static void checkStackSum(Thread* self);
247 # define COMPUTE_STACK_SUM(_self) ((void)0)
248 # define CHECK_STACK_SUM(_self) ((void)0)
253 * ===========================================================================
255 * ===========================================================================
259 * Entry/exit processing for all JNI calls.
261 * If TRUSTED_JNIENV is set, we get to skip the (curiously expensive)
262 * thread-local storage lookup on our Thread*. If the caller has passed
263 * the wrong JNIEnv in, we're going to be accessing unsynchronized
264 * structures from more than one thread, and things are going to fail
265 * in bizarre ways. This is only sensible if the native code has been
266 * fully exercised with CheckJNI enabled.
268 #define TRUSTED_JNIENV
269 #ifdef TRUSTED_JNIENV
270 # define JNI_ENTER() \
271 Thread* _self = ((JNIEnvExt*)env)->self; \
272 CHECK_STACK_SUM(_self); \
273 dvmChangeStatus(_self, THREAD_RUNNING)
275 # define JNI_ENTER() \
276 Thread* _self = dvmThreadSelf(); \
277 UNUSED_PARAMETER(env); \
278 CHECK_STACK_SUM(_self); \
279 dvmChangeStatus(_self, THREAD_RUNNING)
282 dvmChangeStatus(_self, THREAD_NATIVE); \
283 COMPUTE_STACK_SUM(_self)
285 #define kGlobalRefsTableInitialSize 512
286 #define kGlobalRefsTableMaxSize 51200 /* arbitrary, must be < 64K */
287 #define kGrefWaterInterval 100
288 #define kTrackGrefUsage true
290 #define kPinTableInitialSize 16
291 #define kPinTableMaxSize 1024
292 #define kPinComplainThreshold 10
295 * Allocate the global references table, and look up some classes for
296 * the benefit of direct buffer access.
298 bool dvmJniStartup(void)
300 #ifdef USE_INDIRECT_REF
301 if (!dvmInitIndirectRefTable(&gDvm.jniGlobalRefTable,
302 kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize,
303 kIndirectKindGlobal))
306 if (!dvmInitReferenceTable(&gDvm.jniGlobalRefTable,
307 kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize))
311 dvmInitMutex(&gDvm.jniGlobalRefLock);
312 gDvm.jniGlobalRefLoMark = 0;
313 gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
315 if (!dvmInitReferenceTable(&gDvm.jniPinRefTable,
316 kPinTableInitialSize, kPinTableMaxSize))
319 dvmInitMutex(&gDvm.jniPinRefLock);
322 * Look up and cache pointers to some direct buffer classes, fields,
327 ClassObject* platformAddressClass =
328 dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddress;");
329 ClassObject* platformAddressFactoryClass =
330 dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddressFactory;");
331 ClassObject* directBufferClass =
332 dvmFindSystemClassNoInit("Lorg/apache/harmony/nio/internal/DirectBuffer;");
333 ClassObject* readWriteBufferClass =
334 dvmFindSystemClassNoInit("Ljava/nio/ReadWriteDirectByteBuffer;");
335 ClassObject* bufferClass =
336 dvmFindSystemClassNoInit("Ljava/nio/Buffer;");
338 if (platformAddressClass == NULL || platformAddressFactoryClass == NULL ||
339 directBufferClass == NULL || readWriteBufferClass == NULL ||
342 LOGE("Unable to find internal direct buffer classes\n");
345 gDvm.classJavaNioReadWriteDirectByteBuffer = readWriteBufferClass;
346 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer = directBufferClass;
347 /* need a global reference for extended CheckJNI tests */
348 gDvm.jclassOrgApacheHarmonyNioInternalDirectBuffer =
349 addGlobalReference((Object*) directBufferClass);
352 * We need a Method* here rather than a vtable offset, because
353 * DirectBuffer is an interface class.
355 meth = dvmFindVirtualMethodByDescriptor(
356 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer,
357 "getEffectiveAddress",
358 "()Lorg/apache/harmony/luni/platform/PlatformAddress;");
360 LOGE("Unable to find PlatformAddress.getEffectiveAddress\n");
363 gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress = meth;
365 meth = dvmFindVirtualMethodByDescriptor(platformAddressClass,
368 LOGE("Unable to find PlatformAddress.toLong\n");
371 gDvm.voffOrgApacheHarmonyLuniPlatformPlatformAddress_toLong =
374 meth = dvmFindDirectMethodByDescriptor(platformAddressFactoryClass,
376 "(I)Lorg/apache/harmony/luni/platform/PlatformAddress;");
378 LOGE("Unable to find PlatformAddressFactory.on\n");
381 gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on = meth;
383 meth = dvmFindDirectMethodByDescriptor(readWriteBufferClass,
385 "(Lorg/apache/harmony/luni/platform/PlatformAddress;II)V");
387 LOGE("Unable to find ReadWriteDirectByteBuffer.<init>\n");
390 gDvm.methJavaNioReadWriteDirectByteBuffer_init = meth;
392 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr =
393 dvmFindFieldOffset(platformAddressClass, "osaddr", "I");
394 if (gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr < 0) {
395 LOGE("Unable to find PlatformAddress.osaddr\n");
399 gDvm.offJavaNioBuffer_capacity =
400 dvmFindFieldOffset(bufferClass, "capacity", "I");
401 if (gDvm.offJavaNioBuffer_capacity < 0) {
402 LOGE("Unable to find Buffer.capacity\n");
406 gDvm.offJavaNioBuffer_effectiveDirectAddress =
407 dvmFindFieldOffset(bufferClass, "effectiveDirectAddress", "I");
408 if (gDvm.offJavaNioBuffer_effectiveDirectAddress < 0) {
409 LOGE("Unable to find Buffer.effectiveDirectAddress\n");
417 * Free the global references table.
419 void dvmJniShutdown(void)
421 #ifdef USE_INDIRECT_REF
422 dvmClearIndirectRefTable(&gDvm.jniGlobalRefTable);
424 dvmClearReferenceTable(&gDvm.jniGlobalRefTable);
430 * Find the JNIEnv associated with the current thread.
432 * Currently stored in the Thread struct. Could also just drop this into
433 * thread-local storage.
435 JNIEnvExt* dvmGetJNIEnvForThread(void)
437 Thread* self = dvmThreadSelf();
440 return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
444 * Create a new JNIEnv struct and add it to the VM's list.
446 * "self" will be NULL for the main thread, since the VM hasn't started
447 * yet; the value will be filled in later.
449 JNIEnv* dvmCreateJNIEnv(Thread* self)
451 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
455 // LOGI("Ent CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
459 newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
460 newEnv->funcTable = &gNativeInterface;
462 newEnv->forceDataCopy = vm->forceDataCopy;
464 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
465 assert(newEnv->envThreadId != 0);
467 /* make it obvious if we fail to initialize these later */
468 newEnv->envThreadId = 0x77777775;
469 newEnv->self = (Thread*) 0x77777779;
472 dvmUseCheckedJniEnv(newEnv);
474 dvmLockMutex(&vm->envListLock);
476 /* insert at head of list */
477 newEnv->next = vm->envList;
478 assert(newEnv->prev == NULL);
479 if (vm->envList == NULL) // rare, but possible
480 vm->envList = newEnv;
482 vm->envList->prev = newEnv;
483 vm->envList = newEnv;
485 dvmUnlockMutex(&vm->envListLock);
488 // LOGI("Xit CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
489 return (JNIEnv*) newEnv;
493 * Remove a JNIEnv struct from the list and free it.
495 void dvmDestroyJNIEnv(JNIEnv* env)
497 JNIEnvExt* extEnv = (JNIEnvExt*) env;
498 JavaVMExt* vm = extEnv->vm;
504 self = dvmThreadSelf();
505 assert(self != NULL);
507 //LOGI("Ent DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
509 dvmLockMutex(&vm->envListLock);
511 if (extEnv == vm->envList) {
512 assert(extEnv->prev == NULL);
513 vm->envList = extEnv->next;
515 assert(extEnv->prev != NULL);
516 extEnv->prev->next = extEnv->next;
518 if (extEnv->next != NULL)
519 extEnv->next->prev = extEnv->prev;
521 dvmUnlockMutex(&extEnv->vm->envListLock);
524 //LOGI("Xit DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
529 * Retrieve the ReferenceTable struct for the current thread.
531 * Going through "env" rather than dvmThreadSelf() is faster but will
532 * get weird if the JNI code is passing the wrong JNIEnv around.
534 #ifdef USE_INDIRECT_REF
535 static inline IndirectRefTable* getLocalRefTable(JNIEnv* env)
537 return &((JNIEnvExt*)env)->self->jniLocalRefTable;
540 static inline ReferenceTable* getLocalRefTable(JNIEnv* env)
542 //return &dvmThreadSelf()->jniLocalRefTable;
543 return &((JNIEnvExt*)env)->self->jniLocalRefTable;
548 * Convert an indirect reference to an Object reference. The indirect
549 * reference may be local, global, or weak-global.
551 * If "jobj" is NULL or an invalid indirect reference, this returns NULL.
553 Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj)
555 #ifdef USE_INDIRECT_REF
561 switch (dvmGetIndirectRefType(jobj)) {
562 case kIndirectKindLocal:
564 IndirectRefTable* pRefTable = getLocalRefTable(env);
565 result = dvmGetFromIndirectRefTable(pRefTable, jobj);
568 case kIndirectKindGlobal:
570 // TODO: find a way to avoid the mutex activity here
571 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
572 dvmLockMutex(&gDvm.jniGlobalRefLock);
573 result = dvmGetFromIndirectRefTable(pRefTable, jobj);
574 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
577 case kIndirectKindWeakGlobal:
579 LOGE("weak-global not yet supported\n");
584 case kIndirectKindInvalid:
586 LOGW("Invalid indirect reference %p in decodeIndirectRef\n", jobj);
594 return (Object*) jobj;
599 * Add a local reference for an object to the current stack frame. When
600 * the native function returns, the reference will be discarded.
602 * We need to allow the same reference to be added multiple times.
604 * This will be called on otherwise unreferenced objects. We cannot do
605 * GC allocations here, and it's best if we don't grab a mutex.
607 * Returns the local reference (currently just the same pointer that was
608 * passed in), or NULL on failure.
610 static jobject addLocalReference(JNIEnv* env, Object* obj)
617 #ifdef USE_INDIRECT_REF
618 IndirectRefTable* pRefTable = getLocalRefTable(env);
619 void* curFrame = ((JNIEnvExt*)env)->self->curFrame;
620 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
622 jobj = (jobject) dvmAddToIndirectRefTable(pRefTable, cookie, obj);
624 dvmDumpIndirectRefTable(pRefTable, "JNI local");
625 LOGE("Failed adding to JNI local ref table (has %d entries)\n",
626 (int) dvmIndirectRefTableEntries(pRefTable));
627 dvmDumpThread(dvmThreadSelf(), false);
628 dvmAbort(); // spec says call FatalError; this is equivalent
630 LOGVV("LREF add %p (%s.%s) (ent=%d)\n", obj,
631 dvmGetCurrentJNIMethod()->clazz->descriptor,
632 dvmGetCurrentJNIMethod()->name,
633 (int) dvmReferenceTableEntries(pRefTable));
636 ReferenceTable* pRefTable = getLocalRefTable(env);
638 if (!dvmAddToReferenceTable(pRefTable, obj)) {
639 dvmDumpReferenceTable(pRefTable, "JNI local");
640 LOGE("Failed adding to JNI local ref table (has %d entries)\n",
641 (int) dvmReferenceTableEntries(pRefTable));
642 dvmDumpThread(dvmThreadSelf(), false);
643 dvmAbort(); // spec says call FatalError; this is equivalent
645 LOGVV("LREF add %p (%s.%s) (ent=%d)\n", obj,
646 dvmGetCurrentJNIMethod()->clazz->descriptor,
647 dvmGetCurrentJNIMethod()->name,
648 (int) dvmReferenceTableEntries(pRefTable));
651 jobj = (jobject) obj;
658 * Ensure that at least "capacity" references can be held in the local
659 * refs table of the current thread.
661 static bool ensureLocalCapacity(JNIEnv* env, int capacity)
663 #ifdef USE_INDIRECT_REF
664 IndirectRefTable* pRefTable = getLocalRefTable(env);
665 int numEntries = dvmIndirectRefTableEntries(pRefTable);
666 // TODO: this isn't quite right, since "numEntries" includes holes
667 return ((kJniLocalRefMax - numEntries) >= capacity);
669 ReferenceTable* pRefTable = getLocalRefTable(env);
671 return (kJniLocalRefMax - (pRefTable->nextEntry - pRefTable->table) >= capacity);
676 * Explicitly delete a reference from the local list.
678 static void deleteLocalReference(JNIEnv* env, jobject jobj)
683 #ifdef USE_INDIRECT_REF
684 IndirectRefTable* pRefTable = getLocalRefTable(env);
685 Thread* self = ((JNIEnvExt*)env)->self;
686 u4 cookie = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefCookie;
688 if (!dvmRemoveFromIndirectRefTable(pRefTable, cookie, jobj)) {
690 * Attempting to delete a local reference that is not in the
691 * topmost local reference frame is a no-op. DeleteLocalRef returns
692 * void and doesn't throw any exceptions, but we should probably
693 * complain about it so the user will notice that things aren't
694 * going quite the way they expect.
696 LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry\n", jobj);
699 ReferenceTable* pRefTable = getLocalRefTable(env);
700 Thread* self = ((JNIEnvExt*)env)->self;
701 Object** bottom = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefCookie;
703 if (!dvmRemoveFromReferenceTable(pRefTable, bottom, (Object*) jobj)) {
705 * Attempting to delete a local reference that is not in the
706 * topmost local reference frame is a no-op. DeleteLocalRef returns
707 * void and doesn't throw any exceptions, but we should probably
708 * complain about it so the user will notice that things aren't
709 * going quite the way they expect.
711 LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry (valid=%d)\n",
712 jobj, dvmIsValidObject((Object*) jobj));
718 * Add a global reference for an object.
720 * We may add the same object more than once. Add/remove calls are paired,
721 * so it needs to appear on the list multiple times.
723 static jobject addGlobalReference(Object* obj)
728 //LOGI("adding obj=%p\n", obj);
729 //dvmDumpThread(dvmThreadSelf(), false);
731 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangClass) {
732 ClassObject* clazz = (ClassObject*) obj;
734 LOGI("Adding global ref on class %s\n", clazz->descriptor);
735 dvmDumpThread(dvmThreadSelf(), false);
737 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
738 StringObject* strObj = (StringObject*) obj;
739 char* str = dvmCreateCstrFromString(strObj);
740 if (strcmp(str, "sync-response") == 0) {
742 LOGI("Adding global ref on string '%s'\n", str);
743 dvmDumpThread(dvmThreadSelf(), false);
748 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
749 ArrayObject* arrayObj = (ArrayObject*) obj;
750 if (arrayObj->length == 8192 /*&&
751 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
753 LOGI("Adding global ref on byte array %p (len=%d)\n",
754 arrayObj, arrayObj->length);
755 dvmDumpThread(dvmThreadSelf(), false);
761 dvmLockMutex(&gDvm.jniGlobalRefLock);
764 * Throwing an exception on failure is problematic, because JNI code
765 * may not be expecting an exception, and things sort of cascade. We
766 * want to have a hard limit to catch leaks during debugging, but this
767 * otherwise needs to expand until memory is consumed. As a practical
768 * matter, if we have many thousands of global references, chances are
769 * we're either leaking global ref table entries or we're going to
770 * run out of space in the GC heap.
772 #ifdef USE_INDIRECT_REF
773 jobj = dvmAddToIndirectRefTable(&gDvm.jniGlobalRefTable, IRT_FIRST_SEGMENT,
776 dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
777 LOGE("Failed adding to JNI global ref table (%d entries)\n",
778 (int) dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable));
782 LOGVV("GREF add %p (%s.%s)\n", obj,
783 dvmGetCurrentJNIMethod()->clazz->descriptor,
784 dvmGetCurrentJNIMethod()->name);
786 /* GREF usage tracking; should probably be disabled for production env */
787 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
788 int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
789 // TODO: adjust for "holes"
790 if (count > gDvm.jniGlobalRefHiMark) {
791 LOGD("GREF has increased to %d\n", count);
792 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
793 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
795 /* watch for "excessive" use; not generally appropriate */
796 if (count >= gDvm.jniGrefLimit) {
797 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
799 dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable,
801 LOGE("Excessive JNI global references (%d)\n", count);
804 LOGW("Excessive JNI global references (%d)\n", count);
810 if (!dvmAddToReferenceTable(&gDvm.jniGlobalRefTable, obj)) {
811 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
812 LOGE("Failed adding to JNI global ref table (%d entries)\n",
813 (int) dvmReferenceTableEntries(&gDvm.jniGlobalRefTable));
816 jobj = (jobject) obj;
818 LOGVV("GREF add %p (%s.%s)\n", obj,
819 dvmGetCurrentJNIMethod()->clazz->descriptor,
820 dvmGetCurrentJNIMethod()->name);
822 /* GREF usage tracking; should probably be disabled for production env */
823 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
824 int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
825 if (count > gDvm.jniGlobalRefHiMark) {
826 LOGD("GREF has increased to %d\n", count);
827 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
828 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
830 /* watch for "excessive" use; not generally appropriate */
831 if (count >= gDvm.jniGrefLimit) {
832 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
834 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable,"JNI global");
835 LOGE("Excessive JNI global references (%d)\n", count);
838 LOGW("Excessive JNI global references (%d)\n", count);
846 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
851 * Remove a global reference. In most cases it's the entry most recently
852 * added, which makes this pretty quick.
854 * Thought: if it's not the most recent entry, just null it out. When we
855 * fill up, do a compaction pass before we expand the list.
857 static void deleteGlobalReference(jobject jobj)
862 dvmLockMutex(&gDvm.jniGlobalRefLock);
864 #ifdef USE_INDIRECT_REF
865 if (!dvmRemoveFromIndirectRefTable(&gDvm.jniGlobalRefTable,
866 IRT_FIRST_SEGMENT, jobj))
868 LOGW("JNI: DeleteGlobalRef(%p) failed to find entry\n", jobj);
872 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
873 int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
874 // TODO: not quite right, need to subtract holes
875 if (count < gDvm.jniGlobalRefLoMark) {
876 LOGD("GREF has decreased to %d\n", count);
877 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
878 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
882 if (!dvmRemoveFromReferenceTable(&gDvm.jniGlobalRefTable,
883 gDvm.jniGlobalRefTable.table, jobj))
885 LOGW("JNI: DeleteGlobalRef(%p) failed to find entry (valid=%d)\n",
886 jobj, dvmIsValidObject((Object*) jobj));
890 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
891 int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
892 if (count < gDvm.jniGlobalRefLoMark) {
893 LOGD("GREF has decreased to %d\n", count);
894 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
895 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
901 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
905 * Objects don't currently move, so we just need to create a reference
906 * that will ensure the array object isn't collected.
908 * We use a separate reference table, which is part of the GC root set.
910 static void pinPrimitiveArray(ArrayObject* arrayObj)
912 if (arrayObj == NULL)
915 dvmLockMutex(&gDvm.jniPinRefLock);
916 if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
917 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
918 LOGE("Failed adding to JNI pinned array ref table (%d entries)\n",
919 (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
920 dvmDumpThread(dvmThreadSelf(), false);
925 * If we're watching global ref usage, also keep an eye on these.
927 * The total number of pinned primitive arrays should be pretty small.
928 * A single array should not be pinned more than once or twice; any
929 * more than that is a strong indicator that a Release function is
932 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
934 Object** ppObj = gDvm.jniPinRefTable.table;
935 while (ppObj < gDvm.jniPinRefTable.nextEntry) {
936 if (*ppObj++ == (Object*) arrayObj)
940 if (count > kPinComplainThreshold) {
941 LOGW("JNI: pin count on array %p (%s) is now %d\n",
942 arrayObj, arrayObj->obj.clazz->descriptor, count);
947 dvmUnlockMutex(&gDvm.jniPinRefLock);
951 * Un-pin the array object. If an object was pinned twice, it must be
952 * unpinned twice before it's free to move.
954 static void unpinPrimitiveArray(ArrayObject* arrayObj)
956 if (arrayObj == NULL)
959 dvmLockMutex(&gDvm.jniPinRefLock);
960 if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
961 gDvm.jniPinRefTable.table, (Object*) arrayObj))
963 LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)\n",
964 arrayObj, dvmIsValidObject((Object*) arrayObj));
969 dvmUnlockMutex(&gDvm.jniPinRefLock);
973 * GC helper function to mark all JNI global references.
975 * We're currently handling the "pin" table here too.
977 void dvmGcMarkJniGlobalRefs()
981 dvmLockMutex(&gDvm.jniGlobalRefLock);
983 #ifdef USE_INDIRECT_REF
984 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
985 op = pRefTable->table;
986 int numEntries = dvmIndirectRefTableEntries(pRefTable);
989 for (i = 0; i < numEntries; i++) {
992 dvmMarkObjectNonNull(obj);
996 op = gDvm.jniGlobalRefTable.table;
997 while ((uintptr_t)op < (uintptr_t)gDvm.jniGlobalRefTable.nextEntry) {
998 dvmMarkObjectNonNull(*(op++));
1002 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
1005 dvmLockMutex(&gDvm.jniPinRefLock);
1007 op = gDvm.jniPinRefTable.table;
1008 while ((uintptr_t)op < (uintptr_t)gDvm.jniPinRefTable.nextEntry) {
1009 dvmMarkObjectNonNull(*(op++));
1012 dvmUnlockMutex(&gDvm.jniPinRefLock);
1018 * Determine if "obj" appears in the argument list for the native method.
1020 * We use the "shorty" signature to determine which argument slots hold
1023 static bool findInArgList(Thread* self, Object* obj)
1029 fp = self->curFrame;
1032 * Back up over JNI PushLocalFrame frames. This works because the
1033 * previous frame on the interpreted stack is either a break frame
1034 * (if we called here via native code) or an interpreted method (if
1035 * we called here via the interpreter). In both cases the method
1036 * pointer won't match.
1038 StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
1039 meth = saveArea->method;
1040 if (meth != SAVEAREA_FROM_FP(saveArea->prevFrame)->method)
1042 fp = saveArea->prevFrame;
1045 LOGVV("+++ scanning %d args in %s (%s)\n",
1046 meth->insSize, meth->name, meth->shorty);
1047 const char* shorty = meth->shorty +1; /* skip return type char */
1048 for (i = 0; i < meth->insSize; i++) {
1049 if (i == 0 && !dvmIsStaticMethod(meth)) {
1050 /* first arg is "this" ref, not represented in "shorty" */
1051 if (fp[i] == (u4) obj)
1054 /* if this is a reference type, see if it matches */
1057 if (fp[i] == (u4) obj)
1065 LOGE("Whoops! ran off the end of %s (%d)\n",
1066 meth->shorty, meth->insSize);
1069 if (fp[i] == (u4) obj)
1070 LOGI("NOTE: ref %p match on arg type %c\n", obj, *shorty);
1078 * For static methods, we also pass a class pointer in.
1080 if (dvmIsStaticMethod(meth)) {
1081 //LOGI("+++ checking class pointer in %s\n", meth->name);
1082 if ((void*)obj == (void*)meth->clazz)
1090 * Verify that a reference passed in from native code is one that the
1091 * code is allowed to have.
1093 * It's okay for native code to pass us a reference that:
1094 * - was passed in as an argument when invoked by native code (and hence
1095 * is in the JNI local refs table)
1096 * - was returned to it from JNI (and is now in the local refs table)
1097 * - is present in the JNI global refs table
1099 * Used by -Xcheck:jni and GetObjectRefType.
1101 * NOTE: in the current VM, global and local references are identical. If
1102 * something is both global and local, we can't tell them apart, and always
1105 jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj)
1107 #ifdef USE_INDIRECT_REF
1109 * IndirectRefKind is currently defined as an exact match of
1110 * jobjectRefType, so this is easy. We have to decode it to determine
1111 * if it's a valid reference and not merely valid-looking.
1113 Object* obj = dvmDecodeIndirectRef(env, jobj);
1116 /* invalid ref, or jobj was NULL */
1117 return JNIInvalidRefType;
1119 return (jobjectRefType) dvmGetIndirectRefType(jobj);
1122 ReferenceTable* pRefTable = getLocalRefTable(env);
1123 Thread* self = dvmThreadSelf();
1129 if (findInArgList(self, jobj)) {
1130 //LOGI("--- REF found %p on stack\n", jobj);
1131 return JNILocalRefType;
1136 if (dvmFindInReferenceTable(pRefTable, pRefTable->table, jobj) != NULL) {
1137 //LOGI("--- REF found %p in locals\n", jobj);
1138 return JNILocalRefType;
1142 dvmLockMutex(&gDvm.jniGlobalRefLock);
1143 if (dvmFindInReferenceTable(&gDvm.jniGlobalRefTable,
1144 gDvm.jniGlobalRefTable.table, jobj))
1146 //LOGI("--- REF found %p in globals\n", jobj);
1147 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
1148 return JNIGlobalRefType;
1150 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
1153 return JNIInvalidRefType;
1158 * Register a method that uses JNI calling conventions.
1160 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
1161 const char* signature, void* fnPtr)
1164 bool result = false;
1169 method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
1171 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
1172 if (method == NULL) {
1173 LOGW("ERROR: Unable to find decl for native %s.%s %s\n",
1174 clazz->descriptor, methodName, signature);
1178 if (!dvmIsNativeMethod(method)) {
1179 LOGW("Unable to register: not native: %s.%s %s\n",
1180 clazz->descriptor, methodName, signature);
1184 if (method->nativeFunc != dvmResolveNativeMethod) {
1185 LOGW("Warning: %s.%s %s was already registered/resolved?\n",
1186 clazz->descriptor, methodName, signature);
1187 /* keep going, I guess */
1190 dvmUseJNIBridge(method, fnPtr);
1192 LOGV("JNI-registered %s.%s %s\n", clazz->descriptor, methodName,
1201 * Returns "true" if CheckJNI is enabled in the VM.
1203 static bool dvmIsCheckJNIEnabled(void)
1205 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
1206 return vm->useChecked;
1210 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
1211 * to point at the actual function.
1213 void dvmUseJNIBridge(Method* method, void* func)
1218 kJNIVirtualNoRef = 2,
1219 kJNIStaticNoRef = 3,
1221 static const DalvikBridgeFunc stdFunc[] = {
1222 dvmCallJNIMethod_general,
1223 dvmCallJNIMethod_synchronized,
1224 dvmCallJNIMethod_virtualNoRef,
1225 dvmCallJNIMethod_staticNoRef
1227 static const DalvikBridgeFunc checkFunc[] = {
1228 dvmCheckCallJNIMethod_general,
1229 dvmCheckCallJNIMethod_synchronized,
1230 dvmCheckCallJNIMethod_virtualNoRef,
1231 dvmCheckCallJNIMethod_staticNoRef
1234 bool hasRefArg = false;
1236 if (dvmIsSynchronizedMethod(method)) {
1237 /* use version with synchronization; calls into general handler */
1241 * Do a quick scan through the "shorty" signature to see if the method
1242 * takes any reference arguments.
1244 const char* cp = method->shorty;
1245 while (*++cp != '\0') { /* pre-incr to skip return type */
1247 /* 'L' used for both object and array references */
1254 /* use general handler to slurp up reference args */
1257 /* virtual methods have a ref in args[0] (not in signature) */
1258 if (dvmIsStaticMethod(method))
1259 kind = kJNIStaticNoRef;
1261 kind = kJNIVirtualNoRef;
1265 if (dvmIsCheckJNIEnabled()) {
1266 dvmSetNativeFunc(method, checkFunc[kind], func);
1268 dvmSetNativeFunc(method, stdFunc[kind], func);
1273 * Get the method currently being executed by examining the interp stack.
1275 const Method* dvmGetCurrentJNIMethod(void)
1277 assert(dvmThreadSelf() != NULL);
1279 void* fp = dvmThreadSelf()->curFrame;
1280 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
1282 assert(meth != NULL);
1283 assert(dvmIsNativeMethod(meth));
1289 * Track a JNI MonitorEnter in the current thread.
1291 * The goal is to be able to "implicitly" release all JNI-held monitors
1292 * when the thread detaches.
1294 * Monitors may be entered multiple times, so we add a new entry for each
1295 * enter call. It would be more efficient to keep a counter. At present
1296 * there's no real motivation to improve this however.
1298 static void trackMonitorEnter(Thread* self, Object* obj)
1300 static const int kInitialSize = 16;
1301 ReferenceTable* refTable = &self->jniMonitorRefTable;
1303 /* init table on first use */
1304 if (refTable->table == NULL) {
1305 assert(refTable->maxEntries == 0);
1307 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
1308 LOGE("Unable to initialize monitor tracking table\n");
1313 if (!dvmAddToReferenceTable(refTable, obj)) {
1314 /* ran out of memory? could throw exception instead */
1315 LOGE("Unable to add entry to monitor tracking table\n");
1318 LOGVV("--- added monitor %p\n", obj);
1324 * Track a JNI MonitorExit in the current thread.
1326 static void trackMonitorExit(Thread* self, Object* obj)
1328 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
1330 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
1331 LOGE("JNI monitor %p not found in tracking list\n", obj);
1334 LOGVV("--- removed monitor %p\n", obj);
1339 * Release all monitors held by the jniMonitorRefTable list.
1341 void dvmReleaseJniMonitors(Thread* self)
1343 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
1344 Object** top = pRefTable->table;
1349 Object** ptr = pRefTable->nextEntry;
1350 while (--ptr >= top) {
1351 if (!dvmUnlockObject(self, *ptr)) {
1352 LOGW("Unable to unlock monitor %p at thread detach\n", *ptr);
1354 LOGVV("--- detach-releasing monitor %p\n", *ptr);
1359 pRefTable->nextEntry = pRefTable->table;
1362 #ifdef WITH_JNI_STACK_CHECK
1364 * Compute a CRC on the entire interpreted stack.
1366 * Would be nice to compute it on "self" as well, but there are parts of
1367 * the Thread that can be altered by other threads (e.g. prev/next pointers).
1369 static void computeStackSum(Thread* self)
1371 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
1372 u4 crc = dvmInitCrc32();
1374 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
1375 self->stackCrc = crc;
1379 * Compute a CRC on the entire interpreted stack, and compare it to what
1380 * we previously computed.
1382 * We can execute JNI directly from native code without calling in from
1383 * interpreted code during VM initialization and immediately after JNI
1384 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather
1385 * than catching these cases we just ignore them here, which is marginally
1386 * less accurate but reduces the amount of code we have to touch with #ifdefs.
1388 static void checkStackSum(Thread* self)
1390 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
1393 stackCrc = self->stackCrc;
1395 crc = dvmInitCrc32();
1396 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
1397 if (crc != stackCrc) {
1398 const Method* meth = dvmGetCurrentJNIMethod();
1399 if (dvmComputeExactFrameDepth(self->curFrame) == 1) {
1400 LOGD("JNI: bad stack CRC (0x%08x) -- okay during init\n",
1402 } else if (strcmp(meth->name, "nativeLoad") == 0 &&
1403 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0))
1405 LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad\n",
1408 LOGW("JNI: bad stack CRC (%08x vs %08x)\n", crc, stackCrc);
1412 self->stackCrc = (u4) -1; /* make logic errors more noticeable */
1418 * ===========================================================================
1420 * ===========================================================================
1424 * The functions here form a bridge between interpreted code and JNI native
1425 * functions. The basic task is to convert an array of primitives and
1426 * references into C-style function arguments. This is architecture-specific
1427 * and usually requires help from assembly code.
1429 * The bridge takes four arguments: the array of parameters, a place to
1430 * store the function result (if any), the method to call, and a pointer
1431 * to the current thread.
1433 * These functions aren't called directly from elsewhere in the VM.
1434 * A pointer in the Method struct points to one of these, and when a native
1435 * method is invoked the interpreter jumps to it.
1437 * (The "internal native" methods are invoked the same way, but instead
1438 * of calling through a bridge, the target method is called directly.)
1440 * The "args" array should not be modified, but we do so anyway for
1441 * performance reasons. We know that it points to the "outs" area on
1442 * the current method's interpreted stack. This area is ignored by the
1443 * precise GC, because there is no register map for a native method (for
1444 * an interpreted method the args would be listed in the argument set).
1445 * We know all of the values exist elsewhere on the interpreted stack,
1446 * because the method call setup copies them right before making the call,
1447 * so we don't have to worry about concealing stuff from the GC.
1449 * If we don't want to modify "args", we either have to create a local
1450 * copy and modify it before calling dvmPlatformInvoke, or we have to do
1451 * the local reference replacement within dvmPlatformInvoke. The latter
1452 * has some performance advantages, though if we can inline the local
1453 * reference adds we may win when there's a lot of reference args (unless
1454 * we want to code up some local ref table manipulation in assembly.
1458 * If necessary, convert the value in pResult from a local/global reference
1459 * to an object pointer.
1461 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
1462 const Method* method, Thread* self)
1464 if (method->shorty[0] == 'L' && !dvmCheckException(self) &&
1467 pResult->l = dvmDecodeIndirectRef(env, pResult->l);
1472 * General form, handles all cases.
1474 void dvmCallJNIMethod_general(const u4* args, JValue* pResult,
1475 const Method* method, Thread* self)
1478 u4* modArgs = (u4*) args;
1480 assert(method->insns != NULL);
1482 //LOGI("JNI calling %p (%s.%s:%s):\n", method->insns,
1483 // method->clazz->descriptor, method->name, method->shorty);
1486 * Walk the argument list, creating local references for appropriate
1489 JNIEnv* env = self->jniEnv;
1490 jclass staticMethodClass;
1492 if (dvmIsStaticMethod(method)) {
1493 /* add the class object we pass in */
1494 staticMethodClass = addLocalReference(env, (Object*) method->clazz);
1495 if (staticMethodClass == NULL) {
1496 assert(dvmCheckException(self));
1501 staticMethodClass = NULL;
1502 jobject thisObj = addLocalReference(env, (Object*) modArgs[0]);
1503 if (thisObj == NULL) {
1504 assert(dvmCheckException(self));
1507 modArgs[idx] = (u4) thisObj;
1511 const char* shorty = &method->shorty[1]; /* skip return type */
1512 while (*shorty != '\0') {
1513 switch (*shorty++) {
1515 //LOGI(" local %d: 0x%08x\n", idx, modArgs[idx]);
1516 if (modArgs[idx] != 0) {
1517 //if (!dvmIsValidObject((Object*) modArgs[idx]))
1519 jobject argObj = addLocalReference(env, (Object*) modArgs[idx]);
1520 if (argObj == NULL) {
1521 assert(dvmCheckException(self));
1524 modArgs[idx] = (u4) argObj;
1532 /* Z B C S I -- do nothing */
1539 oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1541 COMPUTE_STACK_SUM(self);
1542 dvmPlatformInvoke(self->jniEnv, staticMethodClass,
1543 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1544 (void*)method->insns, pResult);
1545 CHECK_STACK_SUM(self);
1547 dvmChangeStatus(self, oldStatus);
1549 convertReferenceResult(env, pResult, method, self);
1553 * Handler for the unusual case of a synchronized native method.
1555 * Lock the object, then call through the general function.
1557 void dvmCallJNIMethod_synchronized(const u4* args, JValue* pResult,
1558 const Method* method, Thread* self)
1562 assert(dvmIsSynchronizedMethod(method));
1564 if (dvmIsStaticMethod(method))
1565 lockObj = (Object*) method->clazz;
1567 lockObj = (Object*) args[0];
1569 LOGVV("Calling %s.%s: locking %p (%s)\n",
1570 method->clazz->descriptor, method->name,
1571 lockObj, lockObj->clazz->descriptor);
1573 dvmLockObject(self, lockObj);
1574 dvmCallJNIMethod_general(args, pResult, method, self);
1575 dvmUnlockObject(self, lockObj);
1579 * Virtual method call, no reference arguments.
1581 * We need to local-ref the "this" argument, found in args[0].
1583 void dvmCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult,
1584 const Method* method, Thread* self)
1586 u4* modArgs = (u4*) args;
1589 jobject thisObj = addLocalReference(self->jniEnv, (Object*) args[0]);
1590 if (thisObj == NULL) {
1591 assert(dvmCheckException(self));
1594 modArgs[0] = (u4) thisObj;
1596 oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1598 COMPUTE_STACK_SUM(self);
1599 dvmPlatformInvoke(self->jniEnv, NULL,
1600 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1601 (void*)method->insns, pResult);
1602 CHECK_STACK_SUM(self);
1604 dvmChangeStatus(self, oldStatus);
1606 convertReferenceResult(self->jniEnv, pResult, method, self);
1610 * Static method call, no reference arguments.
1612 * We need to local-ref the class reference.
1614 void dvmCallJNIMethod_staticNoRef(const u4* args, JValue* pResult,
1615 const Method* method, Thread* self)
1617 jclass staticMethodClass;
1620 staticMethodClass = addLocalReference(self->jniEnv, (Object*)method->clazz);
1621 if (staticMethodClass == NULL) {
1622 assert(dvmCheckException(self));
1626 oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1628 COMPUTE_STACK_SUM(self);
1629 dvmPlatformInvoke(self->jniEnv, staticMethodClass,
1630 method->jniArgInfo, method->insSize, args, method->shorty,
1631 (void*)method->insns, pResult);
1632 CHECK_STACK_SUM(self);
1634 dvmChangeStatus(self, oldStatus);
1636 convertReferenceResult(self->jniEnv, pResult, method, self);
1640 * Extract the return type enum from the "jniArgInfo" field.
1642 DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
1644 return (jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT;
1649 * ===========================================================================
1650 * JNI implementation
1651 * ===========================================================================
1655 * Return the version of the native method interface.
1657 static jint GetVersion(JNIEnv* env)
1661 * There is absolutely no need to toggle the mode for correct behavior.
1662 * However, it does provide native code with a simple "suspend self
1663 * if necessary" call.
1666 return JNI_VERSION_1_6;
1670 * Create a new class from a bag of bytes.
1672 * This is not currently supported within Dalvik.
1674 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1675 const jbyte* buf, jsize bufLen)
1677 UNUSED_PARAMETER(name);
1678 UNUSED_PARAMETER(loader);
1679 UNUSED_PARAMETER(buf);
1680 UNUSED_PARAMETER(bufLen);
1683 LOGW("JNI DefineClass is not supported\n");
1689 * Find a class by name.
1691 * We have to use the "no init" version of FindClass here, because we might
1692 * be getting the class prior to registering native methods that will be
1695 * We need to get the class loader associated with the current native
1696 * method. If there is no native method, e.g. we're calling this from native
1697 * code right after creating the VM, the spec says we need to use the class
1698 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1699 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1700 * We can't get that until after the VM has initialized though.
1702 static jclass FindClass(JNIEnv* env, const char* name)
1706 const Method* thisMethod;
1708 jclass jclazz = NULL;
1710 char* descriptor = NULL;
1712 thisMethod = dvmGetCurrentJNIMethod();
1713 assert(thisMethod != NULL);
1715 descriptor = dvmNameToDescriptor(name);
1716 if (descriptor == NULL) {
1721 //Thread* self = dvmThreadSelf();
1722 if (_self->classLoaderOverride != NULL) {
1723 /* hack for JNI_OnLoad */
1724 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1725 loader = _self->classLoaderOverride;
1726 } else if (thisMethod == gDvm.methFakeNativeEntry) {
1727 /* start point of invocation interface */
1728 if (!gDvm.initializing)
1729 loader = dvmGetSystemClassLoader();
1733 loader = thisMethod->clazz->classLoader;
1736 clazz = dvmFindClassNoInit(descriptor, loader);
1737 jclazz = addLocalReference(env, (Object*) clazz);
1747 * Return the superclass of a class.
1749 static jclass GetSuperclass(JNIEnv* env, jclass jclazz)
1754 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1758 jsuper = addLocalReference(env, (Object*)clazz->super);
1764 * Determine whether an object of clazz1 can be safely cast to clazz2.
1766 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1768 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2)
1772 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1);
1773 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2);
1775 jboolean result = dvmInstanceof(clazz1, clazz2);
1782 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1784 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod)
1788 Object* method = dvmDecodeIndirectRef(env, jmethod);
1789 methodID = (jmethodID) dvmGetMethodFromReflectObj(method);
1795 * Given a java.lang.reflect.Field, return a fieldID.
1797 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield)
1801 Object* field = dvmDecodeIndirectRef(env, jfield);
1802 fieldID = (jfieldID) dvmGetFieldFromReflectObj(field);
1808 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1810 * (The "isStatic" field does not appear in the spec.)
1812 * Throws OutOfMemory and returns NULL on failure.
1814 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID,
1818 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
1819 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1820 dvmReleaseTrackedAlloc(obj, NULL);
1821 jobject jobj = addLocalReference(env, obj);
1827 * Convert a fieldID to a java.lang.reflect.Field.
1829 * (The "isStatic" field does not appear in the spec.)
1831 * Throws OutOfMemory and returns NULL on failure.
1833 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID,
1837 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
1838 Object* obj = dvmCreateReflectObjForField(jcls, (Field*) fieldID);
1839 dvmReleaseTrackedAlloc(obj, NULL);
1840 jobject jobj = addLocalReference(env, obj);
1846 * Take this exception and throw it.
1848 static jint Throw(JNIEnv* env, jthrowable jobj)
1855 Object* obj = dvmDecodeIndirectRef(env, jobj);
1856 dvmSetException(_self, obj);
1867 * Constructs an exception object from the specified class with the message
1868 * specified by "message", and throws it.
1870 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message)
1874 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
1875 dvmThrowExceptionByClass(clazz, message);
1876 // TODO: should return failure if this didn't work (e.g. OOM)
1883 * If an exception is being thrown, return the exception object. Otherwise,
1886 * TODO: if there is no pending exception, we should be able to skip the
1887 * enter/exit checks. If we find one, we need to enter and then re-fetch
1888 * the exception (in case it got moved by a compacting GC).
1890 static jthrowable ExceptionOccurred(JNIEnv* env)
1895 jobject localException;
1897 exception = dvmGetException(_self);
1898 localException = addLocalReference(env, exception);
1899 if (localException == NULL && exception != NULL) {
1901 * We were unable to add a new local reference, and threw a new
1902 * exception. We can't return "exception", because it's not a
1903 * local reference. So we have to return NULL, indicating that
1904 * there was no exception, even though it's pretty much raining
1905 * exceptions in here.
1907 LOGW("JNI WARNING: addLocal/exception combo\n");
1911 return localException;
1915 * Print an exception and stack trace to stderr.
1917 static void ExceptionDescribe(JNIEnv* env)
1921 Object* exception = dvmGetException(_self);
1922 if (exception != NULL) {
1923 dvmPrintExceptionStackTrace();
1925 LOGI("Odd: ExceptionDescribe called, but no exception pending\n");
1932 * Clear the exception currently being thrown.
1934 * TODO: we should be able to skip the enter/exit stuff.
1936 static void ExceptionClear(JNIEnv* env)
1939 dvmClearException(_self);
1944 * Kill the VM. This function does not return.
1946 static void FatalError(JNIEnv* env, const char* msg)
1948 //dvmChangeStatus(NULL, THREAD_RUNNING);
1949 LOGE("JNI posting fatal error: %s\n", msg);
1954 * Push a new JNI frame on the stack, with a new set of locals.
1956 * The new frame must have the same method pointer. (If for no other
1957 * reason than FindClass needs it to get the appropriate class loader.)
1959 static jint PushLocalFrame(JNIEnv* env, jint capacity)
1962 int result = JNI_OK;
1963 if (!ensureLocalCapacity(env, capacity) ||
1964 !dvmPushLocalFrame(_self /*dvmThreadSelf()*/, dvmGetCurrentJNIMethod()))
1966 /* yes, OutOfMemoryError, not StackOverflowError */
1967 dvmClearException(_self);
1968 dvmThrowException("Ljava/lang/OutOfMemoryError;",
1969 "out of stack in JNI PushLocalFrame");
1977 * Pop the local frame off. If "result" is not null, add it as a
1978 * local reference on the now-current frame.
1980 static jobject PopLocalFrame(JNIEnv* env, jobject jresult)
1983 Object* result = dvmDecodeIndirectRef(env, jresult);
1984 if (!dvmPopLocalFrame(_self /*dvmThreadSelf()*/)) {
1985 LOGW("JNI WARNING: too many PopLocalFrame calls\n");
1986 dvmClearException(_self);
1987 dvmThrowException("Ljava/lang/RuntimeException;",
1988 "too many PopLocalFrame calls");
1990 jresult = addLocalReference(env, result);
1996 * Add a reference to the global list.
1998 static jobject NewGlobalRef(JNIEnv* env, jobject jobj)
2001 Object* obj = dvmDecodeIndirectRef(env, jobj);
2002 jobject retval = addGlobalReference(obj);
2008 * Delete a reference from the global list.
2010 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef)
2013 deleteGlobalReference(jglobalRef);
2019 * Add a reference to the local list.
2021 static jobject NewLocalRef(JNIEnv* env, jobject jref)
2024 Object* obj = dvmDecodeIndirectRef(env, jref);
2025 jobject retval = addLocalReference(env, obj);
2031 * Delete a reference from the local list.
2033 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef)
2036 deleteLocalReference(env, jlocalRef);
2041 * Ensure that the local references table can hold at least this many
2044 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity)
2047 bool okay = ensureLocalCapacity(env, capacity);
2049 dvmThrowException("Ljava/lang/OutOfMemoryError;",
2050 "can't ensure local reference capacity");
2061 * Determine whether two Object references refer to the same underlying object.
2063 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2)
2066 Object* obj1 = dvmDecodeIndirectRef(env, jref1);
2067 Object* obj2 = dvmDecodeIndirectRef(env, jref2);
2068 jboolean result = (obj1 == obj2);
2074 * Allocate a new object without invoking any constructors.
2076 static jobject AllocObject(JNIEnv* env, jclass jclazz)
2080 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2083 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2084 assert(dvmCheckException(_self));
2087 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2088 result = addLocalReference(env, newObj);
2096 * Allocate a new object and invoke the supplied constructor.
2098 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...)
2101 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2104 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2105 assert(dvmCheckException(_self));
2108 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2109 result = addLocalReference(env, newObj);
2110 if (newObj != NULL) {
2113 va_start(args, methodID);
2114 dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused,
2123 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID,
2127 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2130 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2131 result = addLocalReference(env, newObj);
2132 if (newObj != NULL) {
2134 dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused, args);
2140 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID,
2144 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2147 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2148 result = addLocalReference(env, newObj);
2149 if (newObj != NULL) {
2151 dvmCallMethodA(_self, (Method*) methodID, newObj, true, &unused, args);
2159 * Returns the class of an object.
2161 * JNI spec says: obj must not be NULL.
2163 static jclass GetObjectClass(JNIEnv* env, jobject jobj)
2167 assert(jobj != NULL);
2169 Object* obj = dvmDecodeIndirectRef(env, jobj);
2170 jclass jclazz = addLocalReference(env, (Object*) obj->clazz);
2177 * Determine whether "obj" is an instance of "clazz".
2179 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz)
2183 assert(jclazz != NULL);
2190 Object* obj = dvmDecodeIndirectRef(env, jobj);
2191 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2192 result = dvmInstanceof(obj->clazz, clazz);
2200 * Get a method ID for an instance method.
2202 * JNI defines <init> as an instance method, but Dalvik considers it a
2203 * "direct" method, so we have to special-case it here.
2205 * Dalvik also puts all private methods into the "direct" list, so we
2206 * really need to just search both lists.
2208 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,
2213 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2214 jmethodID id = NULL;
2216 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2217 assert(dvmCheckException(_self));
2221 meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
2223 /* search private methods and constructors; non-hierarchical */
2224 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
2226 if (meth != NULL && dvmIsStaticMethod(meth)) {
2228 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
2229 LOGD("GetMethodID: not returning static method %s.%s %s\n",
2230 clazz->descriptor, meth->name, desc);
2236 LOGD("GetMethodID: method not found: %s.%s:%s\n",
2237 clazz->descriptor, name, sig);
2238 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
2242 * The method's class may not be the same as clazz, but if
2243 * it isn't this must be a virtual method and the class must
2244 * be a superclass (and, hence, already initialized).
2247 assert(dvmIsClassInitialized(meth->clazz) ||
2248 dvmIsClassInitializing(meth->clazz));
2250 id = (jmethodID) meth;
2257 * Get a field ID (instance fields).
2259 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,
2260 const char* name, const char* sig)
2264 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2267 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2268 assert(dvmCheckException(_self));
2271 id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
2273 LOGD("GetFieldID: unable to find field %s.%s:%s\n",
2274 clazz->descriptor, name, sig);
2275 dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
2283 * Get the method ID for a static method in a class.
2285 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz,
2286 const char* name, const char* sig)
2290 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2293 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2294 assert(dvmCheckException(_self));
2299 meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
2301 /* make sure it's static, not virtual+private */
2302 if (meth != NULL && !dvmIsStaticMethod(meth)) {
2304 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
2305 LOGD("GetStaticMethodID: "
2306 "not returning nonstatic method %s.%s %s\n",
2307 clazz->descriptor, meth->name, desc);
2313 id = (jmethodID) meth;
2315 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
2323 * Get a field ID (static fields).
2325 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz,
2326 const char* name, const char* sig)
2330 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2333 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2334 assert(dvmCheckException(_self));
2337 id = (jfieldID) dvmFindStaticField(clazz, name, sig);
2339 dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
2346 * Get a static field.
2348 * If we get an object reference, add it to the local refs list.
2350 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
2351 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
2354 UNUSED_PARAMETER(jclazz); \
2356 StaticField* sfield = (StaticField*) fieldID; \
2358 if (_isref) { /* only when _ctype==jobject */ \
2359 Object* obj = dvmGetStaticFieldObject(sfield); \
2360 value = (_ctype)(u4)addLocalReference(env, obj); \
2362 value = dvmGetStaticField##_jname(sfield); \
2367 GET_STATIC_TYPE_FIELD(jobject, Object, true);
2368 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
2369 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
2370 GET_STATIC_TYPE_FIELD(jchar, Char, false);
2371 GET_STATIC_TYPE_FIELD(jshort, Short, false);
2372 GET_STATIC_TYPE_FIELD(jint, Int, false);
2373 GET_STATIC_TYPE_FIELD(jlong, Long, false);
2374 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
2375 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
2378 * Set a static field.
2380 #define SET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
2381 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
2382 jfieldID fieldID, _ctype value) \
2384 UNUSED_PARAMETER(jclazz); \
2386 StaticField* sfield = (StaticField*) fieldID; \
2387 if (_isref) { /* only when _ctype==jobject */ \
2388 Object* valObj = dvmDecodeIndirectRef(env, (jobject)(u4)value); \
2389 dvmSetStaticFieldObject(sfield, valObj); \
2391 dvmSetStaticField##_jname(sfield, value); \
2395 SET_STATIC_TYPE_FIELD(jobject, Object, true);
2396 SET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
2397 SET_STATIC_TYPE_FIELD(jbyte, Byte, false);
2398 SET_STATIC_TYPE_FIELD(jchar, Char, false);
2399 SET_STATIC_TYPE_FIELD(jshort, Short, false);
2400 SET_STATIC_TYPE_FIELD(jint, Int, false);
2401 SET_STATIC_TYPE_FIELD(jlong, Long, false);
2402 SET_STATIC_TYPE_FIELD(jfloat, Float, false);
2403 SET_STATIC_TYPE_FIELD(jdouble, Double, false);
2406 * Get an instance field.
2408 * If we get an object reference, add it to the local refs list.
2410 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \
2411 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \
2415 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2416 InstField* field = (InstField*) fieldID; \
2418 if (_isref) { /* only when _ctype==jobject */ \
2419 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
2420 value = (_ctype)(u4)addLocalReference(env, valObj); \
2422 value = dvmGetField##_jname(obj, field->byteOffset); \
2427 GET_TYPE_FIELD(jobject, Object, true);
2428 GET_TYPE_FIELD(jboolean, Boolean, false);
2429 GET_TYPE_FIELD(jbyte, Byte, false);
2430 GET_TYPE_FIELD(jchar, Char, false);
2431 GET_TYPE_FIELD(jshort, Short, false);
2432 GET_TYPE_FIELD(jint, Int, false);
2433 GET_TYPE_FIELD(jlong, Long, false);
2434 GET_TYPE_FIELD(jfloat, Float, false);
2435 GET_TYPE_FIELD(jdouble, Double, false);
2438 * Set an instance field.
2440 #define SET_TYPE_FIELD(_ctype, _jname, _isref) \
2441 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \
2442 jfieldID fieldID, _ctype value) \
2445 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2446 InstField* field = (InstField*) fieldID; \
2447 if (_isref) { /* only when _ctype==jobject */ \
2448 Object* valObj = dvmDecodeIndirectRef(env, (jobject)(u4)value); \
2449 dvmSetFieldObject(obj, field->byteOffset, valObj); \
2451 dvmSetField##_jname(obj, field->byteOffset, value); \
2455 SET_TYPE_FIELD(jobject, Object, true);
2456 SET_TYPE_FIELD(jboolean, Boolean, false);
2457 SET_TYPE_FIELD(jbyte, Byte, false);
2458 SET_TYPE_FIELD(jchar, Char, false);
2459 SET_TYPE_FIELD(jshort, Short, false);
2460 SET_TYPE_FIELD(jint, Int, false);
2461 SET_TYPE_FIELD(jlong, Long, false);
2462 SET_TYPE_FIELD(jfloat, Float, false);
2463 SET_TYPE_FIELD(jdouble, Double, false);
2466 * Make a virtual method call.
2468 * Three versions (..., va_list, jvalue[]) for each return type. If we're
2469 * returning an Object, we have to add it to the local references table.
2471 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
2472 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \
2473 jmethodID methodID, ...) \
2476 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2477 const Method* meth; \
2480 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
2481 if (meth == NULL) { \
2485 va_start(args, methodID); \
2486 dvmCallMethodV(_self, meth, obj, true, &result, args); \
2488 if (_isref && !dvmCheckException(_self)) \
2489 result.l = addLocalReference(env, result.l); \
2493 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \
2494 jmethodID methodID, va_list args) \
2497 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2498 const Method* meth; \
2500 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
2501 if (meth == NULL) { \
2505 dvmCallMethodV(_self, meth, obj, true, &result, args); \
2506 if (_isref && !dvmCheckException(_self)) \
2507 result.l = addLocalReference(env, result.l); \
2511 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \
2512 jmethodID methodID, jvalue* args) \
2515 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2516 const Method* meth; \
2518 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
2519 if (meth == NULL) { \
2523 dvmCallMethodA(_self, meth, obj, true, &result, args); \
2524 if (_isref && !dvmCheckException(_self)) \
2525 result.l = addLocalReference(env, result.l); \
2529 CALL_VIRTUAL(jobject, Object, NULL, result.l, true);
2530 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
2531 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
2532 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
2533 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
2534 CALL_VIRTUAL(jint, Int, 0, result.i, false);
2535 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
2536 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
2537 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
2538 CALL_VIRTUAL(void, Void, , , false);
2541 * Make a "non-virtual" method call. We're still calling a virtual method,
2542 * but this time we're not doing an indirection through the object's vtable.
2543 * The "clazz" parameter defines which implementation of a method we want.
2545 * Three versions (..., va_list, jvalue[]) for each return type.
2547 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
2548 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
2549 jclass jclazz, jmethodID methodID, ...) \
2552 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2553 ClassObject* clazz = \
2554 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
2555 const Method* meth; \
2558 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2559 if (meth == NULL) { \
2563 va_start(args, methodID); \
2564 dvmCallMethodV(_self, meth, obj, true, &result, args); \
2565 if (_isref && !dvmCheckException(_self)) \
2566 result.l = addLocalReference(env, result.l); \
2571 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
2572 jclass jclazz, jmethodID methodID, va_list args) \
2575 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2576 ClassObject* clazz = \
2577 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
2578 const Method* meth; \
2580 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2581 if (meth == NULL) { \
2585 dvmCallMethodV(_self, meth, obj, true, &result, args); \
2586 if (_isref && !dvmCheckException(_self)) \
2587 result.l = addLocalReference(env, result.l); \
2591 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2592 jclass jclazz, jmethodID methodID, jvalue* args) \
2595 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2596 ClassObject* clazz = \
2597 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
2598 const Method* meth; \
2600 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2601 if (meth == NULL) { \
2605 dvmCallMethodA(_self, meth, obj, true, &result, args); \
2606 if (_isref && !dvmCheckException(_self)) \
2607 result.l = addLocalReference(env, result.l); \
2611 CALL_NONVIRTUAL(jobject, Object, NULL, result.l, true);
2612 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2613 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2614 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2615 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2616 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2617 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2618 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2619 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2620 CALL_NONVIRTUAL(void, Void, , , false);
2624 * Call a static method.
2626 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
2627 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \
2628 jmethodID methodID, ...) \
2630 UNUSED_PARAMETER(jclazz); \
2634 va_start(args, methodID); \
2635 dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
2637 if (_isref && !dvmCheckException(_self)) \
2638 result.l = addLocalReference(env, result.l); \
2642 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
2643 jmethodID methodID, va_list args) \
2645 UNUSED_PARAMETER(jclazz); \
2648 dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
2649 if (_isref && !dvmCheckException(_self)) \
2650 result.l = addLocalReference(env, result.l); \
2654 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \
2655 jmethodID methodID, jvalue* args) \
2657 UNUSED_PARAMETER(jclazz); \
2660 dvmCallMethodA(_self, (Method*)methodID, NULL, true, &result, args);\
2661 if (_isref && !dvmCheckException(_self)) \
2662 result.l = addLocalReference(env, result.l); \
2666 CALL_STATIC(jobject, Object, NULL, result.l, true);
2667 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2668 CALL_STATIC(jbyte, Byte, 0, result.b, false);
2669 CALL_STATIC(jchar, Char, 0, result.c, false);
2670 CALL_STATIC(jshort, Short, 0, result.s, false);
2671 CALL_STATIC(jint, Int, 0, result.i, false);
2672 CALL_STATIC(jlong, Long, 0, result.j, false);
2673 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2674 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2675 CALL_STATIC(void, Void, , , false);
2678 * Create a new String from Unicode data.
2680 * If "len" is zero, we will return an empty string even if "unicodeChars"
2681 * is NULL. (The JNI spec is vague here.)
2683 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len)
2688 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2692 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2693 retval = addLocalReference(env, (Object*) jstr);
2701 * Return the length of a String in Unicode character units.
2703 static jsize GetStringLength(JNIEnv* env, jstring jstr)
2707 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2708 jsize len = dvmStringLen(strObj);
2716 * Get a string's character data.
2718 * The result is guaranteed to be valid until ReleaseStringChars is
2719 * called, which means we have to pin it or return a copy.
2721 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy)
2725 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2726 ArrayObject* strChars = dvmStringCharArray(strObj);
2728 pinPrimitiveArray(strChars);
2730 const u2* data = dvmStringChars(strObj);
2732 *isCopy = JNI_FALSE;
2735 return (jchar*)data;
2739 * Release our grip on some characters from a string.
2741 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars)
2744 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2745 ArrayObject* strChars = dvmStringCharArray(strObj);
2746 unpinPrimitiveArray(strChars);
2751 * Create a new java.lang.String object from chars in modified UTF-8 form.
2753 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2754 * accept it and return a NULL pointer in response.
2756 static jstring NewStringUTF(JNIEnv* env, const char* bytes)
2762 if (bytes == NULL) {
2765 /* note newStr could come back NULL on OOM */
2766 StringObject* newStr = dvmCreateStringFromCstr(bytes, ALLOC_DEFAULT);
2767 result = addLocalReference(env, (Object*) newStr);
2768 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2776 * Return the length in bytes of the modified UTF-8 form of the string.
2778 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr)
2782 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2783 jsize len = dvmStringUtf8ByteLen(strObj);
2790 * Convert "string" to modified UTF-8 and return a pointer. The returned
2791 * value must be released with ReleaseStringUTFChars.
2793 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2794 * or NULL if the operation fails. Returns NULL if and only if an invocation
2795 * of this function has thrown an exception."
2797 * The behavior here currently follows that of other open-source VMs, which
2798 * quietly return NULL if "string" is NULL. We should consider throwing an
2799 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
2800 * which should catch this sort of thing during development.) Certain other
2801 * VMs will crash with a segmentation fault.
2803 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr,
2810 /* this shouldn't happen; throw NPE? */
2816 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2817 newStr = dvmCreateCstrFromString(strObj);
2818 if (newStr == NULL) {
2819 /* assume memory failure */
2820 dvmThrowException("Ljava/lang/OutOfMemoryError;",
2821 "native heap string alloc failed");
2830 * Release a string created by GetStringUTFChars().
2832 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf)
2840 * Return the capacity of the array.
2842 static jsize GetArrayLength(JNIEnv* env, jarray jarr)
2846 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2847 jsize length = arrObj->length;
2854 * Construct a new array that holds objects from class "elementClass".
2856 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2857 jclass jelementClass, jobject jinitialElement)
2861 jobjectArray newArray = NULL;
2862 ClassObject* elemClassObj =
2863 (ClassObject*) dvmDecodeIndirectRef(env, jelementClass);
2865 if (elemClassObj == NULL) {
2866 dvmThrowException("Ljava/lang/NullPointerException;",
2867 "JNI NewObjectArray");
2871 ArrayObject* newObj =
2872 dvmAllocObjectArray(elemClassObj, length, ALLOC_DEFAULT);
2873 if (newObj == NULL) {
2874 assert(dvmCheckException(_self));
2877 newArray = addLocalReference(env, (Object*) newObj);
2878 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2881 * Initialize the array. Trashes "length".
2883 if (jinitialElement != NULL) {
2884 Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement);
2885 Object** arrayData = (Object**) newObj->contents;
2888 *arrayData++ = initialElement;
2898 * Get one element of an Object array.
2900 * Add the object to the local references table in case the array goes away.
2902 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
2907 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2908 jobject retval = NULL;
2910 assert(arrayObj != NULL);
2912 /* check the array bounds */
2913 if (index < 0 || index >= (int) arrayObj->length) {
2914 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
2915 arrayObj->obj.clazz->descriptor);
2919 Object* value = ((Object**) arrayObj->contents)[index];
2920 retval = addLocalReference(env, value);
2928 * Set one element of an Object array.
2930 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
2931 jsize index, jobject jobj)
2935 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
2937 assert(arrayObj != NULL);
2939 /* check the array bounds */
2940 if (index < 0 || index >= (int) arrayObj->length) {
2941 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
2942 arrayObj->obj.clazz->descriptor);
2946 //LOGV("JNI: set element %d in array %p to %p\n", index, array, value);
2948 Object* obj = dvmDecodeIndirectRef(env, jobj);
2949 ((Object**) arrayObj->contents)[index] = obj;
2956 * Create a new array of primitive elements.
2958 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2959 static _artype New##_jname##Array(JNIEnv* env, jsize length) \
2962 ArrayObject* arrayObj; \
2963 arrayObj = dvmAllocPrimitiveArray(_typechar, length, \
2965 jarray jarr = NULL; \
2966 if (arrayObj != NULL) { \
2967 jarr = addLocalReference(env, (Object*) arrayObj); \
2968 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2971 return (_artype)jarr; \
2973 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2974 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2975 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2976 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2977 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2978 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2979 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2980 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2983 * Get a pointer to a C array of primitive elements from an array object
2984 * of the matching type.
2986 * In a compacting GC, we either need to return a copy of the elements or
2987 * "pin" the memory. Otherwise we run the risk of native code using the
2988 * buffer as the destination of e.g. a blocking read() call that wakes up
2991 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2992 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2993 _ctype##Array jarr, jboolean* isCopy) \
2997 ArrayObject* arrayObj = \
2998 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
2999 pinPrimitiveArray(arrayObj); \
3000 data = (_ctype*) arrayObj->contents; \
3001 if (isCopy != NULL) \
3002 *isCopy = JNI_FALSE; \
3008 * Release the storage locked down by the "get" function.
3010 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
3011 * elements in 'array'." They apparently did not anticipate the need to
3014 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
3015 static void Release##_jname##ArrayElements(JNIEnv* env, \
3016 _ctype##Array jarr, _ctype* elems, jint mode) \
3018 UNUSED_PARAMETER(elems); \
3020 if (mode != JNI_COMMIT) { \
3021 ArrayObject* arrayObj = \
3022 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
3023 unpinPrimitiveArray(arrayObj); \
3029 * Copy a section of a primitive array to a buffer.
3031 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
3032 static void Get##_jname##ArrayRegion(JNIEnv* env, \
3033 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
3036 ArrayObject* arrayObj = \
3037 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
3038 _ctype* data = (_ctype*) arrayObj->contents; \
3039 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
3040 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
3041 arrayObj->obj.clazz->descriptor); \
3043 memcpy(buf, data + start, len * sizeof(_ctype)); \
3049 * Copy a section of a primitive array to a buffer.
3051 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
3052 static void Set##_jname##ArrayRegion(JNIEnv* env, \
3053 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
3056 ArrayObject* arrayObj = \
3057 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
3058 _ctype* data = (_ctype*) arrayObj->contents; \
3059 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
3060 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
3061 arrayObj->obj.clazz->descriptor); \
3063 memcpy(data + start, buf, len * sizeof(_ctype)); \
3070 * Get<Type>ArrayElements
3071 * Release<Type>ArrayElements
3072 * Get<Type>ArrayRegion
3073 * Set<Type>ArrayRegion
3075 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
3076 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
3077 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
3078 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
3079 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
3081 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
3082 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
3083 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
3084 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
3085 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
3086 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
3087 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
3088 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
3091 * Register one or more native functions in one class.
3093 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
3094 const JNINativeMethod* methods, jint nMethods)
3098 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
3102 if (gDvm.verboseJni) {
3103 LOGI("[Registering JNI native methods for class %s]\n",
3107 for (i = 0; i < nMethods; i++) {
3108 if (!dvmRegisterJNIMethod(clazz, methods[i].name,
3109 methods[i].signature, methods[i].fnPtr))
3123 * Un-register a native function.
3125 static jint UnregisterNatives(JNIEnv* env, jclass jclazz)
3129 * The JNI docs refer to this as a way to reload/relink native libraries,
3130 * and say it "should not be used in normal native code".
3132 * We can implement it if we decide we need it.
3141 * We have to track all monitor enters and exits, so that we can undo any
3142 * outstanding synchronization before the thread exits.
3144 static jint MonitorEnter(JNIEnv* env, jobject jobj)
3147 Object* obj = dvmDecodeIndirectRef(env, jobj);
3148 dvmLockObject(_self, obj);
3149 trackMonitorEnter(_self, obj);
3155 * Unlock the monitor.
3157 * Throws an IllegalMonitorStateException if the current thread
3158 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
3160 * According to the 1.6 spec, it's legal to call here with an exception
3161 * pending. If this fails, we'll stomp the original exception.
3163 static jint MonitorExit(JNIEnv* env, jobject jobj)
3166 Object* obj = dvmDecodeIndirectRef(env, jobj);
3167 bool success = dvmUnlockObject(_self, obj);
3169 trackMonitorExit(_self, obj);
3171 return success ? JNI_OK : JNI_ERR;
3175 * Return the JavaVM interface associated with the current thread.
3177 static jint GetJavaVM(JNIEnv* env, JavaVM** vm)
3180 //*vm = gDvm.vmList;
3181 *vm = (JavaVM*) ((JNIEnvExt*)env)->vm;
3190 * Copies "len" Unicode characters, from offset "start".
3192 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len,
3196 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
3197 if (start + len > dvmStringLen(strObj))
3198 dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
3200 memcpy(buf, dvmStringChars(strObj) + start, len * sizeof(u2));
3205 * Translates "len" Unicode characters, from offset "start", into
3206 * modified UTF-8 encoding.
3208 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start,
3209 jsize len, char* buf)
3212 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
3213 if (start + len > dvmStringLen(strObj))
3214 dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
3216 dvmCreateCstrFromStringRegion(strObj, start, len, buf);
3221 * Get a raw pointer to array data.
3223 * The caller is expected to call "release" before doing any JNI calls
3224 * or blocking I/O operations.
3226 * We need to pin the memory or block GC.
3228 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr,
3233 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
3234 pinPrimitiveArray(arrayObj);
3235 data = arrayObj->contents;
3237 *isCopy = JNI_FALSE;
3243 * Release an array obtained with GetPrimitiveArrayCritical.
3245 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr,
3246 void* carray, jint mode)
3249 if (mode != JNI_COMMIT) {
3250 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
3251 unpinPrimitiveArray(arrayObj);
3257 * Like GetStringChars, but with restricted use.
3259 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr,
3263 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
3264 ArrayObject* strChars = dvmStringCharArray(strObj);
3266 pinPrimitiveArray(strChars);
3268 const u2* data = dvmStringChars(strObj);
3270 *isCopy = JNI_FALSE;
3273 return (jchar*)data;
3277 * Like ReleaseStringChars, but with restricted use.
3279 static void ReleaseStringCritical(JNIEnv* env, jstring jstr,
3280 const jchar* carray)
3283 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
3284 ArrayObject* strChars = dvmStringCharArray(strObj);
3285 unpinPrimitiveArray(strChars);
3290 * Create a new weak global reference.
3292 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj)
3296 jobject gref = NULL;
3297 LOGE("JNI ERROR: NewWeakGlobalRef not implemented\n");
3304 * Delete the specified weak global reference.
3306 static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj)
3310 LOGE("JNI ERROR: DeleteWeakGlobalRef not implemented\n");
3316 * Quick check for pending exceptions.
3318 * TODO: we should be able to skip the enter/exit macros here.
3320 static jboolean ExceptionCheck(JNIEnv* env)
3323 bool result = dvmCheckException(_self);
3329 * Returns the type of the object referred to by "obj". It can be local,
3330 * global, or weak global.
3332 * In the current implementation, references can be global and local at
3333 * the same time, so while the return value is accurate it may not tell
3336 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj)
3339 jobjectRefType type = dvmGetJNIRefType(env, jobj);
3345 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
3347 * "address" may not be NULL, and "capacity" must be > 0. (These are only
3348 * verified when CheckJNI is enabled.)
3350 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)
3354 Thread* self = _self /*dvmThreadSelf()*/;
3355 Object* platformAddress = NULL;
3357 jobject result = NULL;
3359 /* get an instance of PlatformAddress that wraps the provided address */
3361 gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on,
3362 NULL, &callResult, address);
3363 if (dvmGetException(self) != NULL || callResult.l == NULL)
3366 /* don't let the GC discard it */
3367 platformAddress = (Object*) callResult.l;
3368 dvmAddTrackedAlloc(platformAddress, self);
3369 LOGV("tracking %p for address=%p\n", platformAddress, address);
3371 /* create an instance of java.nio.ReadWriteDirectByteBuffer */
3372 ClassObject* clazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
3373 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
3375 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
3376 if (newObj != NULL) {
3377 /* call the (PlatformAddress, int, int) constructor */
3378 result = addLocalReference(env, newObj);
3379 dvmCallMethod(self, gDvm.methJavaNioReadWriteDirectByteBuffer_init,
3380 newObj, &callResult, platformAddress, (jint) capacity, (jint) 0);
3381 if (dvmGetException(self) != NULL) {
3382 deleteLocalReference(env, result);
3389 if (platformAddress != NULL)
3390 dvmReleaseTrackedAlloc(platformAddress, self);
3396 * Get the starting address of the buffer for the specified java.nio.Buffer.
3398 * If this is not a "direct" buffer, we return NULL.
3400 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf)
3404 Object* bufObj = dvmDecodeIndirectRef(env, jbuf);
3405 Thread* self = _self /*dvmThreadSelf()*/;
3409 * All Buffer objects have an effectiveDirectAddress field. If it's
3410 * nonzero, we can just return that value. If not, we have to call
3411 * through DirectBuffer.getEffectiveAddress(), which as a side-effect
3412 * will set the effectiveDirectAddress field for direct buffers (and
3413 * things that wrap direct buffers).
3415 result = (void*) dvmGetFieldInt(bufObj,
3416 gDvm.offJavaNioBuffer_effectiveDirectAddress);
3417 if (result != NULL) {
3418 //LOGI("fast path for %p\n", buf);
3423 * Start by determining if the object supports the DirectBuffer
3424 * interfaces. Note this does not guarantee that it's a direct buffer.
3426 if (!dvmInstanceof(bufObj->clazz,
3427 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer))
3433 * Get a PlatformAddress object with the effective address.
3435 * If this isn't a direct buffer, the result will be NULL and/or an
3436 * exception will have been thrown.
3439 const Method* meth = dvmGetVirtualizedMethod(bufObj->clazz,
3440 gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress);
3441 dvmCallMethodA(self, meth, bufObj, false, &callResult, NULL);
3442 if (dvmGetException(self) != NULL) {
3443 dvmClearException(self);
3444 callResult.l = NULL;
3447 Object* platformAddr = callResult.l;
3448 if (platformAddr == NULL) {
3449 LOGV("Got request for address of non-direct buffer\n");
3454 * Extract the address from the PlatformAddress object. Instead of
3455 * calling the toLong() method, just grab the field directly. This
3456 * is faster but more fragile.
3458 result = (void*) dvmGetFieldInt(platformAddr,
3459 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr);
3461 //LOGI("slow path for %p --> %p\n", buf, result);
3469 * Get the capacity of the buffer for the specified java.nio.Buffer.
3471 * Returns -1 if the object is not a direct buffer. (We actually skip
3472 * this check, since it's expensive to determine, and just return the
3473 * capacity regardless.)
3475 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf)
3480 * The capacity is always in the Buffer.capacity field.
3482 * (The "check" version should verify that this is actually a Buffer,
3483 * but we're not required to do so here.)
3485 Object* buf = dvmDecodeIndirectRef(env, jbuf);
3486 jlong result = dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
3494 * ===========================================================================
3495 * JNI invocation functions
3496 * ===========================================================================
3500 * Handle AttachCurrentThread{AsDaemon}.
3502 * We need to make sure the VM is actually running. For example, if we start
3503 * up, issue an Attach, and the VM exits almost immediately, by the time the
3504 * attaching happens the VM could already be shutting down.
3506 * It's hard to avoid a race condition here because we don't want to hold
3507 * a lock across the entire operation. What we can do is temporarily
3508 * increment the thread count to prevent a VM exit.
3510 * This could potentially still have problems if a daemon thread calls here
3511 * while the VM is shutting down. dvmThreadSelf() will work, since it just
3512 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
3513 * you shut down a VM while threads are still running inside it.
3515 * Remember that some code may call this as a way to find the per-thread
3516 * JNIEnv pointer. Don't do excess work for that case.
3518 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args,
3521 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
3523 bool result = false;
3526 * Return immediately if we're already one with the VM.
3528 self = dvmThreadSelf();
3530 *p_env = self->jniEnv;
3535 * No threads allowed in zygote mode.
3541 /* increment the count to keep the VM from bailing while we run */
3542 dvmLockThreadList(NULL);
3543 if (gDvm.nonDaemonThreadCount == 0) {
3545 LOGV("Refusing to attach thread '%s' -- VM is shutting down\n",
3546 (thr_args == NULL) ? "(unknown)" : args->name);
3547 dvmUnlockThreadList();
3550 gDvm.nonDaemonThreadCount++;
3551 dvmUnlockThreadList();
3553 /* tweak the JavaVMAttachArgs as needed */
3554 JavaVMAttachArgs argsCopy;
3556 /* allow the v1.1 calling convention */
3557 argsCopy.version = JNI_VERSION_1_2;
3558 argsCopy.name = NULL;
3559 argsCopy.group = dvmGetMainThreadGroup();
3561 assert(args->version >= JNI_VERSION_1_2);
3563 argsCopy.version = args->version;
3564 argsCopy.name = args->name;
3565 if (args->group != NULL)
3566 argsCopy.group = args->group;
3568 argsCopy.group = dvmGetMainThreadGroup();
3571 result = dvmAttachCurrentThread(&argsCopy, isDaemon);
3573 /* restore the count */
3574 dvmLockThreadList(NULL);
3575 gDvm.nonDaemonThreadCount--;
3576 dvmUnlockThreadList();
3579 * Change the status to indicate that we're out in native code. This
3580 * call is not guarded with state-change macros, so we have to do it
3584 self = dvmThreadSelf();
3585 assert(self != NULL);
3586 dvmChangeStatus(self, THREAD_NATIVE);
3587 *p_env = self->jniEnv;
3595 * Attach the current thread to the VM. If the thread is already attached,
3598 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args)
3600 return attachThread(vm, p_env, thr_args, false);
3604 * Like AttachCurrentThread, but set the "daemon" flag.
3606 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env,
3609 return attachThread(vm, p_env, thr_args, true);
3613 * Dissociate the current thread from the VM.
3615 static jint DetachCurrentThread(JavaVM* vm)
3617 Thread* self = dvmThreadSelf();
3619 if (self == NULL) /* not attached, can't do anything */
3622 /* switch to "running" to check for suspension */
3623 dvmChangeStatus(self, THREAD_RUNNING);
3625 /* detach the thread */
3626 dvmDetachCurrentThread();
3628 /* (no need to change status back -- we have no status) */
3633 * If current thread is attached to VM, return the associated JNIEnv.
3634 * Otherwise, stuff NULL in and return JNI_EDETACHED.
3636 * JVMTI overloads this by specifying a magic value for "version", so we
3637 * do want to check that here.
3639 static jint GetEnv(JavaVM* vm, void** env, jint version)
3641 Thread* self = dvmThreadSelf();
3643 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6)
3644 return JNI_EVERSION;
3649 /* TODO: status change is probably unnecessary */
3650 dvmChangeStatus(self, THREAD_RUNNING);
3651 *env = (void*) dvmGetThreadJNIEnv(self);
3652 dvmChangeStatus(self, THREAD_NATIVE);
3655 return JNI_EDETACHED;
3661 * Destroy the VM. This may be called from any thread.
3663 * If the current thread is attached, wait until the current thread is
3664 * the only non-daemon user-level thread. If the current thread is not
3665 * attached, we attach it and do the processing as usual. (If the attach
3666 * fails, it's probably because all the non-daemon threads have already
3667 * exited and the VM doesn't want to let us back in.)
3669 * TODO: we don't really deal with the situation where more than one thread
3670 * has called here. One thread wins, the other stays trapped waiting on
3671 * the condition variable forever. Not sure this situation is interesting
3674 static jint DestroyJavaVM(JavaVM* vm)
3676 JavaVMExt* ext = (JavaVMExt*) vm;
3682 LOGD("DestroyJavaVM waiting for non-daemon threads to exit\n");
3685 * Sleep on a condition variable until it's okay to exit.
3687 self = dvmThreadSelf();
3690 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
3691 LOGV("Unable to reattach main for Destroy; assuming VM is "
3692 "shutting down (count=%d)\n",
3693 gDvm.nonDaemonThreadCount);
3696 LOGV("Attached to wait for shutdown in Destroy\n");
3699 dvmChangeStatus(self, THREAD_VMWAIT);
3701 dvmLockThreadList(self);
3702 gDvm.nonDaemonThreadCount--; // remove current thread from count
3704 while (gDvm.nonDaemonThreadCount > 0)
3705 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
3707 dvmUnlockThreadList();
3711 // TODO: call System.exit() to run any registered shutdown hooks
3712 // (this may not return -- figure out how this should work)
3714 LOGD("DestroyJavaVM shutting VM down\n");
3717 // TODO - free resources associated with JNI-attached daemon threads
3726 * ===========================================================================
3728 * ===========================================================================
3731 static const struct JNINativeInterface gNativeInterface = {
3742 FromReflectedMethod,
3766 EnsureLocalCapacity,
3809 CallNonvirtualObjectMethod,
3810 CallNonvirtualObjectMethodV,
3811 CallNonvirtualObjectMethodA,
3812 CallNonvirtualBooleanMethod,
3813 CallNonvirtualBooleanMethodV,
3814 CallNonvirtualBooleanMethodA,
3815 CallNonvirtualByteMethod,
3816 CallNonvirtualByteMethodV,
3817 CallNonvirtualByteMethodA,
3818 CallNonvirtualCharMethod,
3819 CallNonvirtualCharMethodV,
3820 CallNonvirtualCharMethodA,
3821 CallNonvirtualShortMethod,
3822 CallNonvirtualShortMethodV,
3823 CallNonvirtualShortMethodA,
3824 CallNonvirtualIntMethod,
3825 CallNonvirtualIntMethodV,
3826 CallNonvirtualIntMethodA,
3827 CallNonvirtualLongMethod,
3828 CallNonvirtualLongMethodV,
3829 CallNonvirtualLongMethodA,
3830 CallNonvirtualFloatMethod,
3831 CallNonvirtualFloatMethodV,
3832 CallNonvirtualFloatMethodA,
3833 CallNonvirtualDoubleMethod,
3834 CallNonvirtualDoubleMethodV,
3835 CallNonvirtualDoubleMethodA,
3836 CallNonvirtualVoidMethod,
3837 CallNonvirtualVoidMethodV,
3838 CallNonvirtualVoidMethodA,
3863 CallStaticObjectMethod,
3864 CallStaticObjectMethodV,
3865 CallStaticObjectMethodA,
3866 CallStaticBooleanMethod,
3867 CallStaticBooleanMethodV,
3868 CallStaticBooleanMethodA,
3869 CallStaticByteMethod,
3870 CallStaticByteMethodV,
3871 CallStaticByteMethodA,
3872 CallStaticCharMethod,
3873 CallStaticCharMethodV,
3874 CallStaticCharMethodA,
3875 CallStaticShortMethod,
3876 CallStaticShortMethodV,
3877 CallStaticShortMethodA,
3878 CallStaticIntMethod,
3879 CallStaticIntMethodV,
3880 CallStaticIntMethodA,
3881 CallStaticLongMethod,
3882 CallStaticLongMethodV,
3883 CallStaticLongMethodA,
3884 CallStaticFloatMethod,
3885 CallStaticFloatMethodV,
3886 CallStaticFloatMethodA,
3887 CallStaticDoubleMethod,
3888 CallStaticDoubleMethodV,
3889 CallStaticDoubleMethodA,
3890 CallStaticVoidMethod,
3891 CallStaticVoidMethodV,
3892 CallStaticVoidMethodA,
3896 GetStaticObjectField,
3897 GetStaticBooleanField,
3900 GetStaticShortField,
3903 GetStaticFloatField,
3904 GetStaticDoubleField,
3906 SetStaticObjectField,
3907 SetStaticBooleanField,
3910 SetStaticShortField,
3913 SetStaticFloatField,
3914 SetStaticDoubleField,
3925 ReleaseStringUTFChars,
3929 GetObjectArrayElement,
3930 SetObjectArrayElement,
3941 GetBooleanArrayElements,
3942 GetByteArrayElements,
3943 GetCharArrayElements,
3944 GetShortArrayElements,
3945 GetIntArrayElements,
3946 GetLongArrayElements,
3947 GetFloatArrayElements,
3948 GetDoubleArrayElements,
3950 ReleaseBooleanArrayElements,
3951 ReleaseByteArrayElements,
3952 ReleaseCharArrayElements,
3953 ReleaseShortArrayElements,
3954 ReleaseIntArrayElements,
3955 ReleaseLongArrayElements,
3956 ReleaseFloatArrayElements,
3957 ReleaseDoubleArrayElements,
3959 GetBooleanArrayRegion,
3962 GetShortArrayRegion,
3965 GetFloatArrayRegion,
3966 GetDoubleArrayRegion,
3967 SetBooleanArrayRegion,
3970 SetShortArrayRegion,
3973 SetFloatArrayRegion,
3974 SetDoubleArrayRegion,
3987 GetPrimitiveArrayCritical,
3988 ReleasePrimitiveArrayCritical,
3991 ReleaseStringCritical,
3994 DeleteWeakGlobalRef,
3998 NewDirectByteBuffer,
3999 GetDirectBufferAddress,
4000 GetDirectBufferCapacity,
4004 static const struct JNIInvokeInterface gInvokeInterface = {
4010 AttachCurrentThread,
4011 DetachCurrentThread,
4015 AttachCurrentThreadAsDaemon,
4020 * ===========================================================================
4022 * ===========================================================================
4026 * Enable "checked JNI" after the VM has partially started. This must
4027 * only be called in "zygote" mode, when we have one thread running.
4029 * This doesn't attempt to rewrite the JNI call bridge associated with
4030 * native methods, so we won't get those checks for any methods that have
4031 * already been resolved.
4033 void dvmLateEnableCheckedJni(void)
4038 extEnv = dvmGetJNIEnvForThread();
4039 if (extEnv == NULL) {
4040 LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv\n");
4044 assert(extVm != NULL);
4046 if (!extVm->useChecked) {
4047 LOGD("Late-enabling CheckJNI\n");
4048 dvmUseCheckedJniVm(extVm);
4049 extVm->useChecked = true;
4050 dvmUseCheckedJniEnv(extEnv);
4052 /* currently no way to pick up jniopts features */
4054 LOGD("Not late-enabling CheckJNI (already on)\n");
4061 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args)
4067 * Return a buffer full of created VMs.
4069 * We always have zero or one.
4071 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
4073 if (gDvm.vmList != NULL) {
4077 *vmBuf++ = gDvm.vmList;
4087 * Create a new VM instance.
4089 * The current thread becomes the main VM thread. We return immediately,
4090 * which effectively means the caller is executing in a native method.
4092 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)
4094 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
4095 JNIEnvExt* pEnv = NULL;
4096 JavaVMExt* pVM = NULL;
4100 int result = JNI_ERR;
4101 bool checkJni = false;
4102 bool warnError = true;
4103 bool forceDataCopy = false;
4105 if (args->version < JNI_VERSION_1_2)
4106 return JNI_EVERSION;
4108 // TODO: don't allow creation of multiple VMs -- one per customer for now
4110 /* zero globals; not strictly necessary the first time a VM is started */
4111 memset(&gDvm, 0, sizeof(gDvm));
4114 * Set up structures for JNIEnv and VM.
4116 //pEnv = (JNIEnvExt*) malloc(sizeof(JNIEnvExt));
4117 pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
4119 //memset(pEnv, 0, sizeof(JNIEnvExt));
4120 //pEnv->funcTable = &gNativeInterface;
4122 memset(pVM, 0, sizeof(JavaVMExt));
4123 pVM->funcTable = &gInvokeInterface;
4124 pVM->envList = pEnv;
4125 dvmInitMutex(&pVM->envListLock);
4127 argv = (const char**) malloc(sizeof(char*) * (args->nOptions));
4128 memset(argv, 0, sizeof(char*) * (args->nOptions));
4133 * Convert JNI args to argv.
4135 * We have to pull out vfprintf/exit/abort, because they use the
4136 * "extraInfo" field to pass function pointer "hooks" in. We also
4137 * look for the -Xcheck:jni stuff here.
4139 for (i = 0; i < args->nOptions; i++) {
4140 const char* optStr = args->options[i].optionString;
4142 if (optStr == NULL) {
4143 fprintf(stderr, "ERROR: arg %d string was null\n", i);
4145 } else if (strcmp(optStr, "vfprintf") == 0) {
4146 gDvm.vfprintfHook = args->options[i].extraInfo;
4147 } else if (strcmp(optStr, "exit") == 0) {
4148 gDvm.exitHook = args->options[i].extraInfo;
4149 } else if (strcmp(optStr, "abort") == 0) {
4150 gDvm.abortHook = args->options[i].extraInfo;
4151 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
4153 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
4154 const char* jniOpts = optStr + 9;
4155 while (jniOpts != NULL) {
4156 jniOpts++; /* skip past ':' or ',' */
4157 if (strncmp(jniOpts, "warnonly", 8) == 0) {
4159 } else if (strncmp(jniOpts, "forcecopy", 9) == 0) {
4160 forceDataCopy = true;
4162 LOGW("unknown jni opt starting at '%s'\n", jniOpts);
4164 jniOpts = strchr(jniOpts, ',');
4167 /* regular option */
4168 argv[curOpt++] = optStr;
4174 dvmUseCheckedJniVm(pVM);
4175 pVM->useChecked = true;
4177 pVM->warnError = warnError;
4178 pVM->forceDataCopy = forceDataCopy;
4180 /* set this up before initializing VM, so it can create some JNIEnvs */
4181 gDvm.vmList = (JavaVM*) pVM;
4184 * Create an env for main thread. We need to have something set up
4185 * here because some of the class initialization we do when starting
4186 * up the VM will call into native code.
4188 pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
4191 gDvm.initializing = true;
4192 if (dvmStartup(argc, argv, args->ignoreUnrecognized, (JNIEnv*)pEnv) != 0) {
4199 * Success! Return stuff to caller.
4201 dvmChangeStatus(NULL, THREAD_NATIVE);
4202 *p_env = (JNIEnv*) pEnv;
4203 *p_vm = (JavaVM*) pVM;
4207 gDvm.initializing = false;
4208 if (result == JNI_OK)
4209 LOGV("JNI_CreateJavaVM succeeded\n");
4211 LOGW("JNI_CreateJavaVM failed\n");