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