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