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