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