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.
17 * Dalvik implementation of JNI interfaces.
20 #include "JniInternal.h"
27 Native methods and interaction with the GC
29 All JNI methods must start by changing their thread status to
30 THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
31 returning to native code. The switch to "running" triggers a thread
34 With a rudimentary GC we should be able to skip the status change for
35 simple functions, e.g. IsSameObject, GetJavaVM, GetStringLength, maybe
36 even access to fields with primitive types. Our options are more limited
37 with a compacting GC, so we should replace JNI_ENTER with JNI_ENTER_NCGC
38 or somesuch on the "lite" functions if we want to try this optimization.
40 For performance reasons we do as little error-checking as possible here.
41 For example, we don't check to make sure the correct type of Object is
42 passed in when setting a field, and we don't prevent you from storing
43 new values in a "final" field. Such things are best handled in the
44 "check" version. For actions that are common, dangerous, and must be
45 checked at runtime, such as array bounds checks, we do the tests here.
48 General notes on local/global reference tracking
50 JNI provides explicit control over natively-held references that the VM GC
51 needs to know about. These can be local, in which case they're released
52 when the native method returns, or global, which are held until explicitly
55 The references can be created and deleted with JNI NewLocalRef /
56 NewGlobalRef calls, but this is unusual except perhaps for holding on
57 to a Class reference. Most often they are created transparently by the
58 JNI functions. For example, the paired Get/Release calls guarantee that
59 objects survive until explicitly released, so a simple way to implement
60 this is to create a global reference on "Get" and delete it on "Release".
61 The AllocObject/NewObject functions must create local references, because
62 nothing else in the GC root set has a reference to the new objects.
64 The most common mode of operation is for a method to create zero or
65 more local references and return. Explicit "local delete" operations
66 are expected to be exceedingly rare, except when walking through an
67 object array, and the Push/PopLocalFrame calls are expected to be used
68 infrequently. For efficient operation, we want to add new local refs
69 with a simple store/increment operation; to avoid infinite growth in
70 pathological situations, we need to reclaim the space used by deleted
73 The simplest implementation is an expanding append-only array that compacts
74 when objects are deleted. In typical situations, e.g. running through
75 an array of objects, we will be deleting one of the most recently added
76 entries, so we can minimize the number of elements moved (or avoid having
79 The spec says, "Local references are only valid in the thread in which
80 they are created. The native code must not pass local references from
81 one thread to another." It should also be noted that, while some calls
82 will *create* global references as a side-effect, only the NewGlobalRef
83 and NewWeakGlobalRef calls actually *return* global references.
86 Global reference tracking
88 There should be a small "active" set centered around the most-recently
89 added items. We can use an append-only, compacting array like we do for
92 Because it's global, access to it has to be synchronized.
94 The JNI spec does not define any sort of limit, so the list must be able
95 to expand. It may be useful to log significant increases in usage to
96 help identify resource leaks.
98 TODO: we currently use global references on strings and primitive array
99 data, because they have the property we need (i.e. the pointer we return
100 is guaranteed valid until we explicitly release it). However, if we have
101 a compacting GC and don't want to pin all memory held by all global refs,
102 we actually want to treat these differently. Either we need a way to
103 tell the GC that specific global references are pinned, or we have to
104 make a copy of the data and return that instead (something JNI supports).
107 Local reference tracking
109 The table of local references can be stored on the interpreted stack or
110 in a parallel data structure (one per thread).
112 *** Approach #1: use the interpreted stack
114 The easiest place to tuck it is between the frame ptr and the first saved
115 register, which is always in0. (See the ASCII art in Stack.h.) We can
116 shift the "VM-specific goop" and frame ptr down, effectively inserting
117 the JNI local refs in the space normally occupied by local variables.
119 (Three things are accessed from the frame pointer:
120 (1) framePtr[N] is register vN, used to get at "ins" and "locals".
121 (2) framePtr - sizeof(StackSaveArea) is the VM frame goop.
122 (3) framePtr - sizeof(StackSaveArea) - numOuts is where the "outs" go.
123 The only thing that isn't determined by an offset from the current FP
124 is the previous frame. However, tucking things below the previous frame
125 can be problematic because the "outs" of the previous frame overlap with
126 the "ins" of the current frame. If the "ins" are altered they must be
127 restored before we return. For a native method call, the easiest and
128 safest thing to disrupt is #1, because there are no locals and the "ins"
129 are all copied to the native stack.)
131 We can implement Push/PopLocalFrame with the existing stack frame calls,
132 making sure we copy some goop from the previous frame (notably the method
133 ptr, so that dvmGetCurrentJNIMethod() doesn't require extra effort).
135 We can pre-allocate the storage at the time the stack frame is first
136 set up, but we have to be careful. When calling from interpreted code
137 the frame ptr points directly at the arguments we're passing, but we can
138 offset the args pointer when calling the native bridge.
140 To manage the local ref collection, we need to be able to find three
141 things: (1) the start of the region, (2) the end of the region, and (3)
142 the next available entry. The last is only required for quick adds.
143 We currently have two easily-accessible pointers, the current FP and the
144 previous frame's FP. (The "stack pointer" shown in the ASCII art doesn't
145 actually exist in the interpreted world.)
147 We can't use the current FP to find the first "in", because we want to
148 insert the variable-sized local refs table between them. It's awkward
149 to use the previous frame's FP because native methods invoked via
150 dvmCallMethod() or dvmInvokeMethod() don't have "ins", but native methods
151 invoked from interpreted code do. We can either track the local refs
152 table size with a field in the stack frame, or insert unnecessary items
153 so that all native stack frames have "ins".
155 Assuming we can find the region bounds, we still need pointer #3
156 for an efficient implementation. This can be stored in an otherwise
157 unused-for-native field in the frame goop.
159 When we run out of room we have to make more space. If we start allocating
160 locals immediately below in0 and grow downward, we will detect end-of-space
161 by running into the current frame's FP. We then memmove() the goop down
162 (memcpy if we guarantee the additional size is larger than the frame).
163 This is nice because we only have to move sizeof(StackSaveArea) bytes
166 Stack walking should be okay so long as nothing tries to access the
167 "ins" by an offset from the FP. In theory the "ins" could be read by
168 the debugger or SIGQUIT handler looking for "this" or other arguments,
169 but in practice this behavior isn't expected to work for native methods,
170 so we can simply disallow it.
172 A conservative GC can just scan the entire stack from top to bottom to find
173 all references. An exact GC will need to understand the actual layout.
175 *** Approach #2: use a parallel stack
177 Each Thread/JNIEnv points to a ReferenceTable struct. The struct
178 has a system-heap-allocated array of references and a pointer to the
179 next-available entry ("nextEntry").
181 Each stack frame has a pointer to what it sees as the "top" element in the
182 array (we can double-up the "currentPc" field). This is set to "nextEntry"
183 when the frame is pushed on. As local references are added or removed,
184 "nextEntry" is updated.
186 We implement Push/PopLocalFrame with actual stack frames. Before a JNI
187 frame gets popped, we set "nextEntry" to the "top" pointer of the current
188 frame, effectively releasing the references.
190 The GC will scan all references from the start of the table to the
195 All approaches will return a failure result when they run out of local
196 reference space. For #1 that means blowing out the stack, for #2 it's
197 running out of room in the array.
199 Compared to #1, approach #2:
200 - Needs only one pointer in the stack frame goop.
201 - Makes pre-allocating storage unnecessary.
202 - Doesn't contend with interpreted stack depth for space. In most
203 cases, if something blows out the local ref storage, it's because the
204 JNI code was misbehaving rather than called from way down.
205 - Allows the GC to do a linear scan per thread in a buffer that is 100%
206 references. The GC can be slightly less smart when scanning the stack.
207 - Will be easier to work with if we combine native and interpeted stacks.
209 - Isn't as clean, especially when popping frames, since we have to do
210 explicit work. Fortunately we only have to do it when popping native
211 method calls off, so it doesn't add overhead to interpreted code paths.
212 - Is awkward to expand dynamically. We'll want to pre-allocate the full
213 amount of space; this is fine, since something on the order of 1KB should
214 be plenty. The JNI spec allows us to limit this.
215 - Requires the GC to scan even more memory. With the references embedded
216 in the stack we get better locality of reference.
221 static const struct JNINativeInterface gNativeInterface;
222 static jobject addGlobalReference(jobject obj);
225 #ifdef WITH_JNI_STACK_CHECK
226 # define COMPUTE_STACK_SUM(_self) computeStackSum(_self);
227 # define CHECK_STACK_SUM(_self) checkStackSum(_self);
228 static void computeStackSum(Thread* self);
229 static void checkStackSum(Thread* self);
231 # define COMPUTE_STACK_SUM(_self) ((void)0)
232 # define CHECK_STACK_SUM(_self) ((void)0)
237 * ===========================================================================
239 * ===========================================================================
243 * Bridge to calling a JNI function. This ideally gets some help from
244 * assembly language code in dvmPlatformInvoke, because the arguments
245 * must be pushed into the native stack as if we were calling a <stdarg.h>
248 * The number of values in "args" must match method->insSize.
250 * This is generally just set up by the resolver and then called through.
251 * We don't call here explicitly. This takes the same arguments as all
252 * of the "internal native" methods.
254 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method,
259 assert(method->insns != NULL);
262 //LOGI("JNI calling %p (%s.%s %s):\n", method->insns,
263 // method->clazz->descriptor, method->name, method->signature);
264 //for (i = 0; i < method->insSize; i++)
265 // LOGI(" %d: 0x%08x\n", i, args[i]);
267 oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
269 COMPUTE_STACK_SUM(self);
270 // TODO: should we be converting 'this' to a local ref?
271 dvmPlatformInvoke(self->jniEnv,
272 dvmIsStaticMethod(method) ? method->clazz : NULL,
273 method->jniArgInfo, method->insSize, args, method->shorty,
274 (void*)method->insns, pResult);
275 CHECK_STACK_SUM(self);
277 dvmChangeStatus(self, oldStatus);
281 * Alternate call bridge for the unusual case of a synchronized native method.
283 * Lock the object, then call through the usual function.
285 void dvmCallSynchronizedJNIMethod(const u4* args, JValue* pResult,
286 const Method* method, Thread* self)
290 assert(dvmIsSynchronizedMethod(method));
292 if (dvmIsStaticMethod(method))
293 lockObj = (Object*) method->clazz;
295 lockObj = (Object*) args[0];
297 LOGVV("Calling %s.%s: locking %p (%s)\n",
298 method->clazz->descriptor, method->name,
299 lockObj, lockObj->clazz->descriptor);
301 dvmLockObject(self, lockObj);
302 dvmCallJNIMethod(args, pResult, method, self);
303 dvmUnlockObject(self, lockObj);
307 * Extract the return type enum from the "jniArgInfo" field.
309 DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
311 return (jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT;
316 * ===========================================================================
318 * ===========================================================================
322 * Entry/exit processing for all JNI calls.
324 * If TRUSTED_JNIENV is set, we get to skip the (curiously expensive)
325 * thread-local storage lookup on our Thread*. If the caller has passed
326 * the wrong JNIEnv in, we're going to be accessing unsynchronized
327 * structures from more than one thread, and things are going to fail
328 * in bizarre ways. This is only sensible if the native code has been
329 * fully exercised with CheckJNI enabled.
331 #define TRUSTED_JNIENV
332 #ifdef TRUSTED_JNIENV
333 # define JNI_ENTER() \
334 Thread* _self = ((JNIEnvExt*)env)->self; \
335 CHECK_STACK_SUM(_self); \
336 dvmChangeStatus(_self, THREAD_RUNNING)
338 # define JNI_ENTER() \
339 Thread* _self = dvmThreadSelf(); \
340 UNUSED_PARAMETER(env); \
341 CHECK_STACK_SUM(_self); \
342 dvmChangeStatus(_self, THREAD_RUNNING)
345 dvmChangeStatus(_self, THREAD_NATIVE); \
346 COMPUTE_STACK_SUM(_self)
348 #define kGlobalRefsTableInitialSize 512
349 #define kGlobalRefsTableMaxSize 51200 /* arbitrary */
350 #define kGrefWaterInterval 100
352 #define kTrackGrefUsage true
355 * Allocate the global references table, and look up some classes for
356 * the benefit of direct buffer access.
358 bool dvmJniStartup(void)
360 if (!dvmInitReferenceTable(&gDvm.jniGlobalRefTable,
361 kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize))
364 dvmInitMutex(&gDvm.jniGlobalRefLock);
366 gDvm.jniGlobalRefLoMark = 0;
367 gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
370 * Look up and cache pointers to some direct buffer classes, fields,
375 ClassObject* platformAddressClass =
376 dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddress;");
377 ClassObject* platformAddressFactoryClass =
378 dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddressFactory;");
379 ClassObject* directBufferClass =
380 dvmFindSystemClassNoInit("Lorg/apache/harmony/nio/internal/DirectBuffer;");
381 ClassObject* readWriteBufferClass =
382 dvmFindSystemClassNoInit("Ljava/nio/ReadWriteDirectByteBuffer;");
383 ClassObject* bufferClass =
384 dvmFindSystemClassNoInit("Ljava/nio/Buffer;");
386 if (platformAddressClass == NULL || platformAddressFactoryClass == NULL ||
387 directBufferClass == NULL || readWriteBufferClass == NULL ||
390 LOGE("Unable to find internal direct buffer classes\n");
393 /* needs to be a global ref so CheckJNI thinks we're allowed to see it */
394 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer =
395 addGlobalReference((Object*) directBufferClass);
396 gDvm.classJavaNioReadWriteDirectByteBuffer = readWriteBufferClass;
399 * We need a Method* here rather than a vtable offset, because
400 * DirectBuffer is an interface class.
402 meth = dvmFindVirtualMethodByDescriptor(
403 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer,
404 "getEffectiveAddress",
405 "()Lorg/apache/harmony/luni/platform/PlatformAddress;");
407 LOGE("Unable to find PlatformAddress.getEffectiveAddress\n");
410 gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress = meth;
412 meth = dvmFindVirtualMethodByDescriptor(platformAddressClass,
415 LOGE("Unable to find PlatformAddress.toLong\n");
418 gDvm.voffOrgApacheHarmonyLuniPlatformPlatformAddress_toLong =
421 meth = dvmFindDirectMethodByDescriptor(platformAddressFactoryClass,
423 "(I)Lorg/apache/harmony/luni/platform/PlatformAddress;");
425 LOGE("Unable to find PlatformAddressFactory.on\n");
428 gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on = meth;
430 meth = dvmFindDirectMethodByDescriptor(readWriteBufferClass,
432 "(Lorg/apache/harmony/luni/platform/PlatformAddress;II)V");
434 LOGE("Unable to find ReadWriteDirectByteBuffer.<init>\n");
437 gDvm.methJavaNioReadWriteDirectByteBuffer_init = meth;
439 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr =
440 dvmFindFieldOffset(platformAddressClass, "osaddr", "I");
441 if (gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr < 0) {
442 LOGE("Unable to find PlatformAddress.osaddr\n");
446 gDvm.offJavaNioBuffer_capacity =
447 dvmFindFieldOffset(bufferClass, "capacity", "I");
448 if (gDvm.offJavaNioBuffer_capacity < 0) {
449 LOGE("Unable to find Buffer.capacity\n");
457 * Free the global references table.
459 void dvmJniShutdown(void)
461 dvmClearReferenceTable(&gDvm.jniGlobalRefTable);
466 * Find the JNIEnv associated with the current thread.
468 * Currently stored in the Thread struct. Could also just drop this into
469 * thread-local storage.
471 JNIEnvExt* dvmGetJNIEnvForThread(void)
473 Thread* self = dvmThreadSelf();
476 return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
480 * Create a new JNIEnv struct and add it to the VM's list.
482 * "self" will be NULL for the main thread, since the VM hasn't started
483 * yet; the value will be filled in later.
485 JNIEnv* dvmCreateJNIEnv(Thread* self)
487 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
491 // LOGI("Ent CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
495 newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
496 newEnv->funcTable = &gNativeInterface;
498 newEnv->forceDataCopy = vm->forceDataCopy;
500 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
501 assert(newEnv->envThreadId != 0);
503 /* make it obvious if we fail to initialize these later */
504 newEnv->envThreadId = 0x77777775;
505 newEnv->self = (Thread*) 0x77777779;
508 dvmUseCheckedJniEnv(newEnv);
510 dvmLockMutex(&vm->envListLock);
512 /* insert at head of list */
513 newEnv->next = vm->envList;
514 assert(newEnv->prev == NULL);
515 if (vm->envList == NULL) // rare, but possible
516 vm->envList = newEnv;
518 vm->envList->prev = newEnv;
519 vm->envList = newEnv;
521 dvmUnlockMutex(&vm->envListLock);
524 // LOGI("Xit CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
525 return (JNIEnv*) newEnv;
529 * Remove a JNIEnv struct from the list and free it.
531 void dvmDestroyJNIEnv(JNIEnv* env)
533 JNIEnvExt* extEnv = (JNIEnvExt*) env;
534 JavaVMExt* vm = extEnv->vm;
540 self = dvmThreadSelf();
541 assert(self != NULL);
543 //LOGI("Ent DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
545 dvmLockMutex(&vm->envListLock);
547 if (extEnv == vm->envList) {
548 assert(extEnv->prev == NULL);
549 vm->envList = extEnv->next;
551 assert(extEnv->prev != NULL);
552 extEnv->prev->next = extEnv->next;
554 if (extEnv->next != NULL)
555 extEnv->next->prev = extEnv->prev;
557 dvmUnlockMutex(&extEnv->vm->envListLock);
560 //LOGI("Xit DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
565 * Retrieve the ReferenceTable struct for the current thread.
567 * If we know the code isn't sharing JNIEnv pointers between threads, we
568 * could put this into env and skip the TLS lookup.
570 static inline ReferenceTable* getLocalRefTable(void)
572 return &dvmThreadSelf()->jniLocalRefTable;
576 * Add a local reference for an object to the current stack frame. When
577 * the native function returns, the reference will be discarded.
579 * We need to allow the same reference to be added multiple times.
581 * This will be called on otherwise unreferenced objects. We cannot do
582 * GC allocations here, and it's best if we don't grab a mutex.
584 * Returns the local reference (currently just the same pointer that was
585 * passed in), or NULL on failure.
587 static jobject addLocalReference(jobject obj)
592 ReferenceTable* pRef = getLocalRefTable();
594 if (!dvmAddToReferenceTable(pRef, (Object*)obj)) {
595 dvmDumpReferenceTable(pRef, "JNI local");
596 LOGE("Failed adding to JNI local ref table (has %d entries)\n",
597 (int) dvmReferenceTableEntries(pRef));
598 dvmDumpThread(dvmThreadSelf(), false);
599 dvmAbort(); // spec says call FatalError; this is equivalent
601 LOGVV("LREF add %p (%s.%s)\n", obj,
602 dvmGetCurrentJNIMethod()->clazz->descriptor,
603 dvmGetCurrentJNIMethod()->name);
610 * Ensure that at least "capacity" references can be held in the local
611 * refs table of the current thread.
613 static bool ensureLocalCapacity(int capacity)
615 ReferenceTable* pRef = getLocalRefTable();
617 return (kJniLocalRefMax - (pRef->nextEntry - pRef->table) >= capacity);
621 * Explicitly delete a reference from the local list.
623 static void deleteLocalReference(jobject obj)
628 ReferenceTable* pRef = getLocalRefTable();
629 Thread* self = dvmThreadSelf();
630 Object** top = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefTop;
632 if (!dvmRemoveFromReferenceTable(pRef, top, (Object*) obj)) {
634 * Attempting to delete a local reference that is not in the
635 * topmost local reference frame is a no-op. DeleteLocalRef returns
636 * void and doesn't throw any exceptions, but we should probably
637 * complain about it so the user will notice that things aren't
638 * going quite the way they expect.
640 LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry (valid=%d)\n",
641 obj, dvmIsValidObject((Object*) obj));
646 * Add a global reference for an object.
648 * We may add the same object more than once. Add/remove calls are paired,
649 * so it needs to appear on the list multiple times.
651 static jobject addGlobalReference(jobject obj)
656 //LOGI("adding obj=%p\n", obj);
657 //dvmDumpThread(dvmThreadSelf(), false);
659 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangClass) {
660 ClassObject* clazz = (ClassObject*) obj;
662 LOGI("Adding global ref on class %s\n", clazz->descriptor);
663 dvmDumpThread(dvmThreadSelf(), false);
665 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
666 StringObject* strObj = (StringObject*) obj;
667 char* str = dvmCreateCstrFromString(strObj);
668 if (strcmp(str, "sync-response") == 0) {
670 LOGI("Adding global ref on string '%s'\n", str);
671 dvmDumpThread(dvmThreadSelf(), false);
676 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
677 ArrayObject* arrayObj = (ArrayObject*) obj;
678 if (arrayObj->length == 8192 &&
679 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400)
681 LOGI("Adding global ref on byte array %p (len=%d)\n",
682 arrayObj, arrayObj->length);
683 dvmDumpThread(dvmThreadSelf(), false);
687 dvmLockMutex(&gDvm.jniGlobalRefLock);
690 * Expanding the table should happen rarely, so I'm not overly
691 * concerned about the performance impact of copying the old list
692 * over. We shouldn't see one-time activity spikes, so freeing
693 * up storage shouldn't be required.
695 * Throwing an exception on failure is problematic, because JNI code
696 * may not be expecting an exception, and things sort of cascade. We
697 * want to have a hard limit to catch leaks during debugging, but this
698 * otherwise needs to expand until memory is consumed. As a practical
699 * matter, if we have many thousands of global references, chances are
700 * we're either leaking global ref table entries or we're going to
701 * run out of space in the GC heap.
703 if (!dvmAddToReferenceTable(&gDvm.jniGlobalRefTable, (Object*)obj)) {
704 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
705 LOGE("Failed adding to JNI global ref table (%d entries)\n",
706 (int) dvmReferenceTableEntries(&gDvm.jniGlobalRefTable));
710 LOGVV("GREF add %p (%s.%s)\n", obj,
711 dvmGetCurrentJNIMethod()->clazz->descriptor,
712 dvmGetCurrentJNIMethod()->name);
714 /* GREF usage tracking; should probably be disabled for production env */
715 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
716 int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
717 if (count > gDvm.jniGlobalRefHiMark) {
718 LOGD("GREF has increased to %d\n", count);
719 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
720 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
722 /* watch for "excessive" use; not generally appropriate */
723 if (count >= gDvm.jniGrefLimit) {
724 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
726 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable,"JNI global");
727 LOGE("Excessive JNI global references (%d)\n", count);
730 LOGW("Excessive JNI global references (%d)\n", count);
737 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
742 * Remove a global reference. In most cases it's the entry most recently
743 * added, which makes this pretty quick.
745 * Thought: if it's not the most recent entry, just null it out. When we
746 * fill up, do a compaction pass before we expand the list.
748 static void deleteGlobalReference(jobject obj)
753 dvmLockMutex(&gDvm.jniGlobalRefLock);
755 if (!dvmRemoveFromReferenceTable(&gDvm.jniGlobalRefTable,
756 gDvm.jniGlobalRefTable.table, obj))
758 LOGW("JNI: DeleteGlobalRef(%p) failed to find entry (valid=%d)\n",
759 obj, dvmIsValidObject((Object*) obj));
763 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
764 int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
765 if (count < gDvm.jniGlobalRefLoMark) {
766 LOGD("GREF has decreased to %d\n", count);
767 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
768 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
773 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
777 * GC helper function to mark all JNI global references.
779 void dvmGcMarkJniGlobalRefs()
783 dvmLockMutex(&gDvm.jniGlobalRefLock);
785 op = gDvm.jniGlobalRefTable.table;
786 while ((uintptr_t)op < (uintptr_t)gDvm.jniGlobalRefTable.nextEntry) {
787 dvmMarkObjectNonNull(*(op++));
790 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
795 * Determine if "obj" appears in the argument list for the native method.
797 * We use the "shorty" signature to determine which argument slots hold
800 static bool findInArgList(Thread* self, Object* obj)
809 * Back up over JNI PushLocalFrame frames. This works because the
810 * previous frame on the interpreted stack is either a break frame
811 * (if we called here via native code) or an interpreted method (if
812 * we called here via the interpreter). In both cases the method
813 * pointer won't match.
815 StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
816 meth = saveArea->method;
817 if (meth != SAVEAREA_FROM_FP(saveArea->prevFrame)->method)
819 fp = saveArea->prevFrame;
822 LOGVV("+++ scanning %d args in %s (%s)\n",
823 meth->insSize, meth->name, meth->shorty);
824 const char* shorty = meth->shorty +1; /* skip return type char */
825 for (i = 0; i < meth->insSize; i++) {
826 if (i == 0 && !dvmIsStaticMethod(meth)) {
827 /* first arg is "this" ref, not represented in "shorty" */
828 if (fp[i] == (u4) obj)
831 /* if this is a reference type, see if it matches */
834 if (fp[i] == (u4) obj)
842 LOGE("Whoops! ran off the end of %s (%d)\n",
843 meth->shorty, meth->insSize);
846 if (fp[i] == (u4) obj)
847 LOGI("NOTE: ref %p match on arg type %c\n", obj, *shorty);
855 * For static methods, we also pass a class pointer in.
857 if (dvmIsStaticMethod(meth)) {
858 //LOGI("+++ checking class pointer in %s\n", meth->name);
859 if ((void*)obj == (void*)meth->clazz)
866 * Verify that a reference passed in from native code is one that the
867 * code is allowed to have.
869 * It's okay for native code to pass us a reference that:
870 * - was just passed in as an argument when invoked by native code
871 * - was returned to it from JNI (and is now in the JNI local refs table)
872 * - is present in the JNI global refs table
873 * The first one is a little awkward. The latter two are just table lookups.
875 * Used by -Xcheck:jni and GetObjectRefType.
877 * NOTE: in the current VM, global and local references are identical. If
878 * something is both global and local, we can't tell them apart, and always
881 jobjectRefType dvmGetJNIRefType(Object* obj)
883 ReferenceTable* pRef = getLocalRefTable();
884 Thread* self = dvmThreadSelf();
889 if (findInArgList(self, obj)) {
890 //LOGI("--- REF found %p on stack\n", obj);
891 return JNILocalRefType;
895 //top = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefTop;
896 if (dvmFindInReferenceTable(pRef, pRef->table, obj) != NULL) {
897 //LOGI("--- REF found %p in locals\n", obj);
898 return JNILocalRefType;
902 dvmLockMutex(&gDvm.jniGlobalRefLock);
903 if (dvmFindInReferenceTable(&gDvm.jniGlobalRefTable,
904 gDvm.jniGlobalRefTable.table, obj))
906 //LOGI("--- REF found %p in globals\n", obj);
907 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
908 return JNIGlobalRefType;
910 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
913 return JNIInvalidRefType;
917 * Register a method that uses JNI calling conventions.
919 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
920 const char* signature, void* fnPtr)
928 method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
930 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
931 if (method == NULL) {
932 LOGW("ERROR: Unable to find decl for native %s.%s %s\n",
933 clazz->descriptor, methodName, signature);
937 if (!dvmIsNativeMethod(method)) {
938 LOGW("Unable to register: not native: %s.%s %s\n",
939 clazz->descriptor, methodName, signature);
943 if (method->nativeFunc != dvmResolveNativeMethod) {
944 LOGW("Warning: %s.%s %s was already registered/resolved?\n",
945 clazz->descriptor, methodName, signature);
946 /* keep going, I guess */
950 * Point "nativeFunc" at the JNI bridge, and overload "insns" to
951 * point at the actual function.
953 if (dvmIsSynchronizedMethod(method))
954 dvmSetNativeFunc(method, dvmCallSynchronizedJNIMethod, fnPtr);
956 dvmSetNativeFunc(method, dvmCallJNIMethod, fnPtr);
958 LOGV("JNI-registered %s.%s %s\n", clazz->descriptor, methodName,
967 * Get the method currently being executed by examining the interp stack.
969 const Method* dvmGetCurrentJNIMethod(void)
971 assert(dvmThreadSelf() != NULL);
973 void* fp = dvmThreadSelf()->curFrame;
974 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
976 assert(meth != NULL);
977 assert(dvmIsNativeMethod(meth));
983 * Track a JNI MonitorEnter in the current thread.
985 * The goal is to be able to "implicitly" release all JNI-held monitors
986 * when the thread detaches.
988 * Monitors may be entered multiple times, so we add a new entry for each
989 * enter call. It would be more efficient to keep a counter. At present
990 * there's no real motivation to improve this however.
992 static void trackMonitorEnter(Thread* self, Object* obj)
994 static const int kInitialSize = 16;
995 ReferenceTable* refTable = &self->jniMonitorRefTable;
997 /* init table on first use */
998 if (refTable->table == NULL) {
999 assert(refTable->maxEntries == 0);
1001 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
1002 LOGE("Unable to initialize monitor tracking table\n");
1007 if (!dvmAddToReferenceTable(refTable, obj)) {
1008 /* ran out of memory? could throw exception instead */
1009 LOGE("Unable to add entry to monitor tracking table\n");
1012 LOGVV("--- added monitor %p\n", obj);
1017 * Track a JNI MonitorExit in the current thread.
1019 static void trackMonitorExit(Thread* self, Object* obj)
1021 ReferenceTable* refTable = &self->jniMonitorRefTable;
1023 if (!dvmRemoveFromReferenceTable(refTable, refTable->table, obj)) {
1024 LOGE("JNI monitor %p not found in tracking list\n", obj);
1027 LOGVV("--- removed monitor %p\n", obj);
1032 * Release all monitors held by the jniMonitorRefTable list.
1034 void dvmReleaseJniMonitors(Thread* self)
1036 ReferenceTable* refTable = &self->jniMonitorRefTable;
1037 Object** top = refTable->table;
1042 Object** ptr = refTable->nextEntry;
1043 while (--ptr >= top) {
1044 if (!dvmUnlockObject(self, *ptr)) {
1045 LOGW("Unable to unlock monitor %p at thread detach\n", *ptr);
1047 LOGVV("--- detach-releasing monitor %p\n", *ptr);
1052 refTable->nextEntry = refTable->table;
1055 #ifdef WITH_JNI_STACK_CHECK
1057 * Compute a CRC on the entire interpreted stack.
1059 * Would be nice to compute it on "self" as well, but there are parts of
1060 * the Thread that can be altered by other threads (e.g. prev/next pointers).
1062 static void computeStackSum(Thread* self)
1064 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
1065 u4 crc = dvmInitCrc32();
1067 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
1068 self->stackCrc = crc;
1072 * Compute a CRC on the entire interpreted stack, and compare it to what
1073 * we previously computed.
1075 * We can execute JNI directly from native code without calling in from
1076 * interpreted code during VM initialization and immediately after JNI
1077 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather
1078 * than catching these cases we just ignore them here, which is marginally
1079 * less accurate but reduces the amount of code we have to touch with #ifdefs.
1081 static void checkStackSum(Thread* self)
1083 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
1086 stackCrc = self->stackCrc;
1088 crc = dvmInitCrc32();
1089 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
1090 if (crc != stackCrc) {
1091 const Method* meth = dvmGetCurrentJNIMethod();
1092 if (dvmComputeExactFrameDepth(self->curFrame) == 1) {
1093 LOGD("JNI: bad stack CRC (0x%08x) -- okay during init\n",
1095 } else if (strcmp(meth->name, "nativeLoad") == 0 &&
1096 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0))
1098 LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad\n",
1101 LOGW("JNI: bad stack CRC (%08x vs %08x)\n", crc, stackCrc);
1105 self->stackCrc = (u4) -1; /* make logic errors more noticeable */
1111 * ===========================================================================
1112 * JNI implementation
1113 * ===========================================================================
1117 * Return the version of the native method interface.
1119 static jint GetVersion(JNIEnv* env)
1123 * There is absolutely no need to toggle the mode for correct behavior.
1124 * However, it does provide native code with a simple "suspend self
1125 * if necessary" call.
1128 return JNI_VERSION_1_6;
1132 * Create a new class from a bag of bytes.
1134 * This is not currently supported within Dalvik.
1136 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1137 const jbyte* buf, jsize bufLen)
1139 UNUSED_PARAMETER(name);
1140 UNUSED_PARAMETER(loader);
1141 UNUSED_PARAMETER(buf);
1142 UNUSED_PARAMETER(bufLen);
1145 LOGW("Rejecting JNI DefineClass request\n");
1151 * Find a class by name.
1153 * We have to use the "no init" version of FindClass here, because we might
1154 * be getting the class prior to registering native methods that will be
1157 * We need to get the class loader associated with the current native
1158 * method. If there is no native method, e.g. we're calling this from native
1159 * code right after creating the VM, the spec says we need to use the class
1160 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1161 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1162 * We can't get that until after the VM has initialized though.
1164 static jclass FindClass(JNIEnv* env, const char* name)
1168 const Method* thisMethod;
1171 char* descriptor = NULL;
1173 thisMethod = dvmGetCurrentJNIMethod();
1174 assert(thisMethod != NULL);
1176 descriptor = dvmNameToDescriptor(name);
1177 if (descriptor == NULL) {
1182 //Thread* self = dvmThreadSelf();
1183 if (_self->classLoaderOverride != NULL) {
1184 /* hack for JNI_OnLoad */
1185 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1186 loader = _self->classLoaderOverride;
1187 } else if (thisMethod == gDvm.methFakeNativeEntry) {
1188 /* start point of invocation interface */
1189 if (!gDvm.initializing)
1190 loader = dvmGetSystemClassLoader();
1194 loader = thisMethod->clazz->classLoader;
1197 clazz = dvmFindClassNoInit(descriptor, loader);
1198 clazz = addLocalReference(clazz);
1204 return (jclass)clazz;
1208 * Return the superclass of a class.
1210 static jclass GetSuperclass(JNIEnv* env, jclass clazz)
1213 jclass super = (jclass) ((ClassObject*) clazz)->super;
1214 super = addLocalReference(super);
1220 * Determine whether an object of clazz1 can be safely cast to clazz2.
1222 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1224 static jboolean IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2)
1229 result = dvmInstanceof((ClassObject*) clazz1, (ClassObject*) clazz2);
1236 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1238 static jmethodID FromReflectedMethod(JNIEnv* env, jobject method)
1242 methodID = (jmethodID) dvmGetMethodFromReflectObj((Object*)method);
1248 * Given a java.lang.reflect.Field, return a fieldID.
1250 static jfieldID FromReflectedField(JNIEnv* env, jobject field)
1253 jfieldID fieldID = (jfieldID) dvmGetFieldFromReflectObj((Object*)field);
1259 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1261 * (The "isStatic" field does not appear in the spec.)
1263 * Throws OutOfMemory and returns NULL on failure.
1265 static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID methodID,
1270 obj = (jobject) dvmCreateReflectObjForMethod((ClassObject*) cls,
1271 (Method*) methodID);
1272 dvmReleaseTrackedAlloc(obj, NULL);
1273 obj = addLocalReference(obj);
1279 * Convert a fieldID to a java.lang.reflect.Field.
1281 * (The "isStatic" field does not appear in the spec.)
1283 * Throws OutOfMemory and returns NULL on failure.
1285 static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fieldID,
1290 obj = (jobject) dvmCreateReflectObjForField((ClassObject*) cls,
1292 dvmReleaseTrackedAlloc(obj, NULL);
1293 obj = addLocalReference(obj);
1300 * Take this exception and throw it.
1302 static jint Throw(JNIEnv* env, jthrowable obj)
1309 dvmSetException(_self, obj);
1319 * Constructs an exeption object from the specified class with the message
1320 * specified by "message", and throws it.
1322 static jint ThrowNew(JNIEnv* env, jclass clazz, const char* message)
1326 ClassObject* classObj = (ClassObject*) clazz;
1328 dvmThrowExceptionByClass(classObj, message);
1335 * If an exception is being thrown, return the exception object. Otherwise,
1338 * TODO: if there is no pending exception, we should be able to skip the
1339 * enter/exit checks. If we find one, we need to enter and then re-fetch
1340 * the exception (in case it got moved by a compacting GC).
1342 static jthrowable ExceptionOccurred(JNIEnv* env)
1347 Object* localException;
1349 exception = (Object*) dvmGetException(_self);
1350 localException = addLocalReference(exception);
1351 if (localException == NULL && exception != NULL) {
1353 * We were unable to add a new local reference, and threw a new
1354 * exception. We can't return "exception", because it's not a
1355 * local reference. So we have to return NULL, indicating that
1356 * there was no exception, even though it's pretty much raining
1357 * exceptions in here.
1359 LOGW("JNI WARNING: addLocal/exception combo\n");
1363 return localException;
1367 * Print an exception and stack trace to stderr.
1369 static void ExceptionDescribe(JNIEnv* env)
1373 Object* exception = dvmGetException(_self);
1374 if (exception != NULL) {
1375 dvmPrintExceptionStackTrace();
1377 LOGI("Odd: ExceptionDescribe called, but no exception pending\n");
1384 * Clear the exception currently being thrown.
1386 * TODO: we should be able to skip the enter/exit stuff.
1388 static void ExceptionClear(JNIEnv* env)
1391 dvmClearException(_self);
1396 * Kill the VM. This function does not return.
1398 static void FatalError(JNIEnv* env, const char* msg)
1400 //dvmChangeStatus(NULL, THREAD_RUNNING);
1401 LOGE("JNI posting fatal error: %s\n", msg);
1406 * Push a new JNI frame on the stack, with a new set of locals.
1408 * The new frame must have the same method pointer. (If for no other
1409 * reason than FindClass needs it to get the appropriate class loader.)
1411 static jint PushLocalFrame(JNIEnv* env, jint capacity)
1414 int result = JNI_OK;
1415 if (!ensureLocalCapacity(capacity) ||
1416 !dvmPushLocalFrame(_self /*dvmThreadSelf()*/, dvmGetCurrentJNIMethod()))
1418 /* yes, OutOfMemoryError, not StackOverflowError */
1419 dvmClearException(_self);
1420 dvmThrowException("Ljava/lang/OutOfMemoryError;",
1421 "out of stack in JNI PushLocalFrame");
1429 * Pop the local frame off. If "result" is not null, add it as a
1430 * local reference on the now-current frame.
1432 static jobject PopLocalFrame(JNIEnv* env, jobject result)
1435 if (!dvmPopLocalFrame(_self /*dvmThreadSelf()*/)) {
1436 LOGW("JNI WARNING: too many PopLocalFrame calls\n");
1437 dvmClearException(_self);
1438 dvmThrowException("Ljava/lang/RuntimeException;",
1439 "too many PopLocalFrame calls");
1441 result = addLocalReference(result);
1447 * Add a reference to the global list.
1449 static jobject NewGlobalRef(JNIEnv* env, jobject obj)
1452 jobject retval = addGlobalReference(obj);
1458 * Delete a reference from the global list.
1460 static void DeleteGlobalRef(JNIEnv* env, jobject globalRef)
1463 deleteGlobalReference(globalRef);
1469 * Add a reference to the local list.
1471 static jobject NewLocalRef(JNIEnv* env, jobject ref)
1475 jobject retval = addLocalReference(ref);
1482 * Delete a reference from the local list.
1484 static void DeleteLocalRef(JNIEnv* env, jobject localRef)
1487 deleteLocalReference(localRef);
1492 * Ensure that the local references table can hold at least this many
1495 static jint EnsureLocalCapacity(JNIEnv *env, jint capacity)
1498 bool okay = ensureLocalCapacity(capacity);
1500 dvmThrowException("Ljava/lang/OutOfMemoryError;",
1501 "can't ensure local reference capacity");
1512 * Determine whether two Object references refer to the same underlying object.
1514 static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2)
1517 jboolean result = (ref1 == ref2);
1523 * Allocate a new object without invoking any constructors.
1525 static jobject AllocObject(JNIEnv* env, jclass jclazz)
1529 ClassObject* clazz = (ClassObject*) jclazz;
1532 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1533 assert(dvmCheckException(_self));
1536 newObj = (jobject) dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1537 newObj = addLocalReference(newObj);
1545 * Construct a new object.
1547 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...)
1551 ClassObject* clazz = (ClassObject*) jclazz;
1554 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1555 assert(dvmCheckException(_self));
1558 newObj = (jobject) dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1559 newObj = addLocalReference(newObj);
1560 if (newObj != NULL) {
1563 va_start(args, methodID);
1564 dvmCallMethodV(_self, (Method*) methodID, (Object*)newObj, &unused,
1573 static jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID,
1579 newObj = (jobject) dvmAllocObject((ClassObject*) clazz, ALLOC_DONT_TRACK);
1580 newObj = addLocalReference(newObj);
1581 if (newObj != NULL) {
1583 dvmCallMethodV(_self, (Method*) methodID, (Object*)newObj, &unused,
1590 static jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID,
1596 newObj = (jobject) dvmAllocObject((ClassObject*) clazz, ALLOC_DONT_TRACK);
1597 newObj = addLocalReference(newObj);
1598 if (newObj != NULL) {
1600 dvmCallMethodA(_self, (Method*) methodID, (Object*)newObj, &unused,
1609 * Returns the class of an object.
1611 * JNI spec says: obj must not be NULL.
1613 static jclass GetObjectClass(JNIEnv* env, jobject obj)
1617 assert(obj != NULL);
1620 clazz = (jclass) ((Object*)obj)->clazz;
1621 clazz = addLocalReference(clazz);
1628 * Determine whether "obj" is an instance of "clazz".
1630 static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz)
1639 result = dvmInstanceof(((Object*)obj)->clazz, (ClassObject*) clazz);
1646 * Get a method ID for an instance method.
1648 * JNI defines <init> as an instance method, but Dalvik considers it a
1649 * "direct" method, so we have to special-case it here.
1651 * Dalvik also puts all private methods into the "direct" list, so we
1652 * really need to just search both lists.
1654 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,
1659 ClassObject* clazz = (ClassObject*) jclazz;
1660 jmethodID id = NULL;
1662 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1663 assert(dvmCheckException(_self));
1667 meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1669 /* search private methods and constructors; non-hierarchical */
1670 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1672 if (meth != NULL && dvmIsStaticMethod(meth)) {
1674 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1675 LOGD("GetMethodID: not returning static method %s.%s %s\n",
1676 clazz->descriptor, meth->name, desc);
1682 LOGI("Method not found: '%s' '%s' in %s\n",
1683 name, sig, clazz->descriptor);
1684 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
1688 * The method's class may not be the same as clazz, but if
1689 * it isn't this must be a virtual method and the class must
1690 * be a superclass (and, hence, already initialized).
1693 assert(dvmIsClassInitialized(meth->clazz) ||
1694 dvmIsClassInitializing(meth->clazz));
1696 id = (jmethodID) meth;
1703 * Get a field ID (instance fields).
1705 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,
1706 const char* name, const char* sig)
1710 ClassObject* clazz = (ClassObject*) jclazz;
1713 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1714 assert(dvmCheckException(_self));
1717 id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1719 dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
1726 * Get the method ID for a static method in a class.
1728 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz,
1729 const char* name, const char* sig)
1733 ClassObject* clazz = (ClassObject*) jclazz;
1736 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1737 assert(dvmCheckException(_self));
1742 meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1744 /* make sure it's static, not virtual+private */
1745 if (meth != NULL && !dvmIsStaticMethod(meth)) {
1747 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1748 LOGD("GetStaticMethodID: "
1749 "not returning nonstatic method %s.%s %s\n",
1750 clazz->descriptor, meth->name, desc);
1756 id = (jmethodID) meth;
1758 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
1766 * Get a field ID (static fields).
1768 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz,
1769 const char* name, const char* sig)
1773 ClassObject* clazz = (ClassObject*) jclazz;
1776 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1777 assert(dvmCheckException(_self));
1780 id = (jfieldID) dvmFindStaticField(clazz, name, sig);
1782 dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
1789 * Get a static field.
1791 * If we get an object reference, add it to the local refs list.
1793 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
1794 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass clazz, \
1797 UNUSED_PARAMETER(clazz); \
1799 StaticField* sfield = (StaticField*) fieldID; \
1800 _ctype value = dvmGetStaticField##_jname(sfield); \
1801 if (_isref) /* only when _ctype==jobject */ \
1802 value = (_ctype)(u4)addLocalReference((jobject)(u4)value); \
1806 GET_STATIC_TYPE_FIELD(jobject, Object, true);
1807 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1808 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1809 GET_STATIC_TYPE_FIELD(jchar, Char, false);
1810 GET_STATIC_TYPE_FIELD(jshort, Short, false);
1811 GET_STATIC_TYPE_FIELD(jint, Int, false);
1812 GET_STATIC_TYPE_FIELD(jlong, Long, false);
1813 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1814 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1817 * Set a static field.
1819 #define SET_STATIC_TYPE_FIELD(_ctype, _jname, _jvfld) \
1820 static void SetStatic##_jname##Field(JNIEnv* env, jclass clazz, \
1821 jfieldID fieldID, _ctype value) \
1823 UNUSED_PARAMETER(clazz); \
1825 StaticField* sfield = (StaticField*) fieldID; \
1826 dvmSetStaticField##_jname(sfield, value); \
1829 SET_STATIC_TYPE_FIELD(jobject, Object, l);
1830 SET_STATIC_TYPE_FIELD(jboolean, Boolean, z);
1831 SET_STATIC_TYPE_FIELD(jbyte, Byte, b);
1832 SET_STATIC_TYPE_FIELD(jchar, Char, c);
1833 SET_STATIC_TYPE_FIELD(jshort, Short, s);
1834 SET_STATIC_TYPE_FIELD(jint, Int, i);
1835 SET_STATIC_TYPE_FIELD(jlong, Long, j);
1836 SET_STATIC_TYPE_FIELD(jfloat, Float, f);
1837 SET_STATIC_TYPE_FIELD(jdouble, Double, d);
1840 * Get an instance field.
1842 * If we get an object reference, add it to the local refs list.
1844 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \
1845 static _ctype Get##_jname##Field(JNIEnv* env, jobject obj, \
1849 InstField* field = (InstField*) fieldID; \
1850 _ctype value = dvmGetField##_jname((Object*) obj,field->byteOffset);\
1851 if (_isref) /* only when _ctype==jobject */ \
1852 value = (_ctype)(u4)addLocalReference((jobject)(u4)value); \
1856 GET_TYPE_FIELD(jobject, Object, true);
1857 GET_TYPE_FIELD(jboolean, Boolean, false);
1858 GET_TYPE_FIELD(jbyte, Byte, false);
1859 GET_TYPE_FIELD(jchar, Char, false);
1860 GET_TYPE_FIELD(jshort, Short, false);
1861 GET_TYPE_FIELD(jint, Int, false);
1862 GET_TYPE_FIELD(jlong, Long, false);
1863 GET_TYPE_FIELD(jfloat, Float, false);
1864 GET_TYPE_FIELD(jdouble, Double, false);
1867 * Set an instance field.
1869 #define SET_TYPE_FIELD(_ctype, _jname) \
1870 static void Set##_jname##Field(JNIEnv* env, jobject obj, \
1871 jfieldID fieldID, _ctype value) \
1874 InstField* field = (InstField*) fieldID; \
1875 dvmSetField##_jname((Object*) obj, field->byteOffset, value); \
1878 SET_TYPE_FIELD(jobject, Object);
1879 SET_TYPE_FIELD(jboolean, Boolean);
1880 SET_TYPE_FIELD(jbyte, Byte);
1881 SET_TYPE_FIELD(jchar, Char);
1882 SET_TYPE_FIELD(jshort, Short);
1883 SET_TYPE_FIELD(jint, Int);
1884 SET_TYPE_FIELD(jlong, Long);
1885 SET_TYPE_FIELD(jfloat, Float);
1886 SET_TYPE_FIELD(jdouble, Double);
1889 * Make a virtual method call.
1891 * Three versions (..., va_list, jvalue[]) for each return type. If we're
1892 * returning an Object, we have to add it to the local references table.
1894 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1895 static _ctype Call##_jname##Method(JNIEnv* env, jobject obj, \
1896 jmethodID methodID, ...) \
1899 Object* dobj = (Object*) obj; \
1900 const Method* meth; \
1903 meth = dvmGetVirtualizedMethod(dobj->clazz, (Method*)methodID); \
1904 if (meth == NULL) { \
1908 va_start(args, methodID); \
1909 dvmCallMethodV(_self, meth, dobj, &result, args); \
1912 result.l = addLocalReference(result.l); \
1916 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject obj, \
1917 jmethodID methodID, va_list args) \
1920 Object* dobj = (Object*) obj; \
1921 const Method* meth; \
1923 meth = dvmGetVirtualizedMethod(dobj->clazz, (Method*)methodID); \
1924 if (meth == NULL) { \
1928 dvmCallMethodV(_self, meth, dobj, &result, args); \
1930 result.l = addLocalReference(result.l); \
1934 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject obj, \
1935 jmethodID methodID, jvalue* args) \
1938 Object* dobj = (Object*) obj; \
1939 const Method* meth; \
1941 meth = dvmGetVirtualizedMethod(dobj->clazz, (Method*)methodID); \
1942 if (meth == NULL) { \
1946 dvmCallMethodA(_self, meth, dobj, &result, args); \
1948 result.l = addLocalReference(result.l); \
1952 CALL_VIRTUAL(jobject, Object, NULL, result.l, true);
1953 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
1954 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
1955 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
1956 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
1957 CALL_VIRTUAL(jint, Int, 0, result.i, false);
1958 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
1959 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
1960 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
1961 CALL_VIRTUAL(void, Void, , , false);
1964 * Make a "non-virtual" method call. We're still calling a virtual method,
1965 * but this time we're not doing an indirection through the object's vtable.
1966 * The "clazz" parameter defines which implementation of a method we want.
1968 * Three versions (..., va_list, jvalue[]) for each return type.
1970 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1971 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject obj, \
1972 jclass clazz, jmethodID methodID, ...) \
1975 Object* dobj = (Object*) obj; \
1976 const Method* meth; \
1979 meth = dvmGetVirtualizedMethod((ClassObject*)clazz, \
1980 (Method*)methodID); \
1981 if (meth == NULL) { \
1985 va_start(args, methodID); \
1986 dvmCallMethodV(_self, meth, dobj, &result, args); \
1988 result.l = addLocalReference(result.l); \
1993 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject obj, \
1994 jclass clazz, jmethodID methodID, va_list args) \
1997 Object* dobj = (Object*) obj; \
1998 const Method* meth; \
2000 meth = dvmGetVirtualizedMethod((ClassObject*)clazz, \
2001 (Method*)methodID); \
2002 if (meth == NULL) { \
2006 dvmCallMethodV(_self, meth, dobj, &result, args); \
2008 result.l = addLocalReference(result.l); \
2012 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject obj, \
2013 jclass clazz, jmethodID methodID, jvalue* args) \
2016 Object* dobj = (Object*) obj; \
2017 const Method* meth; \
2019 meth = dvmGetVirtualizedMethod((ClassObject*)clazz, \
2020 (Method*)methodID); \
2021 if (meth == NULL) { \
2025 dvmCallMethodA(_self, meth, dobj, &result, args); \
2027 result.l = addLocalReference(result.l); \
2031 CALL_NONVIRTUAL(jobject, Object, NULL, result.l, true);
2032 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2033 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2034 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2035 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2036 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2037 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2038 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2039 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2040 CALL_NONVIRTUAL(void, Void, , , false);
2044 * Call a static method.
2046 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
2047 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass clazz, \
2048 jmethodID methodID, ...) \
2053 assert((ClassObject*) clazz == ((Method*)methodID)->clazz); \
2054 va_start(args, methodID); \
2055 dvmCallMethodV(_self, (Method*) methodID, NULL, &result, args); \
2058 result.l = addLocalReference(result.l); \
2062 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass clazz, \
2063 jmethodID methodID, va_list args) \
2067 assert((ClassObject*) clazz == ((Method*)methodID)->clazz); \
2068 dvmCallMethodV(_self, (Method*) methodID, NULL, &result, args); \
2070 result.l = addLocalReference(result.l); \
2074 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass clazz, \
2075 jmethodID methodID, jvalue* args) \
2079 assert((ClassObject*) clazz == ((Method*)methodID)->clazz); \
2080 dvmCallMethodA(_self, (Method*) methodID, NULL, &result, args); \
2082 result.l = addLocalReference(result.l); \
2086 CALL_STATIC(jobject, Object, NULL, result.l, true);
2087 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2088 CALL_STATIC(jbyte, Byte, 0, result.b, false);
2089 CALL_STATIC(jchar, Char, 0, result.c, false);
2090 CALL_STATIC(jshort, Short, 0, result.s, false);
2091 CALL_STATIC(jint, Int, 0, result.i, false);
2092 CALL_STATIC(jlong, Long, 0, result.j, false);
2093 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2094 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2095 CALL_STATIC(void, Void, , , false);
2098 * Create a new String from Unicode data.
2100 * If "len" is zero, we will return an empty string even if "unicodeChars"
2101 * is NULL. (The JNI spec is vague here.)
2103 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len)
2108 jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2110 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2111 jstr = addLocalReference((jstring) jstr);
2119 * Return the length of a String in Unicode character units.
2121 static jsize GetStringLength(JNIEnv* env, jstring string)
2125 jsize len = dvmStringLen((StringObject*) string);
2132 * Get a pointer to the string's character data.
2134 * The result is guaranteed to be valid until ReleaseStringChars is
2135 * called, which means we can't just hold a reference to it in the local
2136 * refs table. We have to add it to the global refs.
2138 * Technically, we don't need to hold a reference to the String, but rather
2139 * to the Char[] object within the String.
2141 * We could also just allocate some storage and copy the data into it,
2142 * but it's a choice between our synchronized global reference table and
2143 * libc's synchronized heap allocator.
2145 static const jchar* GetStringChars(JNIEnv* env, jstring string,
2150 const u2* data = dvmStringChars((StringObject*) string);
2151 addGlobalReference(string);
2154 *isCopy = JNI_FALSE;
2157 return (jchar*)data;
2161 * Release our grip on some characters from a string.
2163 static void ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars)
2166 deleteGlobalReference(string);
2171 * Create a new java.lang.String object from chars in modified UTF-8 form.
2173 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2174 * accept it and return a NULL pointer in response.
2176 static jstring NewStringUTF(JNIEnv* env, const char* bytes)
2180 StringObject* newStr;
2182 if (bytes == NULL) {
2185 newStr = dvmCreateStringFromCstr(bytes, ALLOC_DEFAULT);
2186 if (newStr != NULL) {
2187 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2188 newStr = addLocalReference((jstring) newStr);
2193 return (jstring)newStr;
2197 * Return the length in bytes of the modified UTF-8 form of the string.
2199 static jsize GetStringUTFLength(JNIEnv* env, jstring string)
2203 jsize len = dvmStringUtf8ByteLen((StringObject*) string);
2210 * Convert "string" to modified UTF-8 and return a pointer. The returned
2211 * value must be released with ReleaseStringUTFChars.
2213 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2214 * or NULL if the operation fails. Returns NULL if and only if an invocation
2215 * of this function has thrown an exception."
2217 * The behavior here currently follows that of other open-source VMs, which
2218 * quietly return NULL if "string" is NULL. We should consider throwing an
2219 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
2220 * which should catch this sort of thing during development.) Certain other
2221 * VMs will crash with a segmentation fault.
2223 static const char* GetStringUTFChars(JNIEnv* env, jstring string,
2229 if (string == NULL) {
2230 /* this shouldn't happen; throw NPE? */
2236 newStr = dvmCreateCstrFromString((StringObject*) string);
2237 if (newStr == NULL) {
2238 /* assume memory failure */
2239 dvmThrowException("Ljava/lang/OutOfMemoryError;",
2240 "native heap string alloc failed");
2249 * Release a string created by GetStringUTFChars().
2251 static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf)
2259 * Return the capacity of the array.
2261 static jsize GetArrayLength(JNIEnv* env, jarray array)
2265 jsize length = ((ArrayObject*) array)->length;
2272 * Construct a new array that holds objects from class "elementClass".
2274 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2275 jclass elementClass, jobject initialElement)
2279 ClassObject* elemClassObj = (ClassObject*) elementClass;
2280 ArrayObject* newObj = NULL;
2282 if (elemClassObj == NULL) {
2283 dvmThrowException("Ljava/lang/NullPointerException;",
2284 "JNI NewObjectArray");
2288 newObj = dvmAllocObjectArray(elemClassObj, length, ALLOC_DEFAULT);
2289 if (newObj == NULL) {
2290 assert(dvmCheckException(_self));
2293 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2296 * Initialize the array. Trashes "length".
2298 if (initialElement != NULL) {
2299 Object** arrayData = (Object**) newObj->contents;
2302 *arrayData++ = (Object*) initialElement;
2305 newObj = addLocalReference((jobjectArray) newObj);
2309 return (jobjectArray) newObj;
2313 * Get one element of an Object array.
2315 * Add the object to the local references table in case the array goes away.
2317 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array,
2322 ArrayObject* arrayObj = (ArrayObject*) array;
2323 Object* value = NULL;
2325 assert(array != NULL);
2327 /* check the array bounds */
2328 if (index < 0 || index >= (int) arrayObj->length) {
2329 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
2330 arrayObj->obj.clazz->descriptor);
2334 value = ((Object**) arrayObj->contents)[index];
2335 value = addLocalReference(value);
2339 return (jobject) value;
2343 * Set one element of an Object array.
2345 static void SetObjectArrayElement(JNIEnv* env, jobjectArray array,
2346 jsize index, jobject value)
2350 ArrayObject* arrayObj = (ArrayObject*) array;
2352 assert(array != NULL);
2354 /* check the array bounds */
2355 if (index < 0 || index >= (int) arrayObj->length) {
2356 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
2357 arrayObj->obj.clazz->descriptor);
2361 //LOGV("JNI: set element %d in array %p to %p\n", index, array, value);
2363 ((Object**) arrayObj->contents)[index] = (Object*) value;
2370 * Create a new array of primitive elements.
2372 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2373 static _artype New##_jname##Array(JNIEnv* env, jsize length) \
2376 ArrayObject* arrayObj; \
2377 arrayObj = dvmAllocPrimitiveArray(_typechar, length, \
2379 if (arrayObj != NULL) { \
2380 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2381 arrayObj = addLocalReference(arrayObj); \
2384 return (_artype)arrayObj; \
2386 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2387 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2388 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2389 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2390 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2391 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2392 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2393 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2396 * Get a pointer to a C array of primitive elements from an array object
2397 * of the matching type.
2399 * We guarantee availability until Release is called, so we have to add
2400 * the array object to the global refs table.
2402 * In a compacting GC, we either need to return a copy of the elements
2403 * or "pin" the memory. Otherwise we run the risk of native code using
2404 * the buffer as the destination of a blocking read() call that wakes up
2407 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2408 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2409 _ctype##Array array, jboolean* isCopy) \
2413 ArrayObject* arrayObj = (ArrayObject*)array; \
2414 addGlobalReference(arrayObj); \
2415 data = (_ctype*) arrayObj->contents; \
2416 if (isCopy != NULL) \
2417 *isCopy = JNI_FALSE; \
2423 * Release the storage locked down by the "get" function.
2425 * The API says, ""'mode' has no effect if 'elems' is not a copy of the
2426 * elements in 'array'." They apparently did not anticipate the need to
2427 * create a global reference to avoid GC race conditions. We actually
2428 * want to delete the global reference in all circumstances that would
2429 * result in a copied array being freed. This means anything but a
2430 * JNI_COMMIT release.
2432 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2433 static void Release##_jname##ArrayElements(JNIEnv* env, \
2434 _ctype##Array array, _ctype* elems, jint mode) \
2436 UNUSED_PARAMETER(elems); \
2438 if (mode != JNI_COMMIT) \
2439 deleteGlobalReference(array); \
2444 * Copy a section of a primitive array to a buffer.
2446 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2447 static void Get##_jname##ArrayRegion(JNIEnv* env, \
2448 _ctype##Array array, jsize start, jsize len, _ctype* buf) \
2451 ArrayObject* arrayObj = (ArrayObject*)array; \
2452 _ctype* data = (_ctype*) arrayObj->contents; \
2453 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2454 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
2455 arrayObj->obj.clazz->descriptor); \
2457 memcpy(buf, data + start, len * sizeof(_ctype)); \
2463 * Copy a section of a primitive array to a buffer.
2465 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2466 static void Set##_jname##ArrayRegion(JNIEnv* env, \
2467 _ctype##Array array, jsize start, jsize len, const _ctype* buf) \
2470 ArrayObject* arrayObj = (ArrayObject*)array; \
2471 _ctype* data = (_ctype*) arrayObj->contents; \
2472 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2473 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
2474 arrayObj->obj.clazz->descriptor); \
2476 memcpy(data + start, buf, len * sizeof(_ctype)); \
2483 * Get<Type>ArrayElements
2484 * Release<Type>ArrayElements
2485 * Get<Type>ArrayRegion
2486 * Set<Type>ArrayRegion
2488 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
2489 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2490 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2491 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
2492 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2494 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2495 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2496 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2497 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2498 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2499 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2500 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2501 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2504 * Register one or more native functions in one class.
2506 static jint RegisterNatives(JNIEnv* env, jclass clazz,
2507 const JNINativeMethod* methods, jint nMethods)
2514 if (gDvm.verboseJni) {
2515 LOGI("[Registering JNI native methods for class %s]\n",
2516 ((ClassObject*) clazz)->descriptor);
2519 for (i = 0; i < nMethods; i++) {
2520 if (!dvmRegisterJNIMethod((ClassObject*) clazz,
2521 methods[i].name, methods[i].signature, methods[i].fnPtr))
2535 * Un-register a native function.
2537 static jint UnregisterNatives(JNIEnv* env, jclass clazz)
2541 * The JNI docs refer to this as a way to reload/relink native libraries,
2542 * and say it "should not be used in normal native code".
2544 * We can implement it if we decide we need it.
2553 * We have to track all monitor enters and exits, so that we can undo any
2554 * outstanding synchronization before the thread exits.
2556 static jint MonitorEnter(JNIEnv* env, jobject obj)
2559 dvmLockObject(_self, (Object*) obj);
2560 trackMonitorEnter(_self, (Object*) obj);
2566 * Unlock the monitor.
2568 * Throws an IllegalMonitorStateException if the current thread
2569 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
2571 * According to the 1.6 spec, it's legal to call here with an exception
2572 * pending. If this fails, we'll stomp the original exception.
2574 static jint MonitorExit(JNIEnv* env, jobject obj)
2577 bool success = dvmUnlockObject(_self, (Object*) obj);
2579 trackMonitorExit(_self, (Object*) obj);
2581 return success ? JNI_OK : JNI_ERR;
2585 * Return the JavaVM interface associated with the current thread.
2587 static jint GetJavaVM(JNIEnv* env, JavaVM** vm)
2590 //*vm = gDvm.vmList;
2591 *vm = (JavaVM*) ((JNIEnvExt*)env)->vm;
2600 * Copies "len" Unicode characters, from offset "start".
2602 static void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len,
2606 StringObject* strObj = (StringObject*) str;
2607 if (start + len > dvmStringLen(strObj))
2608 dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
2610 memcpy(buf, dvmStringChars(strObj) + start, len * sizeof(u2));
2615 * Translates "len" Unicode characters, from offset "start", into
2616 * modified UTF-8 encoding.
2618 static void GetStringUTFRegion(JNIEnv* env, jstring str, jsize start,
2619 jsize len, char* buf)
2622 StringObject* strObj = (StringObject*) str;
2623 if (start + len > dvmStringLen(strObj))
2624 dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
2626 dvmCreateCstrFromStringRegion(strObj, start, len, buf);
2631 * Get a raw pointer to array data.
2633 * The caller is expected to call "release" before doing any JNI calls
2634 * or blocking I/O operations.
2636 * In a compacting GC, we need to pin the memory or block GC.
2638 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array,
2643 ArrayObject* arrayObj = (ArrayObject*)array;
2644 addGlobalReference(arrayObj);
2645 data = arrayObj->contents;
2647 *isCopy = JNI_FALSE;
2653 * Release an array obtained with GetPrimitiveArrayCritical.
2655 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array,
2656 void* carray, jint mode)
2659 if (mode != JNI_COMMIT)
2660 deleteGlobalReference(array);
2665 * Like GetStringChars, but with restricted use.
2667 static const jchar* GetStringCritical(JNIEnv* env, jstring string,
2671 const u2* data = dvmStringChars((StringObject*) string);
2672 addGlobalReference(string);
2675 *isCopy = JNI_FALSE;
2678 return (jchar*)data;
2682 * Like ReleaseStringChars, but with restricted use.
2684 static void ReleaseStringCritical(JNIEnv* env, jstring string,
2685 const jchar* carray)
2688 deleteGlobalReference(string);
2693 * Create a new weak global reference.
2695 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj)
2699 jobject gref = NULL;
2700 LOGE("JNI ERROR: NewWeakGlobalRef not implemented\n");
2707 * Delete the specified weak global reference.
2709 static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj)
2713 LOGE("JNI ERROR: DeleteWeakGlobalRef not implemented\n");
2719 * Quick check for pending exceptions.
2721 * TODO: we should be able to skip the enter/exit macros here.
2723 static jboolean ExceptionCheck(JNIEnv* env)
2726 bool result = dvmCheckException(_self);
2732 * Returns the type of the object referred to by "obj". It can be local,
2733 * global, or weak global.
2735 * In the current implementation, references can be global and local at
2736 * the same time, so while the return value is accurate it may not tell
2739 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj)
2742 jobjectRefType type;
2745 type = JNIInvalidRefType;
2747 type = dvmGetJNIRefType(obj);
2753 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2755 * "address" may not be NULL, and "capacity" must be > 0. (These are only
2756 * verified when CheckJNI is enabled.)
2758 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)
2762 Thread* self = _self /*dvmThreadSelf()*/;
2763 Object* platformAddress = NULL;
2765 jobject result = NULL;
2767 /* get an instance of PlatformAddress that wraps the provided address */
2769 gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on,
2770 NULL, &callResult, address);
2771 if (dvmGetException(self) != NULL || callResult.l == NULL)
2774 /* don't let the GC discard it */
2775 platformAddress = (Object*) callResult.l;
2776 dvmAddTrackedAlloc(platformAddress, self);
2777 LOGV("tracking %p for address=%p\n", platformAddress, address);
2779 /* create an instance of java.nio.ReadWriteDirectByteBuffer */
2780 ClassObject* clazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
2781 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
2783 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2784 if (newObj != NULL) {
2785 /* call the (PlatformAddress, int, int) constructor */
2786 newObj = addLocalReference(newObj);
2787 dvmCallMethod(self, gDvm.methJavaNioReadWriteDirectByteBuffer_init,
2788 newObj, &callResult, platformAddress, (jint) capacity, (jint) 0);
2789 if (dvmGetException(self) != NULL)
2793 result = (jobject) newObj;
2796 if (platformAddress != NULL)
2797 dvmReleaseTrackedAlloc(platformAddress, self);
2803 * Get the starting address of the buffer for the specified java.nio.Buffer.
2805 * If this is not a "direct" buffer, we return NULL.
2807 static void* GetDirectBufferAddress(JNIEnv* env, jobject buf)
2811 Object* bufObj = (Object*) buf;
2812 Thread* self = _self /*dvmThreadSelf()*/;
2813 Object* platformAddr;
2815 void* result = NULL;
2818 * Start by determining if the object supports the DirectBuffer
2819 * interfaces. Note this does not guarantee that it's a direct buffer.
2821 if (!dvmInstanceof(bufObj->clazz,
2822 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer))
2828 * Get a PlatformAddress object with the effective address.
2830 * If this isn't a direct buffer, the result will be NULL and/or an
2831 * exception will have been thrown.
2833 * TODO: eliminate the getEffectiveAddress() method call.
2835 const Method* meth = dvmGetVirtualizedMethod(bufObj->clazz,
2836 gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress);
2837 dvmCallMethodA(self, meth, bufObj, &callResult, NULL);
2838 if (dvmGetException(self) != NULL) {
2839 dvmClearException(self);
2840 callResult.l = NULL;
2843 platformAddr = callResult.l;
2844 if (platformAddr == NULL) {
2845 LOGD("Got request for address of non-direct buffer\n");
2850 * Extract the address from the PlatformAddress object. Instead of
2851 * calling the toLong() method, just grab the field directly. This
2852 * is faster but more fragile.
2854 result = (void*) dvmGetFieldInt(platformAddr,
2855 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr);
2863 * Get the capacity of the buffer for the specified java.nio.Buffer.
2865 * Returns -1 if the object is not a direct buffer. (We actually skip
2866 * this check, since it's expensive to determine, and just return the
2867 * capacity regardless.)
2869 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf)
2874 * The capacity is always in the Buffer.capacity field.
2876 * (The "check" version should verify that this is actually a Buffer,
2877 * but we're not required to do so here.)
2879 jlong result = dvmGetFieldInt((Object*)buf, gDvm.offJavaNioBuffer_capacity);
2887 * ===========================================================================
2888 * JNI invocation functions
2889 * ===========================================================================
2893 * Handle AttachCurrentThread{AsDaemon}.
2895 * We need to make sure the VM is actually running. For example, if we start
2896 * up, issue an Attach, and the VM exits almost immediately, by the time the
2897 * attaching happens the VM could already be shutting down.
2899 * It's hard to avoid a race condition here because we don't want to hold
2900 * a lock across the entire operation. What we can do is temporarily
2901 * increment the thread count to prevent a VM exit.
2903 * This could potentially still have problems if a daemon thread calls here
2904 * while the VM is shutting down. dvmThreadSelf() will work, since it just
2905 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
2906 * you shut down a VM while threads are still running inside it.
2908 * Remember that some code may call this as a way to find the per-thread
2909 * JNIEnv pointer. Don't do excess work for that case.
2911 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args,
2914 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2916 bool result = false;
2919 * Return immediately if we're already one with the VM.
2921 self = dvmThreadSelf();
2923 *p_env = self->jniEnv;
2928 * No threads allowed in zygote mode.
2934 /* increment the count to keep the VM from bailing while we run */
2935 dvmLockThreadList(NULL);
2936 if (gDvm.nonDaemonThreadCount == 0) {
2938 LOGV("Refusing to attach thread '%s' -- VM is shutting down\n",
2939 (thr_args == NULL) ? "(unknown)" : args->name);
2940 dvmUnlockThreadList();
2943 gDvm.nonDaemonThreadCount++;
2944 dvmUnlockThreadList();
2946 /* tweak the JavaVMAttachArgs as needed */
2947 JavaVMAttachArgs argsCopy;
2949 /* allow the v1.1 calling convention */
2950 argsCopy.version = JNI_VERSION_1_2;
2951 argsCopy.name = NULL;
2952 argsCopy.group = dvmGetMainThreadGroup();
2954 assert(args->version >= JNI_VERSION_1_2);
2956 argsCopy.version = args->version;
2957 argsCopy.name = args->name;
2958 if (args->group != NULL)
2959 argsCopy.group = args->group;
2961 argsCopy.group = dvmGetMainThreadGroup();
2964 result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2966 /* restore the count */
2967 dvmLockThreadList(NULL);
2968 gDvm.nonDaemonThreadCount--;
2969 dvmUnlockThreadList();
2972 * Change the status to indicate that we're out in native code. This
2973 * call is not guarded with state-change macros, so we have to do it
2977 self = dvmThreadSelf();
2978 assert(self != NULL);
2979 dvmChangeStatus(self, THREAD_NATIVE);
2980 *p_env = self->jniEnv;
2988 * Attach the current thread to the VM. If the thread is already attached,
2991 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2993 return attachThread(vm, p_env, thr_args, false);
2997 * Like AttachCurrentThread, but set the "daemon" flag.
2999 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env,
3002 return attachThread(vm, p_env, thr_args, true);
3006 * Dissociate the current thread from the VM.
3008 static jint DetachCurrentThread(JavaVM* vm)
3010 Thread* self = dvmThreadSelf();
3012 if (self == NULL) /* not attached, can't do anything */
3015 /* switch to "running" to check for suspension */
3016 dvmChangeStatus(self, THREAD_RUNNING);
3018 /* detach the thread */
3019 dvmDetachCurrentThread();
3021 /* (no need to change status back -- we have no status) */
3026 * If current thread is attached to VM, return the associated JNIEnv.
3027 * Otherwise, stuff NULL in and return JNI_EDETACHED.
3029 * JVMTI overloads this by specifying a magic value for "version", so we
3030 * do want to check that here.
3032 static jint GetEnv(JavaVM* vm, void** env, jint version)
3034 Thread* self = dvmThreadSelf();
3036 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6)
3037 return JNI_EVERSION;
3042 /* TODO: status change is probably unnecessary */
3043 dvmChangeStatus(self, THREAD_RUNNING);
3044 *env = (void*) dvmGetThreadJNIEnv(self);
3045 dvmChangeStatus(self, THREAD_NATIVE);
3048 return JNI_EDETACHED;
3054 * Destroy the VM. This may be called from any thread.
3056 * If the current thread is attached, wait until the current thread is
3057 * the only non-daemon user-level thread. If the current thread is not
3058 * attached, we attach it and do the processing as usual. (If the attach
3059 * fails, it's probably because all the non-daemon threads have already
3060 * exited and the VM doesn't want to let us back in.)
3062 * TODO: we don't really deal with the situation where more than one thread
3063 * has called here. One thread wins, the other stays trapped waiting on
3064 * the condition variable forever. Not sure this situation is interesting
3067 static jint DestroyJavaVM(JavaVM* vm)
3069 JavaVMExt* ext = (JavaVMExt*) vm;
3075 LOGD("DestroyJavaVM waiting for non-daemon threads to exit\n");
3078 * Sleep on a condition variable until it's okay to exit.
3080 self = dvmThreadSelf();
3083 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
3084 LOGV("Unable to reattach main for Destroy; assuming VM is "
3085 "shutting down (count=%d)\n",
3086 gDvm.nonDaemonThreadCount);
3089 LOGV("Attached to wait for shutdown in Destroy\n");
3092 dvmChangeStatus(self, THREAD_VMWAIT);
3094 dvmLockThreadList(self);
3095 gDvm.nonDaemonThreadCount--; // remove current thread from count
3097 while (gDvm.nonDaemonThreadCount > 0)
3098 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
3100 dvmUnlockThreadList();
3104 // TODO: call System.exit() to run any registered shutdown hooks
3105 // (this may not return -- figure out how this should work)
3107 LOGD("DestroyJavaVM shutting VM down\n");
3110 // TODO - free resources associated with JNI-attached daemon threads
3119 * ===========================================================================
3121 * ===========================================================================
3124 static const struct JNINativeInterface gNativeInterface = {
3135 FromReflectedMethod,
3159 EnsureLocalCapacity,
3202 CallNonvirtualObjectMethod,
3203 CallNonvirtualObjectMethodV,
3204 CallNonvirtualObjectMethodA,
3205 CallNonvirtualBooleanMethod,
3206 CallNonvirtualBooleanMethodV,
3207 CallNonvirtualBooleanMethodA,
3208 CallNonvirtualByteMethod,
3209 CallNonvirtualByteMethodV,
3210 CallNonvirtualByteMethodA,
3211 CallNonvirtualCharMethod,
3212 CallNonvirtualCharMethodV,
3213 CallNonvirtualCharMethodA,
3214 CallNonvirtualShortMethod,
3215 CallNonvirtualShortMethodV,
3216 CallNonvirtualShortMethodA,
3217 CallNonvirtualIntMethod,
3218 CallNonvirtualIntMethodV,
3219 CallNonvirtualIntMethodA,
3220 CallNonvirtualLongMethod,
3221 CallNonvirtualLongMethodV,
3222 CallNonvirtualLongMethodA,
3223 CallNonvirtualFloatMethod,
3224 CallNonvirtualFloatMethodV,
3225 CallNonvirtualFloatMethodA,
3226 CallNonvirtualDoubleMethod,
3227 CallNonvirtualDoubleMethodV,
3228 CallNonvirtualDoubleMethodA,
3229 CallNonvirtualVoidMethod,
3230 CallNonvirtualVoidMethodV,
3231 CallNonvirtualVoidMethodA,
3256 CallStaticObjectMethod,
3257 CallStaticObjectMethodV,
3258 CallStaticObjectMethodA,
3259 CallStaticBooleanMethod,
3260 CallStaticBooleanMethodV,
3261 CallStaticBooleanMethodA,
3262 CallStaticByteMethod,
3263 CallStaticByteMethodV,
3264 CallStaticByteMethodA,
3265 CallStaticCharMethod,
3266 CallStaticCharMethodV,
3267 CallStaticCharMethodA,
3268 CallStaticShortMethod,
3269 CallStaticShortMethodV,
3270 CallStaticShortMethodA,
3271 CallStaticIntMethod,
3272 CallStaticIntMethodV,
3273 CallStaticIntMethodA,
3274 CallStaticLongMethod,
3275 CallStaticLongMethodV,
3276 CallStaticLongMethodA,
3277 CallStaticFloatMethod,
3278 CallStaticFloatMethodV,
3279 CallStaticFloatMethodA,
3280 CallStaticDoubleMethod,
3281 CallStaticDoubleMethodV,
3282 CallStaticDoubleMethodA,
3283 CallStaticVoidMethod,
3284 CallStaticVoidMethodV,
3285 CallStaticVoidMethodA,
3289 GetStaticObjectField,
3290 GetStaticBooleanField,
3293 GetStaticShortField,
3296 GetStaticFloatField,
3297 GetStaticDoubleField,
3299 SetStaticObjectField,
3300 SetStaticBooleanField,
3303 SetStaticShortField,
3306 SetStaticFloatField,
3307 SetStaticDoubleField,
3318 ReleaseStringUTFChars,
3322 GetObjectArrayElement,
3323 SetObjectArrayElement,
3334 GetBooleanArrayElements,
3335 GetByteArrayElements,
3336 GetCharArrayElements,
3337 GetShortArrayElements,
3338 GetIntArrayElements,
3339 GetLongArrayElements,
3340 GetFloatArrayElements,
3341 GetDoubleArrayElements,
3343 ReleaseBooleanArrayElements,
3344 ReleaseByteArrayElements,
3345 ReleaseCharArrayElements,
3346 ReleaseShortArrayElements,
3347 ReleaseIntArrayElements,
3348 ReleaseLongArrayElements,
3349 ReleaseFloatArrayElements,
3350 ReleaseDoubleArrayElements,
3352 GetBooleanArrayRegion,
3355 GetShortArrayRegion,
3358 GetFloatArrayRegion,
3359 GetDoubleArrayRegion,
3360 SetBooleanArrayRegion,
3363 SetShortArrayRegion,
3366 SetFloatArrayRegion,
3367 SetDoubleArrayRegion,
3380 GetPrimitiveArrayCritical,
3381 ReleasePrimitiveArrayCritical,
3384 ReleaseStringCritical,
3387 DeleteWeakGlobalRef,
3391 NewDirectByteBuffer,
3392 GetDirectBufferAddress,
3393 GetDirectBufferCapacity,
3397 static const struct JNIInvokeInterface gInvokeInterface = {
3403 AttachCurrentThread,
3404 DetachCurrentThread,
3408 AttachCurrentThreadAsDaemon,
3413 * ===========================================================================
3415 * ===========================================================================
3419 * Enable "checked JNI" after the VM has partially started. This must
3420 * only be called in "zygote" mode, when we have one thread running.
3422 void dvmLateEnableCheckedJni(void)
3427 extEnv = dvmGetJNIEnvForThread();
3428 if (extEnv == NULL) {
3429 LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv\n");
3433 assert(extVm != NULL);
3435 if (!extVm->useChecked) {
3436 LOGD("Late-enabling CheckJNI\n");
3437 dvmUseCheckedJniVm(extVm);
3438 extVm->useChecked = true;
3439 dvmUseCheckedJniEnv(extEnv);
3441 /* currently no way to pick up jniopts features */
3443 LOGD("Not late-enabling CheckJNI (already on)\n");
3450 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args)
3456 * Return a buffer full of created VMs.
3458 * We always have zero or one.
3460 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
3462 if (gDvm.vmList != NULL) {
3466 *vmBuf++ = gDvm.vmList;
3476 * Create a new VM instance.
3478 * The current thread becomes the main VM thread. We return immediately,
3479 * which effectively means the caller is executing in a native method.
3481 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)
3483 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3484 JNIEnvExt* pEnv = NULL;
3485 JavaVMExt* pVM = NULL;
3489 int result = JNI_ERR;
3490 bool checkJni = false;
3491 bool warnError = true;
3492 bool forceDataCopy = false;
3494 if (args->version < JNI_VERSION_1_2)
3495 return JNI_EVERSION;
3497 // TODO: don't allow creation of multiple VMs -- one per customer for now
3499 /* zero globals; not strictly necessary the first time a VM is started */
3500 memset(&gDvm, 0, sizeof(gDvm));
3503 * Set up structures for JNIEnv and VM.
3505 //pEnv = (JNIEnvExt*) malloc(sizeof(JNIEnvExt));
3506 pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
3508 //memset(pEnv, 0, sizeof(JNIEnvExt));
3509 //pEnv->funcTable = &gNativeInterface;
3511 memset(pVM, 0, sizeof(JavaVMExt));
3512 pVM->funcTable = &gInvokeInterface;
3513 pVM->envList = pEnv;
3514 dvmInitMutex(&pVM->envListLock);
3516 argv = (const char**) malloc(sizeof(char*) * (args->nOptions));
3517 memset(argv, 0, sizeof(char*) * (args->nOptions));
3522 * Convert JNI args to argv.
3524 * We have to pull out vfprintf/exit/abort, because they use the
3525 * "extraInfo" field to pass function pointer "hooks" in. We also
3526 * look for the -Xcheck:jni stuff here.
3528 for (i = 0; i < args->nOptions; i++) {
3529 const char* optStr = args->options[i].optionString;
3531 if (optStr == NULL) {
3532 fprintf(stderr, "ERROR: arg %d string was null\n", i);
3534 } else if (strcmp(optStr, "vfprintf") == 0) {
3535 gDvm.vfprintfHook = args->options[i].extraInfo;
3536 } else if (strcmp(optStr, "exit") == 0) {
3537 gDvm.exitHook = args->options[i].extraInfo;
3538 } else if (strcmp(optStr, "abort") == 0) {
3539 gDvm.abortHook = args->options[i].extraInfo;
3540 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3542 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3543 const char* jniOpts = optStr + 9;
3544 while (jniOpts != NULL) {
3545 jniOpts++; /* skip past ':' or ',' */
3546 if (strncmp(jniOpts, "warnonly", 8) == 0) {
3548 } else if (strncmp(jniOpts, "forcecopy", 9) == 0) {
3549 forceDataCopy = true;
3551 LOGW("unknown jni opt starting at '%s'\n", jniOpts);
3553 jniOpts = strchr(jniOpts, ',');
3556 /* regular option */
3557 argv[curOpt++] = optStr;
3563 dvmUseCheckedJniVm(pVM);
3564 pVM->useChecked = true;
3566 pVM->warnError = warnError;
3567 pVM->forceDataCopy = forceDataCopy;
3569 /* set this up before initializing VM, so it can create some JNIEnvs */
3570 gDvm.vmList = (JavaVM*) pVM;
3573 * Create an env for main thread. We need to have something set up
3574 * here because some of the class initialization we do when starting
3575 * up the VM will call into native code.
3577 pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3580 gDvm.initializing = true;
3581 if (dvmStartup(argc, argv, args->ignoreUnrecognized, (JNIEnv*)pEnv) != 0) {
3588 * Success! Return stuff to caller.
3590 dvmChangeStatus(NULL, THREAD_NATIVE);
3591 *p_env = (JNIEnv*) pEnv;
3592 *p_vm = (JavaVM*) pVM;
3596 gDvm.initializing = false;
3597 if (result == JNI_OK)
3598 LOGV("JNI_CreateJavaVM succeeded\n");
3600 LOGW("JNI_CreateJavaVM failed\n");