blob: 8967f46f8272472aef86cd5ab3b7f0698839ee69 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Andy McFadden59b61772009-05-13 16:44:34 -070016
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080017/*
18 * Dalvik implementation of JNI interfaces.
19 */
20#include "Dalvik.h"
21#include "JniInternal.h"
22
23#include <stdlib.h>
24#include <stdarg.h>
25#include <limits.h>
26
27/*
28Native methods and interaction with the GC
29
30All JNI methods must start by changing their thread status to
31THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
32returning to native code. The switch to "running" triggers a thread
33suspension check.
34
35With a rudimentary GC we should be able to skip the status change for
36simple functions, e.g. IsSameObject, GetJavaVM, GetStringLength, maybe
37even access to fields with primitive types. Our options are more limited
38with a compacting GC, so we should replace JNI_ENTER with JNI_ENTER_NCGC
39or somesuch on the "lite" functions if we want to try this optimization.
40
41For performance reasons we do as little error-checking as possible here.
42For example, we don't check to make sure the correct type of Object is
43passed in when setting a field, and we don't prevent you from storing
44new values in a "final" field. Such things are best handled in the
45"check" version. For actions that are common, dangerous, and must be
46checked at runtime, such as array bounds checks, we do the tests here.
47
48
49General notes on local/global reference tracking
50
Andy McFadden0083d372009-08-21 14:44:04 -070051JNI provides explicit control over natively-held references that the GC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080052needs to know about. These can be local, in which case they're released
Andy McFadden0083d372009-08-21 14:44:04 -070053when the native method returns into the VM, or global, which are held
Andy McFaddend5ab7262009-08-25 07:19:34 -070054until explicitly released. (There are also weak-global references,
55which have the lifespan and visibility of global references, but the
56object they refer to may be collected.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080057
Andy McFadden0083d372009-08-21 14:44:04 -070058The references can be created with explicit JNI NewLocalRef / NewGlobalRef
59calls. The former is very unusual, the latter is reasonably common
60(e.g. for caching references to class objects).
61
62Local references are most often created as a side-effect of JNI functions.
63For example, the AllocObject/NewObject functions must create local
64references to the objects returned, because nothing else in the GC root
65set has a reference to the new objects.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080066
67The most common mode of operation is for a method to create zero or
68more local references and return. Explicit "local delete" operations
69are expected to be exceedingly rare, except when walking through an
70object array, and the Push/PopLocalFrame calls are expected to be used
71infrequently. For efficient operation, we want to add new local refs
72with a simple store/increment operation; to avoid infinite growth in
73pathological situations, we need to reclaim the space used by deleted
74entries.
75
Andy McFaddend5ab7262009-08-25 07:19:34 -070076If we just want to maintain a list for the GC root set, we can use an
77expanding append-only array that compacts when objects are deleted.
78In typical situations, e.g. running through an array of objects, we will
79be deleting one of the most recently added entries, so we can minimize
80the number of elements moved (or avoid having to move any).
81
82If we want to conceal the pointer values from native code, which is
83necessary to allow the GC to move JNI-referenced objects around, then we
84have to use a more complicated indirection mechanism.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080085
86The spec says, "Local references are only valid in the thread in which
87they are created. The native code must not pass local references from
Andy McFadden0083d372009-08-21 14:44:04 -070088one thread to another."
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080089
90
Andy McFaddend5ab7262009-08-25 07:19:34 -070091Pinned objects
92
93For some large chunks of data, notably primitive arrays and String data,
94JNI allows the VM to choose whether it wants to pin the array object or
95make a copy. We currently pin the memory for better execution performance.
96
97TODO: we're using simple root set references to pin primitive array data,
98because they have the property we need (i.e. the pointer we return is
99guaranteed valid until we explicitly release it). However, if we have a
100compacting GC and don't want to pin all memory held by all global refs,
101we need to treat these differently.
102
103
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800104Global reference tracking
105
106There should be a small "active" set centered around the most-recently
Andy McFaddend5ab7262009-08-25 07:19:34 -0700107added items.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108
Andy McFaddend5ab7262009-08-25 07:19:34 -0700109Because it's global, access to it has to be synchronized. Additions and
110removals require grabbing a mutex. If the table serves as an indirection
111mechanism (i.e. it's not just a list for the benefit of the garbage
112collector), reference lookups may also require grabbing a mutex.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800113
114The JNI spec does not define any sort of limit, so the list must be able
Andy McFaddend5ab7262009-08-25 07:19:34 -0700115to expand to a reasonable size. It may be useful to log significant
116increases in usage to help identify resource leaks.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800117
Andy McFaddend5ab7262009-08-25 07:19:34 -0700118
119Weak-global reference tracking
120
121[TBD]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800122
123
124Local reference tracking
125
126The table of local references can be stored on the interpreted stack or
127in a parallel data structure (one per thread).
128
129*** Approach #1: use the interpreted stack
130
131The easiest place to tuck it is between the frame ptr and the first saved
132register, which is always in0. (See the ASCII art in Stack.h.) We can
133shift the "VM-specific goop" and frame ptr down, effectively inserting
134the JNI local refs in the space normally occupied by local variables.
135
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.
140The only thing that isn't determined by an offset from the current FP
141is the previous frame. However, tucking things below the previous frame
142can be problematic because the "outs" of the previous frame overlap with
143the "ins" of the current frame. If the "ins" are altered they must be
144restored before we return. For a native method call, the easiest and
145safest thing to disrupt is #1, because there are no locals and the "ins"
146are all copied to the native stack.)
147
148We can implement Push/PopLocalFrame with the existing stack frame calls,
149making sure we copy some goop from the previous frame (notably the method
150ptr, so that dvmGetCurrentJNIMethod() doesn't require extra effort).
151
152We can pre-allocate the storage at the time the stack frame is first
153set up, but we have to be careful. When calling from interpreted code
154the frame ptr points directly at the arguments we're passing, but we can
155offset the args pointer when calling the native bridge.
156
157To manage the local ref collection, we need to be able to find three
158things: (1) the start of the region, (2) the end of the region, and (3)
159the next available entry. The last is only required for quick adds.
160We currently have two easily-accessible pointers, the current FP and the
161previous frame's FP. (The "stack pointer" shown in the ASCII art doesn't
162actually exist in the interpreted world.)
163
164We can't use the current FP to find the first "in", because we want to
165insert the variable-sized local refs table between them. It's awkward
166to use the previous frame's FP because native methods invoked via
167dvmCallMethod() or dvmInvokeMethod() don't have "ins", but native methods
168invoked from interpreted code do. We can either track the local refs
169table size with a field in the stack frame, or insert unnecessary items
170so that all native stack frames have "ins".
171
172Assuming we can find the region bounds, we still need pointer #3
173for an efficient implementation. This can be stored in an otherwise
174unused-for-native field in the frame goop.
175
176When we run out of room we have to make more space. If we start allocating
177locals immediately below in0 and grow downward, we will detect end-of-space
178by 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).
180This is nice because we only have to move sizeof(StackSaveArea) bytes
181each time.
182
183Stack 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
185the debugger or SIGQUIT handler looking for "this" or other arguments,
186but in practice this behavior isn't expected to work for native methods,
187so we can simply disallow it.
188
189A conservative GC can just scan the entire stack from top to bottom to find
190all references. An exact GC will need to understand the actual layout.
191
192*** Approach #2: use a parallel stack
193
Andy McFaddend5ab7262009-08-25 07:19:34 -0700194Each Thread/JNIEnv points to a reference table. The struct has
195a system-heap-allocated array of references and a pointer to the
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800196next-available entry ("nextEntry").
197
Andy McFaddend5ab7262009-08-25 07:19:34 -0700198Each stack frame has a pointer to what it sees as the "bottom" element
199in 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
201or removed, "nextEntry" is updated.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800202
203We implement Push/PopLocalFrame with actual stack frames. Before a JNI
204frame gets popped, we set "nextEntry" to the "top" pointer of the current
205frame, effectively releasing the references.
206
207The GC will scan all references from the start of the table to the
208"nextEntry" pointer.
209
210*** Comparison
211
212All approaches will return a failure result when they run out of local
213reference space. For #1 that means blowing out the stack, for #2 it's
214running out of room in the array.
215
216Compared 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.
225
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.
234
235*/
236
Andy McFadden5f612b82009-07-22 15:07:27 -0700237/* fwd */
238static const struct JNINativeInterface gNativeInterface;
Andy McFaddenab00d452009-08-19 07:21:41 -0700239static jobject addGlobalReference(Object* obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800240
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800241#ifdef WITH_JNI_STACK_CHECK
242# define COMPUTE_STACK_SUM(_self) computeStackSum(_self);
243# define CHECK_STACK_SUM(_self) checkStackSum(_self);
Andy McFaddend5ab7262009-08-25 07:19:34 -0700244//static void computeStackSum(Thread* self);
245//static void checkStackSum(Thread* self);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800246#else
247# define COMPUTE_STACK_SUM(_self) ((void)0)
248# define CHECK_STACK_SUM(_self) ((void)0)
249#endif
250
251
252/*
253 * ===========================================================================
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800254 * Utility functions
255 * ===========================================================================
256 */
257
258/*
259 * Entry/exit processing for all JNI calls.
260 *
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.
267 */
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)
274#else
275# define JNI_ENTER() \
276 Thread* _self = dvmThreadSelf(); \
277 UNUSED_PARAMETER(env); \
278 CHECK_STACK_SUM(_self); \
279 dvmChangeStatus(_self, THREAD_RUNNING)
280#endif
281#define JNI_EXIT() \
282 dvmChangeStatus(_self, THREAD_NATIVE); \
283 COMPUTE_STACK_SUM(_self)
284
285#define kGlobalRefsTableInitialSize 512
Andy McFaddenab00d452009-08-19 07:21:41 -0700286#define kGlobalRefsTableMaxSize 51200 /* arbitrary, must be < 64K */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800287#define kGrefWaterInterval 100
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800288#define kTrackGrefUsage true
289
Andy McFaddenc26bb632009-08-21 12:01:31 -0700290#define kPinTableInitialSize 16
291#define kPinTableMaxSize 1024
292#define kPinComplainThreshold 10
293
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800294/*
Andy McFadden5f612b82009-07-22 15:07:27 -0700295 * Allocate the global references table, and look up some classes for
296 * the benefit of direct buffer access.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800297 */
298bool dvmJniStartup(void)
299{
Andy McFaddend5ab7262009-08-25 07:19:34 -0700300#ifdef USE_INDIRECT_REF
301 if (!dvmInitIndirectRefTable(&gDvm.jniGlobalRefTable,
302 kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize,
303 kIndirectKindGlobal))
304 return false;
305#else
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800306 if (!dvmInitReferenceTable(&gDvm.jniGlobalRefTable,
307 kGlobalRefsTableInitialSize, kGlobalRefsTableMaxSize))
308 return false;
Andy McFaddend5ab7262009-08-25 07:19:34 -0700309#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800310
311 dvmInitMutex(&gDvm.jniGlobalRefLock);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800312 gDvm.jniGlobalRefLoMark = 0;
313 gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
314
Andy McFaddenc26bb632009-08-21 12:01:31 -0700315 if (!dvmInitReferenceTable(&gDvm.jniPinRefTable,
316 kPinTableInitialSize, kPinTableMaxSize))
317 return false;
318
319 dvmInitMutex(&gDvm.jniPinRefLock);
320
Andy McFaddenb18992f2009-09-25 10:42:15 -0700321 Method* meth;
322
323 /*
324 * Grab the PhantomReference constructor.
325 */
326 gDvm.classJavaLangRefPhantomReference =
327 dvmFindSystemClassNoInit("Ljava/lang/ref/PhantomReference;");
328 if (gDvm.classJavaLangRefPhantomReference == NULL) {
329 LOGE("Unable to find PhantomReference class\n");
330 return false;
331 }
332 meth= dvmFindDirectMethodByDescriptor(gDvm.classJavaLangRefPhantomReference,
333 "<init>", "(Ljava/lang/Object;Ljava/lang/ref/ReferenceQueue;)V");
334 if (meth == NULL) {
335 LOGE("Unable to find constructor for PhantomReference\n");
336 return false;
337 }
338 gDvm.methJavaLangRefPhantomReference_init = meth;
339
340
Andy McFadden8e5c7842009-07-23 17:47:18 -0700341 /*
342 * Look up and cache pointers to some direct buffer classes, fields,
343 * and methods.
344 */
Andy McFadden5f612b82009-07-22 15:07:27 -0700345 ClassObject* platformAddressClass =
346 dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddress;");
Andy McFadden8e5c7842009-07-23 17:47:18 -0700347 ClassObject* platformAddressFactoryClass =
348 dvmFindSystemClassNoInit("Lorg/apache/harmony/luni/platform/PlatformAddressFactory;");
Andy McFadden5f612b82009-07-22 15:07:27 -0700349 ClassObject* directBufferClass =
350 dvmFindSystemClassNoInit("Lorg/apache/harmony/nio/internal/DirectBuffer;");
Andy McFadden8e5c7842009-07-23 17:47:18 -0700351 ClassObject* readWriteBufferClass =
352 dvmFindSystemClassNoInit("Ljava/nio/ReadWriteDirectByteBuffer;");
353 ClassObject* bufferClass =
354 dvmFindSystemClassNoInit("Ljava/nio/Buffer;");
355
356 if (platformAddressClass == NULL || platformAddressFactoryClass == NULL ||
357 directBufferClass == NULL || readWriteBufferClass == NULL ||
358 bufferClass == NULL)
359 {
Andy McFadden5f612b82009-07-22 15:07:27 -0700360 LOGE("Unable to find internal direct buffer classes\n");
361 return false;
362 }
Andy McFadden8e5c7842009-07-23 17:47:18 -0700363 gDvm.classJavaNioReadWriteDirectByteBuffer = readWriteBufferClass;
Andy McFaddend5ab7262009-08-25 07:19:34 -0700364 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer = directBufferClass;
365 /* need a global reference for extended CheckJNI tests */
366 gDvm.jclassOrgApacheHarmonyNioInternalDirectBuffer =
367 addGlobalReference((Object*) directBufferClass);
Andy McFadden5f612b82009-07-22 15:07:27 -0700368
Andy McFadden8e5c7842009-07-23 17:47:18 -0700369 /*
370 * We need a Method* here rather than a vtable offset, because
371 * DirectBuffer is an interface class.
372 */
Andy McFadden5f612b82009-07-22 15:07:27 -0700373 meth = dvmFindVirtualMethodByDescriptor(
374 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer,
375 "getEffectiveAddress",
376 "()Lorg/apache/harmony/luni/platform/PlatformAddress;");
377 if (meth == NULL) {
378 LOGE("Unable to find PlatformAddress.getEffectiveAddress\n");
379 return false;
380 }
381 gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress = meth;
382
383 meth = dvmFindVirtualMethodByDescriptor(platformAddressClass,
384 "toLong", "()J");
385 if (meth == NULL) {
386 LOGE("Unable to find PlatformAddress.toLong\n");
387 return false;
388 }
Andy McFadden8e5c7842009-07-23 17:47:18 -0700389 gDvm.voffOrgApacheHarmonyLuniPlatformPlatformAddress_toLong =
390 meth->methodIndex;
391
392 meth = dvmFindDirectMethodByDescriptor(platformAddressFactoryClass,
393 "on",
394 "(I)Lorg/apache/harmony/luni/platform/PlatformAddress;");
395 if (meth == NULL) {
396 LOGE("Unable to find PlatformAddressFactory.on\n");
397 return false;
398 }
399 gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on = meth;
400
401 meth = dvmFindDirectMethodByDescriptor(readWriteBufferClass,
402 "<init>",
403 "(Lorg/apache/harmony/luni/platform/PlatformAddress;II)V");
404 if (meth == NULL) {
405 LOGE("Unable to find ReadWriteDirectByteBuffer.<init>\n");
406 return false;
407 }
408 gDvm.methJavaNioReadWriteDirectByteBuffer_init = meth;
409
410 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr =
411 dvmFindFieldOffset(platformAddressClass, "osaddr", "I");
412 if (gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr < 0) {
413 LOGE("Unable to find PlatformAddress.osaddr\n");
414 return false;
415 }
416
417 gDvm.offJavaNioBuffer_capacity =
418 dvmFindFieldOffset(bufferClass, "capacity", "I");
419 if (gDvm.offJavaNioBuffer_capacity < 0) {
420 LOGE("Unable to find Buffer.capacity\n");
421 return false;
422 }
Andy McFadden5f612b82009-07-22 15:07:27 -0700423
Andy McFadden8e696dc2009-07-24 15:28:16 -0700424 gDvm.offJavaNioBuffer_effectiveDirectAddress =
425 dvmFindFieldOffset(bufferClass, "effectiveDirectAddress", "I");
426 if (gDvm.offJavaNioBuffer_effectiveDirectAddress < 0) {
427 LOGE("Unable to find Buffer.effectiveDirectAddress\n");
428 return false;
429 }
430
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800431 return true;
432}
433
434/*
435 * Free the global references table.
436 */
437void dvmJniShutdown(void)
438{
Andy McFaddend5ab7262009-08-25 07:19:34 -0700439#ifdef USE_INDIRECT_REF
440 dvmClearIndirectRefTable(&gDvm.jniGlobalRefTable);
441#else
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800442 dvmClearReferenceTable(&gDvm.jniGlobalRefTable);
Andy McFaddend5ab7262009-08-25 07:19:34 -0700443#endif
Andy McFadden96516932009-10-28 17:39:02 -0700444 dvmClearReferenceTable(&gDvm.jniPinRefTable);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800445}
446
447
448/*
449 * Find the JNIEnv associated with the current thread.
450 *
451 * Currently stored in the Thread struct. Could also just drop this into
452 * thread-local storage.
453 */
454JNIEnvExt* dvmGetJNIEnvForThread(void)
455{
456 Thread* self = dvmThreadSelf();
457 if (self == NULL)
458 return NULL;
459 return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
460}
461
462/*
463 * Create a new JNIEnv struct and add it to the VM's list.
464 *
465 * "self" will be NULL for the main thread, since the VM hasn't started
466 * yet; the value will be filled in later.
467 */
468JNIEnv* dvmCreateJNIEnv(Thread* self)
469{
470 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
471 JNIEnvExt* newEnv;
472
473 //if (self != NULL)
474 // LOGI("Ent CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
475
476 assert(vm != NULL);
477
478 newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
479 newEnv->funcTable = &gNativeInterface;
480 newEnv->vm = vm;
481 newEnv->forceDataCopy = vm->forceDataCopy;
482 if (self != NULL) {
483 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
484 assert(newEnv->envThreadId != 0);
485 } else {
486 /* make it obvious if we fail to initialize these later */
487 newEnv->envThreadId = 0x77777775;
488 newEnv->self = (Thread*) 0x77777779;
489 }
490 if (vm->useChecked)
491 dvmUseCheckedJniEnv(newEnv);
492
493 dvmLockMutex(&vm->envListLock);
494
495 /* insert at head of list */
496 newEnv->next = vm->envList;
497 assert(newEnv->prev == NULL);
498 if (vm->envList == NULL) // rare, but possible
499 vm->envList = newEnv;
500 else
501 vm->envList->prev = newEnv;
502 vm->envList = newEnv;
503
504 dvmUnlockMutex(&vm->envListLock);
505
506 //if (self != NULL)
507 // LOGI("Xit CreateJNIEnv: threadid=%d %p\n", self->threadId, self);
508 return (JNIEnv*) newEnv;
509}
510
511/*
512 * Remove a JNIEnv struct from the list and free it.
513 */
514void dvmDestroyJNIEnv(JNIEnv* env)
515{
516 JNIEnvExt* extEnv = (JNIEnvExt*) env;
517 JavaVMExt* vm = extEnv->vm;
518 Thread* self;
519
520 if (env == NULL)
521 return;
522
523 self = dvmThreadSelf();
524 assert(self != NULL);
525
526 //LOGI("Ent DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
527
528 dvmLockMutex(&vm->envListLock);
529
530 if (extEnv == vm->envList) {
531 assert(extEnv->prev == NULL);
532 vm->envList = extEnv->next;
533 } else {
534 assert(extEnv->prev != NULL);
535 extEnv->prev->next = extEnv->next;
536 }
537 if (extEnv->next != NULL)
538 extEnv->next->prev = extEnv->prev;
539
540 dvmUnlockMutex(&extEnv->vm->envListLock);
541
542 free(env);
543 //LOGI("Xit DestroyJNIEnv: threadid=%d %p\n", self->threadId, self);
544}
545
546
547/*
548 * Retrieve the ReferenceTable struct for the current thread.
549 *
Andy McFaddenab00d452009-08-19 07:21:41 -0700550 * Going through "env" rather than dvmThreadSelf() is faster but will
551 * get weird if the JNI code is passing the wrong JNIEnv around.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800552 */
Andy McFaddend5ab7262009-08-25 07:19:34 -0700553#ifdef USE_INDIRECT_REF
554static inline IndirectRefTable* getLocalRefTable(JNIEnv* env)
Andy McFaddend5ab7262009-08-25 07:19:34 -0700555#else
Andy McFaddenab00d452009-08-19 07:21:41 -0700556static inline ReferenceTable* getLocalRefTable(JNIEnv* env)
Andy McFaddeneb9cbc32009-08-28 14:45:12 -0700557#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800558{
Andy McFaddenab00d452009-08-19 07:21:41 -0700559 //return &dvmThreadSelf()->jniLocalRefTable;
560 return &((JNIEnvExt*)env)->self->jniLocalRefTable;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800561}
Andy McFaddend5ab7262009-08-25 07:19:34 -0700562
Andy McFaddeneb9cbc32009-08-28 14:45:12 -0700563#ifdef USE_INDIRECT_REF
Andy McFaddend5ab7262009-08-25 07:19:34 -0700564/*
565 * Convert an indirect reference to an Object reference. The indirect
566 * reference may be local, global, or weak-global.
567 *
568 * If "jobj" is NULL or an invalid indirect reference, this returns NULL.
569 */
570Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj)
571{
Andy McFaddend5ab7262009-08-25 07:19:34 -0700572 if (jobj == NULL)
573 return NULL;
574
575 Object* result;
576
577 switch (dvmGetIndirectRefType(jobj)) {
578 case kIndirectKindLocal:
579 {
580 IndirectRefTable* pRefTable = getLocalRefTable(env);
581 result = dvmGetFromIndirectRefTable(pRefTable, jobj);
582 }
583 break;
584 case kIndirectKindGlobal:
585 {
586 // TODO: find a way to avoid the mutex activity here
587 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
588 dvmLockMutex(&gDvm.jniGlobalRefLock);
589 result = dvmGetFromIndirectRefTable(pRefTable, jobj);
590 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
591 }
592 break;
593 case kIndirectKindWeakGlobal:
594 {
Andy McFaddenb18992f2009-09-25 10:42:15 -0700595 // TODO: implement
Andy McFaddend5ab7262009-08-25 07:19:34 -0700596 LOGE("weak-global not yet supported\n");
597 result = NULL;
598 dvmAbort();
599 }
600 break;
601 case kIndirectKindInvalid:
602 default:
603 LOGW("Invalid indirect reference %p in decodeIndirectRef\n", jobj);
604 dvmAbort();
605 result = NULL;
606 break;
607 }
608
609 return result;
Andy McFaddend5ab7262009-08-25 07:19:34 -0700610}
Andy McFaddeneb9cbc32009-08-28 14:45:12 -0700611#else
612 /* use trivial inline in JniInternal.h for performance */
613#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800614
615/*
616 * Add a local reference for an object to the current stack frame. When
617 * the native function returns, the reference will be discarded.
618 *
619 * We need to allow the same reference to be added multiple times.
620 *
621 * This will be called on otherwise unreferenced objects. We cannot do
622 * GC allocations here, and it's best if we don't grab a mutex.
623 *
624 * Returns the local reference (currently just the same pointer that was
625 * passed in), or NULL on failure.
626 */
Andy McFaddenab00d452009-08-19 07:21:41 -0700627static jobject addLocalReference(JNIEnv* env, Object* obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800628{
629 if (obj == NULL)
630 return NULL;
631
Andy McFaddend5ab7262009-08-25 07:19:34 -0700632 jobject jobj;
633
634#ifdef USE_INDIRECT_REF
635 IndirectRefTable* pRefTable = getLocalRefTable(env);
636 void* curFrame = ((JNIEnvExt*)env)->self->curFrame;
637 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
638
639 jobj = (jobject) dvmAddToIndirectRefTable(pRefTable, cookie, obj);
640 if (jobj == NULL) {
641 dvmDumpIndirectRefTable(pRefTable, "JNI local");
642 LOGE("Failed adding to JNI local ref table (has %d entries)\n",
643 (int) dvmIndirectRefTableEntries(pRefTable));
644 dvmDumpThread(dvmThreadSelf(), false);
645 dvmAbort(); // spec says call FatalError; this is equivalent
646 } else {
647 LOGVV("LREF add %p (%s.%s) (ent=%d)\n", obj,
648 dvmGetCurrentJNIMethod()->clazz->descriptor,
649 dvmGetCurrentJNIMethod()->name,
650 (int) dvmReferenceTableEntries(pRefTable));
651 }
652#else
Andy McFaddenab00d452009-08-19 07:21:41 -0700653 ReferenceTable* pRefTable = getLocalRefTable(env);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800654
Andy McFaddenab00d452009-08-19 07:21:41 -0700655 if (!dvmAddToReferenceTable(pRefTable, obj)) {
656 dvmDumpReferenceTable(pRefTable, "JNI local");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800657 LOGE("Failed adding to JNI local ref table (has %d entries)\n",
Andy McFaddenab00d452009-08-19 07:21:41 -0700658 (int) dvmReferenceTableEntries(pRefTable));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800659 dvmDumpThread(dvmThreadSelf(), false);
660 dvmAbort(); // spec says call FatalError; this is equivalent
661 } else {
Andy McFadden0083d372009-08-21 14:44:04 -0700662 LOGVV("LREF add %p (%s.%s) (ent=%d)\n", obj,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800663 dvmGetCurrentJNIMethod()->clazz->descriptor,
Andy McFadden0083d372009-08-21 14:44:04 -0700664 dvmGetCurrentJNIMethod()->name,
665 (int) dvmReferenceTableEntries(pRefTable));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800666 }
667
Andy McFaddend5ab7262009-08-25 07:19:34 -0700668 jobj = (jobject) obj;
669#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800670
Andy McFaddend5ab7262009-08-25 07:19:34 -0700671 return jobj;
Andy McFaddenab00d452009-08-19 07:21:41 -0700672}
673
674/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800675 * Ensure that at least "capacity" references can be held in the local
676 * refs table of the current thread.
677 */
Andy McFaddenab00d452009-08-19 07:21:41 -0700678static bool ensureLocalCapacity(JNIEnv* env, int capacity)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800679{
Andy McFaddend5ab7262009-08-25 07:19:34 -0700680#ifdef USE_INDIRECT_REF
681 IndirectRefTable* pRefTable = getLocalRefTable(env);
682 int numEntries = dvmIndirectRefTableEntries(pRefTable);
683 // TODO: this isn't quite right, since "numEntries" includes holes
684 return ((kJniLocalRefMax - numEntries) >= capacity);
685#else
Andy McFaddenab00d452009-08-19 07:21:41 -0700686 ReferenceTable* pRefTable = getLocalRefTable(env);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800687
Andy McFaddenab00d452009-08-19 07:21:41 -0700688 return (kJniLocalRefMax - (pRefTable->nextEntry - pRefTable->table) >= capacity);
Andy McFaddend5ab7262009-08-25 07:19:34 -0700689#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800690}
691
692/*
693 * Explicitly delete a reference from the local list.
694 */
Andy McFaddenab00d452009-08-19 07:21:41 -0700695static void deleteLocalReference(JNIEnv* env, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800696{
Andy McFaddenab00d452009-08-19 07:21:41 -0700697 if (jobj == NULL)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800698 return;
699
Andy McFaddend5ab7262009-08-25 07:19:34 -0700700#ifdef USE_INDIRECT_REF
701 IndirectRefTable* pRefTable = getLocalRefTable(env);
702 Thread* self = ((JNIEnvExt*)env)->self;
703 u4 cookie = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefCookie;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800704
Andy McFaddend5ab7262009-08-25 07:19:34 -0700705 if (!dvmRemoveFromIndirectRefTable(pRefTable, cookie, jobj)) {
706 /*
707 * Attempting to delete a local reference that is not in the
708 * topmost local reference frame is a no-op. DeleteLocalRef returns
709 * void and doesn't throw any exceptions, but we should probably
710 * complain about it so the user will notice that things aren't
711 * going quite the way they expect.
712 */
713 LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry\n", jobj);
714 }
715#else
716 ReferenceTable* pRefTable = getLocalRefTable(env);
717 Thread* self = ((JNIEnvExt*)env)->self;
718 Object** bottom = SAVEAREA_FROM_FP(self->curFrame)->xtra.localRefCookie;
719
720 if (!dvmRemoveFromReferenceTable(pRefTable, bottom, (Object*) jobj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800721 /*
722 * Attempting to delete a local reference that is not in the
723 * topmost local reference frame is a no-op. DeleteLocalRef returns
724 * void and doesn't throw any exceptions, but we should probably
725 * complain about it so the user will notice that things aren't
726 * going quite the way they expect.
727 */
728 LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry (valid=%d)\n",
Andy McFaddenab00d452009-08-19 07:21:41 -0700729 jobj, dvmIsValidObject((Object*) jobj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800730 }
Andy McFaddend5ab7262009-08-25 07:19:34 -0700731#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800732}
733
734/*
735 * Add a global reference for an object.
736 *
737 * We may add the same object more than once. Add/remove calls are paired,
738 * so it needs to appear on the list multiple times.
739 */
Andy McFaddenab00d452009-08-19 07:21:41 -0700740static jobject addGlobalReference(Object* obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800741{
742 if (obj == NULL)
743 return NULL;
744
745 //LOGI("adding obj=%p\n", obj);
746 //dvmDumpThread(dvmThreadSelf(), false);
747
748 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangClass) {
749 ClassObject* clazz = (ClassObject*) obj;
750 LOGI("-------\n");
751 LOGI("Adding global ref on class %s\n", clazz->descriptor);
752 dvmDumpThread(dvmThreadSelf(), false);
753 }
754 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
755 StringObject* strObj = (StringObject*) obj;
756 char* str = dvmCreateCstrFromString(strObj);
757 if (strcmp(str, "sync-response") == 0) {
758 LOGI("-------\n");
759 LOGI("Adding global ref on string '%s'\n", str);
760 dvmDumpThread(dvmThreadSelf(), false);
761 //dvmAbort();
762 }
763 free(str);
764 }
765 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
766 ArrayObject* arrayObj = (ArrayObject*) obj;
Andy McFaddend5ab7262009-08-25 07:19:34 -0700767 if (arrayObj->length == 8192 /*&&
768 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800769 {
770 LOGI("Adding global ref on byte array %p (len=%d)\n",
771 arrayObj, arrayObj->length);
772 dvmDumpThread(dvmThreadSelf(), false);
773 }
774 }
775
Andy McFaddend5ab7262009-08-25 07:19:34 -0700776 jobject jobj;
777
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800778 dvmLockMutex(&gDvm.jniGlobalRefLock);
779
780 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800781 * Throwing an exception on failure is problematic, because JNI code
782 * may not be expecting an exception, and things sort of cascade. We
783 * want to have a hard limit to catch leaks during debugging, but this
784 * otherwise needs to expand until memory is consumed. As a practical
785 * matter, if we have many thousands of global references, chances are
786 * we're either leaking global ref table entries or we're going to
787 * run out of space in the GC heap.
788 */
Andy McFaddend5ab7262009-08-25 07:19:34 -0700789#ifdef USE_INDIRECT_REF
790 jobj = dvmAddToIndirectRefTable(&gDvm.jniGlobalRefTable, IRT_FIRST_SEGMENT,
791 obj);
792 if (jobj == NULL) {
793 dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
794 LOGE("Failed adding to JNI global ref table (%d entries)\n",
795 (int) dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable));
796 dvmAbort();
797 }
798
799 LOGVV("GREF add %p (%s.%s)\n", obj,
800 dvmGetCurrentJNIMethod()->clazz->descriptor,
801 dvmGetCurrentJNIMethod()->name);
802
803 /* GREF usage tracking; should probably be disabled for production env */
804 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
805 int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
806 // TODO: adjust for "holes"
807 if (count > gDvm.jniGlobalRefHiMark) {
808 LOGD("GREF has increased to %d\n", count);
809 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
810 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
811
812 /* watch for "excessive" use; not generally appropriate */
813 if (count >= gDvm.jniGrefLimit) {
814 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
815 if (vm->warnError) {
816 dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable,
817 "JNI global");
818 LOGE("Excessive JNI global references (%d)\n", count);
819 dvmAbort();
820 } else {
821 LOGW("Excessive JNI global references (%d)\n", count);
822 }
823 }
824 }
825 }
826#else
827 if (!dvmAddToReferenceTable(&gDvm.jniGlobalRefTable, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800828 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
829 LOGE("Failed adding to JNI global ref table (%d entries)\n",
830 (int) dvmReferenceTableEntries(&gDvm.jniGlobalRefTable));
831 dvmAbort();
832 }
Andy McFaddend5ab7262009-08-25 07:19:34 -0700833 jobj = (jobject) obj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800834
835 LOGVV("GREF add %p (%s.%s)\n", obj,
836 dvmGetCurrentJNIMethod()->clazz->descriptor,
837 dvmGetCurrentJNIMethod()->name);
838
839 /* GREF usage tracking; should probably be disabled for production env */
840 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
841 int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
842 if (count > gDvm.jniGlobalRefHiMark) {
843 LOGD("GREF has increased to %d\n", count);
844 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
845 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
846
847 /* watch for "excessive" use; not generally appropriate */
848 if (count >= gDvm.jniGrefLimit) {
849 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
850 if (vm->warnError) {
851 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable,"JNI global");
852 LOGE("Excessive JNI global references (%d)\n", count);
853 dvmAbort();
854 } else {
855 LOGW("Excessive JNI global references (%d)\n", count);
856 }
857 }
858 }
859 }
Andy McFaddend5ab7262009-08-25 07:19:34 -0700860#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800861
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800862 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
Andy McFaddend5ab7262009-08-25 07:19:34 -0700863 return jobj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800864}
865
866/*
867 * Remove a global reference. In most cases it's the entry most recently
868 * added, which makes this pretty quick.
869 *
870 * Thought: if it's not the most recent entry, just null it out. When we
871 * fill up, do a compaction pass before we expand the list.
872 */
Andy McFaddenab00d452009-08-19 07:21:41 -0700873static void deleteGlobalReference(jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800874{
Andy McFaddenab00d452009-08-19 07:21:41 -0700875 if (jobj == NULL)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800876 return;
877
878 dvmLockMutex(&gDvm.jniGlobalRefLock);
879
Andy McFaddend5ab7262009-08-25 07:19:34 -0700880#ifdef USE_INDIRECT_REF
881 if (!dvmRemoveFromIndirectRefTable(&gDvm.jniGlobalRefTable,
882 IRT_FIRST_SEGMENT, jobj))
883 {
884 LOGW("JNI: DeleteGlobalRef(%p) failed to find entry\n", jobj);
885 goto bail;
886 }
887
888 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
889 int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
890 // TODO: not quite right, need to subtract holes
891 if (count < gDvm.jniGlobalRefLoMark) {
892 LOGD("GREF has decreased to %d\n", count);
893 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
894 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
895 }
896 }
897#else
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800898 if (!dvmRemoveFromReferenceTable(&gDvm.jniGlobalRefTable,
Andy McFaddenab00d452009-08-19 07:21:41 -0700899 gDvm.jniGlobalRefTable.table, jobj))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800900 {
901 LOGW("JNI: DeleteGlobalRef(%p) failed to find entry (valid=%d)\n",
Andy McFaddenab00d452009-08-19 07:21:41 -0700902 jobj, dvmIsValidObject((Object*) jobj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800903 goto bail;
904 }
905
906 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
907 int count = dvmReferenceTableEntries(&gDvm.jniGlobalRefTable);
908 if (count < gDvm.jniGlobalRefLoMark) {
909 LOGD("GREF has decreased to %d\n", count);
910 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
911 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
912 }
913 }
Andy McFaddend5ab7262009-08-25 07:19:34 -0700914#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800915
916bail:
917 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
918}
919
Andy McFaddenb18992f2009-09-25 10:42:15 -0700920/*
921 * We create a PhantomReference that references the object, add a
922 * global reference to it, and then flip some bits before returning it.
923 * The last step ensures that we detect it as special and that only
924 * appropriate calls will accept it.
925 *
926 * On failure, returns NULL with an exception pending.
927 */
928static jweak createWeakGlobalRef(JNIEnv* env, jobject jobj)
929{
930 if (jobj == NULL)
931 return NULL;
932
933 Thread* self = ((JNIEnvExt*)env)->self;
934 Object* obj = dvmDecodeIndirectRef(env, jobj);
Andy McFaddenb18992f2009-09-25 10:42:15 -0700935 Object* phantomObj;
936 jobject phantomRef;
937
938 /*
939 * Allocate a PhantomReference, then call the constructor to set
940 * the referent and the reference queue.
941 *
942 * We use a "magic" reference queue that the GC knows about; it behaves
943 * more like a queueless WeakReference, clearing the referent and
944 * not calling enqueue().
945 */
946 if (!dvmIsClassInitialized(gDvm.classJavaLangRefPhantomReference))
947 dvmInitClass(gDvm.classJavaLangRefPhantomReference);
948 phantomObj = dvmAllocObject(gDvm.classJavaLangRefPhantomReference,
949 ALLOC_DEFAULT);
950 if (phantomObj == NULL) {
951 assert(dvmCheckException(self));
952 LOGW("Failed on WeakGlobalRef alloc\n");
953 return NULL;
954 }
955
956 JValue unused;
957 dvmCallMethod(self, gDvm.methJavaLangRefPhantomReference_init, phantomObj,
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700958 &unused, obj, NULL);
Andy McFaddenb18992f2009-09-25 10:42:15 -0700959 dvmReleaseTrackedAlloc(phantomObj, self);
960
961 if (dvmCheckException(self)) {
962 LOGW("PhantomReference init failed\n");
963 return NULL;
964 }
965
966 LOGV("+++ WGR: created phantom ref %p for object %p\n", phantomObj, obj);
967
968 /*
969 * Add it to the global reference table, and mangle the pointer.
970 */
971 phantomRef = addGlobalReference(phantomObj);
972 return dvmObfuscateWeakGlobalRef(phantomRef);
973}
974
975/*
976 * Delete the global reference that's keeping the PhantomReference around.
977 * The PhantomReference will eventually be discarded by the GC.
978 */
979static void deleteWeakGlobalRef(JNIEnv* env, jweak wref)
980{
981 if (wref == NULL)
982 return;
983
984 jobject phantomRef = dvmNormalizeWeakGlobalRef(wref);
985 deleteGlobalReference(phantomRef);
986}
987
988/*
989 * Extract the referent from a PhantomReference. Used for weak global
990 * references.
991 *
992 * "jwobj" is a "mangled" WGR pointer.
993 */
994static Object* getPhantomReferent(JNIEnv* env, jweak jwobj)
995{
996 jobject jobj = dvmNormalizeWeakGlobalRef(jwobj);
997 Object* obj = dvmDecodeIndirectRef(env, jobj);
998
999 if (obj->clazz != gDvm.classJavaLangRefPhantomReference) {
1000 LOGE("%p is not a phantom reference (%s)\n",
1001 jwobj, obj->clazz->descriptor);
1002 return NULL;
1003 }
1004
1005 return dvmGetFieldObject(obj, gDvm.offJavaLangRefReference_referent);
1006}
1007
1008
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001009/*
Andy McFaddenab00d452009-08-19 07:21:41 -07001010 * Objects don't currently move, so we just need to create a reference
1011 * that will ensure the array object isn't collected.
1012 *
Andy McFaddenc26bb632009-08-21 12:01:31 -07001013 * We use a separate reference table, which is part of the GC root set.
Andy McFaddenab00d452009-08-19 07:21:41 -07001014 */
1015static void pinPrimitiveArray(ArrayObject* arrayObj)
1016{
Andy McFaddenc26bb632009-08-21 12:01:31 -07001017 if (arrayObj == NULL)
1018 return;
1019
1020 dvmLockMutex(&gDvm.jniPinRefLock);
1021 if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
1022 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
1023 LOGE("Failed adding to JNI pinned array ref table (%d entries)\n",
1024 (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
1025 dvmDumpThread(dvmThreadSelf(), false);
1026 dvmAbort();
1027 }
1028
1029 /*
1030 * If we're watching global ref usage, also keep an eye on these.
1031 *
1032 * The total number of pinned primitive arrays should be pretty small.
1033 * A single array should not be pinned more than once or twice; any
1034 * more than that is a strong indicator that a Release function is
1035 * not being called.
1036 */
1037 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
1038 int count = 0;
1039 Object** ppObj = gDvm.jniPinRefTable.table;
1040 while (ppObj < gDvm.jniPinRefTable.nextEntry) {
1041 if (*ppObj++ == (Object*) arrayObj)
1042 count++;
1043 }
1044
1045 if (count > kPinComplainThreshold) {
1046 LOGW("JNI: pin count on array %p (%s) is now %d\n",
1047 arrayObj, arrayObj->obj.clazz->descriptor, count);
1048 /* keep going */
1049 }
1050 }
1051
1052 dvmUnlockMutex(&gDvm.jniPinRefLock);
Andy McFaddenab00d452009-08-19 07:21:41 -07001053}
1054
1055/*
1056 * Un-pin the array object. If an object was pinned twice, it must be
1057 * unpinned twice before it's free to move.
Andy McFaddenab00d452009-08-19 07:21:41 -07001058 */
1059static void unpinPrimitiveArray(ArrayObject* arrayObj)
1060{
Andy McFaddenc26bb632009-08-21 12:01:31 -07001061 if (arrayObj == NULL)
1062 return;
1063
1064 dvmLockMutex(&gDvm.jniPinRefLock);
1065 if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
1066 gDvm.jniPinRefTable.table, (Object*) arrayObj))
1067 {
1068 LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)\n",
1069 arrayObj, dvmIsValidObject((Object*) arrayObj));
1070 goto bail;
1071 }
1072
1073bail:
1074 dvmUnlockMutex(&gDvm.jniPinRefLock);
Andy McFaddenab00d452009-08-19 07:21:41 -07001075}
1076
1077/*
Andy McFadden92fa4762009-10-22 17:24:45 -07001078 * Dump the contents of the JNI reference tables to the log file.
1079 *
1080 * We only dump the local refs associated with the current thread.
1081 */
1082void dvmDumpJniReferenceTables(void)
1083{
1084 Thread* self = dvmThreadSelf();
1085 JNIEnv* env = self->jniEnv;
1086 ReferenceTable* pLocalRefs = getLocalRefTable(env);
1087
1088#ifdef USE_INDIRECT_REF
1089 dvmDumpIndirectRefTable(pLocalRefs, "JNI local");
1090 dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
1091#else
1092 dvmDumpReferenceTable(pLocalRefs, "JNI local");
1093 dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
1094#endif
1095 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
1096}
1097
1098/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001099 * GC helper function to mark all JNI global references.
Andy McFaddenc26bb632009-08-21 12:01:31 -07001100 *
1101 * We're currently handling the "pin" table here too.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001102 */
1103void dvmGcMarkJniGlobalRefs()
1104{
Andy McFaddend5ab7262009-08-25 07:19:34 -07001105 Object** op;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001106
1107 dvmLockMutex(&gDvm.jniGlobalRefLock);
1108
Andy McFaddend5ab7262009-08-25 07:19:34 -07001109#ifdef USE_INDIRECT_REF
1110 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
1111 op = pRefTable->table;
1112 int numEntries = dvmIndirectRefTableEntries(pRefTable);
1113 int i;
1114
1115 for (i = 0; i < numEntries; i++) {
1116 Object* obj = *op;
1117 if (obj != NULL)
1118 dvmMarkObjectNonNull(obj);
1119 op++;
1120 }
1121#else
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001122 op = gDvm.jniGlobalRefTable.table;
1123 while ((uintptr_t)op < (uintptr_t)gDvm.jniGlobalRefTable.nextEntry) {
1124 dvmMarkObjectNonNull(*(op++));
1125 }
Andy McFaddend5ab7262009-08-25 07:19:34 -07001126#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001127
1128 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
Andy McFaddenc26bb632009-08-21 12:01:31 -07001129
1130
1131 dvmLockMutex(&gDvm.jniPinRefLock);
1132
1133 op = gDvm.jniPinRefTable.table;
1134 while ((uintptr_t)op < (uintptr_t)gDvm.jniPinRefTable.nextEntry) {
1135 dvmMarkObjectNonNull(*(op++));
1136 }
1137
1138 dvmUnlockMutex(&gDvm.jniPinRefLock);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001139}
1140
1141
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001142#ifndef USE_INDIRECT_REF
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001143/*
1144 * Determine if "obj" appears in the argument list for the native method.
1145 *
1146 * We use the "shorty" signature to determine which argument slots hold
1147 * reference types.
1148 */
1149static bool findInArgList(Thread* self, Object* obj)
1150{
1151 const Method* meth;
1152 u4* fp;
1153 int i;
1154
1155 fp = self->curFrame;
1156 while (1) {
1157 /*
1158 * Back up over JNI PushLocalFrame frames. This works because the
1159 * previous frame on the interpreted stack is either a break frame
1160 * (if we called here via native code) or an interpreted method (if
1161 * we called here via the interpreter). In both cases the method
1162 * pointer won't match.
1163 */
1164 StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
1165 meth = saveArea->method;
1166 if (meth != SAVEAREA_FROM_FP(saveArea->prevFrame)->method)
1167 break;
1168 fp = saveArea->prevFrame;
1169 }
1170
1171 LOGVV("+++ scanning %d args in %s (%s)\n",
1172 meth->insSize, meth->name, meth->shorty);
1173 const char* shorty = meth->shorty +1; /* skip return type char */
1174 for (i = 0; i < meth->insSize; i++) {
1175 if (i == 0 && !dvmIsStaticMethod(meth)) {
1176 /* first arg is "this" ref, not represented in "shorty" */
1177 if (fp[i] == (u4) obj)
1178 return true;
1179 } else {
1180 /* if this is a reference type, see if it matches */
1181 switch (*shorty) {
1182 case 'L':
1183 if (fp[i] == (u4) obj)
1184 return true;
1185 break;
1186 case 'D':
1187 case 'J':
1188 i++;
1189 break;
1190 case '\0':
1191 LOGE("Whoops! ran off the end of %s (%d)\n",
1192 meth->shorty, meth->insSize);
1193 break;
1194 default:
1195 if (fp[i] == (u4) obj)
1196 LOGI("NOTE: ref %p match on arg type %c\n", obj, *shorty);
1197 break;
1198 }
1199 shorty++;
1200 }
1201 }
1202
1203 /*
1204 * For static methods, we also pass a class pointer in.
1205 */
1206 if (dvmIsStaticMethod(meth)) {
1207 //LOGI("+++ checking class pointer in %s\n", meth->name);
1208 if ((void*)obj == (void*)meth->clazz)
1209 return true;
1210 }
1211 return false;
1212}
Andy McFadden0083d372009-08-21 14:44:04 -07001213#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001214
1215/*
1216 * Verify that a reference passed in from native code is one that the
1217 * code is allowed to have.
1218 *
1219 * It's okay for native code to pass us a reference that:
Andy McFadden0083d372009-08-21 14:44:04 -07001220 * - was passed in as an argument when invoked by native code (and hence
1221 * is in the JNI local refs table)
1222 * - was returned to it from JNI (and is now in the local refs table)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001223 * - is present in the JNI global refs table
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001224 *
1225 * Used by -Xcheck:jni and GetObjectRefType.
1226 *
1227 * NOTE: in the current VM, global and local references are identical. If
1228 * something is both global and local, we can't tell them apart, and always
1229 * return "local".
1230 */
Andy McFaddenab00d452009-08-19 07:21:41 -07001231jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001232{
Andy McFaddend5ab7262009-08-25 07:19:34 -07001233#ifdef USE_INDIRECT_REF
1234 /*
1235 * IndirectRefKind is currently defined as an exact match of
Andy McFadden0423f0e2009-08-26 07:21:53 -07001236 * jobjectRefType, so this is easy. We have to decode it to determine
1237 * if it's a valid reference and not merely valid-looking.
Andy McFaddend5ab7262009-08-25 07:19:34 -07001238 */
Andy McFadden0423f0e2009-08-26 07:21:53 -07001239 Object* obj = dvmDecodeIndirectRef(env, jobj);
1240
1241 if (obj == NULL) {
1242 /* invalid ref, or jobj was NULL */
1243 return JNIInvalidRefType;
1244 } else {
1245 return (jobjectRefType) dvmGetIndirectRefType(jobj);
1246 }
Andy McFaddend5ab7262009-08-25 07:19:34 -07001247#else
Andy McFaddenab00d452009-08-19 07:21:41 -07001248 ReferenceTable* pRefTable = getLocalRefTable(env);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001249 Thread* self = dvmThreadSelf();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001250
Andy McFaddenb18992f2009-09-25 10:42:15 -07001251 if (dvmIsWeakGlobalRef(jobj)) {
1252 return JNIWeakGlobalRefType;
1253 }
1254
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001255 /* check args */
Andy McFaddenab00d452009-08-19 07:21:41 -07001256 if (findInArgList(self, jobj)) {
1257 //LOGI("--- REF found %p on stack\n", jobj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001258 return JNILocalRefType;
1259 }
1260
1261 /* check locals */
Andy McFaddenab00d452009-08-19 07:21:41 -07001262 if (dvmFindInReferenceTable(pRefTable, pRefTable->table, jobj) != NULL) {
1263 //LOGI("--- REF found %p in locals\n", jobj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001264 return JNILocalRefType;
1265 }
1266
1267 /* check globals */
1268 dvmLockMutex(&gDvm.jniGlobalRefLock);
1269 if (dvmFindInReferenceTable(&gDvm.jniGlobalRefTable,
Andy McFaddenab00d452009-08-19 07:21:41 -07001270 gDvm.jniGlobalRefTable.table, jobj))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001271 {
Andy McFaddenab00d452009-08-19 07:21:41 -07001272 //LOGI("--- REF found %p in globals\n", jobj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001273 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
1274 return JNIGlobalRefType;
1275 }
1276 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
1277
1278 /* not found! */
1279 return JNIInvalidRefType;
Andy McFaddend5ab7262009-08-25 07:19:34 -07001280#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001281}
1282
1283/*
1284 * Register a method that uses JNI calling conventions.
1285 */
1286static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
1287 const char* signature, void* fnPtr)
1288{
1289 Method* method;
1290 bool result = false;
1291
1292 if (fnPtr == NULL)
1293 goto bail;
1294
1295 method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
1296 if (method == NULL)
1297 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
1298 if (method == NULL) {
Andy McFadden1e83b4d2010-07-15 17:20:24 -07001299 LOGW("ERROR: Unable to find decl for native %s.%s:%s\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001300 clazz->descriptor, methodName, signature);
1301 goto bail;
1302 }
1303
1304 if (!dvmIsNativeMethod(method)) {
Andy McFadden1e83b4d2010-07-15 17:20:24 -07001305 LOGW("Unable to register: not native: %s.%s:%s\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001306 clazz->descriptor, methodName, signature);
1307 goto bail;
1308 }
1309
1310 if (method->nativeFunc != dvmResolveNativeMethod) {
Andy McFadden1e83b4d2010-07-15 17:20:24 -07001311 /* this is allowed, but unusual */
1312 LOGV("Note: %s.%s:%s was already registered\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001313 clazz->descriptor, methodName, signature);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001314 }
1315
Andy McFadden59b61772009-05-13 16:44:34 -07001316 dvmUseJNIBridge(method, fnPtr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001317
Andy McFadden1e83b4d2010-07-15 17:20:24 -07001318 LOGV("JNI-registered %s.%s:%s\n", clazz->descriptor, methodName,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001319 signature);
1320 result = true;
1321
1322bail:
1323 return result;
1324}
1325
1326/*
Andy McFadden59b61772009-05-13 16:44:34 -07001327 * Returns "true" if CheckJNI is enabled in the VM.
1328 */
1329static bool dvmIsCheckJNIEnabled(void)
1330{
1331 JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
1332 return vm->useChecked;
1333}
1334
1335/*
Elliott Hughesde66fcb2010-07-30 13:34:49 -07001336 * Returns the appropriate JNI bridge for 'method', also taking into account
1337 * the -Xcheck:jni setting.
Andy McFadden59b61772009-05-13 16:44:34 -07001338 */
Elliott Hughesde66fcb2010-07-30 13:34:49 -07001339static DalvikBridgeFunc dvmSelectJNIBridge(const Method* method)
Andy McFadden59b61772009-05-13 16:44:34 -07001340{
Andy McFadden0083d372009-08-21 14:44:04 -07001341 enum {
1342 kJNIGeneral = 0,
1343 kJNISync = 1,
1344 kJNIVirtualNoRef = 2,
1345 kJNIStaticNoRef = 3,
1346 } kind;
1347 static const DalvikBridgeFunc stdFunc[] = {
1348 dvmCallJNIMethod_general,
1349 dvmCallJNIMethod_synchronized,
1350 dvmCallJNIMethod_virtualNoRef,
1351 dvmCallJNIMethod_staticNoRef
1352 };
1353 static const DalvikBridgeFunc checkFunc[] = {
1354 dvmCheckCallJNIMethod_general,
1355 dvmCheckCallJNIMethod_synchronized,
1356 dvmCheckCallJNIMethod_virtualNoRef,
1357 dvmCheckCallJNIMethod_staticNoRef
1358 };
1359
1360 bool hasRefArg = false;
1361
1362 if (dvmIsSynchronizedMethod(method)) {
1363 /* use version with synchronization; calls into general handler */
1364 kind = kJNISync;
Andy McFadden59b61772009-05-13 16:44:34 -07001365 } else {
Andy McFadden0083d372009-08-21 14:44:04 -07001366 /*
1367 * Do a quick scan through the "shorty" signature to see if the method
1368 * takes any reference arguments.
1369 */
1370 const char* cp = method->shorty;
1371 while (*++cp != '\0') { /* pre-incr to skip return type */
1372 if (*cp == 'L') {
1373 /* 'L' used for both object and array references */
1374 hasRefArg = true;
1375 break;
1376 }
1377 }
1378
1379 if (hasRefArg) {
1380 /* use general handler to slurp up reference args */
1381 kind = kJNIGeneral;
1382 } else {
1383 /* virtual methods have a ref in args[0] (not in signature) */
1384 if (dvmIsStaticMethod(method))
1385 kind = kJNIStaticNoRef;
1386 else
1387 kind = kJNIVirtualNoRef;
1388 }
1389 }
1390
Elliott Hughesde66fcb2010-07-30 13:34:49 -07001391 return dvmIsCheckJNIEnabled() ? checkFunc[kind] : stdFunc[kind];
1392}
1393
1394/*
1395 * Trace a call into native code.
1396 */
1397static void dvmTraceCallJNIMethod(const u4* args, JValue* pResult,
1398 const Method* method, Thread* self)
1399{
1400 dvmLogNativeMethodEntry(method, args);
1401 DalvikBridgeFunc bridge = dvmSelectJNIBridge(method);
1402 (*bridge)(args, pResult, method, self);
1403 dvmLogNativeMethodExit(method, self, *pResult);
1404}
1405
1406/**
1407 * Returns true if the -Xjnitrace setting implies we should trace 'method'.
1408 */
1409static bool shouldTrace(Method* method)
1410{
1411 return gDvm.jniTrace && strstr(method->clazz->descriptor, gDvm.jniTrace);
1412}
1413
1414/*
1415 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
1416 * to point at the actual function.
1417 */
1418void dvmUseJNIBridge(Method* method, void* func)
1419{
1420 DalvikBridgeFunc bridge = shouldTrace(method)
1421 ? dvmTraceCallJNIMethod
1422 : dvmSelectJNIBridge(method);
1423 dvmSetNativeFunc(method, bridge, func);
Andy McFadden59b61772009-05-13 16:44:34 -07001424}
1425
1426/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001427 * Get the method currently being executed by examining the interp stack.
1428 */
1429const Method* dvmGetCurrentJNIMethod(void)
1430{
1431 assert(dvmThreadSelf() != NULL);
1432
1433 void* fp = dvmThreadSelf()->curFrame;
1434 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
1435
1436 assert(meth != NULL);
1437 assert(dvmIsNativeMethod(meth));
1438 return meth;
1439}
1440
1441
1442/*
1443 * Track a JNI MonitorEnter in the current thread.
1444 *
1445 * The goal is to be able to "implicitly" release all JNI-held monitors
1446 * when the thread detaches.
1447 *
1448 * Monitors may be entered multiple times, so we add a new entry for each
1449 * enter call. It would be more efficient to keep a counter. At present
1450 * there's no real motivation to improve this however.
1451 */
1452static void trackMonitorEnter(Thread* self, Object* obj)
1453{
1454 static const int kInitialSize = 16;
1455 ReferenceTable* refTable = &self->jniMonitorRefTable;
1456
1457 /* init table on first use */
1458 if (refTable->table == NULL) {
1459 assert(refTable->maxEntries == 0);
1460
1461 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
1462 LOGE("Unable to initialize monitor tracking table\n");
1463 dvmAbort();
1464 }
1465 }
1466
1467 if (!dvmAddToReferenceTable(refTable, obj)) {
1468 /* ran out of memory? could throw exception instead */
1469 LOGE("Unable to add entry to monitor tracking table\n");
1470 dvmAbort();
1471 } else {
1472 LOGVV("--- added monitor %p\n", obj);
1473 }
1474}
1475
Andy McFaddenab00d452009-08-19 07:21:41 -07001476
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001477/*
1478 * Track a JNI MonitorExit in the current thread.
1479 */
1480static void trackMonitorExit(Thread* self, Object* obj)
1481{
Andy McFaddenab00d452009-08-19 07:21:41 -07001482 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001483
Andy McFaddenab00d452009-08-19 07:21:41 -07001484 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001485 LOGE("JNI monitor %p not found in tracking list\n", obj);
1486 /* keep going? */
1487 } else {
1488 LOGVV("--- removed monitor %p\n", obj);
1489 }
1490}
1491
1492/*
1493 * Release all monitors held by the jniMonitorRefTable list.
1494 */
1495void dvmReleaseJniMonitors(Thread* self)
1496{
Andy McFaddenab00d452009-08-19 07:21:41 -07001497 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
1498 Object** top = pRefTable->table;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001499
1500 if (top == NULL)
1501 return;
1502
Andy McFaddenab00d452009-08-19 07:21:41 -07001503 Object** ptr = pRefTable->nextEntry;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001504 while (--ptr >= top) {
1505 if (!dvmUnlockObject(self, *ptr)) {
1506 LOGW("Unable to unlock monitor %p at thread detach\n", *ptr);
1507 } else {
1508 LOGVV("--- detach-releasing monitor %p\n", *ptr);
1509 }
1510 }
1511
1512 /* zap it */
Andy McFaddenab00d452009-08-19 07:21:41 -07001513 pRefTable->nextEntry = pRefTable->table;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001514}
1515
Andy McFaddenb76594d2010-07-19 15:44:56 -07001516/*
1517 * Determine if the specified class can be instantiated from JNI. This
1518 * is used by AllocObject / NewObject, which are documented as throwing
1519 * an exception for abstract and interface classes, and not accepting
1520 * array classes. We also want to reject attempts to create new Class
1521 * objects, since only DefineClass should do that.
1522 */
1523static bool canAllocClass(ClassObject* clazz)
1524{
1525 if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
1526 /* JNI spec defines what this throws */
1527 dvmThrowExceptionFmt("Ljava/lang/InstantiationException;",
1528 "Can't instantiate %s (abstract or interface)", clazz->descriptor);
1529 return false;
1530 } else if (dvmIsArrayClass(clazz) || clazz == gDvm.classJavaLangClass) {
1531 /* spec says "must not" for arrays, ignores Class */
1532 dvmThrowExceptionFmt("Ljava/lang/IllegalArgumentException;",
1533 "Can't instantiate %s (array or Class) with this JNI function",
1534 clazz->descriptor);
1535 return false;
1536 }
1537
1538 return true;
1539}
1540
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001541#ifdef WITH_JNI_STACK_CHECK
1542/*
1543 * Compute a CRC on the entire interpreted stack.
1544 *
1545 * Would be nice to compute it on "self" as well, but there are parts of
1546 * the Thread that can be altered by other threads (e.g. prev/next pointers).
1547 */
1548static void computeStackSum(Thread* self)
1549{
1550 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
1551 u4 crc = dvmInitCrc32();
1552 self->stackCrc = 0;
1553 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
1554 self->stackCrc = crc;
1555}
1556
1557/*
1558 * Compute a CRC on the entire interpreted stack, and compare it to what
1559 * we previously computed.
1560 *
1561 * We can execute JNI directly from native code without calling in from
1562 * interpreted code during VM initialization and immediately after JNI
1563 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather
1564 * than catching these cases we just ignore them here, which is marginally
1565 * less accurate but reduces the amount of code we have to touch with #ifdefs.
1566 */
1567static void checkStackSum(Thread* self)
1568{
1569 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->curFrame);
1570 u4 stackCrc, crc;
1571
1572 stackCrc = self->stackCrc;
1573 self->stackCrc = 0;
1574 crc = dvmInitCrc32();
1575 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
1576 if (crc != stackCrc) {
1577 const Method* meth = dvmGetCurrentJNIMethod();
1578 if (dvmComputeExactFrameDepth(self->curFrame) == 1) {
1579 LOGD("JNI: bad stack CRC (0x%08x) -- okay during init\n",
1580 stackCrc);
1581 } else if (strcmp(meth->name, "nativeLoad") == 0 &&
1582 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0))
1583 {
1584 LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad\n",
1585 stackCrc);
1586 } else {
1587 LOGW("JNI: bad stack CRC (%08x vs %08x)\n", crc, stackCrc);
1588 dvmAbort();
1589 }
1590 }
1591 self->stackCrc = (u4) -1; /* make logic errors more noticeable */
1592}
1593#endif
1594
1595
1596/*
1597 * ===========================================================================
Andy McFaddend5ab7262009-08-25 07:19:34 -07001598 * JNI call bridge
1599 * ===========================================================================
1600 */
1601
1602/*
1603 * The functions here form a bridge between interpreted code and JNI native
1604 * functions. The basic task is to convert an array of primitives and
1605 * references into C-style function arguments. This is architecture-specific
1606 * and usually requires help from assembly code.
1607 *
1608 * The bridge takes four arguments: the array of parameters, a place to
1609 * store the function result (if any), the method to call, and a pointer
1610 * to the current thread.
1611 *
1612 * These functions aren't called directly from elsewhere in the VM.
1613 * A pointer in the Method struct points to one of these, and when a native
1614 * method is invoked the interpreter jumps to it.
1615 *
1616 * (The "internal native" methods are invoked the same way, but instead
1617 * of calling through a bridge, the target method is called directly.)
1618 *
1619 * The "args" array should not be modified, but we do so anyway for
1620 * performance reasons. We know that it points to the "outs" area on
1621 * the current method's interpreted stack. This area is ignored by the
1622 * precise GC, because there is no register map for a native method (for
1623 * an interpreted method the args would be listed in the argument set).
1624 * We know all of the values exist elsewhere on the interpreted stack,
1625 * because the method call setup copies them right before making the call,
1626 * so we don't have to worry about concealing stuff from the GC.
1627 *
1628 * If we don't want to modify "args", we either have to create a local
1629 * copy and modify it before calling dvmPlatformInvoke, or we have to do
1630 * the local reference replacement within dvmPlatformInvoke. The latter
1631 * has some performance advantages, though if we can inline the local
1632 * reference adds we may win when there's a lot of reference args (unless
1633 * we want to code up some local ref table manipulation in assembly.
1634 */
1635
1636/*
Andy McFadden0423f0e2009-08-26 07:21:53 -07001637 * If necessary, convert the value in pResult from a local/global reference
1638 * to an object pointer.
1639 */
1640static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
1641 const Method* method, Thread* self)
1642{
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001643#ifdef USE_INDIRECT_REF
Andy McFadden0423f0e2009-08-26 07:21:53 -07001644 if (method->shorty[0] == 'L' && !dvmCheckException(self) &&
1645 pResult->l != NULL)
1646 {
1647 pResult->l = dvmDecodeIndirectRef(env, pResult->l);
1648 }
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001649#endif
Andy McFadden0423f0e2009-08-26 07:21:53 -07001650}
1651
1652/*
Andy McFaddend5ab7262009-08-25 07:19:34 -07001653 * General form, handles all cases.
1654 */
1655void dvmCallJNIMethod_general(const u4* args, JValue* pResult,
1656 const Method* method, Thread* self)
1657{
1658 int oldStatus;
1659 u4* modArgs = (u4*) args;
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001660 jclass staticMethodClass;
1661 JNIEnv* env = self->jniEnv;
Andy McFaddend5ab7262009-08-25 07:19:34 -07001662
Andy McFaddend5ab7262009-08-25 07:19:34 -07001663 //LOGI("JNI calling %p (%s.%s:%s):\n", method->insns,
1664 // method->clazz->descriptor, method->name, method->shorty);
1665
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001666#ifdef USE_INDIRECT_REF
Andy McFaddend5ab7262009-08-25 07:19:34 -07001667 /*
1668 * Walk the argument list, creating local references for appropriate
1669 * arguments.
1670 */
Andy McFaddend5ab7262009-08-25 07:19:34 -07001671 int idx = 0;
1672 if (dvmIsStaticMethod(method)) {
1673 /* add the class object we pass in */
1674 staticMethodClass = addLocalReference(env, (Object*) method->clazz);
1675 if (staticMethodClass == NULL) {
1676 assert(dvmCheckException(self));
1677 return;
1678 }
1679 } else {
1680 /* add "this" */
1681 staticMethodClass = NULL;
1682 jobject thisObj = addLocalReference(env, (Object*) modArgs[0]);
1683 if (thisObj == NULL) {
1684 assert(dvmCheckException(self));
1685 return;
1686 }
1687 modArgs[idx] = (u4) thisObj;
1688 idx = 1;
1689 }
1690
1691 const char* shorty = &method->shorty[1]; /* skip return type */
1692 while (*shorty != '\0') {
1693 switch (*shorty++) {
1694 case 'L':
1695 //LOGI(" local %d: 0x%08x\n", idx, modArgs[idx]);
1696 if (modArgs[idx] != 0) {
1697 //if (!dvmIsValidObject((Object*) modArgs[idx]))
1698 // dvmAbort();
1699 jobject argObj = addLocalReference(env, (Object*) modArgs[idx]);
1700 if (argObj == NULL) {
1701 assert(dvmCheckException(self));
1702 return;
1703 }
1704 modArgs[idx] = (u4) argObj;
1705 }
1706 break;
1707 case 'D':
1708 case 'J':
1709 idx++;
1710 break;
1711 default:
1712 /* Z B C S I -- do nothing */
1713 break;
1714 }
1715
1716 idx++;
1717 }
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001718#else
1719 staticMethodClass = dvmIsStaticMethod(method) ?
1720 (jclass) method->clazz : NULL;
1721#endif
Andy McFaddend5ab7262009-08-25 07:19:34 -07001722
1723 oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1724
Andy McFadden1e83b4d2010-07-15 17:20:24 -07001725 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
1726 assert(method->insns != NULL);
1727
Andy McFaddend5ab7262009-08-25 07:19:34 -07001728 COMPUTE_STACK_SUM(self);
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001729 dvmPlatformInvoke(env, staticMethodClass,
Andy McFaddend5ab7262009-08-25 07:19:34 -07001730 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1731 (void*)method->insns, pResult);
1732 CHECK_STACK_SUM(self);
1733
1734 dvmChangeStatus(self, oldStatus);
Andy McFadden0423f0e2009-08-26 07:21:53 -07001735
1736 convertReferenceResult(env, pResult, method, self);
Andy McFaddend5ab7262009-08-25 07:19:34 -07001737}
1738
1739/*
1740 * Handler for the unusual case of a synchronized native method.
1741 *
1742 * Lock the object, then call through the general function.
1743 */
1744void dvmCallJNIMethod_synchronized(const u4* args, JValue* pResult,
1745 const Method* method, Thread* self)
1746{
1747 Object* lockObj;
1748
1749 assert(dvmIsSynchronizedMethod(method));
1750
1751 if (dvmIsStaticMethod(method))
1752 lockObj = (Object*) method->clazz;
1753 else
1754 lockObj = (Object*) args[0];
1755
1756 LOGVV("Calling %s.%s: locking %p (%s)\n",
1757 method->clazz->descriptor, method->name,
1758 lockObj, lockObj->clazz->descriptor);
1759
1760 dvmLockObject(self, lockObj);
1761 dvmCallJNIMethod_general(args, pResult, method, self);
1762 dvmUnlockObject(self, lockObj);
1763}
1764
1765/*
1766 * Virtual method call, no reference arguments.
1767 *
1768 * We need to local-ref the "this" argument, found in args[0].
1769 */
1770void dvmCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult,
1771 const Method* method, Thread* self)
1772{
1773 u4* modArgs = (u4*) args;
1774 int oldStatus;
1775
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001776#ifdef USE_INDIRECT_REF
Andy McFaddend5ab7262009-08-25 07:19:34 -07001777 jobject thisObj = addLocalReference(self->jniEnv, (Object*) args[0]);
1778 if (thisObj == NULL) {
1779 assert(dvmCheckException(self));
1780 return;
1781 }
1782 modArgs[0] = (u4) thisObj;
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001783#endif
Andy McFaddend5ab7262009-08-25 07:19:34 -07001784
1785 oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1786
Andy McFadden1e83b4d2010-07-15 17:20:24 -07001787 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
1788
Andy McFaddend5ab7262009-08-25 07:19:34 -07001789 COMPUTE_STACK_SUM(self);
1790 dvmPlatformInvoke(self->jniEnv, NULL,
1791 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1792 (void*)method->insns, pResult);
1793 CHECK_STACK_SUM(self);
1794
1795 dvmChangeStatus(self, oldStatus);
Andy McFadden0423f0e2009-08-26 07:21:53 -07001796
1797 convertReferenceResult(self->jniEnv, pResult, method, self);
Andy McFaddend5ab7262009-08-25 07:19:34 -07001798}
1799
1800/*
1801 * Static method call, no reference arguments.
1802 *
1803 * We need to local-ref the class reference.
1804 */
1805void dvmCallJNIMethod_staticNoRef(const u4* args, JValue* pResult,
1806 const Method* method, Thread* self)
1807{
1808 jclass staticMethodClass;
1809 int oldStatus;
1810
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001811#ifdef USE_INDIRECT_REF
Andy McFaddend5ab7262009-08-25 07:19:34 -07001812 staticMethodClass = addLocalReference(self->jniEnv, (Object*)method->clazz);
1813 if (staticMethodClass == NULL) {
1814 assert(dvmCheckException(self));
1815 return;
1816 }
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001817#else
1818 staticMethodClass = (jobject) method->clazz;
1819#endif
Andy McFaddend5ab7262009-08-25 07:19:34 -07001820
1821 oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1822
Andy McFadden1e83b4d2010-07-15 17:20:24 -07001823 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
1824
Andy McFaddend5ab7262009-08-25 07:19:34 -07001825 COMPUTE_STACK_SUM(self);
1826 dvmPlatformInvoke(self->jniEnv, staticMethodClass,
1827 method->jniArgInfo, method->insSize, args, method->shorty,
1828 (void*)method->insns, pResult);
1829 CHECK_STACK_SUM(self);
1830
1831 dvmChangeStatus(self, oldStatus);
Andy McFadden0423f0e2009-08-26 07:21:53 -07001832
1833 convertReferenceResult(self->jniEnv, pResult, method, self);
Andy McFaddend5ab7262009-08-25 07:19:34 -07001834}
1835
1836/*
1837 * Extract the return type enum from the "jniArgInfo" field.
1838 */
1839DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo)
1840{
1841 return (jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT;
1842}
1843
1844
1845/*
1846 * ===========================================================================
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001847 * JNI implementation
1848 * ===========================================================================
1849 */
1850
1851/*
1852 * Return the version of the native method interface.
1853 */
1854static jint GetVersion(JNIEnv* env)
1855{
1856 JNI_ENTER();
1857 /*
1858 * There is absolutely no need to toggle the mode for correct behavior.
1859 * However, it does provide native code with a simple "suspend self
1860 * if necessary" call.
1861 */
1862 JNI_EXIT();
1863 return JNI_VERSION_1_6;
1864}
1865
1866/*
1867 * Create a new class from a bag of bytes.
1868 *
1869 * This is not currently supported within Dalvik.
1870 */
1871static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1872 const jbyte* buf, jsize bufLen)
1873{
1874 UNUSED_PARAMETER(name);
1875 UNUSED_PARAMETER(loader);
1876 UNUSED_PARAMETER(buf);
1877 UNUSED_PARAMETER(bufLen);
1878
1879 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07001880 LOGW("JNI DefineClass is not supported\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001881 JNI_EXIT();
1882 return NULL;
1883}
1884
1885/*
1886 * Find a class by name.
1887 *
1888 * We have to use the "no init" version of FindClass here, because we might
1889 * be getting the class prior to registering native methods that will be
1890 * used in <clinit>.
1891 *
1892 * We need to get the class loader associated with the current native
1893 * method. If there is no native method, e.g. we're calling this from native
1894 * code right after creating the VM, the spec says we need to use the class
1895 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1896 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1897 * We can't get that until after the VM has initialized though.
1898 */
1899static jclass FindClass(JNIEnv* env, const char* name)
1900{
1901 JNI_ENTER();
1902
1903 const Method* thisMethod;
1904 ClassObject* clazz;
Andy McFaddenab00d452009-08-19 07:21:41 -07001905 jclass jclazz = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001906 Object* loader;
1907 char* descriptor = NULL;
1908
1909 thisMethod = dvmGetCurrentJNIMethod();
1910 assert(thisMethod != NULL);
1911
1912 descriptor = dvmNameToDescriptor(name);
1913 if (descriptor == NULL) {
1914 clazz = NULL;
1915 goto bail;
1916 }
1917
1918 //Thread* self = dvmThreadSelf();
1919 if (_self->classLoaderOverride != NULL) {
1920 /* hack for JNI_OnLoad */
1921 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1922 loader = _self->classLoaderOverride;
1923 } else if (thisMethod == gDvm.methFakeNativeEntry) {
1924 /* start point of invocation interface */
1925 if (!gDvm.initializing)
1926 loader = dvmGetSystemClassLoader();
1927 else
1928 loader = NULL;
1929 } else {
1930 loader = thisMethod->clazz->classLoader;
1931 }
1932
1933 clazz = dvmFindClassNoInit(descriptor, loader);
Andy McFaddenab00d452009-08-19 07:21:41 -07001934 jclazz = addLocalReference(env, (Object*) clazz);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001935
1936bail:
1937 free(descriptor);
Andy McFaddenab00d452009-08-19 07:21:41 -07001938
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001939 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07001940 return jclazz;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001941}
1942
1943/*
1944 * Return the superclass of a class.
1945 */
Andy McFaddenab00d452009-08-19 07:21:41 -07001946static jclass GetSuperclass(JNIEnv* env, jclass jclazz)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001947{
1948 JNI_ENTER();
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001949 jclass jsuper = NULL;
Andy McFaddenab00d452009-08-19 07:21:41 -07001950
1951 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
Andy McFaddeneb9cbc32009-08-28 14:45:12 -07001952 if (clazz != NULL)
Andy McFaddenab00d452009-08-19 07:21:41 -07001953 jsuper = addLocalReference(env, (Object*)clazz->super);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001954 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07001955 return jsuper;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001956}
1957
1958/*
1959 * Determine whether an object of clazz1 can be safely cast to clazz2.
1960 *
1961 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1962 */
Andy McFaddenab00d452009-08-19 07:21:41 -07001963static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001964{
1965 JNI_ENTER();
1966
Andy McFaddenab00d452009-08-19 07:21:41 -07001967 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1);
1968 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2);
1969
1970 jboolean result = dvmInstanceof(clazz1, clazz2);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001971
1972 JNI_EXIT();
1973 return result;
1974}
1975
1976/*
1977 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1978 */
Andy McFaddenab00d452009-08-19 07:21:41 -07001979static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001980{
1981 JNI_ENTER();
1982 jmethodID methodID;
Andy McFaddenab00d452009-08-19 07:21:41 -07001983 Object* method = dvmDecodeIndirectRef(env, jmethod);
1984 methodID = (jmethodID) dvmGetMethodFromReflectObj(method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001985 JNI_EXIT();
1986 return methodID;
1987}
1988
1989/*
1990 * Given a java.lang.reflect.Field, return a fieldID.
1991 */
Andy McFaddenab00d452009-08-19 07:21:41 -07001992static jfieldID FromReflectedField(JNIEnv* env, jobject jfield)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001993{
1994 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07001995 jfieldID fieldID;
1996 Object* field = dvmDecodeIndirectRef(env, jfield);
1997 fieldID = (jfieldID) dvmGetFieldFromReflectObj(field);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001998 JNI_EXIT();
1999 return fieldID;
2000}
2001
2002/*
2003 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
2004 *
2005 * (The "isStatic" field does not appear in the spec.)
2006 *
2007 * Throws OutOfMemory and returns NULL on failure.
2008 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002009static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002010 jboolean isStatic)
2011{
2012 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002013 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
2014 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002015 dvmReleaseTrackedAlloc(obj, NULL);
Andy McFaddenab00d452009-08-19 07:21:41 -07002016 jobject jobj = addLocalReference(env, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002017 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07002018 return jobj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002019}
2020
2021/*
2022 * Convert a fieldID to a java.lang.reflect.Field.
2023 *
2024 * (The "isStatic" field does not appear in the spec.)
2025 *
2026 * Throws OutOfMemory and returns NULL on failure.
2027 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002028static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002029 jboolean isStatic)
2030{
2031 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002032 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
Carl Shapiroe3c01da2010-05-20 22:54:18 -07002033 Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002034 dvmReleaseTrackedAlloc(obj, NULL);
Andy McFaddenab00d452009-08-19 07:21:41 -07002035 jobject jobj = addLocalReference(env, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002036 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07002037 return jobj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002038}
2039
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002040/*
2041 * Take this exception and throw it.
2042 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002043static jint Throw(JNIEnv* env, jthrowable jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002044{
2045 JNI_ENTER();
2046
2047 jint retval;
2048
Andy McFaddenab00d452009-08-19 07:21:41 -07002049 if (jobj != NULL) {
2050 Object* obj = dvmDecodeIndirectRef(env, jobj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002051 dvmSetException(_self, obj);
2052 retval = JNI_OK;
Andy McFaddenab00d452009-08-19 07:21:41 -07002053 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002054 retval = JNI_ERR;
Andy McFaddenab00d452009-08-19 07:21:41 -07002055 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002056
2057 JNI_EXIT();
2058 return retval;
2059}
2060
2061/*
Andy McFaddenab00d452009-08-19 07:21:41 -07002062 * Constructs an exception object from the specified class with the message
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002063 * specified by "message", and throws it.
2064 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002065static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002066{
2067 JNI_ENTER();
2068
Andy McFaddenab00d452009-08-19 07:21:41 -07002069 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2070 dvmThrowExceptionByClass(clazz, message);
2071 // TODO: should return failure if this didn't work (e.g. OOM)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002072
2073 JNI_EXIT();
2074 return JNI_OK;
2075}
2076
2077/*
2078 * If an exception is being thrown, return the exception object. Otherwise,
2079 * return NULL.
2080 *
2081 * TODO: if there is no pending exception, we should be able to skip the
2082 * enter/exit checks. If we find one, we need to enter and then re-fetch
2083 * the exception (in case it got moved by a compacting GC).
2084 */
2085static jthrowable ExceptionOccurred(JNIEnv* env)
2086{
2087 JNI_ENTER();
2088
2089 Object* exception;
Andy McFaddenab00d452009-08-19 07:21:41 -07002090 jobject localException;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002091
Andy McFaddenab00d452009-08-19 07:21:41 -07002092 exception = dvmGetException(_self);
2093 localException = addLocalReference(env, exception);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002094 if (localException == NULL && exception != NULL) {
2095 /*
2096 * We were unable to add a new local reference, and threw a new
2097 * exception. We can't return "exception", because it's not a
2098 * local reference. So we have to return NULL, indicating that
2099 * there was no exception, even though it's pretty much raining
2100 * exceptions in here.
2101 */
2102 LOGW("JNI WARNING: addLocal/exception combo\n");
2103 }
2104
2105 JNI_EXIT();
2106 return localException;
2107}
2108
2109/*
2110 * Print an exception and stack trace to stderr.
2111 */
2112static void ExceptionDescribe(JNIEnv* env)
2113{
2114 JNI_ENTER();
2115
2116 Object* exception = dvmGetException(_self);
2117 if (exception != NULL) {
2118 dvmPrintExceptionStackTrace();
2119 } else {
2120 LOGI("Odd: ExceptionDescribe called, but no exception pending\n");
2121 }
2122
2123 JNI_EXIT();
2124}
2125
2126/*
2127 * Clear the exception currently being thrown.
2128 *
2129 * TODO: we should be able to skip the enter/exit stuff.
2130 */
2131static void ExceptionClear(JNIEnv* env)
2132{
2133 JNI_ENTER();
2134 dvmClearException(_self);
2135 JNI_EXIT();
2136}
2137
2138/*
2139 * Kill the VM. This function does not return.
2140 */
2141static void FatalError(JNIEnv* env, const char* msg)
2142{
2143 //dvmChangeStatus(NULL, THREAD_RUNNING);
2144 LOGE("JNI posting fatal error: %s\n", msg);
2145 dvmAbort();
2146}
2147
2148/*
2149 * Push a new JNI frame on the stack, with a new set of locals.
2150 *
2151 * The new frame must have the same method pointer. (If for no other
2152 * reason than FindClass needs it to get the appropriate class loader.)
2153 */
2154static jint PushLocalFrame(JNIEnv* env, jint capacity)
2155{
2156 JNI_ENTER();
2157 int result = JNI_OK;
Andy McFaddenab00d452009-08-19 07:21:41 -07002158 if (!ensureLocalCapacity(env, capacity) ||
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002159 !dvmPushLocalFrame(_self /*dvmThreadSelf()*/, dvmGetCurrentJNIMethod()))
2160 {
2161 /* yes, OutOfMemoryError, not StackOverflowError */
2162 dvmClearException(_self);
2163 dvmThrowException("Ljava/lang/OutOfMemoryError;",
2164 "out of stack in JNI PushLocalFrame");
2165 result = JNI_ERR;
2166 }
2167 JNI_EXIT();
2168 return result;
2169}
2170
2171/*
2172 * Pop the local frame off. If "result" is not null, add it as a
2173 * local reference on the now-current frame.
2174 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002175static jobject PopLocalFrame(JNIEnv* env, jobject jresult)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002176{
2177 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002178 Object* result = dvmDecodeIndirectRef(env, jresult);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002179 if (!dvmPopLocalFrame(_self /*dvmThreadSelf()*/)) {
2180 LOGW("JNI WARNING: too many PopLocalFrame calls\n");
2181 dvmClearException(_self);
2182 dvmThrowException("Ljava/lang/RuntimeException;",
2183 "too many PopLocalFrame calls");
2184 }
Andy McFaddenab00d452009-08-19 07:21:41 -07002185 jresult = addLocalReference(env, result);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002186 JNI_EXIT();
2187 return result;
2188}
2189
2190/*
2191 * Add a reference to the global list.
2192 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002193static jobject NewGlobalRef(JNIEnv* env, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002194{
Andy McFaddenb18992f2009-09-25 10:42:15 -07002195 Object* obj;
2196
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002197 JNI_ENTER();
Andy McFaddenb18992f2009-09-25 10:42:15 -07002198 if (dvmIsWeakGlobalRef(jobj))
2199 obj = getPhantomReferent(env, (jweak) jobj);
2200 else
2201 obj = dvmDecodeIndirectRef(env, jobj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002202 jobject retval = addGlobalReference(obj);
2203 JNI_EXIT();
2204 return retval;
2205}
2206
2207/*
2208 * Delete a reference from the global list.
2209 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002210static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002211{
2212 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002213 deleteGlobalReference(jglobalRef);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002214 JNI_EXIT();
2215}
2216
2217
2218/*
2219 * Add a reference to the local list.
2220 */
Andy McFaddenb18992f2009-09-25 10:42:15 -07002221static jobject NewLocalRef(JNIEnv* env, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002222{
Andy McFaddenb18992f2009-09-25 10:42:15 -07002223 Object* obj;
2224
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002225 JNI_ENTER();
Andy McFaddenb18992f2009-09-25 10:42:15 -07002226 if (dvmIsWeakGlobalRef(jobj))
2227 obj = getPhantomReferent(env, (jweak) jobj);
2228 else
2229 obj = dvmDecodeIndirectRef(env, jobj);
Andy McFaddenab00d452009-08-19 07:21:41 -07002230 jobject retval = addLocalReference(env, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002231 JNI_EXIT();
2232 return retval;
2233}
2234
2235/*
2236 * Delete a reference from the local list.
2237 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002238static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002239{
2240 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002241 deleteLocalReference(env, jlocalRef);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002242 JNI_EXIT();
2243}
2244
2245/*
2246 * Ensure that the local references table can hold at least this many
2247 * references.
2248 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002249static jint EnsureLocalCapacity(JNIEnv* env, jint capacity)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002250{
2251 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002252 bool okay = ensureLocalCapacity(env, capacity);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002253 if (!okay) {
2254 dvmThrowException("Ljava/lang/OutOfMemoryError;",
2255 "can't ensure local reference capacity");
2256 }
2257 JNI_EXIT();
2258 if (okay)
2259 return 0;
2260 else
2261 return -1;
2262}
2263
2264
2265/*
2266 * Determine whether two Object references refer to the same underlying object.
2267 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002268static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002269{
2270 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002271 Object* obj1 = dvmDecodeIndirectRef(env, jref1);
2272 Object* obj2 = dvmDecodeIndirectRef(env, jref2);
2273 jboolean result = (obj1 == obj2);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002274 JNI_EXIT();
2275 return result;
2276}
2277
2278/*
2279 * Allocate a new object without invoking any constructors.
2280 */
2281static jobject AllocObject(JNIEnv* env, jclass jclazz)
2282{
2283 JNI_ENTER();
2284
Andy McFaddenab00d452009-08-19 07:21:41 -07002285 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2286 jobject result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002287
Andy McFaddenb76594d2010-07-19 15:44:56 -07002288 if (!canAllocClass(clazz) ||
2289 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
2290 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002291 assert(dvmCheckException(_self));
Andy McFaddenab00d452009-08-19 07:21:41 -07002292 result = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002293 } else {
Andy McFaddenab00d452009-08-19 07:21:41 -07002294 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2295 result = addLocalReference(env, newObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002296 }
2297
2298 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07002299 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002300}
2301
2302/*
Andy McFaddenab00d452009-08-19 07:21:41 -07002303 * Allocate a new object and invoke the supplied constructor.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002304 */
2305static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...)
2306{
2307 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002308 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2309 jobject result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002310
Andy McFaddenb76594d2010-07-19 15:44:56 -07002311 if (!canAllocClass(clazz) ||
2312 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
2313 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002314 assert(dvmCheckException(_self));
Andy McFaddenab00d452009-08-19 07:21:41 -07002315 result = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002316 } else {
Andy McFaddenab00d452009-08-19 07:21:41 -07002317 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2318 result = addLocalReference(env, newObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002319 if (newObj != NULL) {
2320 JValue unused;
2321 va_list args;
2322 va_start(args, methodID);
Andy McFaddend5ab7262009-08-25 07:19:34 -07002323 dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused,
2324 args);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002325 va_end(args);
2326 }
2327 }
2328
2329 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07002330 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002331}
Andy McFaddenab00d452009-08-19 07:21:41 -07002332static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002333 va_list args)
2334{
2335 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002336 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2337 jobject result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002338
Andy McFaddenb76594d2010-07-19 15:44:56 -07002339 if (!canAllocClass(clazz) ||
2340 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
2341 {
2342 assert(dvmCheckException(_self));
2343 result = NULL;
2344 } else {
2345 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2346 result = addLocalReference(env, newObj);
2347 if (newObj != NULL) {
2348 JValue unused;
2349 dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused,
2350 args);
2351 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002352 }
2353
2354 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07002355 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002356}
Andy McFaddenab00d452009-08-19 07:21:41 -07002357static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002358 jvalue* args)
2359{
2360 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002361 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2362 jobject result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002363
Andy McFaddenb76594d2010-07-19 15:44:56 -07002364 if (!canAllocClass(clazz) ||
2365 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
2366 {
2367 assert(dvmCheckException(_self));
2368 result = NULL;
2369 } else {
2370 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
2371 result = addLocalReference(env, newObj);
2372 if (newObj != NULL) {
2373 JValue unused;
2374 dvmCallMethodA(_self, (Method*) methodID, newObj, true, &unused,
2375 args);
2376 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002377 }
2378
2379 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07002380 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002381}
2382
2383/*
2384 * Returns the class of an object.
2385 *
2386 * JNI spec says: obj must not be NULL.
2387 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002388static jclass GetObjectClass(JNIEnv* env, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002389{
2390 JNI_ENTER();
2391
Andy McFaddenab00d452009-08-19 07:21:41 -07002392 assert(jobj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002393
Andy McFaddenab00d452009-08-19 07:21:41 -07002394 Object* obj = dvmDecodeIndirectRef(env, jobj);
2395 jclass jclazz = addLocalReference(env, (Object*) obj->clazz);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002396
2397 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07002398 return jclazz;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002399}
2400
2401/*
2402 * Determine whether "obj" is an instance of "clazz".
2403 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002404static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002405{
2406 JNI_ENTER();
2407
Andy McFaddenab00d452009-08-19 07:21:41 -07002408 assert(jclazz != NULL);
2409
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002410 jboolean result;
2411
Andy McFaddenab00d452009-08-19 07:21:41 -07002412 if (jobj == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002413 result = true;
Andy McFaddenab00d452009-08-19 07:21:41 -07002414 } else {
2415 Object* obj = dvmDecodeIndirectRef(env, jobj);
2416 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
2417 result = dvmInstanceof(obj->clazz, clazz);
2418 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002419
2420 JNI_EXIT();
2421 return result;
2422}
2423
2424/*
2425 * Get a method ID for an instance method.
2426 *
2427 * JNI defines <init> as an instance method, but Dalvik considers it a
2428 * "direct" method, so we have to special-case it here.
2429 *
2430 * Dalvik also puts all private methods into the "direct" list, so we
2431 * really need to just search both lists.
2432 */
2433static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,
2434 const char* sig)
2435{
2436 JNI_ENTER();
2437
Andy McFaddenab00d452009-08-19 07:21:41 -07002438 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002439 jmethodID id = NULL;
2440
2441 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2442 assert(dvmCheckException(_self));
2443 } else {
2444 Method* meth;
2445
2446 meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
2447 if (meth == NULL) {
2448 /* search private methods and constructors; non-hierarchical */
2449 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
2450 }
2451 if (meth != NULL && dvmIsStaticMethod(meth)) {
2452 IF_LOGD() {
2453 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
2454 LOGD("GetMethodID: not returning static method %s.%s %s\n",
2455 clazz->descriptor, meth->name, desc);
2456 free(desc);
2457 }
2458 meth = NULL;
2459 }
2460 if (meth == NULL) {
Andy McFadden03bd0d52009-08-18 15:32:27 -07002461 LOGD("GetMethodID: method not found: %s.%s:%s\n",
2462 clazz->descriptor, name, sig);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002463 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
2464 }
2465
2466 /*
2467 * The method's class may not be the same as clazz, but if
2468 * it isn't this must be a virtual method and the class must
2469 * be a superclass (and, hence, already initialized).
2470 */
2471 if (meth != NULL) {
2472 assert(dvmIsClassInitialized(meth->clazz) ||
2473 dvmIsClassInitializing(meth->clazz));
2474 }
2475 id = (jmethodID) meth;
2476 }
2477 JNI_EXIT();
2478 return id;
2479}
2480
2481/*
2482 * Get a field ID (instance fields).
2483 */
2484static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,
2485 const char* name, const char* sig)
2486{
2487 JNI_ENTER();
2488
Andy McFaddenab00d452009-08-19 07:21:41 -07002489 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002490 jfieldID id;
2491
2492 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2493 assert(dvmCheckException(_self));
2494 id = NULL;
2495 } else {
2496 id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
Andy McFadden03bd0d52009-08-18 15:32:27 -07002497 if (id == NULL) {
2498 LOGD("GetFieldID: unable to find field %s.%s:%s\n",
2499 clazz->descriptor, name, sig);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002500 dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
Andy McFadden03bd0d52009-08-18 15:32:27 -07002501 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002502 }
2503 JNI_EXIT();
2504 return id;
2505}
2506
2507/*
2508 * Get the method ID for a static method in a class.
2509 */
2510static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz,
2511 const char* name, const char* sig)
2512{
2513 JNI_ENTER();
2514
Andy McFaddenab00d452009-08-19 07:21:41 -07002515 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002516 jmethodID id;
2517
2518 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2519 assert(dvmCheckException(_self));
2520 id = NULL;
2521 } else {
2522 Method* meth;
2523
2524 meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
2525
2526 /* make sure it's static, not virtual+private */
2527 if (meth != NULL && !dvmIsStaticMethod(meth)) {
2528 IF_LOGD() {
2529 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
2530 LOGD("GetStaticMethodID: "
2531 "not returning nonstatic method %s.%s %s\n",
2532 clazz->descriptor, meth->name, desc);
2533 free(desc);
2534 }
2535 meth = NULL;
2536 }
2537
2538 id = (jmethodID) meth;
2539 if (id == NULL)
2540 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
2541 }
2542
2543 JNI_EXIT();
2544 return id;
2545}
2546
2547/*
2548 * Get a field ID (static fields).
2549 */
2550static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz,
2551 const char* name, const char* sig)
2552{
2553 JNI_ENTER();
2554
Andy McFaddenab00d452009-08-19 07:21:41 -07002555 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002556 jfieldID id;
2557
2558 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
2559 assert(dvmCheckException(_self));
2560 id = NULL;
2561 } else {
2562 id = (jfieldID) dvmFindStaticField(clazz, name, sig);
2563 if (id == NULL)
2564 dvmThrowException("Ljava/lang/NoSuchFieldError;", name);
2565 }
2566 JNI_EXIT();
2567 return id;
2568}
2569
2570/*
2571 * Get a static field.
2572 *
2573 * If we get an object reference, add it to the local refs list.
2574 */
2575#define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002576 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002577 jfieldID fieldID) \
2578 { \
Andy McFaddenab00d452009-08-19 07:21:41 -07002579 UNUSED_PARAMETER(jclazz); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002580 JNI_ENTER(); \
2581 StaticField* sfield = (StaticField*) fieldID; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002582 _ctype value; \
2583 if (_isref) { /* only when _ctype==jobject */ \
2584 Object* obj = dvmGetStaticFieldObject(sfield); \
2585 value = (_ctype)(u4)addLocalReference(env, obj); \
2586 } else { \
2587 value = dvmGetStaticField##_jname(sfield); \
2588 } \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002589 JNI_EXIT(); \
2590 return value; \
2591 }
2592GET_STATIC_TYPE_FIELD(jobject, Object, true);
2593GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
2594GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
2595GET_STATIC_TYPE_FIELD(jchar, Char, false);
2596GET_STATIC_TYPE_FIELD(jshort, Short, false);
2597GET_STATIC_TYPE_FIELD(jint, Int, false);
2598GET_STATIC_TYPE_FIELD(jlong, Long, false);
2599GET_STATIC_TYPE_FIELD(jfloat, Float, false);
2600GET_STATIC_TYPE_FIELD(jdouble, Double, false);
2601
2602/*
2603 * Set a static field.
2604 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002605#define SET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
2606 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002607 jfieldID fieldID, _ctype value) \
2608 { \
Andy McFaddenab00d452009-08-19 07:21:41 -07002609 UNUSED_PARAMETER(jclazz); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002610 JNI_ENTER(); \
2611 StaticField* sfield = (StaticField*) fieldID; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002612 if (_isref) { /* only when _ctype==jobject */ \
2613 Object* valObj = dvmDecodeIndirectRef(env, (jobject)(u4)value); \
2614 dvmSetStaticFieldObject(sfield, valObj); \
2615 } else { \
2616 dvmSetStaticField##_jname(sfield, value); \
2617 } \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002618 JNI_EXIT(); \
2619 }
Andy McFaddenab00d452009-08-19 07:21:41 -07002620SET_STATIC_TYPE_FIELD(jobject, Object, true);
2621SET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
2622SET_STATIC_TYPE_FIELD(jbyte, Byte, false);
2623SET_STATIC_TYPE_FIELD(jchar, Char, false);
2624SET_STATIC_TYPE_FIELD(jshort, Short, false);
2625SET_STATIC_TYPE_FIELD(jint, Int, false);
2626SET_STATIC_TYPE_FIELD(jlong, Long, false);
2627SET_STATIC_TYPE_FIELD(jfloat, Float, false);
2628SET_STATIC_TYPE_FIELD(jdouble, Double, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002629
2630/*
2631 * Get an instance field.
2632 *
2633 * If we get an object reference, add it to the local refs list.
2634 */
2635#define GET_TYPE_FIELD(_ctype, _jname, _isref) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002636 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002637 jfieldID fieldID) \
2638 { \
2639 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07002640 Object* obj = dvmDecodeIndirectRef(env, jobj); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002641 InstField* field = (InstField*) fieldID; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002642 _ctype value; \
2643 if (_isref) { /* only when _ctype==jobject */ \
2644 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
2645 value = (_ctype)(u4)addLocalReference(env, valObj); \
2646 } else { \
2647 value = dvmGetField##_jname(obj, field->byteOffset); \
2648 } \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002649 JNI_EXIT(); \
2650 return value; \
2651 }
2652GET_TYPE_FIELD(jobject, Object, true);
2653GET_TYPE_FIELD(jboolean, Boolean, false);
2654GET_TYPE_FIELD(jbyte, Byte, false);
2655GET_TYPE_FIELD(jchar, Char, false);
2656GET_TYPE_FIELD(jshort, Short, false);
2657GET_TYPE_FIELD(jint, Int, false);
2658GET_TYPE_FIELD(jlong, Long, false);
2659GET_TYPE_FIELD(jfloat, Float, false);
2660GET_TYPE_FIELD(jdouble, Double, false);
2661
2662/*
2663 * Set an instance field.
2664 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002665#define SET_TYPE_FIELD(_ctype, _jname, _isref) \
2666 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002667 jfieldID fieldID, _ctype value) \
2668 { \
2669 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07002670 Object* obj = dvmDecodeIndirectRef(env, jobj); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002671 InstField* field = (InstField*) fieldID; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002672 if (_isref) { /* only when _ctype==jobject */ \
2673 Object* valObj = dvmDecodeIndirectRef(env, (jobject)(u4)value); \
2674 dvmSetFieldObject(obj, field->byteOffset, valObj); \
2675 } else { \
2676 dvmSetField##_jname(obj, field->byteOffset, value); \
2677 } \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002678 JNI_EXIT(); \
2679 }
Andy McFaddenab00d452009-08-19 07:21:41 -07002680SET_TYPE_FIELD(jobject, Object, true);
2681SET_TYPE_FIELD(jboolean, Boolean, false);
2682SET_TYPE_FIELD(jbyte, Byte, false);
2683SET_TYPE_FIELD(jchar, Char, false);
2684SET_TYPE_FIELD(jshort, Short, false);
2685SET_TYPE_FIELD(jint, Int, false);
2686SET_TYPE_FIELD(jlong, Long, false);
2687SET_TYPE_FIELD(jfloat, Float, false);
2688SET_TYPE_FIELD(jdouble, Double, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002689
2690/*
2691 * Make a virtual method call.
2692 *
2693 * Three versions (..., va_list, jvalue[]) for each return type. If we're
2694 * returning an Object, we have to add it to the local references table.
2695 */
2696#define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002697 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002698 jmethodID methodID, ...) \
2699 { \
2700 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07002701 Object* obj = dvmDecodeIndirectRef(env, jobj); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002702 const Method* meth; \
2703 va_list args; \
2704 JValue result; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002705 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002706 if (meth == NULL) { \
2707 JNI_EXIT(); \
2708 return _retfail; \
2709 } \
2710 va_start(args, methodID); \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002711 dvmCallMethodV(_self, meth, obj, true, &result, args); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002712 va_end(args); \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002713 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002714 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002715 JNI_EXIT(); \
2716 return _retok; \
2717 } \
Andy McFaddenab00d452009-08-19 07:21:41 -07002718 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002719 jmethodID methodID, va_list args) \
2720 { \
2721 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07002722 Object* obj = dvmDecodeIndirectRef(env, jobj); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002723 const Method* meth; \
2724 JValue result; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002725 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002726 if (meth == NULL) { \
2727 JNI_EXIT(); \
2728 return _retfail; \
2729 } \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002730 dvmCallMethodV(_self, meth, obj, true, &result, args); \
2731 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002732 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002733 JNI_EXIT(); \
2734 return _retok; \
2735 } \
Andy McFaddenab00d452009-08-19 07:21:41 -07002736 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002737 jmethodID methodID, jvalue* args) \
2738 { \
2739 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07002740 Object* obj = dvmDecodeIndirectRef(env, jobj); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002741 const Method* meth; \
2742 JValue result; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002743 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002744 if (meth == NULL) { \
2745 JNI_EXIT(); \
2746 return _retfail; \
2747 } \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002748 dvmCallMethodA(_self, meth, obj, true, &result, args); \
2749 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002750 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002751 JNI_EXIT(); \
2752 return _retok; \
2753 }
2754CALL_VIRTUAL(jobject, Object, NULL, result.l, true);
2755CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
2756CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
2757CALL_VIRTUAL(jchar, Char, 0, result.c, false);
2758CALL_VIRTUAL(jshort, Short, 0, result.s, false);
2759CALL_VIRTUAL(jint, Int, 0, result.i, false);
2760CALL_VIRTUAL(jlong, Long, 0, result.j, false);
2761CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
2762CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
2763CALL_VIRTUAL(void, Void, , , false);
2764
2765/*
2766 * Make a "non-virtual" method call. We're still calling a virtual method,
2767 * but this time we're not doing an indirection through the object's vtable.
2768 * The "clazz" parameter defines which implementation of a method we want.
2769 *
2770 * Three versions (..., va_list, jvalue[]) for each return type.
2771 */
2772#define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002773 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
2774 jclass jclazz, jmethodID methodID, ...) \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002775 { \
2776 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07002777 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2778 ClassObject* clazz = \
2779 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002780 const Method* meth; \
2781 va_list args; \
2782 JValue result; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002783 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002784 if (meth == NULL) { \
2785 JNI_EXIT(); \
2786 return _retfail; \
2787 } \
2788 va_start(args, methodID); \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002789 dvmCallMethodV(_self, meth, obj, true, &result, args); \
2790 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002791 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002792 va_end(args); \
2793 JNI_EXIT(); \
2794 return _retok; \
2795 } \
Andy McFaddenab00d452009-08-19 07:21:41 -07002796 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
2797 jclass jclazz, jmethodID methodID, va_list args) \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002798 { \
2799 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07002800 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2801 ClassObject* clazz = \
2802 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002803 const Method* meth; \
2804 JValue result; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002805 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002806 if (meth == NULL) { \
2807 JNI_EXIT(); \
2808 return _retfail; \
2809 } \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002810 dvmCallMethodV(_self, meth, obj, true, &result, args); \
2811 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002812 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002813 JNI_EXIT(); \
2814 return _retok; \
2815 } \
Andy McFaddenab00d452009-08-19 07:21:41 -07002816 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2817 jclass jclazz, jmethodID methodID, jvalue* args) \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002818 { \
2819 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07002820 Object* obj = dvmDecodeIndirectRef(env, jobj); \
2821 ClassObject* clazz = \
2822 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002823 const Method* meth; \
2824 JValue result; \
Andy McFaddenab00d452009-08-19 07:21:41 -07002825 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002826 if (meth == NULL) { \
2827 JNI_EXIT(); \
2828 return _retfail; \
2829 } \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002830 dvmCallMethodA(_self, meth, obj, true, &result, args); \
2831 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002832 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002833 JNI_EXIT(); \
2834 return _retok; \
2835 }
2836CALL_NONVIRTUAL(jobject, Object, NULL, result.l, true);
2837CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2838CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2839CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2840CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2841CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2842CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2843CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2844CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2845CALL_NONVIRTUAL(void, Void, , , false);
2846
2847
2848/*
2849 * Call a static method.
2850 */
2851#define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002852 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002853 jmethodID methodID, ...) \
2854 { \
Andy McFaddenab00d452009-08-19 07:21:41 -07002855 UNUSED_PARAMETER(jclazz); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002856 JNI_ENTER(); \
2857 JValue result; \
2858 va_list args; \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002859 va_start(args, methodID); \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002860 dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002861 va_end(args); \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002862 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002863 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002864 JNI_EXIT(); \
2865 return _retok; \
2866 } \
Andy McFaddenab00d452009-08-19 07:21:41 -07002867 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002868 jmethodID methodID, va_list args) \
2869 { \
Andy McFaddenab00d452009-08-19 07:21:41 -07002870 UNUSED_PARAMETER(jclazz); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002871 JNI_ENTER(); \
2872 JValue result; \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002873 dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);\
2874 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002875 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002876 JNI_EXIT(); \
2877 return _retok; \
2878 } \
Andy McFaddenab00d452009-08-19 07:21:41 -07002879 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002880 jmethodID methodID, jvalue* args) \
2881 { \
Andy McFaddenab00d452009-08-19 07:21:41 -07002882 UNUSED_PARAMETER(jclazz); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002883 JNI_ENTER(); \
2884 JValue result; \
Andy McFaddend5ab7262009-08-25 07:19:34 -07002885 dvmCallMethodA(_self, (Method*)methodID, NULL, true, &result, args);\
2886 if (_isref && !dvmCheckException(_self)) \
Andy McFaddenab00d452009-08-19 07:21:41 -07002887 result.l = addLocalReference(env, result.l); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002888 JNI_EXIT(); \
2889 return _retok; \
2890 }
2891CALL_STATIC(jobject, Object, NULL, result.l, true);
2892CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2893CALL_STATIC(jbyte, Byte, 0, result.b, false);
2894CALL_STATIC(jchar, Char, 0, result.c, false);
2895CALL_STATIC(jshort, Short, 0, result.s, false);
2896CALL_STATIC(jint, Int, 0, result.i, false);
2897CALL_STATIC(jlong, Long, 0, result.j, false);
2898CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2899CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2900CALL_STATIC(void, Void, , , false);
2901
2902/*
2903 * Create a new String from Unicode data.
2904 *
2905 * If "len" is zero, we will return an empty string even if "unicodeChars"
2906 * is NULL. (The JNI spec is vague here.)
2907 */
2908static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len)
2909{
2910 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002911 jobject retval;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002912
Andy McFaddenab00d452009-08-19 07:21:41 -07002913 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2914 if (jstr == NULL) {
2915 retval = NULL;
2916 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002917 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
Andy McFaddenab00d452009-08-19 07:21:41 -07002918 retval = addLocalReference(env, (Object*) jstr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002919 }
2920
2921 JNI_EXIT();
Andy McFadden0423f0e2009-08-26 07:21:53 -07002922 return retval;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002923}
2924
2925/*
2926 * Return the length of a String in Unicode character units.
2927 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002928static jsize GetStringLength(JNIEnv* env, jstring jstr)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002929{
2930 JNI_ENTER();
2931
Andy McFaddenab00d452009-08-19 07:21:41 -07002932 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
2933 jsize len = dvmStringLen(strObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002934
2935 JNI_EXIT();
2936 return len;
2937}
2938
Andy McFaddenab00d452009-08-19 07:21:41 -07002939
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002940/*
Andy McFaddenab00d452009-08-19 07:21:41 -07002941 * Get a string's character data.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002942 *
2943 * The result is guaranteed to be valid until ReleaseStringChars is
Andy McFaddenab00d452009-08-19 07:21:41 -07002944 * called, which means we have to pin it or return a copy.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002945 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002946static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002947{
2948 JNI_ENTER();
2949
Andy McFaddenab00d452009-08-19 07:21:41 -07002950 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
Andy McFaddend5ab7262009-08-25 07:19:34 -07002951 ArrayObject* strChars = dvmStringCharArray(strObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002952
Andy McFaddenab00d452009-08-19 07:21:41 -07002953 pinPrimitiveArray(strChars);
2954
2955 const u2* data = dvmStringChars(strObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002956 if (isCopy != NULL)
2957 *isCopy = JNI_FALSE;
2958
2959 JNI_EXIT();
2960 return (jchar*)data;
2961}
2962
2963/*
2964 * Release our grip on some characters from a string.
2965 */
Andy McFaddenab00d452009-08-19 07:21:41 -07002966static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002967{
2968 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07002969 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
Andy McFaddend5ab7262009-08-25 07:19:34 -07002970 ArrayObject* strChars = dvmStringCharArray(strObj);
Andy McFaddenab00d452009-08-19 07:21:41 -07002971 unpinPrimitiveArray(strChars);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002972 JNI_EXIT();
2973}
2974
2975/*
2976 * Create a new java.lang.String object from chars in modified UTF-8 form.
2977 *
2978 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2979 * accept it and return a NULL pointer in response.
2980 */
2981static jstring NewStringUTF(JNIEnv* env, const char* bytes)
2982{
2983 JNI_ENTER();
2984
Andy McFaddenab00d452009-08-19 07:21:41 -07002985 jstring result;
2986
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002987 if (bytes == NULL) {
Andy McFaddenab00d452009-08-19 07:21:41 -07002988 result = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002989 } else {
Andy McFaddenab00d452009-08-19 07:21:41 -07002990 /* note newStr could come back NULL on OOM */
Barry Hayes81f3ebe2010-06-15 16:17:37 -07002991 StringObject* newStr = dvmCreateStringFromCstr(bytes);
Andy McFaddenab00d452009-08-19 07:21:41 -07002992 result = addLocalReference(env, (Object*) newStr);
2993 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002994 }
2995
2996 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07002997 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002998}
2999
3000/*
3001 * Return the length in bytes of the modified UTF-8 form of the string.
3002 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003003static jsize GetStringUTFLength(JNIEnv* env, jstring jstr)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003004{
3005 JNI_ENTER();
3006
Andy McFaddenab00d452009-08-19 07:21:41 -07003007 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
3008 jsize len = dvmStringUtf8ByteLen(strObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003009
3010 JNI_EXIT();
3011 return len;
3012}
3013
3014/*
3015 * Convert "string" to modified UTF-8 and return a pointer. The returned
3016 * value must be released with ReleaseStringUTFChars.
3017 *
3018 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
3019 * or NULL if the operation fails. Returns NULL if and only if an invocation
3020 * of this function has thrown an exception."
3021 *
3022 * The behavior here currently follows that of other open-source VMs, which
3023 * quietly return NULL if "string" is NULL. We should consider throwing an
3024 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
3025 * which should catch this sort of thing during development.) Certain other
3026 * VMs will crash with a segmentation fault.
3027 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003028static const char* GetStringUTFChars(JNIEnv* env, jstring jstr,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003029 jboolean* isCopy)
3030{
3031 JNI_ENTER();
3032 char* newStr;
3033
Andy McFaddenab00d452009-08-19 07:21:41 -07003034 if (jstr == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003035 /* this shouldn't happen; throw NPE? */
3036 newStr = NULL;
3037 } else {
3038 if (isCopy != NULL)
3039 *isCopy = JNI_TRUE;
3040
Andy McFaddenab00d452009-08-19 07:21:41 -07003041 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
3042 newStr = dvmCreateCstrFromString(strObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003043 if (newStr == NULL) {
3044 /* assume memory failure */
3045 dvmThrowException("Ljava/lang/OutOfMemoryError;",
3046 "native heap string alloc failed");
3047 }
3048 }
3049
3050 JNI_EXIT();
3051 return newStr;
3052}
3053
3054/*
3055 * Release a string created by GetStringUTFChars().
3056 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003057static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003058{
3059 JNI_ENTER();
3060 free((char*)utf);
3061 JNI_EXIT();
3062}
3063
3064/*
3065 * Return the capacity of the array.
3066 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003067static jsize GetArrayLength(JNIEnv* env, jarray jarr)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003068{
3069 JNI_ENTER();
3070
Andy McFaddenab00d452009-08-19 07:21:41 -07003071 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
3072 jsize length = arrObj->length;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003073
3074 JNI_EXIT();
3075 return length;
3076}
3077
3078/*
3079 * Construct a new array that holds objects from class "elementClass".
3080 */
3081static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
Andy McFaddenab00d452009-08-19 07:21:41 -07003082 jclass jelementClass, jobject jinitialElement)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003083{
3084 JNI_ENTER();
3085
Andy McFaddenab00d452009-08-19 07:21:41 -07003086 jobjectArray newArray = NULL;
3087 ClassObject* elemClassObj =
3088 (ClassObject*) dvmDecodeIndirectRef(env, jelementClass);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003089
3090 if (elemClassObj == NULL) {
3091 dvmThrowException("Ljava/lang/NullPointerException;",
3092 "JNI NewObjectArray");
3093 goto bail;
3094 }
3095
Andy McFaddenab00d452009-08-19 07:21:41 -07003096 ArrayObject* newObj =
3097 dvmAllocObjectArray(elemClassObj, length, ALLOC_DEFAULT);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003098 if (newObj == NULL) {
3099 assert(dvmCheckException(_self));
3100 goto bail;
3101 }
Andy McFaddenab00d452009-08-19 07:21:41 -07003102 newArray = addLocalReference(env, (Object*) newObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003103 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
3104
3105 /*
3106 * Initialize the array. Trashes "length".
3107 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003108 if (jinitialElement != NULL) {
3109 Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003110 Object** arrayData = (Object**) newObj->contents;
3111
3112 while (length--)
Andy McFaddenab00d452009-08-19 07:21:41 -07003113 *arrayData++ = initialElement;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003114 }
3115
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003116
3117bail:
3118 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07003119 return newArray;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003120}
3121
3122/*
3123 * Get one element of an Object array.
3124 *
3125 * Add the object to the local references table in case the array goes away.
3126 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003127static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003128 jsize index)
3129{
3130 JNI_ENTER();
3131
Andy McFaddenab00d452009-08-19 07:21:41 -07003132 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
3133 jobject retval = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003134
Andy McFaddenab00d452009-08-19 07:21:41 -07003135 assert(arrayObj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003136
3137 /* check the array bounds */
3138 if (index < 0 || index >= (int) arrayObj->length) {
3139 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
3140 arrayObj->obj.clazz->descriptor);
3141 goto bail;
3142 }
3143
Andy McFaddenab00d452009-08-19 07:21:41 -07003144 Object* value = ((Object**) arrayObj->contents)[index];
3145 retval = addLocalReference(env, value);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003146
3147bail:
3148 JNI_EXIT();
Andy McFaddenab00d452009-08-19 07:21:41 -07003149 return retval;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003150}
3151
3152/*
3153 * Set one element of an Object array.
3154 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003155static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr,
3156 jsize index, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003157{
3158 JNI_ENTER();
3159
Andy McFaddenab00d452009-08-19 07:21:41 -07003160 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003161
Andy McFaddenab00d452009-08-19 07:21:41 -07003162 assert(arrayObj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003163
3164 /* check the array bounds */
3165 if (index < 0 || index >= (int) arrayObj->length) {
3166 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;",
3167 arrayObj->obj.clazz->descriptor);
3168 goto bail;
3169 }
3170
3171 //LOGV("JNI: set element %d in array %p to %p\n", index, array, value);
3172
Andy McFadden0423f0e2009-08-26 07:21:53 -07003173 Object* obj = dvmDecodeIndirectRef(env, jobj);
Barry Hayes364f9d92010-06-11 16:12:47 -07003174 dvmSetObjectArrayElement(arrayObj, index, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003175
3176bail:
3177 JNI_EXIT();
3178}
3179
3180/*
3181 * Create a new array of primitive elements.
3182 */
3183#define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
3184 static _artype New##_jname##Array(JNIEnv* env, jsize length) \
3185 { \
3186 JNI_ENTER(); \
3187 ArrayObject* arrayObj; \
3188 arrayObj = dvmAllocPrimitiveArray(_typechar, length, \
3189 ALLOC_DEFAULT); \
Andy McFaddenab00d452009-08-19 07:21:41 -07003190 jarray jarr = NULL; \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003191 if (arrayObj != NULL) { \
Andy McFaddenab00d452009-08-19 07:21:41 -07003192 jarr = addLocalReference(env, (Object*) arrayObj); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003193 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003194 } \
3195 JNI_EXIT(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07003196 return (_artype)jarr; \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003197 }
3198NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
3199NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
3200NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
3201NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
3202NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
3203NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
3204NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
3205NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
3206
3207/*
3208 * Get a pointer to a C array of primitive elements from an array object
3209 * of the matching type.
3210 *
Andy McFaddenab00d452009-08-19 07:21:41 -07003211 * In a compacting GC, we either need to return a copy of the elements or
3212 * "pin" the memory. Otherwise we run the risk of native code using the
3213 * buffer as the destination of e.g. a blocking read() call that wakes up
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003214 * during a GC.
3215 */
3216#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
3217 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
Andy McFaddenab00d452009-08-19 07:21:41 -07003218 _ctype##Array jarr, jboolean* isCopy) \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003219 { \
3220 JNI_ENTER(); \
3221 _ctype* data; \
Andy McFaddenab00d452009-08-19 07:21:41 -07003222 ArrayObject* arrayObj = \
3223 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
3224 pinPrimitiveArray(arrayObj); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003225 data = (_ctype*) arrayObj->contents; \
3226 if (isCopy != NULL) \
3227 *isCopy = JNI_FALSE; \
3228 JNI_EXIT(); \
3229 return data; \
3230 }
3231
3232/*
3233 * Release the storage locked down by the "get" function.
3234 *
Andy McFaddenab00d452009-08-19 07:21:41 -07003235 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003236 * elements in 'array'." They apparently did not anticipate the need to
Andy McFaddenab00d452009-08-19 07:21:41 -07003237 * un-pin memory.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003238 */
3239#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
3240 static void Release##_jname##ArrayElements(JNIEnv* env, \
Andy McFaddenab00d452009-08-19 07:21:41 -07003241 _ctype##Array jarr, _ctype* elems, jint mode) \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003242 { \
3243 UNUSED_PARAMETER(elems); \
3244 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07003245 if (mode != JNI_COMMIT) { \
3246 ArrayObject* arrayObj = \
3247 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
3248 unpinPrimitiveArray(arrayObj); \
3249 } \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003250 JNI_EXIT(); \
3251 }
3252
3253/*
3254 * Copy a section of a primitive array to a buffer.
3255 */
3256#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
3257 static void Get##_jname##ArrayRegion(JNIEnv* env, \
Andy McFaddenab00d452009-08-19 07:21:41 -07003258 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003259 { \
3260 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07003261 ArrayObject* arrayObj = \
3262 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003263 _ctype* data = (_ctype*) arrayObj->contents; \
3264 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
3265 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
3266 arrayObj->obj.clazz->descriptor); \
3267 } else { \
3268 memcpy(buf, data + start, len * sizeof(_ctype)); \
3269 } \
3270 JNI_EXIT(); \
3271 }
3272
3273/*
3274 * Copy a section of a primitive array to a buffer.
3275 */
3276#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
3277 static void Set##_jname##ArrayRegion(JNIEnv* env, \
Andy McFaddenab00d452009-08-19 07:21:41 -07003278 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003279 { \
3280 JNI_ENTER(); \
Andy McFaddenab00d452009-08-19 07:21:41 -07003281 ArrayObject* arrayObj = \
3282 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003283 _ctype* data = (_ctype*) arrayObj->contents; \
3284 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
3285 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
3286 arrayObj->obj.clazz->descriptor); \
3287 } else { \
3288 memcpy(data + start, buf, len * sizeof(_ctype)); \
3289 } \
3290 JNI_EXIT(); \
3291 }
3292
3293/*
3294 * 4-in-1:
3295 * Get<Type>ArrayElements
3296 * Release<Type>ArrayElements
3297 * Get<Type>ArrayRegion
3298 * Set<Type>ArrayRegion
3299 */
3300#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
3301 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
3302 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
3303 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
3304 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
3305
3306PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
3307PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
3308PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
3309PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
3310PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
3311PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
3312PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
3313PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
3314
3315/*
3316 * Register one or more native functions in one class.
Andy McFadden1e83b4d2010-07-15 17:20:24 -07003317 *
3318 * This can be called multiple times on the same method, allowing the
3319 * caller to redefine the method implementation at will.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003320 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003321static jint RegisterNatives(JNIEnv* env, jclass jclazz,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003322 const JNINativeMethod* methods, jint nMethods)
3323{
3324 JNI_ENTER();
3325
Andy McFaddenab00d452009-08-19 07:21:41 -07003326 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
Elliott Hughes09239e32009-09-29 18:35:43 -07003327 jint retval = JNI_OK;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003328 int i;
3329
3330 if (gDvm.verboseJni) {
3331 LOGI("[Registering JNI native methods for class %s]\n",
Andy McFaddenab00d452009-08-19 07:21:41 -07003332 clazz->descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003333 }
3334
3335 for (i = 0; i < nMethods; i++) {
Andy McFaddenab00d452009-08-19 07:21:41 -07003336 if (!dvmRegisterJNIMethod(clazz, methods[i].name,
3337 methods[i].signature, methods[i].fnPtr))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003338 {
3339 retval = JNI_ERR;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003340 }
3341 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003342
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003343 JNI_EXIT();
3344 return retval;
3345}
3346
3347/*
Andy McFadden1e83b4d2010-07-15 17:20:24 -07003348 * Un-register all native methods associated with the class.
3349 *
3350 * The JNI docs refer to this as a way to reload/relink native libraries,
3351 * and say it "should not be used in normal native code". In particular,
3352 * there is no need to do this during shutdown, and you do not need to do
3353 * this before redefining a method implementation with RegisterNatives.
3354 *
3355 * It's chiefly useful for a native "plugin"-style library that wasn't
3356 * loaded with System.loadLibrary() (since there's no way to unload those).
3357 * For example, the library could upgrade itself by:
3358 *
3359 * 1. call UnregisterNatives to unbind the old methods
3360 * 2. ensure that no code is still executing inside it (somehow)
3361 * 3. dlclose() the library
3362 * 4. dlopen() the new library
3363 * 5. use RegisterNatives to bind the methods from the new library
3364 *
3365 * The above can work correctly without the UnregisterNatives call, but
3366 * creates a window of opportunity in which somebody might try to call a
3367 * method that is pointing at unmapped memory, crashing the VM. In theory
3368 * the same guards that prevent dlclose() from unmapping executing code could
3369 * prevent that anyway, but with this we can be more thorough and also deal
3370 * with methods that only exist in the old or new form of the library (maybe
3371 * the lib wants to try the call and catch the UnsatisfiedLinkError).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003372 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003373static jint UnregisterNatives(JNIEnv* env, jclass jclazz)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003374{
3375 JNI_ENTER();
Andy McFadden1e83b4d2010-07-15 17:20:24 -07003376
3377 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
3378 if (gDvm.verboseJni) {
3379 LOGI("[Unregistering JNI native methods for class %s]\n",
3380 clazz->descriptor);
3381 }
3382 dvmUnregisterJNINativeMethods(clazz);
3383
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003384 JNI_EXIT();
Andy McFadden1e83b4d2010-07-15 17:20:24 -07003385 return JNI_OK;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003386}
3387
3388/*
3389 * Lock the monitor.
3390 *
3391 * We have to track all monitor enters and exits, so that we can undo any
3392 * outstanding synchronization before the thread exits.
3393 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003394static jint MonitorEnter(JNIEnv* env, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003395{
3396 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07003397 Object* obj = dvmDecodeIndirectRef(env, jobj);
3398 dvmLockObject(_self, obj);
3399 trackMonitorEnter(_self, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003400 JNI_EXIT();
3401 return JNI_OK;
3402}
3403
3404/*
3405 * Unlock the monitor.
3406 *
3407 * Throws an IllegalMonitorStateException if the current thread
Andy McFaddenab00d452009-08-19 07:21:41 -07003408 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003409 *
3410 * According to the 1.6 spec, it's legal to call here with an exception
3411 * pending. If this fails, we'll stomp the original exception.
3412 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003413static jint MonitorExit(JNIEnv* env, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003414{
3415 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07003416 Object* obj = dvmDecodeIndirectRef(env, jobj);
3417 bool success = dvmUnlockObject(_self, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003418 if (success)
Andy McFaddenab00d452009-08-19 07:21:41 -07003419 trackMonitorExit(_self, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003420 JNI_EXIT();
3421 return success ? JNI_OK : JNI_ERR;
3422}
3423
3424/*
3425 * Return the JavaVM interface associated with the current thread.
3426 */
3427static jint GetJavaVM(JNIEnv* env, JavaVM** vm)
3428{
3429 JNI_ENTER();
3430 //*vm = gDvm.vmList;
3431 *vm = (JavaVM*) ((JNIEnvExt*)env)->vm;
3432 JNI_EXIT();
3433 if (*vm == NULL)
3434 return JNI_ERR;
3435 else
3436 return JNI_OK;
3437}
3438
3439/*
3440 * Copies "len" Unicode characters, from offset "start".
3441 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003442static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003443 jchar* buf)
3444{
3445 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07003446 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003447 if (start + len > dvmStringLen(strObj))
3448 dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
3449 else
3450 memcpy(buf, dvmStringChars(strObj) + start, len * sizeof(u2));
3451 JNI_EXIT();
3452}
3453
3454/*
3455 * Translates "len" Unicode characters, from offset "start", into
3456 * modified UTF-8 encoding.
3457 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003458static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003459 jsize len, char* buf)
3460{
3461 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07003462 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003463 if (start + len > dvmStringLen(strObj))
3464 dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
3465 else
3466 dvmCreateCstrFromStringRegion(strObj, start, len, buf);
3467 JNI_EXIT();
3468}
3469
3470/*
3471 * Get a raw pointer to array data.
3472 *
3473 * The caller is expected to call "release" before doing any JNI calls
3474 * or blocking I/O operations.
3475 *
Andy McFaddenab00d452009-08-19 07:21:41 -07003476 * We need to pin the memory or block GC.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003477 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003478static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003479 jboolean* isCopy)
3480{
3481 JNI_ENTER();
3482 void* data;
Andy McFaddenab00d452009-08-19 07:21:41 -07003483 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
3484 pinPrimitiveArray(arrayObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003485 data = arrayObj->contents;
3486 if (isCopy != NULL)
3487 *isCopy = JNI_FALSE;
3488 JNI_EXIT();
3489 return data;
3490}
3491
3492/*
3493 * Release an array obtained with GetPrimitiveArrayCritical.
3494 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003495static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003496 void* carray, jint mode)
3497{
3498 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07003499 if (mode != JNI_COMMIT) {
3500 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
3501 unpinPrimitiveArray(arrayObj);
3502 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003503 JNI_EXIT();
3504}
3505
3506/*
3507 * Like GetStringChars, but with restricted use.
3508 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003509static const jchar* GetStringCritical(JNIEnv* env, jstring jstr,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003510 jboolean* isCopy)
3511{
3512 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07003513 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
3514 ArrayObject* strChars = dvmStringCharArray(strObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003515
Andy McFaddenab00d452009-08-19 07:21:41 -07003516 pinPrimitiveArray(strChars);
3517
3518 const u2* data = dvmStringChars(strObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003519 if (isCopy != NULL)
3520 *isCopy = JNI_FALSE;
3521
3522 JNI_EXIT();
3523 return (jchar*)data;
3524}
3525
3526/*
3527 * Like ReleaseStringChars, but with restricted use.
3528 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003529static void ReleaseStringCritical(JNIEnv* env, jstring jstr,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003530 const jchar* carray)
3531{
3532 JNI_ENTER();
Andy McFaddenab00d452009-08-19 07:21:41 -07003533 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
Andy McFadden0423f0e2009-08-26 07:21:53 -07003534 ArrayObject* strChars = dvmStringCharArray(strObj);
Andy McFaddenab00d452009-08-19 07:21:41 -07003535 unpinPrimitiveArray(strChars);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003536 JNI_EXIT();
3537}
3538
3539/*
3540 * Create a new weak global reference.
3541 */
3542static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj)
3543{
3544 JNI_ENTER();
Andy McFaddenb18992f2009-09-25 10:42:15 -07003545 jweak wref = createWeakGlobalRef(env, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003546 JNI_EXIT();
Andy McFaddenb18992f2009-09-25 10:42:15 -07003547 return wref;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003548}
3549
3550/*
3551 * Delete the specified weak global reference.
3552 */
Andy McFaddenb18992f2009-09-25 10:42:15 -07003553static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003554{
3555 JNI_ENTER();
Andy McFaddenb18992f2009-09-25 10:42:15 -07003556 deleteWeakGlobalRef(env, wref);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003557 JNI_EXIT();
3558}
3559
3560/*
3561 * Quick check for pending exceptions.
3562 *
3563 * TODO: we should be able to skip the enter/exit macros here.
3564 */
3565static jboolean ExceptionCheck(JNIEnv* env)
3566{
3567 JNI_ENTER();
3568 bool result = dvmCheckException(_self);
3569 JNI_EXIT();
3570 return result;
3571}
3572
3573/*
3574 * Returns the type of the object referred to by "obj". It can be local,
3575 * global, or weak global.
3576 *
3577 * In the current implementation, references can be global and local at
3578 * the same time, so while the return value is accurate it may not tell
3579 * the whole story.
3580 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003581static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003582{
3583 JNI_ENTER();
Andy McFadden0423f0e2009-08-26 07:21:53 -07003584 jobjectRefType type = dvmGetJNIRefType(env, jobj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003585 JNI_EXIT();
3586 return type;
3587}
3588
3589/*
3590 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
3591 *
Andy McFadden8e5c7842009-07-23 17:47:18 -07003592 * "address" may not be NULL, and "capacity" must be > 0. (These are only
3593 * verified when CheckJNI is enabled.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003594 */
Andy McFadden8e5c7842009-07-23 17:47:18 -07003595static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003596{
Andy McFadden8e5c7842009-07-23 17:47:18 -07003597 JNI_ENTER();
3598
3599 Thread* self = _self /*dvmThreadSelf()*/;
3600 Object* platformAddress = NULL;
3601 JValue callResult;
The Android Open Source Project99409882009-03-18 22:20:24 -07003602 jobject result = NULL;
Andy McFaddenac175b42009-12-17 11:21:09 -08003603 ClassObject* tmpClazz;
3604
3605 tmpClazz = gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on->clazz;
3606 if (!dvmIsClassInitialized(tmpClazz) && !dvmInitClass(tmpClazz))
3607 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003608
Andy McFadden8e5c7842009-07-23 17:47:18 -07003609 /* get an instance of PlatformAddress that wraps the provided address */
3610 dvmCallMethod(self,
3611 gDvm.methOrgApacheHarmonyLuniPlatformPlatformAddress_on,
3612 NULL, &callResult, address);
3613 if (dvmGetException(self) != NULL || callResult.l == NULL)
The Android Open Source Project99409882009-03-18 22:20:24 -07003614 goto bail;
Andy McFadden8e5c7842009-07-23 17:47:18 -07003615
3616 /* don't let the GC discard it */
3617 platformAddress = (Object*) callResult.l;
3618 dvmAddTrackedAlloc(platformAddress, self);
3619 LOGV("tracking %p for address=%p\n", platformAddress, address);
3620
3621 /* create an instance of java.nio.ReadWriteDirectByteBuffer */
Andy McFaddenac175b42009-12-17 11:21:09 -08003622 tmpClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
3623 if (!dvmIsClassInitialized(tmpClazz) && !dvmInitClass(tmpClazz))
Andy McFadden8e5c7842009-07-23 17:47:18 -07003624 goto bail;
Andy McFaddenac175b42009-12-17 11:21:09 -08003625 Object* newObj = dvmAllocObject(tmpClazz, ALLOC_DONT_TRACK);
Andy McFadden8e5c7842009-07-23 17:47:18 -07003626 if (newObj != NULL) {
3627 /* call the (PlatformAddress, int, int) constructor */
Andy McFaddenab00d452009-08-19 07:21:41 -07003628 result = addLocalReference(env, newObj);
Andy McFadden8e5c7842009-07-23 17:47:18 -07003629 dvmCallMethod(self, gDvm.methJavaNioReadWriteDirectByteBuffer_init,
3630 newObj, &callResult, platformAddress, (jint) capacity, (jint) 0);
Andy McFaddenab00d452009-08-19 07:21:41 -07003631 if (dvmGetException(self) != NULL) {
3632 deleteLocalReference(env, result);
3633 result = NULL;
Andy McFadden8e5c7842009-07-23 17:47:18 -07003634 goto bail;
Andy McFaddenab00d452009-08-19 07:21:41 -07003635 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003636 }
3637
The Android Open Source Project99409882009-03-18 22:20:24 -07003638bail:
Andy McFadden8e5c7842009-07-23 17:47:18 -07003639 if (platformAddress != NULL)
3640 dvmReleaseTrackedAlloc(platformAddress, self);
3641 JNI_EXIT();
The Android Open Source Project99409882009-03-18 22:20:24 -07003642 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003643}
3644
3645/*
3646 * Get the starting address of the buffer for the specified java.nio.Buffer.
3647 *
Andy McFadden8e5c7842009-07-23 17:47:18 -07003648 * If this is not a "direct" buffer, we return NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003649 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003650static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003651{
Andy McFadden8e5c7842009-07-23 17:47:18 -07003652 JNI_ENTER();
3653
Andy McFaddenab00d452009-08-19 07:21:41 -07003654 Object* bufObj = dvmDecodeIndirectRef(env, jbuf);
Andy McFadden8e5c7842009-07-23 17:47:18 -07003655 Thread* self = _self /*dvmThreadSelf()*/;
Andy McFadden8e696dc2009-07-24 15:28:16 -07003656 void* result;
3657
3658 /*
3659 * All Buffer objects have an effectiveDirectAddress field. If it's
3660 * nonzero, we can just return that value. If not, we have to call
3661 * through DirectBuffer.getEffectiveAddress(), which as a side-effect
3662 * will set the effectiveDirectAddress field for direct buffers (and
3663 * things that wrap direct buffers).
3664 */
3665 result = (void*) dvmGetFieldInt(bufObj,
3666 gDvm.offJavaNioBuffer_effectiveDirectAddress);
3667 if (result != NULL) {
3668 //LOGI("fast path for %p\n", buf);
3669 goto bail;
3670 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003671
Andy McFadden72d61fb2009-06-24 16:56:06 -07003672 /*
3673 * Start by determining if the object supports the DirectBuffer
3674 * interfaces. Note this does not guarantee that it's a direct buffer.
3675 */
Andy McFadden8e5c7842009-07-23 17:47:18 -07003676 if (!dvmInstanceof(bufObj->clazz,
3677 gDvm.classOrgApacheHarmonyNioInternalDirectBuffer))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003678 {
The Android Open Source Project99409882009-03-18 22:20:24 -07003679 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003680 }
3681
Andy McFadden72d61fb2009-06-24 16:56:06 -07003682 /*
Andy McFadden8e5c7842009-07-23 17:47:18 -07003683 * Get a PlatformAddress object with the effective address.
Andy McFadden5f612b82009-07-22 15:07:27 -07003684 *
Andy McFadden8e5c7842009-07-23 17:47:18 -07003685 * If this isn't a direct buffer, the result will be NULL and/or an
Andy McFadden72d61fb2009-06-24 16:56:06 -07003686 * exception will have been thrown.
3687 */
Andy McFadden8e696dc2009-07-24 15:28:16 -07003688 JValue callResult;
Andy McFadden8e5c7842009-07-23 17:47:18 -07003689 const Method* meth = dvmGetVirtualizedMethod(bufObj->clazz,
3690 gDvm.methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress);
Andy McFaddend5ab7262009-08-25 07:19:34 -07003691 dvmCallMethodA(self, meth, bufObj, false, &callResult, NULL);
Andy McFadden8e5c7842009-07-23 17:47:18 -07003692 if (dvmGetException(self) != NULL) {
3693 dvmClearException(self);
3694 callResult.l = NULL;
Andy McFadden72d61fb2009-06-24 16:56:06 -07003695 }
Andy McFadden8e5c7842009-07-23 17:47:18 -07003696
Andy McFadden8e696dc2009-07-24 15:28:16 -07003697 Object* platformAddr = callResult.l;
Andy McFadden72d61fb2009-06-24 16:56:06 -07003698 if (platformAddr == NULL) {
Andy McFadden8e696dc2009-07-24 15:28:16 -07003699 LOGV("Got request for address of non-direct buffer\n");
Andy McFadden72d61fb2009-06-24 16:56:06 -07003700 goto bail;
3701 }
3702
Andy McFadden8e5c7842009-07-23 17:47:18 -07003703 /*
3704 * Extract the address from the PlatformAddress object. Instead of
3705 * calling the toLong() method, just grab the field directly. This
3706 * is faster but more fragile.
3707 */
3708 result = (void*) dvmGetFieldInt(platformAddr,
3709 gDvm.offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr);
The Android Open Source Project99409882009-03-18 22:20:24 -07003710
Andy McFadden8e696dc2009-07-24 15:28:16 -07003711 //LOGI("slow path for %p --> %p\n", buf, result);
3712
The Android Open Source Project99409882009-03-18 22:20:24 -07003713bail:
Andy McFadden8e5c7842009-07-23 17:47:18 -07003714 JNI_EXIT();
The Android Open Source Project99409882009-03-18 22:20:24 -07003715 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003716}
3717
3718/*
3719 * Get the capacity of the buffer for the specified java.nio.Buffer.
3720 *
Andy McFadden8e5c7842009-07-23 17:47:18 -07003721 * Returns -1 if the object is not a direct buffer. (We actually skip
3722 * this check, since it's expensive to determine, and just return the
3723 * capacity regardless.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003724 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003725static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003726{
Andy McFadden8e5c7842009-07-23 17:47:18 -07003727 JNI_ENTER();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003728
Andy McFadden8e5c7842009-07-23 17:47:18 -07003729 /*
3730 * The capacity is always in the Buffer.capacity field.
3731 *
3732 * (The "check" version should verify that this is actually a Buffer,
3733 * but we're not required to do so here.)
3734 */
Andy McFaddenab00d452009-08-19 07:21:41 -07003735 Object* buf = dvmDecodeIndirectRef(env, jbuf);
3736 jlong result = dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003737
Andy McFadden8e5c7842009-07-23 17:47:18 -07003738 JNI_EXIT();
The Android Open Source Project99409882009-03-18 22:20:24 -07003739 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003740}
3741
3742
3743/*
3744 * ===========================================================================
3745 * JNI invocation functions
3746 * ===========================================================================
3747 */
3748
3749/*
3750 * Handle AttachCurrentThread{AsDaemon}.
3751 *
3752 * We need to make sure the VM is actually running. For example, if we start
3753 * up, issue an Attach, and the VM exits almost immediately, by the time the
3754 * attaching happens the VM could already be shutting down.
3755 *
3756 * It's hard to avoid a race condition here because we don't want to hold
3757 * a lock across the entire operation. What we can do is temporarily
3758 * increment the thread count to prevent a VM exit.
3759 *
3760 * This could potentially still have problems if a daemon thread calls here
3761 * while the VM is shutting down. dvmThreadSelf() will work, since it just
3762 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
3763 * you shut down a VM while threads are still running inside it.
3764 *
3765 * Remember that some code may call this as a way to find the per-thread
3766 * JNIEnv pointer. Don't do excess work for that case.
3767 */
3768static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args,
3769 bool isDaemon)
3770{
3771 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
3772 Thread* self;
3773 bool result = false;
3774
3775 /*
3776 * Return immediately if we're already one with the VM.
3777 */
3778 self = dvmThreadSelf();
3779 if (self != NULL) {
3780 *p_env = self->jniEnv;
3781 return JNI_OK;
3782 }
3783
3784 /*
3785 * No threads allowed in zygote mode.
3786 */
3787 if (gDvm.zygote) {
3788 return JNI_ERR;
3789 }
3790
3791 /* increment the count to keep the VM from bailing while we run */
3792 dvmLockThreadList(NULL);
3793 if (gDvm.nonDaemonThreadCount == 0) {
3794 // dead or dying
3795 LOGV("Refusing to attach thread '%s' -- VM is shutting down\n",
3796 (thr_args == NULL) ? "(unknown)" : args->name);
3797 dvmUnlockThreadList();
3798 return JNI_ERR;
3799 }
3800 gDvm.nonDaemonThreadCount++;
3801 dvmUnlockThreadList();
3802
3803 /* tweak the JavaVMAttachArgs as needed */
3804 JavaVMAttachArgs argsCopy;
3805 if (args == NULL) {
3806 /* allow the v1.1 calling convention */
3807 argsCopy.version = JNI_VERSION_1_2;
3808 argsCopy.name = NULL;
3809 argsCopy.group = dvmGetMainThreadGroup();
3810 } else {
3811 assert(args->version >= JNI_VERSION_1_2);
3812
3813 argsCopy.version = args->version;
3814 argsCopy.name = args->name;
3815 if (args->group != NULL)
3816 argsCopy.group = args->group;
3817 else
3818 argsCopy.group = dvmGetMainThreadGroup();
3819 }
3820
3821 result = dvmAttachCurrentThread(&argsCopy, isDaemon);
3822
3823 /* restore the count */
3824 dvmLockThreadList(NULL);
3825 gDvm.nonDaemonThreadCount--;
3826 dvmUnlockThreadList();
3827
3828 /*
3829 * Change the status to indicate that we're out in native code. This
3830 * call is not guarded with state-change macros, so we have to do it
3831 * by hand.
3832 */
3833 if (result) {
3834 self = dvmThreadSelf();
3835 assert(self != NULL);
3836 dvmChangeStatus(self, THREAD_NATIVE);
3837 *p_env = self->jniEnv;
3838 return JNI_OK;
3839 } else {
3840 return JNI_ERR;
3841 }
3842}
3843
3844/*
3845 * Attach the current thread to the VM. If the thread is already attached,
3846 * this is a no-op.
3847 */
3848static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args)
3849{
3850 return attachThread(vm, p_env, thr_args, false);
3851}
3852
3853/*
3854 * Like AttachCurrentThread, but set the "daemon" flag.
3855 */
3856static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env,
3857 void* thr_args)
3858{
3859 return attachThread(vm, p_env, thr_args, true);
3860}
3861
3862/*
3863 * Dissociate the current thread from the VM.
3864 */
3865static jint DetachCurrentThread(JavaVM* vm)
3866{
3867 Thread* self = dvmThreadSelf();
3868
3869 if (self == NULL) /* not attached, can't do anything */
3870 return JNI_ERR;
3871
3872 /* switch to "running" to check for suspension */
3873 dvmChangeStatus(self, THREAD_RUNNING);
3874
3875 /* detach the thread */
3876 dvmDetachCurrentThread();
3877
3878 /* (no need to change status back -- we have no status) */
3879 return JNI_OK;
3880}
3881
3882/*
3883 * If current thread is attached to VM, return the associated JNIEnv.
3884 * Otherwise, stuff NULL in and return JNI_EDETACHED.
3885 *
3886 * JVMTI overloads this by specifying a magic value for "version", so we
3887 * do want to check that here.
3888 */
3889static jint GetEnv(JavaVM* vm, void** env, jint version)
3890{
3891 Thread* self = dvmThreadSelf();
3892
3893 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6)
3894 return JNI_EVERSION;
3895
3896 if (self == NULL) {
3897 *env = NULL;
3898 } else {
3899 /* TODO: status change is probably unnecessary */
3900 dvmChangeStatus(self, THREAD_RUNNING);
3901 *env = (void*) dvmGetThreadJNIEnv(self);
3902 dvmChangeStatus(self, THREAD_NATIVE);
3903 }
3904 if (*env == NULL)
3905 return JNI_EDETACHED;
3906 else
3907 return JNI_OK;
3908}
3909
3910/*
3911 * Destroy the VM. This may be called from any thread.
3912 *
3913 * If the current thread is attached, wait until the current thread is
3914 * the only non-daemon user-level thread. If the current thread is not
3915 * attached, we attach it and do the processing as usual. (If the attach
3916 * fails, it's probably because all the non-daemon threads have already
3917 * exited and the VM doesn't want to let us back in.)
3918 *
3919 * TODO: we don't really deal with the situation where more than one thread
3920 * has called here. One thread wins, the other stays trapped waiting on
3921 * the condition variable forever. Not sure this situation is interesting
3922 * in real life.
3923 */
3924static jint DestroyJavaVM(JavaVM* vm)
3925{
3926 JavaVMExt* ext = (JavaVMExt*) vm;
3927 Thread* self;
3928
3929 if (ext == NULL)
3930 return JNI_ERR;
3931
Andy McFadden43eb5012010-02-01 16:56:53 -08003932 if (gDvm.verboseShutdown)
3933 LOGD("DestroyJavaVM waiting for non-daemon threads to exit\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003934
3935 /*
3936 * Sleep on a condition variable until it's okay to exit.
3937 */
3938 self = dvmThreadSelf();
3939 if (self == NULL) {
3940 JNIEnv* tmpEnv;
3941 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
3942 LOGV("Unable to reattach main for Destroy; assuming VM is "
3943 "shutting down (count=%d)\n",
3944 gDvm.nonDaemonThreadCount);
3945 goto shutdown;
3946 } else {
3947 LOGV("Attached to wait for shutdown in Destroy\n");
3948 }
3949 }
3950 dvmChangeStatus(self, THREAD_VMWAIT);
3951
3952 dvmLockThreadList(self);
3953 gDvm.nonDaemonThreadCount--; // remove current thread from count
3954
3955 while (gDvm.nonDaemonThreadCount > 0)
3956 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
3957
3958 dvmUnlockThreadList();
3959 self = NULL;
3960
3961shutdown:
3962 // TODO: call System.exit() to run any registered shutdown hooks
3963 // (this may not return -- figure out how this should work)
3964
Andy McFadden43eb5012010-02-01 16:56:53 -08003965 if (gDvm.verboseShutdown)
3966 LOGD("DestroyJavaVM shutting VM down\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003967 dvmShutdown();
3968
3969 // TODO - free resources associated with JNI-attached daemon threads
3970 free(ext->envList);
3971 free(ext);
3972
3973 return JNI_OK;
3974}
3975
3976
3977/*
3978 * ===========================================================================
3979 * Function tables
3980 * ===========================================================================
3981 */
3982
3983static const struct JNINativeInterface gNativeInterface = {
3984 NULL,
3985 NULL,
3986 NULL,
3987 NULL,
3988
3989 GetVersion,
3990
3991 DefineClass,
3992 FindClass,
3993
3994 FromReflectedMethod,
3995 FromReflectedField,
3996 ToReflectedMethod,
3997
3998 GetSuperclass,
3999 IsAssignableFrom,
4000
4001 ToReflectedField,
4002
4003 Throw,
4004 ThrowNew,
4005 ExceptionOccurred,
4006 ExceptionDescribe,
4007 ExceptionClear,
4008 FatalError,
4009
4010 PushLocalFrame,
4011 PopLocalFrame,
4012
4013 NewGlobalRef,
4014 DeleteGlobalRef,
4015 DeleteLocalRef,
4016 IsSameObject,
4017 NewLocalRef,
4018 EnsureLocalCapacity,
4019
4020 AllocObject,
4021 NewObject,
4022 NewObjectV,
4023 NewObjectA,
4024
4025 GetObjectClass,
4026 IsInstanceOf,
4027
4028 GetMethodID,
4029
4030 CallObjectMethod,
4031 CallObjectMethodV,
4032 CallObjectMethodA,
4033 CallBooleanMethod,
4034 CallBooleanMethodV,
4035 CallBooleanMethodA,
4036 CallByteMethod,
4037 CallByteMethodV,
4038 CallByteMethodA,
4039 CallCharMethod,
4040 CallCharMethodV,
4041 CallCharMethodA,
4042 CallShortMethod,
4043 CallShortMethodV,
4044 CallShortMethodA,
4045 CallIntMethod,
4046 CallIntMethodV,
4047 CallIntMethodA,
4048 CallLongMethod,
4049 CallLongMethodV,
4050 CallLongMethodA,
4051 CallFloatMethod,
4052 CallFloatMethodV,
4053 CallFloatMethodA,
4054 CallDoubleMethod,
4055 CallDoubleMethodV,
4056 CallDoubleMethodA,
4057 CallVoidMethod,
4058 CallVoidMethodV,
4059 CallVoidMethodA,
4060
4061 CallNonvirtualObjectMethod,
4062 CallNonvirtualObjectMethodV,
4063 CallNonvirtualObjectMethodA,
4064 CallNonvirtualBooleanMethod,
4065 CallNonvirtualBooleanMethodV,
4066 CallNonvirtualBooleanMethodA,
4067 CallNonvirtualByteMethod,
4068 CallNonvirtualByteMethodV,
4069 CallNonvirtualByteMethodA,
4070 CallNonvirtualCharMethod,
4071 CallNonvirtualCharMethodV,
4072 CallNonvirtualCharMethodA,
4073 CallNonvirtualShortMethod,
4074 CallNonvirtualShortMethodV,
4075 CallNonvirtualShortMethodA,
4076 CallNonvirtualIntMethod,
4077 CallNonvirtualIntMethodV,
4078 CallNonvirtualIntMethodA,
4079 CallNonvirtualLongMethod,
4080 CallNonvirtualLongMethodV,
4081 CallNonvirtualLongMethodA,
4082 CallNonvirtualFloatMethod,
4083 CallNonvirtualFloatMethodV,
4084 CallNonvirtualFloatMethodA,
4085 CallNonvirtualDoubleMethod,
4086 CallNonvirtualDoubleMethodV,
4087 CallNonvirtualDoubleMethodA,
4088 CallNonvirtualVoidMethod,
4089 CallNonvirtualVoidMethodV,
4090 CallNonvirtualVoidMethodA,
4091
4092 GetFieldID,
4093
4094 GetObjectField,
4095 GetBooleanField,
4096 GetByteField,
4097 GetCharField,
4098 GetShortField,
4099 GetIntField,
4100 GetLongField,
4101 GetFloatField,
4102 GetDoubleField,
4103 SetObjectField,
4104 SetBooleanField,
4105 SetByteField,
4106 SetCharField,
4107 SetShortField,
4108 SetIntField,
4109 SetLongField,
4110 SetFloatField,
4111 SetDoubleField,
4112
4113 GetStaticMethodID,
4114
4115 CallStaticObjectMethod,
4116 CallStaticObjectMethodV,
4117 CallStaticObjectMethodA,
4118 CallStaticBooleanMethod,
4119 CallStaticBooleanMethodV,
4120 CallStaticBooleanMethodA,
4121 CallStaticByteMethod,
4122 CallStaticByteMethodV,
4123 CallStaticByteMethodA,
4124 CallStaticCharMethod,
4125 CallStaticCharMethodV,
4126 CallStaticCharMethodA,
4127 CallStaticShortMethod,
4128 CallStaticShortMethodV,
4129 CallStaticShortMethodA,
4130 CallStaticIntMethod,
4131 CallStaticIntMethodV,
4132 CallStaticIntMethodA,
4133 CallStaticLongMethod,
4134 CallStaticLongMethodV,
4135 CallStaticLongMethodA,
4136 CallStaticFloatMethod,
4137 CallStaticFloatMethodV,
4138 CallStaticFloatMethodA,
4139 CallStaticDoubleMethod,
4140 CallStaticDoubleMethodV,
4141 CallStaticDoubleMethodA,
4142 CallStaticVoidMethod,
4143 CallStaticVoidMethodV,
4144 CallStaticVoidMethodA,
4145
4146 GetStaticFieldID,
4147
4148 GetStaticObjectField,
4149 GetStaticBooleanField,
4150 GetStaticByteField,
4151 GetStaticCharField,
4152 GetStaticShortField,
4153 GetStaticIntField,
4154 GetStaticLongField,
4155 GetStaticFloatField,
4156 GetStaticDoubleField,
4157
4158 SetStaticObjectField,
4159 SetStaticBooleanField,
4160 SetStaticByteField,
4161 SetStaticCharField,
4162 SetStaticShortField,
4163 SetStaticIntField,
4164 SetStaticLongField,
4165 SetStaticFloatField,
4166 SetStaticDoubleField,
4167
4168 NewString,
4169
4170 GetStringLength,
4171 GetStringChars,
4172 ReleaseStringChars,
4173
4174 NewStringUTF,
4175 GetStringUTFLength,
4176 GetStringUTFChars,
4177 ReleaseStringUTFChars,
4178
4179 GetArrayLength,
4180 NewObjectArray,
4181 GetObjectArrayElement,
4182 SetObjectArrayElement,
4183
4184 NewBooleanArray,
4185 NewByteArray,
4186 NewCharArray,
4187 NewShortArray,
4188 NewIntArray,
4189 NewLongArray,
4190 NewFloatArray,
4191 NewDoubleArray,
4192
4193 GetBooleanArrayElements,
4194 GetByteArrayElements,
4195 GetCharArrayElements,
4196 GetShortArrayElements,
4197 GetIntArrayElements,
4198 GetLongArrayElements,
4199 GetFloatArrayElements,
4200 GetDoubleArrayElements,
4201
4202 ReleaseBooleanArrayElements,
4203 ReleaseByteArrayElements,
4204 ReleaseCharArrayElements,
4205 ReleaseShortArrayElements,
4206 ReleaseIntArrayElements,
4207 ReleaseLongArrayElements,
4208 ReleaseFloatArrayElements,
4209 ReleaseDoubleArrayElements,
4210
4211 GetBooleanArrayRegion,
4212 GetByteArrayRegion,
4213 GetCharArrayRegion,
4214 GetShortArrayRegion,
4215 GetIntArrayRegion,
4216 GetLongArrayRegion,
4217 GetFloatArrayRegion,
4218 GetDoubleArrayRegion,
4219 SetBooleanArrayRegion,
4220 SetByteArrayRegion,
4221 SetCharArrayRegion,
4222 SetShortArrayRegion,
4223 SetIntArrayRegion,
4224 SetLongArrayRegion,
4225 SetFloatArrayRegion,
4226 SetDoubleArrayRegion,
4227
4228 RegisterNatives,
4229 UnregisterNatives,
4230
4231 MonitorEnter,
4232 MonitorExit,
4233
4234 GetJavaVM,
4235
4236 GetStringRegion,
4237 GetStringUTFRegion,
4238
4239 GetPrimitiveArrayCritical,
4240 ReleasePrimitiveArrayCritical,
4241
4242 GetStringCritical,
4243 ReleaseStringCritical,
4244
4245 NewWeakGlobalRef,
4246 DeleteWeakGlobalRef,
4247
4248 ExceptionCheck,
4249
4250 NewDirectByteBuffer,
4251 GetDirectBufferAddress,
4252 GetDirectBufferCapacity,
4253
4254 GetObjectRefType
4255};
4256static const struct JNIInvokeInterface gInvokeInterface = {
4257 NULL,
4258 NULL,
4259 NULL,
4260
4261 DestroyJavaVM,
4262 AttachCurrentThread,
4263 DetachCurrentThread,
4264
4265 GetEnv,
4266
4267 AttachCurrentThreadAsDaemon,
4268};
4269
4270
4271/*
4272 * ===========================================================================
4273 * VM/Env creation
4274 * ===========================================================================
4275 */
4276
4277/*
4278 * Enable "checked JNI" after the VM has partially started. This must
4279 * only be called in "zygote" mode, when we have one thread running.
Andy McFadden59b61772009-05-13 16:44:34 -07004280 *
4281 * This doesn't attempt to rewrite the JNI call bridge associated with
4282 * native methods, so we won't get those checks for any methods that have
4283 * already been resolved.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004284 */
4285void dvmLateEnableCheckedJni(void)
4286{
4287 JNIEnvExt* extEnv;
4288 JavaVMExt* extVm;
Andy McFaddenab00d452009-08-19 07:21:41 -07004289
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004290 extEnv = dvmGetJNIEnvForThread();
4291 if (extEnv == NULL) {
4292 LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv\n");
4293 return;
4294 }
4295 extVm = extEnv->vm;
4296 assert(extVm != NULL);
4297
4298 if (!extVm->useChecked) {
4299 LOGD("Late-enabling CheckJNI\n");
4300 dvmUseCheckedJniVm(extVm);
4301 extVm->useChecked = true;
4302 dvmUseCheckedJniEnv(extEnv);
4303
4304 /* currently no way to pick up jniopts features */
4305 } else {
4306 LOGD("Not late-enabling CheckJNI (already on)\n");
4307 }
4308}
4309
4310/*
4311 * Not supported.
4312 */
4313jint JNI_GetDefaultJavaVMInitArgs(void* vm_args)
4314{
4315 return JNI_ERR;
4316}
4317
4318/*
4319 * Return a buffer full of created VMs.
4320 *
4321 * We always have zero or one.
4322 */
4323jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
4324{
4325 if (gDvm.vmList != NULL) {
4326 *nVMs = 1;
4327
4328 if (bufLen > 0)
4329 *vmBuf++ = gDvm.vmList;
4330 } else {
4331 *nVMs = 0;
4332 }
4333
4334 return JNI_OK;
4335}
4336
4337
4338/*
4339 * Create a new VM instance.
4340 *
4341 * The current thread becomes the main VM thread. We return immediately,
4342 * which effectively means the caller is executing in a native method.
4343 */
4344jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)
4345{
4346 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
4347 JNIEnvExt* pEnv = NULL;
4348 JavaVMExt* pVM = NULL;
4349 const char** argv;
4350 int argc = 0;
4351 int i, curOpt;
4352 int result = JNI_ERR;
4353 bool checkJni = false;
4354 bool warnError = true;
4355 bool forceDataCopy = false;
4356
4357 if (args->version < JNI_VERSION_1_2)
4358 return JNI_EVERSION;
4359
4360 // TODO: don't allow creation of multiple VMs -- one per customer for now
4361
4362 /* zero globals; not strictly necessary the first time a VM is started */
4363 memset(&gDvm, 0, sizeof(gDvm));
4364
4365 /*
4366 * Set up structures for JNIEnv and VM.
4367 */
4368 //pEnv = (JNIEnvExt*) malloc(sizeof(JNIEnvExt));
4369 pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
4370
4371 //memset(pEnv, 0, sizeof(JNIEnvExt));
4372 //pEnv->funcTable = &gNativeInterface;
4373 //pEnv->vm = pVM;
4374 memset(pVM, 0, sizeof(JavaVMExt));
4375 pVM->funcTable = &gInvokeInterface;
4376 pVM->envList = pEnv;
4377 dvmInitMutex(&pVM->envListLock);
4378
4379 argv = (const char**) malloc(sizeof(char*) * (args->nOptions));
4380 memset(argv, 0, sizeof(char*) * (args->nOptions));
4381
4382 curOpt = 0;
4383
4384 /*
4385 * Convert JNI args to argv.
4386 *
4387 * We have to pull out vfprintf/exit/abort, because they use the
4388 * "extraInfo" field to pass function pointer "hooks" in. We also
4389 * look for the -Xcheck:jni stuff here.
4390 */
4391 for (i = 0; i < args->nOptions; i++) {
4392 const char* optStr = args->options[i].optionString;
4393
4394 if (optStr == NULL) {
4395 fprintf(stderr, "ERROR: arg %d string was null\n", i);
4396 goto bail;
4397 } else if (strcmp(optStr, "vfprintf") == 0) {
4398 gDvm.vfprintfHook = args->options[i].extraInfo;
4399 } else if (strcmp(optStr, "exit") == 0) {
4400 gDvm.exitHook = args->options[i].extraInfo;
4401 } else if (strcmp(optStr, "abort") == 0) {
4402 gDvm.abortHook = args->options[i].extraInfo;
4403 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
4404 checkJni = true;
4405 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
4406 const char* jniOpts = optStr + 9;
4407 while (jniOpts != NULL) {
4408 jniOpts++; /* skip past ':' or ',' */
4409 if (strncmp(jniOpts, "warnonly", 8) == 0) {
4410 warnError = false;
4411 } else if (strncmp(jniOpts, "forcecopy", 9) == 0) {
4412 forceDataCopy = true;
4413 } else {
4414 LOGW("unknown jni opt starting at '%s'\n", jniOpts);
4415 }
4416 jniOpts = strchr(jniOpts, ',');
4417 }
4418 } else {
4419 /* regular option */
4420 argv[curOpt++] = optStr;
4421 }
4422 }
4423 argc = curOpt;
4424
4425 if (checkJni) {
4426 dvmUseCheckedJniVm(pVM);
4427 pVM->useChecked = true;
4428 }
4429 pVM->warnError = warnError;
4430 pVM->forceDataCopy = forceDataCopy;
4431
4432 /* set this up before initializing VM, so it can create some JNIEnvs */
4433 gDvm.vmList = (JavaVM*) pVM;
4434
4435 /*
4436 * Create an env for main thread. We need to have something set up
4437 * here because some of the class initialization we do when starting
4438 * up the VM will call into native code.
4439 */
4440 pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
4441
4442 /* initialize VM */
4443 gDvm.initializing = true;
4444 if (dvmStartup(argc, argv, args->ignoreUnrecognized, (JNIEnv*)pEnv) != 0) {
4445 free(pEnv);
4446 free(pVM);
4447 goto bail;
4448 }
4449
4450 /*
4451 * Success! Return stuff to caller.
4452 */
4453 dvmChangeStatus(NULL, THREAD_NATIVE);
4454 *p_env = (JNIEnv*) pEnv;
4455 *p_vm = (JavaVM*) pVM;
4456 result = JNI_OK;
4457
4458bail:
4459 gDvm.initializing = false;
4460 if (result == JNI_OK)
4461 LOGV("JNI_CreateJavaVM succeeded\n");
4462 else
4463 LOGW("JNI_CreateJavaVM failed\n");
4464 free(argv);
4465 return result;
4466}