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