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