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