Jni.cpp revision a62c3a0ab3fcdde37f47d16e9699a935ae7a8e88
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 /* start point of invocation interface */ 1231 if (!gDvm.initializing) { 1232 loader = trackedLoader = dvmGetSystemClassLoader(); 1233 } else { 1234 loader = NULL; 1235 } 1236 } else { 1237 loader = thisMethod->clazz->classLoader; 1238 } 1239 1240 char* descriptor = dvmNameToDescriptor(name); 1241 if (descriptor == NULL) { 1242 return NULL; 1243 } 1244 ClassObject* clazz = dvmFindClassNoInit(descriptor, loader); 1245 free(descriptor); 1246 1247 jclass jclazz = (jclass) addLocalReference(env, (Object*) clazz); 1248 dvmReleaseTrackedAlloc(trackedLoader, ts.self()); 1249 return jclazz; 1250} 1251 1252/* 1253 * Return the superclass of a class. 1254 */ 1255static jclass GetSuperclass(JNIEnv* env, jclass jclazz) { 1256 ScopedJniThreadState ts(env); 1257 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1258 return (jclass) addLocalReference(env, (Object*)clazz->super); 1259} 1260 1261/* 1262 * Determine whether an object of clazz1 can be safely cast to clazz2. 1263 * 1264 * Like IsInstanceOf, but with a pair of class objects instead of obj+class. 1265 */ 1266static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) { 1267 ScopedJniThreadState ts(env); 1268 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1); 1269 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2); 1270 return dvmInstanceof(clazz1, clazz2); 1271} 1272 1273/* 1274 * Given a java.lang.reflect.Method or .Constructor, return a methodID. 1275 */ 1276static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) { 1277 ScopedJniThreadState ts(env); 1278 Object* method = dvmDecodeIndirectRef(env, jmethod); 1279 return (jmethodID) dvmGetMethodFromReflectObj(method); 1280} 1281 1282/* 1283 * Given a java.lang.reflect.Field, return a fieldID. 1284 */ 1285static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) { 1286 ScopedJniThreadState ts(env); 1287 Object* field = dvmDecodeIndirectRef(env, jfield); 1288 return (jfieldID) dvmGetFieldFromReflectObj(field); 1289} 1290 1291/* 1292 * Convert a methodID to a java.lang.reflect.Method or .Constructor. 1293 * 1294 * (The "isStatic" field does not appear in the spec.) 1295 * 1296 * Throws OutOfMemory and returns NULL on failure. 1297 */ 1298static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) { 1299 ScopedJniThreadState ts(env); 1300 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls); 1301 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID); 1302 dvmReleaseTrackedAlloc(obj, NULL); 1303 return addLocalReference(env, obj); 1304} 1305 1306/* 1307 * Convert a fieldID to a java.lang.reflect.Field. 1308 * 1309 * (The "isStatic" field does not appear in the spec.) 1310 * 1311 * Throws OutOfMemory and returns NULL on failure. 1312 */ 1313static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) { 1314 ScopedJniThreadState ts(env); 1315 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls); 1316 Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID); 1317 dvmReleaseTrackedAlloc(obj, NULL); 1318 return addLocalReference(env, obj); 1319} 1320 1321/* 1322 * Take this exception and throw it. 1323 */ 1324static jint Throw(JNIEnv* env, jthrowable jobj) { 1325 ScopedJniThreadState ts(env); 1326 if (jobj != NULL) { 1327 Object* obj = dvmDecodeIndirectRef(env, jobj); 1328 dvmSetException(ts.self(), obj); 1329 return JNI_OK; 1330 } 1331 return JNI_ERR; 1332} 1333 1334/* 1335 * Constructs an exception object from the specified class with the message 1336 * specified by "message", and throws it. 1337 */ 1338static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) { 1339 ScopedJniThreadState ts(env); 1340 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1341 dvmThrowException(clazz, message); 1342 // TODO: should return failure if this didn't work (e.g. OOM) 1343 return JNI_OK; 1344} 1345 1346/* 1347 * If an exception is being thrown, return the exception object. Otherwise, 1348 * return NULL. 1349 * 1350 * TODO: if there is no pending exception, we should be able to skip the 1351 * enter/exit checks. If we find one, we need to enter and then re-fetch 1352 * the exception (in case it got moved by a compacting GC). 1353 */ 1354static jthrowable ExceptionOccurred(JNIEnv* env) { 1355 ScopedJniThreadState ts(env); 1356 Object* exception = dvmGetException(ts.self()); 1357 jthrowable localException = (jthrowable) addLocalReference(env, exception); 1358 if (localException == NULL && exception != NULL) { 1359 /* 1360 * We were unable to add a new local reference, and threw a new 1361 * exception. We can't return "exception", because it's not a 1362 * local reference. So we have to return NULL, indicating that 1363 * there was no exception, even though it's pretty much raining 1364 * exceptions in here. 1365 */ 1366 LOGW("JNI WARNING: addLocal/exception combo"); 1367 } 1368 return localException; 1369} 1370 1371/* 1372 * Print an exception and stack trace to stderr. 1373 */ 1374static void ExceptionDescribe(JNIEnv* env) { 1375 ScopedJniThreadState ts(env); 1376 Object* exception = dvmGetException(ts.self()); 1377 if (exception != NULL) { 1378 dvmPrintExceptionStackTrace(); 1379 } else { 1380 LOGI("Odd: ExceptionDescribe called, but no exception pending"); 1381 } 1382} 1383 1384/* 1385 * Clear the exception currently being thrown. 1386 * 1387 * TODO: we should be able to skip the enter/exit stuff. 1388 */ 1389static void ExceptionClear(JNIEnv* env) { 1390 ScopedJniThreadState ts(env); 1391 dvmClearException(ts.self()); 1392} 1393 1394/* 1395 * Kill the VM. This function does not return. 1396 */ 1397static void FatalError(JNIEnv* env, const char* msg) { 1398 //dvmChangeStatus(NULL, THREAD_RUNNING); 1399 LOGE("JNI posting fatal error: %s", msg); 1400 dvmAbort(); 1401} 1402 1403/* 1404 * Push a new JNI frame on the stack, with a new set of locals. 1405 * 1406 * The new frame must have the same method pointer. (If for no other 1407 * reason than FindClass needs it to get the appropriate class loader.) 1408 */ 1409static jint PushLocalFrame(JNIEnv* env, jint capacity) { 1410 ScopedJniThreadState ts(env); 1411 if (!ensureLocalCapacity(env, capacity) || 1412 !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod())) 1413 { 1414 /* yes, OutOfMemoryError, not StackOverflowError */ 1415 dvmClearException(ts.self()); 1416 dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame"); 1417 return JNI_ERR; 1418 } 1419 return JNI_OK; 1420} 1421 1422/* 1423 * Pop the local frame off. If "jresult" is not null, add it as a 1424 * local reference on the now-current frame. 1425 */ 1426static jobject PopLocalFrame(JNIEnv* env, jobject jresult) { 1427 ScopedJniThreadState ts(env); 1428 Object* result = dvmDecodeIndirectRef(env, jresult); 1429 if (!dvmPopLocalFrame(ts.self())) { 1430 LOGW("JNI WARNING: too many PopLocalFrame calls"); 1431 dvmClearException(ts.self()); 1432 dvmThrowRuntimeException("too many PopLocalFrame calls"); 1433 } 1434 return addLocalReference(env, result); 1435} 1436 1437/* 1438 * Add a reference to the global list. 1439 */ 1440static jobject NewGlobalRef(JNIEnv* env, jobject jobj) { 1441 ScopedJniThreadState ts(env); 1442 Object* obj = dvmDecodeIndirectRef(env, jobj); 1443 return addGlobalReference(obj); 1444} 1445 1446/* 1447 * Delete a reference from the global list. 1448 */ 1449static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) { 1450 ScopedJniThreadState ts(env); 1451 deleteGlobalReference(jglobalRef); 1452} 1453 1454 1455/* 1456 * Add a reference to the local list. 1457 */ 1458static jobject NewLocalRef(JNIEnv* env, jobject jobj) { 1459 ScopedJniThreadState ts(env); 1460 Object* obj = dvmDecodeIndirectRef(env, jobj); 1461 return addLocalReference(env, obj); 1462} 1463 1464/* 1465 * Delete a reference from the local list. 1466 */ 1467static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) { 1468 ScopedJniThreadState ts(env); 1469 deleteLocalReference(env, jlocalRef); 1470} 1471 1472/* 1473 * Ensure that the local references table can hold at least this many 1474 * references. 1475 */ 1476static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) { 1477 ScopedJniThreadState ts(env); 1478 bool okay = ensureLocalCapacity(env, capacity); 1479 if (!okay) { 1480 dvmThrowOutOfMemoryError("can't ensure local reference capacity"); 1481 } 1482 return okay ? 0 : -1; 1483} 1484 1485 1486/* 1487 * Determine whether two Object references refer to the same underlying object. 1488 */ 1489static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) { 1490 ScopedJniThreadState ts(env); 1491 Object* obj1 = dvmDecodeIndirectRef(env, jref1); 1492 Object* obj2 = dvmDecodeIndirectRef(env, jref2); 1493 return (obj1 == obj2); 1494} 1495 1496/* 1497 * Allocate a new object without invoking any constructors. 1498 */ 1499static jobject AllocObject(JNIEnv* env, jclass jclazz) { 1500 ScopedJniThreadState ts(env); 1501 1502 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1503 if (!canAllocClass(clazz) || 1504 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) 1505 { 1506 assert(dvmCheckException(ts.self())); 1507 return NULL; 1508 } 1509 1510 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK); 1511 return addLocalReference(env, newObj); 1512} 1513 1514/* 1515 * Allocate a new object and invoke the supplied constructor. 1516 */ 1517static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) { 1518 ScopedJniThreadState ts(env); 1519 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1520 1521 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) { 1522 assert(dvmCheckException(ts.self())); 1523 return NULL; 1524 } 1525 1526 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK); 1527 jobject result = addLocalReference(env, newObj); 1528 if (newObj != NULL) { 1529 JValue unused; 1530 va_list args; 1531 va_start(args, methodID); 1532 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args); 1533 va_end(args); 1534 } 1535 return result; 1536} 1537 1538static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) { 1539 ScopedJniThreadState ts(env); 1540 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1541 1542 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) { 1543 assert(dvmCheckException(ts.self())); 1544 return NULL; 1545 } 1546 1547 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK); 1548 jobject result = addLocalReference(env, newObj); 1549 if (newObj != NULL) { 1550 JValue unused; 1551 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args); 1552 } 1553 return result; 1554} 1555 1556static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) { 1557 ScopedJniThreadState ts(env); 1558 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1559 1560 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) { 1561 assert(dvmCheckException(ts.self())); 1562 return NULL; 1563 } 1564 1565 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK); 1566 jobject result = addLocalReference(env, newObj); 1567 if (newObj != NULL) { 1568 JValue unused; 1569 dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args); 1570 } 1571 return result; 1572} 1573 1574/* 1575 * Returns the class of an object. 1576 * 1577 * JNI spec says: obj must not be NULL. 1578 */ 1579static jclass GetObjectClass(JNIEnv* env, jobject jobj) { 1580 ScopedJniThreadState ts(env); 1581 1582 assert(jobj != NULL); 1583 1584 Object* obj = dvmDecodeIndirectRef(env, jobj); 1585 return (jclass) addLocalReference(env, (Object*) obj->clazz); 1586} 1587 1588/* 1589 * Determine whether "obj" is an instance of "clazz". 1590 */ 1591static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) { 1592 ScopedJniThreadState ts(env); 1593 1594 assert(jclazz != NULL); 1595 if (jobj == NULL) { 1596 return true; 1597 } 1598 1599 Object* obj = dvmDecodeIndirectRef(env, jobj); 1600 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1601 return dvmInstanceof(obj->clazz, clazz); 1602} 1603 1604/* 1605 * Get a method ID for an instance method. 1606 * 1607 * While Dalvik bytecode has distinct instructions for virtual, super, 1608 * static, direct, and interface method invocation, JNI only provides 1609 * two functions for acquiring a method ID. This call handles everything 1610 * but static methods. 1611 * 1612 * JNI defines <init> as an instance method, but Dalvik considers it a 1613 * "direct" method, so we have to special-case it here. 1614 * 1615 * Dalvik also puts all private methods into the "direct" list, so we 1616 * really need to just search both lists. 1617 */ 1618static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) { 1619 ScopedJniThreadState ts(env); 1620 1621 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1622 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { 1623 assert(dvmCheckException(ts.self())); 1624 } else if (dvmIsInterfaceClass(clazz)) { 1625 Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig); 1626 if (meth == NULL) { 1627 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError, 1628 "no method with name='%s' signature='%s' in interface %s", 1629 name, sig, clazz->descriptor); 1630 } 1631 return (jmethodID) meth; 1632 } 1633 Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig); 1634 if (meth == NULL) { 1635 /* search private methods and constructors; non-hierarchical */ 1636 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig); 1637 } 1638 if (meth != NULL && dvmIsStaticMethod(meth)) { 1639 IF_LOGD() { 1640 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); 1641 LOGD("GetMethodID: not returning static method %s.%s %s", 1642 clazz->descriptor, meth->name, desc); 1643 free(desc); 1644 } 1645 meth = NULL; 1646 } 1647 if (meth == NULL) { 1648 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError, 1649 "no method with name='%s' signature='%s' in class %s", 1650 name, sig, clazz->descriptor); 1651 } else { 1652 /* 1653 * The method's class may not be the same as clazz, but if 1654 * it isn't this must be a virtual method and the class must 1655 * be a superclass (and, hence, already initialized). 1656 */ 1657 assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz)); 1658 } 1659 return (jmethodID) meth; 1660} 1661 1662/* 1663 * Get a field ID (instance fields). 1664 */ 1665static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) { 1666 ScopedJniThreadState ts(env); 1667 1668 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1669 1670 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { 1671 assert(dvmCheckException(ts.self())); 1672 return NULL; 1673 } 1674 1675 jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig); 1676 if (id == NULL) { 1677 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError, 1678 "no field with name='%s' signature='%s' in class %s", 1679 name, sig, clazz->descriptor); 1680 } 1681 return id; 1682} 1683 1684/* 1685 * Get the method ID for a static method in a class. 1686 */ 1687static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) { 1688 ScopedJniThreadState ts(env); 1689 1690 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1691 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { 1692 assert(dvmCheckException(ts.self())); 1693 return NULL; 1694 } 1695 1696 Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig); 1697 1698 /* make sure it's static, not virtual+private */ 1699 if (meth != NULL && !dvmIsStaticMethod(meth)) { 1700 IF_LOGD() { 1701 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); 1702 LOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s", 1703 clazz->descriptor, meth->name, desc); 1704 free(desc); 1705 } 1706 meth = NULL; 1707 } 1708 1709 jmethodID id = (jmethodID) meth; 1710 if (id == NULL) { 1711 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError, 1712 "no static method with name='%s' signature='%s' in class %s", 1713 name, sig, clazz->descriptor); 1714 } 1715 return id; 1716} 1717 1718/* 1719 * Get a field ID (static fields). 1720 */ 1721static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) { 1722 ScopedJniThreadState ts(env); 1723 1724 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1725 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { 1726 assert(dvmCheckException(ts.self())); 1727 return NULL; 1728 } 1729 1730 jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig); 1731 if (id == NULL) { 1732 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError, 1733 "no static field with name='%s' signature='%s' in class %s", 1734 name, sig, clazz->descriptor); 1735 } 1736 return id; 1737} 1738 1739/* 1740 * Get a static field. 1741 * 1742 * If we get an object reference, add it to the local refs list. 1743 */ 1744#define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \ 1745 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \ 1746 jfieldID fieldID) \ 1747 { \ 1748 UNUSED_PARAMETER(jclazz); \ 1749 ScopedJniThreadState ts(env); \ 1750 StaticField* sfield = (StaticField*) fieldID; \ 1751 _ctype value; \ 1752 if (dvmIsVolatileField(&sfield->field)) { \ 1753 if (_isref) { /* only when _ctype==jobject */ \ 1754 Object* obj = dvmGetStaticFieldObjectVolatile(sfield); \ 1755 value = (_ctype)(u4)addLocalReference(env, obj); \ 1756 } else { \ 1757 value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\ 1758 } \ 1759 } else { \ 1760 if (_isref) { \ 1761 Object* obj = dvmGetStaticFieldObject(sfield); \ 1762 value = (_ctype)(u4)addLocalReference(env, obj); \ 1763 } else { \ 1764 value = (_ctype) dvmGetStaticField##_jname(sfield); \ 1765 } \ 1766 } \ 1767 return value; \ 1768 } 1769GET_STATIC_TYPE_FIELD(jobject, Object, true); 1770GET_STATIC_TYPE_FIELD(jboolean, Boolean, false); 1771GET_STATIC_TYPE_FIELD(jbyte, Byte, false); 1772GET_STATIC_TYPE_FIELD(jchar, Char, false); 1773GET_STATIC_TYPE_FIELD(jshort, Short, false); 1774GET_STATIC_TYPE_FIELD(jint, Int, false); 1775GET_STATIC_TYPE_FIELD(jlong, Long, false); 1776GET_STATIC_TYPE_FIELD(jfloat, Float, false); 1777GET_STATIC_TYPE_FIELD(jdouble, Double, false); 1778 1779/* 1780 * Set a static field. 1781 */ 1782#define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \ 1783 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \ 1784 jfieldID fieldID, _ctype value) \ 1785 { \ 1786 UNUSED_PARAMETER(jclazz); \ 1787 ScopedJniThreadState ts(env); \ 1788 StaticField* sfield = (StaticField*) fieldID; \ 1789 if (dvmIsVolatileField(&sfield->field)) { \ 1790 if (_isref) { /* only when _ctype==jobject */ \ 1791 Object* valObj = \ 1792 dvmDecodeIndirectRef(env, (jobject)(u4)value); \ 1793 dvmSetStaticFieldObjectVolatile(sfield, valObj); \ 1794 } else { \ 1795 dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\ 1796 } \ 1797 } else { \ 1798 if (_isref) { \ 1799 Object* valObj = \ 1800 dvmDecodeIndirectRef(env, (jobject)(u4)value); \ 1801 dvmSetStaticFieldObject(sfield, valObj); \ 1802 } else { \ 1803 dvmSetStaticField##_jname(sfield, (_ctype2)value); \ 1804 } \ 1805 } \ 1806 } 1807SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true); 1808SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false); 1809SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false); 1810SET_STATIC_TYPE_FIELD(jchar, u2, Char, false); 1811SET_STATIC_TYPE_FIELD(jshort, s2, Short, false); 1812SET_STATIC_TYPE_FIELD(jint, s4, Int, false); 1813SET_STATIC_TYPE_FIELD(jlong, s8, Long, false); 1814SET_STATIC_TYPE_FIELD(jfloat, float, Float, false); 1815SET_STATIC_TYPE_FIELD(jdouble, double, Double, false); 1816 1817/* 1818 * Get an instance field. 1819 * 1820 * If we get an object reference, add it to the local refs list. 1821 */ 1822#define GET_TYPE_FIELD(_ctype, _jname, _isref) \ 1823 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \ 1824 jfieldID fieldID) \ 1825 { \ 1826 ScopedJniThreadState ts(env); \ 1827 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1828 InstField* field = (InstField*) fieldID; \ 1829 _ctype value; \ 1830 if (dvmIsVolatileField(&field->field)) { \ 1831 if (_isref) { /* only when _ctype==jobject */ \ 1832 Object* valObj = \ 1833 dvmGetFieldObjectVolatile(obj, field->byteOffset); \ 1834 value = (_ctype)(u4)addLocalReference(env, valObj); \ 1835 } else { \ 1836 value = (_ctype) \ 1837 dvmGetField##_jname##Volatile(obj, field->byteOffset); \ 1838 } \ 1839 } else { \ 1840 if (_isref) { \ 1841 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \ 1842 value = (_ctype)(u4)addLocalReference(env, valObj); \ 1843 } else { \ 1844 value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\ 1845 } \ 1846 } \ 1847 return value; \ 1848 } 1849GET_TYPE_FIELD(jobject, Object, true); 1850GET_TYPE_FIELD(jboolean, Boolean, false); 1851GET_TYPE_FIELD(jbyte, Byte, false); 1852GET_TYPE_FIELD(jchar, Char, false); 1853GET_TYPE_FIELD(jshort, Short, false); 1854GET_TYPE_FIELD(jint, Int, false); 1855GET_TYPE_FIELD(jlong, Long, false); 1856GET_TYPE_FIELD(jfloat, Float, false); 1857GET_TYPE_FIELD(jdouble, Double, false); 1858 1859/* 1860 * Set an instance field. 1861 */ 1862#define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \ 1863 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \ 1864 jfieldID fieldID, _ctype value) \ 1865 { \ 1866 ScopedJniThreadState ts(env); \ 1867 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1868 InstField* field = (InstField*) fieldID; \ 1869 if (dvmIsVolatileField(&field->field)) { \ 1870 if (_isref) { /* only when _ctype==jobject */ \ 1871 Object* valObj = \ 1872 dvmDecodeIndirectRef(env, (jobject)(u4)value); \ 1873 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj); \ 1874 } else { \ 1875 dvmSetField##_jname##Volatile(obj, \ 1876 field->byteOffset, (_ctype2)value); \ 1877 } \ 1878 } else { \ 1879 if (_isref) { \ 1880 Object* valObj = \ 1881 dvmDecodeIndirectRef(env, (jobject)(u4)value); \ 1882 dvmSetFieldObject(obj, field->byteOffset, valObj); \ 1883 } else { \ 1884 dvmSetField##_jname(obj, \ 1885 field->byteOffset, (_ctype2)value); \ 1886 } \ 1887 } \ 1888 } 1889SET_TYPE_FIELD(jobject, Object*, Object, true); 1890SET_TYPE_FIELD(jboolean, bool, Boolean, false); 1891SET_TYPE_FIELD(jbyte, s1, Byte, false); 1892SET_TYPE_FIELD(jchar, u2, Char, false); 1893SET_TYPE_FIELD(jshort, s2, Short, false); 1894SET_TYPE_FIELD(jint, s4, Int, false); 1895SET_TYPE_FIELD(jlong, s8, Long, false); 1896SET_TYPE_FIELD(jfloat, float, Float, false); 1897SET_TYPE_FIELD(jdouble, double, Double, false); 1898 1899/* 1900 * Make a virtual method call. 1901 * 1902 * Three versions (..., va_list, jvalue[]) for each return type. If we're 1903 * returning an Object, we have to add it to the local references table. 1904 */ 1905#define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \ 1906 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \ 1907 jmethodID methodID, ...) \ 1908 { \ 1909 ScopedJniThreadState ts(env); \ 1910 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1911 const Method* meth; \ 1912 va_list args; \ 1913 JValue result; \ 1914 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \ 1915 if (meth == NULL) { \ 1916 return _retfail; \ 1917 } \ 1918 va_start(args, methodID); \ 1919 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \ 1920 va_end(args); \ 1921 if (_isref && !dvmCheckException(ts.self())) \ 1922 result.l = (Object*)addLocalReference(env, result.l); \ 1923 return _retok; \ 1924 } \ 1925 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \ 1926 jmethodID methodID, va_list args) \ 1927 { \ 1928 ScopedJniThreadState ts(env); \ 1929 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1930 const Method* meth; \ 1931 JValue result; \ 1932 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \ 1933 if (meth == NULL) { \ 1934 return _retfail; \ 1935 } \ 1936 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \ 1937 if (_isref && !dvmCheckException(ts.self())) \ 1938 result.l = (Object*)addLocalReference(env, result.l); \ 1939 return _retok; \ 1940 } \ 1941 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \ 1942 jmethodID methodID, jvalue* args) \ 1943 { \ 1944 ScopedJniThreadState ts(env); \ 1945 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1946 const Method* meth; \ 1947 JValue result; \ 1948 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \ 1949 if (meth == NULL) { \ 1950 return _retfail; \ 1951 } \ 1952 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \ 1953 if (_isref && !dvmCheckException(ts.self())) \ 1954 result.l = (Object*)addLocalReference(env, result.l); \ 1955 return _retok; \ 1956 } 1957CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true); 1958CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false); 1959CALL_VIRTUAL(jbyte, Byte, 0, result.b, false); 1960CALL_VIRTUAL(jchar, Char, 0, result.c, false); 1961CALL_VIRTUAL(jshort, Short, 0, result.s, false); 1962CALL_VIRTUAL(jint, Int, 0, result.i, false); 1963CALL_VIRTUAL(jlong, Long, 0, result.j, false); 1964CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false); 1965CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false); 1966CALL_VIRTUAL(void, Void, , , false); 1967 1968/* 1969 * Make a "non-virtual" method call. We're still calling a virtual method, 1970 * but this time we're not doing an indirection through the object's vtable. 1971 * The "clazz" parameter defines which implementation of a method we want. 1972 * 1973 * Three versions (..., va_list, jvalue[]) for each return type. 1974 */ 1975#define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \ 1976 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \ 1977 jclass jclazz, jmethodID methodID, ...) \ 1978 { \ 1979 ScopedJniThreadState ts(env); \ 1980 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1981 ClassObject* clazz = \ 1982 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \ 1983 const Method* meth; \ 1984 va_list args; \ 1985 JValue result; \ 1986 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \ 1987 if (meth == NULL) { \ 1988 return _retfail; \ 1989 } \ 1990 va_start(args, methodID); \ 1991 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \ 1992 if (_isref && !dvmCheckException(ts.self())) \ 1993 result.l = (Object*)addLocalReference(env, result.l); \ 1994 va_end(args); \ 1995 return _retok; \ 1996 } \ 1997 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\ 1998 jclass jclazz, jmethodID methodID, va_list args) \ 1999 { \ 2000 ScopedJniThreadState ts(env); \ 2001 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 2002 ClassObject* clazz = \ 2003 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \ 2004 const Method* meth; \ 2005 JValue result; \ 2006 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \ 2007 if (meth == NULL) { \ 2008 return _retfail; \ 2009 } \ 2010 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \ 2011 if (_isref && !dvmCheckException(ts.self())) \ 2012 result.l = (Object*)addLocalReference(env, result.l); \ 2013 return _retok; \ 2014 } \ 2015 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\ 2016 jclass jclazz, jmethodID methodID, jvalue* args) \ 2017 { \ 2018 ScopedJniThreadState ts(env); \ 2019 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 2020 ClassObject* clazz = \ 2021 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \ 2022 const Method* meth; \ 2023 JValue result; \ 2024 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \ 2025 if (meth == NULL) { \ 2026 return _retfail; \ 2027 } \ 2028 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \ 2029 if (_isref && !dvmCheckException(ts.self())) \ 2030 result.l = (Object*)addLocalReference(env, result.l); \ 2031 return _retok; \ 2032 } 2033CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true); 2034CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false); 2035CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false); 2036CALL_NONVIRTUAL(jchar, Char, 0, result.c, false); 2037CALL_NONVIRTUAL(jshort, Short, 0, result.s, false); 2038CALL_NONVIRTUAL(jint, Int, 0, result.i, false); 2039CALL_NONVIRTUAL(jlong, Long, 0, result.j, false); 2040CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false); 2041CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false); 2042CALL_NONVIRTUAL(void, Void, , , false); 2043 2044 2045/* 2046 * Call a static method. 2047 */ 2048#define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \ 2049 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \ 2050 jmethodID methodID, ...) \ 2051 { \ 2052 UNUSED_PARAMETER(jclazz); \ 2053 ScopedJniThreadState ts(env); \ 2054 JValue result; \ 2055 va_list args; \ 2056 va_start(args, methodID); \ 2057 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\ 2058 va_end(args); \ 2059 if (_isref && !dvmCheckException(ts.self())) \ 2060 result.l = (Object*)addLocalReference(env, result.l); \ 2061 return _retok; \ 2062 } \ 2063 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \ 2064 jmethodID methodID, va_list args) \ 2065 { \ 2066 UNUSED_PARAMETER(jclazz); \ 2067 ScopedJniThreadState ts(env); \ 2068 JValue result; \ 2069 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\ 2070 if (_isref && !dvmCheckException(ts.self())) \ 2071 result.l = (Object*)addLocalReference(env, result.l); \ 2072 return _retok; \ 2073 } \ 2074 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \ 2075 jmethodID methodID, jvalue* args) \ 2076 { \ 2077 UNUSED_PARAMETER(jclazz); \ 2078 ScopedJniThreadState ts(env); \ 2079 JValue result; \ 2080 dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\ 2081 if (_isref && !dvmCheckException(ts.self())) \ 2082 result.l = (Object*)addLocalReference(env, result.l); \ 2083 return _retok; \ 2084 } 2085CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true); 2086CALL_STATIC(jboolean, Boolean, 0, result.z, false); 2087CALL_STATIC(jbyte, Byte, 0, result.b, false); 2088CALL_STATIC(jchar, Char, 0, result.c, false); 2089CALL_STATIC(jshort, Short, 0, result.s, false); 2090CALL_STATIC(jint, Int, 0, result.i, false); 2091CALL_STATIC(jlong, Long, 0, result.j, false); 2092CALL_STATIC(jfloat, Float, 0.0f, result.f, false); 2093CALL_STATIC(jdouble, Double, 0.0, result.d, false); 2094CALL_STATIC(void, Void, , , false); 2095 2096/* 2097 * Create a new String from Unicode data. 2098 * 2099 * If "len" is zero, we will return an empty string even if "unicodeChars" 2100 * is NULL. (The JNI spec is vague here.) 2101 */ 2102static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) { 2103 ScopedJniThreadState ts(env); 2104 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len); 2105 if (jstr == NULL) { 2106 return NULL; 2107 } 2108 dvmReleaseTrackedAlloc((Object*) jstr, NULL); 2109 return (jstring) addLocalReference(env, (Object*) jstr); 2110} 2111 2112/* 2113 * Return the length of a String in Unicode character units. 2114 */ 2115static jsize GetStringLength(JNIEnv* env, jstring jstr) { 2116 ScopedJniThreadState ts(env); 2117 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2118 return dvmStringLen(strObj); 2119} 2120 2121 2122/* 2123 * Get a string's character data. 2124 * 2125 * The result is guaranteed to be valid until ReleaseStringChars is 2126 * called, which means we have to pin it or return a copy. 2127 */ 2128static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) { 2129 ScopedJniThreadState ts(env); 2130 2131 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2132 ArrayObject* strChars = dvmStringCharArray(strObj); 2133 2134 pinPrimitiveArray(strChars); 2135 2136 const u2* data = dvmStringChars(strObj); 2137 if (isCopy != NULL) { 2138 *isCopy = JNI_FALSE; 2139 } 2140 return (jchar*) data; 2141} 2142 2143/* 2144 * Release our grip on some characters from a string. 2145 */ 2146static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) { 2147 ScopedJniThreadState ts(env); 2148 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2149 ArrayObject* strChars = dvmStringCharArray(strObj); 2150 unpinPrimitiveArray(strChars); 2151} 2152 2153/* 2154 * Create a new java.lang.String object from chars in modified UTF-8 form. 2155 * 2156 * The spec doesn't say how to handle a NULL string. Popular desktop VMs 2157 * accept it and return a NULL pointer in response. 2158 */ 2159static jstring NewStringUTF(JNIEnv* env, const char* bytes) { 2160 ScopedJniThreadState ts(env); 2161 if (bytes == NULL) { 2162 return NULL; 2163 } 2164 /* note newStr could come back NULL on OOM */ 2165 StringObject* newStr = dvmCreateStringFromCstr(bytes); 2166 jstring result = (jstring) addLocalReference(env, (Object*) newStr); 2167 dvmReleaseTrackedAlloc((Object*)newStr, NULL); 2168 return result; 2169} 2170 2171/* 2172 * Return the length in bytes of the modified UTF-8 form of the string. 2173 */ 2174static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) { 2175 ScopedJniThreadState ts(env); 2176 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2177 return dvmStringUtf8ByteLen(strObj); 2178} 2179 2180/* 2181 * Convert "string" to modified UTF-8 and return a pointer. The returned 2182 * value must be released with ReleaseStringUTFChars. 2183 * 2184 * According to the JNI reference, "Returns a pointer to a UTF-8 string, 2185 * or NULL if the operation fails. Returns NULL if and only if an invocation 2186 * of this function has thrown an exception." 2187 * 2188 * The behavior here currently follows that of other open-source VMs, which 2189 * quietly return NULL if "string" is NULL. We should consider throwing an 2190 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string, 2191 * which should catch this sort of thing during development.) Certain other 2192 * VMs will crash with a segmentation fault. 2193 */ 2194static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) { 2195 ScopedJniThreadState ts(env); 2196 if (jstr == NULL) { 2197 /* this shouldn't happen; throw NPE? */ 2198 return NULL; 2199 } 2200 if (isCopy != NULL) { 2201 *isCopy = JNI_TRUE; 2202 } 2203 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2204 char* newStr = dvmCreateCstrFromString(strObj); 2205 if (newStr == NULL) { 2206 /* assume memory failure */ 2207 dvmThrowOutOfMemoryError("native heap string alloc failed"); 2208 } 2209 return newStr; 2210} 2211 2212/* 2213 * Release a string created by GetStringUTFChars(). 2214 */ 2215static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) { 2216 ScopedJniThreadState ts(env); 2217 free((char*) utf); 2218} 2219 2220/* 2221 * Return the capacity of the array. 2222 */ 2223static jsize GetArrayLength(JNIEnv* env, jarray jarr) { 2224 ScopedJniThreadState ts(env); 2225 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2226 return arrObj->length; 2227} 2228 2229/* 2230 * Construct a new array that holds objects from class "elementClass". 2231 */ 2232static jobjectArray NewObjectArray(JNIEnv* env, jsize length, 2233 jclass jelementClass, jobject jinitialElement) 2234{ 2235 ScopedJniThreadState ts(env); 2236 2237 if (jelementClass == NULL) { 2238 dvmThrowNullPointerException("JNI NewObjectArray element class"); 2239 return NULL; 2240 } 2241 2242 ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(env, jelementClass); 2243 ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj); 2244 ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT); 2245 if (newObj == NULL) { 2246 assert(dvmCheckException(ts.self())); 2247 return NULL; 2248 } 2249 jobjectArray newArray = (jobjectArray) addLocalReference(env, (Object*) newObj); 2250 dvmReleaseTrackedAlloc((Object*) newObj, NULL); 2251 2252 /* 2253 * Initialize the array. 2254 */ 2255 if (jinitialElement != NULL) { 2256 Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement); 2257 Object** arrayData = (Object**) (void*) newObj->contents; 2258 for (jsize i = 0; i < length; ++i) { 2259 arrayData[i] = initialElement; 2260 } 2261 } 2262 2263 return newArray; 2264} 2265 2266static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) { 2267 assert(arrayObj != NULL); 2268 if (index < 0 || index >= (int) arrayObj->length) { 2269 dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index); 2270 return false; 2271 } 2272 return true; 2273} 2274 2275/* 2276 * Get one element of an Object array. 2277 * 2278 * Add the object to the local references table in case the array goes away. 2279 */ 2280static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) { 2281 ScopedJniThreadState ts(env); 2282 2283 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2284 if (!checkArrayElementBounds(arrayObj, index)) { 2285 return NULL; 2286 } 2287 2288 Object* value = ((Object**) (void*) arrayObj->contents)[index]; 2289 return addLocalReference(env, value); 2290} 2291 2292/* 2293 * Set one element of an Object array. 2294 */ 2295static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) { 2296 ScopedJniThreadState ts(env); 2297 2298 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2299 if (!checkArrayElementBounds(arrayObj, index)) { 2300 return; 2301 } 2302 2303 //LOGV("JNI: set element %d in array %p to %p", index, array, value); 2304 2305 Object* obj = dvmDecodeIndirectRef(env, jobj); 2306 dvmSetObjectArrayElement(arrayObj, index, obj); 2307} 2308 2309/* 2310 * Create a new array of primitive elements. 2311 */ 2312#define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \ 2313 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \ 2314 ScopedJniThreadState ts(env); \ 2315 ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \ 2316 if (arrayObj == NULL) { \ 2317 return NULL; \ 2318 } \ 2319 _artype result = (_artype) addLocalReference(env, (Object*) arrayObj); \ 2320 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \ 2321 return result; \ 2322 } 2323NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z'); 2324NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B'); 2325NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C'); 2326NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S'); 2327NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I'); 2328NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J'); 2329NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F'); 2330NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D'); 2331 2332/* 2333 * Get a pointer to a C array of primitive elements from an array object 2334 * of the matching type. 2335 * 2336 * In a compacting GC, we either need to return a copy of the elements or 2337 * "pin" the memory. Otherwise we run the risk of native code using the 2338 * buffer as the destination of e.g. a blocking read() call that wakes up 2339 * during a GC. 2340 */ 2341#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 2342 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \ 2343 _ctype##Array jarr, jboolean* isCopy) \ 2344 { \ 2345 ScopedJniThreadState ts(env); \ 2346 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \ 2347 pinPrimitiveArray(arrayObj); \ 2348 _ctype* data = (_ctype*) (void*) arrayObj->contents; \ 2349 if (isCopy != NULL) { \ 2350 *isCopy = JNI_FALSE; \ 2351 } \ 2352 return data; \ 2353 } 2354 2355/* 2356 * Release the storage locked down by the "get" function. 2357 * 2358 * The spec says, "'mode' has no effect if 'elems' is not a copy of the 2359 * elements in 'array'." They apparently did not anticipate the need to 2360 * un-pin memory. 2361 */ 2362#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 2363 static void Release##_jname##ArrayElements(JNIEnv* env, \ 2364 _ctype##Array jarr, _ctype* elems, jint mode) \ 2365 { \ 2366 UNUSED_PARAMETER(elems); \ 2367 if (mode != JNI_COMMIT) { \ 2368 ScopedJniThreadState ts(env); \ 2369 ArrayObject* arrayObj = \ 2370 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \ 2371 unpinPrimitiveArray(arrayObj); \ 2372 } \ 2373 } 2374 2375static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start, 2376 jsize len, const char* arrayIdentifier) 2377{ 2378 dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException, 2379 "%s offset=%d length=%d %s.length=%d", 2380 arrayObj->clazz->descriptor, start, len, arrayIdentifier, 2381 arrayObj->length); 2382} 2383 2384/* 2385 * Copy a section of a primitive array to a buffer. 2386 */ 2387#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 2388 static void Get##_jname##ArrayRegion(JNIEnv* env, \ 2389 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \ 2390 { \ 2391 ScopedJniThreadState ts(env); \ 2392 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \ 2393 _ctype* data = (_ctype*) (void*) arrayObj->contents; \ 2394 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \ 2395 throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \ 2396 } else { \ 2397 memcpy(buf, data + start, len * sizeof(_ctype)); \ 2398 } \ 2399 } 2400 2401/* 2402 * Copy a section of a primitive array from a buffer. 2403 */ 2404#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 2405 static void Set##_jname##ArrayRegion(JNIEnv* env, \ 2406 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \ 2407 { \ 2408 ScopedJniThreadState ts(env); \ 2409 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \ 2410 _ctype* data = (_ctype*) (void*) arrayObj->contents; \ 2411 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \ 2412 throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \ 2413 } else { \ 2414 memcpy(data + start, buf, len * sizeof(_ctype)); \ 2415 } \ 2416 } 2417 2418/* 2419 * 4-in-1: 2420 * Get<Type>ArrayElements 2421 * Release<Type>ArrayElements 2422 * Get<Type>ArrayRegion 2423 * Set<Type>ArrayRegion 2424 */ 2425#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \ 2426 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 2427 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 2428 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \ 2429 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); 2430 2431PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean); 2432PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte); 2433PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char); 2434PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short); 2435PRIMITIVE_ARRAY_FUNCTIONS(jint, Int); 2436PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long); 2437PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float); 2438PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double); 2439 2440/* 2441 * Register one or more native functions in one class. 2442 * 2443 * This can be called multiple times on the same method, allowing the 2444 * caller to redefine the method implementation at will. 2445 */ 2446static jint RegisterNatives(JNIEnv* env, jclass jclazz, 2447 const JNINativeMethod* methods, jint nMethods) 2448{ 2449 ScopedJniThreadState ts(env); 2450 2451 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 2452 2453 if (gDvm.verboseJni) { 2454 LOGI("[Registering JNI native methods for class %s]", 2455 clazz->descriptor); 2456 } 2457 2458 for (int i = 0; i < nMethods; i++) { 2459 if (!dvmRegisterJNIMethod(clazz, methods[i].name, 2460 methods[i].signature, methods[i].fnPtr)) 2461 { 2462 return JNI_ERR; 2463 } 2464 } 2465 return JNI_OK; 2466} 2467 2468/* 2469 * Un-register all native methods associated with the class. 2470 * 2471 * The JNI docs refer to this as a way to reload/relink native libraries, 2472 * and say it "should not be used in normal native code". In particular, 2473 * there is no need to do this during shutdown, and you do not need to do 2474 * this before redefining a method implementation with RegisterNatives. 2475 * 2476 * It's chiefly useful for a native "plugin"-style library that wasn't 2477 * loaded with System.loadLibrary() (since there's no way to unload those). 2478 * For example, the library could upgrade itself by: 2479 * 2480 * 1. call UnregisterNatives to unbind the old methods 2481 * 2. ensure that no code is still executing inside it (somehow) 2482 * 3. dlclose() the library 2483 * 4. dlopen() the new library 2484 * 5. use RegisterNatives to bind the methods from the new library 2485 * 2486 * The above can work correctly without the UnregisterNatives call, but 2487 * creates a window of opportunity in which somebody might try to call a 2488 * method that is pointing at unmapped memory, crashing the VM. In theory 2489 * the same guards that prevent dlclose() from unmapping executing code could 2490 * prevent that anyway, but with this we can be more thorough and also deal 2491 * with methods that only exist in the old or new form of the library (maybe 2492 * the lib wants to try the call and catch the UnsatisfiedLinkError). 2493 */ 2494static jint UnregisterNatives(JNIEnv* env, jclass jclazz) { 2495 ScopedJniThreadState ts(env); 2496 2497 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 2498 if (gDvm.verboseJni) { 2499 LOGI("[Unregistering JNI native methods for class %s]", 2500 clazz->descriptor); 2501 } 2502 dvmUnregisterJNINativeMethods(clazz); 2503 return JNI_OK; 2504} 2505 2506/* 2507 * Lock the monitor. 2508 * 2509 * We have to track all monitor enters and exits, so that we can undo any 2510 * outstanding synchronization before the thread exits. 2511 */ 2512static jint MonitorEnter(JNIEnv* env, jobject jobj) { 2513 ScopedJniThreadState ts(env); 2514 Object* obj = dvmDecodeIndirectRef(env, jobj); 2515 dvmLockObject(ts.self(), obj); 2516 trackMonitorEnter(ts.self(), obj); 2517 return JNI_OK; 2518} 2519 2520/* 2521 * Unlock the monitor. 2522 * 2523 * Throws an IllegalMonitorStateException if the current thread 2524 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.) 2525 * 2526 * According to the 1.6 spec, it's legal to call here with an exception 2527 * pending. If this fails, we'll stomp the original exception. 2528 */ 2529static jint MonitorExit(JNIEnv* env, jobject jobj) { 2530 ScopedJniThreadState ts(env); 2531 Object* obj = dvmDecodeIndirectRef(env, jobj); 2532 bool success = dvmUnlockObject(ts.self(), obj); 2533 if (success) { 2534 trackMonitorExit(ts.self(), obj); 2535 } 2536 return success ? JNI_OK : JNI_ERR; 2537} 2538 2539/* 2540 * Return the JavaVM interface associated with the current thread. 2541 */ 2542static jint GetJavaVM(JNIEnv* env, JavaVM** vm) { 2543 ScopedJniThreadState ts(env); 2544 *vm = gDvmJni.jniVm; 2545 return (*vm == NULL) ? JNI_ERR : JNI_OK; 2546} 2547 2548/* 2549 * Copies "len" Unicode characters, from offset "start". 2550 */ 2551static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) { 2552 ScopedJniThreadState ts(env); 2553 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2554 int strLen = dvmStringLen(strObj); 2555 if (((start|len) < 0) || (start + len > dvmStringLen(strObj))) { 2556 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len); 2557 return; 2558 } 2559 memcpy(buf, dvmStringChars(strObj) + start, len * sizeof(u2)); 2560} 2561 2562/* 2563 * Translates "len" Unicode characters, from offset "start", into 2564 * modified UTF-8 encoding. 2565 */ 2566static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) { 2567 ScopedJniThreadState ts(env); 2568 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2569 int strLen = dvmStringLen(strObj); 2570 if (((start|len) < 0) || (start + len > dvmStringLen(strObj))) { 2571 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len); 2572 return; 2573 } 2574 dvmCreateCstrFromStringRegion(strObj, start, len, buf); 2575} 2576 2577/* 2578 * Get a raw pointer to array data. 2579 * 2580 * The caller is expected to call "release" before doing any JNI calls 2581 * or blocking I/O operations. 2582 * 2583 * We need to pin the memory or block GC. 2584 */ 2585static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) { 2586 ScopedJniThreadState ts(env); 2587 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2588 pinPrimitiveArray(arrayObj); 2589 void* data = arrayObj->contents; 2590 if (isCopy != NULL) { 2591 *isCopy = JNI_FALSE; 2592 } 2593 return data; 2594} 2595 2596/* 2597 * Release an array obtained with GetPrimitiveArrayCritical. 2598 */ 2599static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) { 2600 if (mode != JNI_COMMIT) { 2601 ScopedJniThreadState ts(env); 2602 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2603 unpinPrimitiveArray(arrayObj); 2604 } 2605} 2606 2607/* 2608 * Like GetStringChars, but with restricted use. 2609 */ 2610static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) { 2611 ScopedJniThreadState ts(env); 2612 2613 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2614 ArrayObject* strChars = dvmStringCharArray(strObj); 2615 2616 pinPrimitiveArray(strChars); 2617 2618 const u2* data = dvmStringChars(strObj); 2619 if (isCopy != NULL) { 2620 *isCopy = JNI_FALSE; 2621 } 2622 return (jchar*) data; 2623} 2624 2625/* 2626 * Like ReleaseStringChars, but with restricted use. 2627 */ 2628static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) { 2629 ScopedJniThreadState ts(env); 2630 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2631 ArrayObject* strChars = dvmStringCharArray(strObj); 2632 unpinPrimitiveArray(strChars); 2633} 2634 2635/* 2636 * Create a new weak global reference. 2637 */ 2638static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) { 2639 ScopedJniThreadState ts(env); 2640 Object *obj = dvmDecodeIndirectRef(env, jobj); 2641 return (jweak) addWeakGlobalReference(obj); 2642} 2643 2644/* 2645 * Delete the specified weak global reference. 2646 */ 2647static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) { 2648 ScopedJniThreadState ts(env); 2649 deleteWeakGlobalReference(wref); 2650} 2651 2652/* 2653 * Quick check for pending exceptions. 2654 * 2655 * TODO: we should be able to skip the enter/exit macros here. 2656 */ 2657static jboolean ExceptionCheck(JNIEnv* env) { 2658 ScopedJniThreadState ts(env); 2659 return dvmCheckException(ts.self()); 2660} 2661 2662/* 2663 * Returns the type of the object referred to by "obj". It can be local, 2664 * global, or weak global. 2665 * 2666 * In the current implementation, references can be global and local at 2667 * the same time, so while the return value is accurate it may not tell 2668 * the whole story. 2669 */ 2670static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) { 2671 ScopedJniThreadState ts(env); 2672 return dvmGetJNIRefType(env, jobj); 2673} 2674 2675/* 2676 * Allocate and return a new java.nio.ByteBuffer for this block of memory. 2677 * 2678 * "address" may not be NULL, and "capacity" must be > 0. (These are only 2679 * verified when CheckJNI is enabled.) 2680 */ 2681static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) { 2682 ScopedJniThreadState ts(env); 2683 2684 /* create an instance of java.nio.ReadWriteDirectByteBuffer */ 2685 ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer; 2686 if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) { 2687 return NULL; 2688 } 2689 Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK); 2690 if (newObj == NULL) { 2691 return NULL; 2692 } 2693 /* call the constructor */ 2694 jobject result = addLocalReference(env, newObj); 2695 JValue unused; 2696 dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init, 2697 newObj, &unused, (jint) address, (jint) capacity); 2698 if (dvmGetException(ts.self()) != NULL) { 2699 deleteLocalReference(env, result); 2700 return NULL; 2701 } 2702 return result; 2703} 2704 2705/* 2706 * Get the starting address of the buffer for the specified java.nio.Buffer. 2707 * 2708 * If this is not a "direct" buffer, we return NULL. 2709 */ 2710static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) { 2711 ScopedJniThreadState ts(env); 2712 2713 // All Buffer objects have an effectiveDirectAddress field. 2714 Object* bufObj = dvmDecodeIndirectRef(env, jbuf); 2715 return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress); 2716} 2717 2718/* 2719 * Get the capacity of the buffer for the specified java.nio.Buffer. 2720 * 2721 * Returns -1 if the object is not a direct buffer. (We actually skip 2722 * this check, since it's expensive to determine, and just return the 2723 * capacity regardless.) 2724 */ 2725static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) { 2726 ScopedJniThreadState ts(env); 2727 2728 /* 2729 * The capacity is always in the Buffer.capacity field. 2730 * 2731 * (The "check" version should verify that this is actually a Buffer, 2732 * but we're not required to do so here.) 2733 */ 2734 Object* buf = dvmDecodeIndirectRef(env, jbuf); 2735 return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity); 2736} 2737 2738 2739/* 2740 * =========================================================================== 2741 * JNI invocation functions 2742 * =========================================================================== 2743 */ 2744 2745/* 2746 * Handle AttachCurrentThread{AsDaemon}. 2747 * 2748 * We need to make sure the VM is actually running. For example, if we start 2749 * up, issue an Attach, and the VM exits almost immediately, by the time the 2750 * attaching happens the VM could already be shutting down. 2751 * 2752 * It's hard to avoid a race condition here because we don't want to hold 2753 * a lock across the entire operation. What we can do is temporarily 2754 * increment the thread count to prevent a VM exit. 2755 * 2756 * This could potentially still have problems if a daemon thread calls here 2757 * while the VM is shutting down. dvmThreadSelf() will work, since it just 2758 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when 2759 * you shut down a VM while threads are still running inside it. 2760 * 2761 * Remember that some code may call this as a way to find the per-thread 2762 * JNIEnv pointer. Don't do excess work for that case. 2763 */ 2764static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) { 2765 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args; 2766 2767 /* 2768 * Return immediately if we're already one with the VM. 2769 */ 2770 Thread* self = dvmThreadSelf(); 2771 if (self != NULL) { 2772 *p_env = self->jniEnv; 2773 return JNI_OK; 2774 } 2775 2776 /* 2777 * No threads allowed in zygote mode. 2778 */ 2779 if (gDvm.zygote) { 2780 return JNI_ERR; 2781 } 2782 2783 /* increment the count to keep the VM from bailing while we run */ 2784 dvmLockThreadList(NULL); 2785 if (gDvm.nonDaemonThreadCount == 0) { 2786 // dead or dying 2787 LOGV("Refusing to attach thread '%s' -- VM is shutting down", 2788 (thr_args == NULL) ? "(unknown)" : args->name); 2789 dvmUnlockThreadList(); 2790 return JNI_ERR; 2791 } 2792 gDvm.nonDaemonThreadCount++; 2793 dvmUnlockThreadList(); 2794 2795 /* tweak the JavaVMAttachArgs as needed */ 2796 JavaVMAttachArgs argsCopy; 2797 if (args == NULL) { 2798 /* allow the v1.1 calling convention */ 2799 argsCopy.version = JNI_VERSION_1_2; 2800 argsCopy.name = NULL; 2801 argsCopy.group = (jobject) dvmGetMainThreadGroup(); 2802 } else { 2803 assert(args->version >= JNI_VERSION_1_2); 2804 2805 argsCopy.version = args->version; 2806 argsCopy.name = args->name; 2807 if (args->group != NULL) { 2808 argsCopy.group = args->group; 2809 } else { 2810 argsCopy.group = (jobject) dvmGetMainThreadGroup(); 2811 } 2812 } 2813 2814 bool result = dvmAttachCurrentThread(&argsCopy, isDaemon); 2815 2816 /* restore the count */ 2817 dvmLockThreadList(NULL); 2818 gDvm.nonDaemonThreadCount--; 2819 dvmUnlockThreadList(); 2820 2821 /* 2822 * Change the status to indicate that we're out in native code. This 2823 * call is not guarded with state-change macros, so we have to do it 2824 * by hand. 2825 */ 2826 if (result) { 2827 self = dvmThreadSelf(); 2828 assert(self != NULL); 2829 dvmChangeStatus(self, THREAD_NATIVE); 2830 *p_env = self->jniEnv; 2831 return JNI_OK; 2832 } else { 2833 return JNI_ERR; 2834 } 2835} 2836 2837/* 2838 * Attach the current thread to the VM. If the thread is already attached, 2839 * this is a no-op. 2840 */ 2841static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) { 2842 return attachThread(vm, p_env, thr_args, false); 2843} 2844 2845/* 2846 * Like AttachCurrentThread, but set the "daemon" flag. 2847 */ 2848static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) 2849{ 2850 return attachThread(vm, p_env, thr_args, true); 2851} 2852 2853/* 2854 * Dissociate the current thread from the VM. 2855 */ 2856static jint DetachCurrentThread(JavaVM* vm) { 2857 Thread* self = dvmThreadSelf(); 2858 if (self == NULL) { 2859 /* not attached, can't do anything */ 2860 return JNI_ERR; 2861 } 2862 2863 /* switch to "running" to check for suspension */ 2864 dvmChangeStatus(self, THREAD_RUNNING); 2865 2866 /* detach the thread */ 2867 dvmDetachCurrentThread(); 2868 2869 /* (no need to change status back -- we have no status) */ 2870 return JNI_OK; 2871} 2872 2873/* 2874 * If current thread is attached to VM, return the associated JNIEnv. 2875 * Otherwise, stuff NULL in and return JNI_EDETACHED. 2876 * 2877 * JVMTI overloads this by specifying a magic value for "version", so we 2878 * do want to check that here. 2879 */ 2880static jint GetEnv(JavaVM* vm, void** env, jint version) { 2881 Thread* self = dvmThreadSelf(); 2882 2883 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) { 2884 return JNI_EVERSION; 2885 } 2886 2887 if (self == NULL) { 2888 *env = NULL; 2889 } else { 2890 /* TODO: status change is probably unnecessary */ 2891 dvmChangeStatus(self, THREAD_RUNNING); 2892 *env = (void*) dvmGetThreadJNIEnv(self); 2893 dvmChangeStatus(self, THREAD_NATIVE); 2894 } 2895 return (*env != NULL) ? JNI_OK : JNI_EDETACHED; 2896} 2897 2898/* 2899 * Destroy the VM. This may be called from any thread. 2900 * 2901 * If the current thread is attached, wait until the current thread is 2902 * the only non-daemon user-level thread. If the current thread is not 2903 * attached, we attach it and do the processing as usual. (If the attach 2904 * fails, it's probably because all the non-daemon threads have already 2905 * exited and the VM doesn't want to let us back in.) 2906 * 2907 * TODO: we don't really deal with the situation where more than one thread 2908 * has called here. One thread wins, the other stays trapped waiting on 2909 * the condition variable forever. Not sure this situation is interesting 2910 * in real life. 2911 */ 2912static jint DestroyJavaVM(JavaVM* vm) { 2913 JavaVMExt* ext = (JavaVMExt*) vm; 2914 if (ext == NULL) { 2915 return JNI_ERR; 2916 } 2917 2918 if (gDvm.verboseShutdown) { 2919 LOGD("DestroyJavaVM waiting for non-daemon threads to exit"); 2920 } 2921 2922 /* 2923 * Sleep on a condition variable until it's okay to exit. 2924 */ 2925 Thread* self = dvmThreadSelf(); 2926 if (self == NULL) { 2927 JNIEnv* tmpEnv; 2928 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) { 2929 LOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)", 2930 gDvm.nonDaemonThreadCount); 2931 goto shutdown; 2932 } else { 2933 LOGV("Attached to wait for shutdown in Destroy"); 2934 } 2935 } 2936 dvmChangeStatus(self, THREAD_VMWAIT); 2937 2938 dvmLockThreadList(self); 2939 gDvm.nonDaemonThreadCount--; // remove current thread from count 2940 2941 while (gDvm.nonDaemonThreadCount > 0) { 2942 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock); 2943 } 2944 2945 dvmUnlockThreadList(); 2946 self = NULL; 2947 2948shutdown: 2949 // TODO: call System.exit() to run any registered shutdown hooks 2950 // (this may not return -- figure out how this should work) 2951 2952 if (gDvm.verboseShutdown) { 2953 LOGD("DestroyJavaVM shutting VM down"); 2954 } 2955 dvmShutdown(); 2956 2957 // TODO - free resources associated with JNI-attached daemon threads 2958 free(ext->envList); 2959 free(ext); 2960 2961 return JNI_OK; 2962} 2963 2964 2965/* 2966 * =========================================================================== 2967 * Function tables 2968 * =========================================================================== 2969 */ 2970 2971static const struct JNINativeInterface gNativeInterface = { 2972 NULL, 2973 NULL, 2974 NULL, 2975 NULL, 2976 2977 GetVersion, 2978 2979 DefineClass, 2980 FindClass, 2981 2982 FromReflectedMethod, 2983 FromReflectedField, 2984 ToReflectedMethod, 2985 2986 GetSuperclass, 2987 IsAssignableFrom, 2988 2989 ToReflectedField, 2990 2991 Throw, 2992 ThrowNew, 2993 ExceptionOccurred, 2994 ExceptionDescribe, 2995 ExceptionClear, 2996 FatalError, 2997 2998 PushLocalFrame, 2999 PopLocalFrame, 3000 3001 NewGlobalRef, 3002 DeleteGlobalRef, 3003 DeleteLocalRef, 3004 IsSameObject, 3005 NewLocalRef, 3006 EnsureLocalCapacity, 3007 3008 AllocObject, 3009 NewObject, 3010 NewObjectV, 3011 NewObjectA, 3012 3013 GetObjectClass, 3014 IsInstanceOf, 3015 3016 GetMethodID, 3017 3018 CallObjectMethod, 3019 CallObjectMethodV, 3020 CallObjectMethodA, 3021 CallBooleanMethod, 3022 CallBooleanMethodV, 3023 CallBooleanMethodA, 3024 CallByteMethod, 3025 CallByteMethodV, 3026 CallByteMethodA, 3027 CallCharMethod, 3028 CallCharMethodV, 3029 CallCharMethodA, 3030 CallShortMethod, 3031 CallShortMethodV, 3032 CallShortMethodA, 3033 CallIntMethod, 3034 CallIntMethodV, 3035 CallIntMethodA, 3036 CallLongMethod, 3037 CallLongMethodV, 3038 CallLongMethodA, 3039 CallFloatMethod, 3040 CallFloatMethodV, 3041 CallFloatMethodA, 3042 CallDoubleMethod, 3043 CallDoubleMethodV, 3044 CallDoubleMethodA, 3045 CallVoidMethod, 3046 CallVoidMethodV, 3047 CallVoidMethodA, 3048 3049 CallNonvirtualObjectMethod, 3050 CallNonvirtualObjectMethodV, 3051 CallNonvirtualObjectMethodA, 3052 CallNonvirtualBooleanMethod, 3053 CallNonvirtualBooleanMethodV, 3054 CallNonvirtualBooleanMethodA, 3055 CallNonvirtualByteMethod, 3056 CallNonvirtualByteMethodV, 3057 CallNonvirtualByteMethodA, 3058 CallNonvirtualCharMethod, 3059 CallNonvirtualCharMethodV, 3060 CallNonvirtualCharMethodA, 3061 CallNonvirtualShortMethod, 3062 CallNonvirtualShortMethodV, 3063 CallNonvirtualShortMethodA, 3064 CallNonvirtualIntMethod, 3065 CallNonvirtualIntMethodV, 3066 CallNonvirtualIntMethodA, 3067 CallNonvirtualLongMethod, 3068 CallNonvirtualLongMethodV, 3069 CallNonvirtualLongMethodA, 3070 CallNonvirtualFloatMethod, 3071 CallNonvirtualFloatMethodV, 3072 CallNonvirtualFloatMethodA, 3073 CallNonvirtualDoubleMethod, 3074 CallNonvirtualDoubleMethodV, 3075 CallNonvirtualDoubleMethodA, 3076 CallNonvirtualVoidMethod, 3077 CallNonvirtualVoidMethodV, 3078 CallNonvirtualVoidMethodA, 3079 3080 GetFieldID, 3081 3082 GetObjectField, 3083 GetBooleanField, 3084 GetByteField, 3085 GetCharField, 3086 GetShortField, 3087 GetIntField, 3088 GetLongField, 3089 GetFloatField, 3090 GetDoubleField, 3091 SetObjectField, 3092 SetBooleanField, 3093 SetByteField, 3094 SetCharField, 3095 SetShortField, 3096 SetIntField, 3097 SetLongField, 3098 SetFloatField, 3099 SetDoubleField, 3100 3101 GetStaticMethodID, 3102 3103 CallStaticObjectMethod, 3104 CallStaticObjectMethodV, 3105 CallStaticObjectMethodA, 3106 CallStaticBooleanMethod, 3107 CallStaticBooleanMethodV, 3108 CallStaticBooleanMethodA, 3109 CallStaticByteMethod, 3110 CallStaticByteMethodV, 3111 CallStaticByteMethodA, 3112 CallStaticCharMethod, 3113 CallStaticCharMethodV, 3114 CallStaticCharMethodA, 3115 CallStaticShortMethod, 3116 CallStaticShortMethodV, 3117 CallStaticShortMethodA, 3118 CallStaticIntMethod, 3119 CallStaticIntMethodV, 3120 CallStaticIntMethodA, 3121 CallStaticLongMethod, 3122 CallStaticLongMethodV, 3123 CallStaticLongMethodA, 3124 CallStaticFloatMethod, 3125 CallStaticFloatMethodV, 3126 CallStaticFloatMethodA, 3127 CallStaticDoubleMethod, 3128 CallStaticDoubleMethodV, 3129 CallStaticDoubleMethodA, 3130 CallStaticVoidMethod, 3131 CallStaticVoidMethodV, 3132 CallStaticVoidMethodA, 3133 3134 GetStaticFieldID, 3135 3136 GetStaticObjectField, 3137 GetStaticBooleanField, 3138 GetStaticByteField, 3139 GetStaticCharField, 3140 GetStaticShortField, 3141 GetStaticIntField, 3142 GetStaticLongField, 3143 GetStaticFloatField, 3144 GetStaticDoubleField, 3145 3146 SetStaticObjectField, 3147 SetStaticBooleanField, 3148 SetStaticByteField, 3149 SetStaticCharField, 3150 SetStaticShortField, 3151 SetStaticIntField, 3152 SetStaticLongField, 3153 SetStaticFloatField, 3154 SetStaticDoubleField, 3155 3156 NewString, 3157 3158 GetStringLength, 3159 GetStringChars, 3160 ReleaseStringChars, 3161 3162 NewStringUTF, 3163 GetStringUTFLength, 3164 GetStringUTFChars, 3165 ReleaseStringUTFChars, 3166 3167 GetArrayLength, 3168 NewObjectArray, 3169 GetObjectArrayElement, 3170 SetObjectArrayElement, 3171 3172 NewBooleanArray, 3173 NewByteArray, 3174 NewCharArray, 3175 NewShortArray, 3176 NewIntArray, 3177 NewLongArray, 3178 NewFloatArray, 3179 NewDoubleArray, 3180 3181 GetBooleanArrayElements, 3182 GetByteArrayElements, 3183 GetCharArrayElements, 3184 GetShortArrayElements, 3185 GetIntArrayElements, 3186 GetLongArrayElements, 3187 GetFloatArrayElements, 3188 GetDoubleArrayElements, 3189 3190 ReleaseBooleanArrayElements, 3191 ReleaseByteArrayElements, 3192 ReleaseCharArrayElements, 3193 ReleaseShortArrayElements, 3194 ReleaseIntArrayElements, 3195 ReleaseLongArrayElements, 3196 ReleaseFloatArrayElements, 3197 ReleaseDoubleArrayElements, 3198 3199 GetBooleanArrayRegion, 3200 GetByteArrayRegion, 3201 GetCharArrayRegion, 3202 GetShortArrayRegion, 3203 GetIntArrayRegion, 3204 GetLongArrayRegion, 3205 GetFloatArrayRegion, 3206 GetDoubleArrayRegion, 3207 SetBooleanArrayRegion, 3208 SetByteArrayRegion, 3209 SetCharArrayRegion, 3210 SetShortArrayRegion, 3211 SetIntArrayRegion, 3212 SetLongArrayRegion, 3213 SetFloatArrayRegion, 3214 SetDoubleArrayRegion, 3215 3216 RegisterNatives, 3217 UnregisterNatives, 3218 3219 MonitorEnter, 3220 MonitorExit, 3221 3222 GetJavaVM, 3223 3224 GetStringRegion, 3225 GetStringUTFRegion, 3226 3227 GetPrimitiveArrayCritical, 3228 ReleasePrimitiveArrayCritical, 3229 3230 GetStringCritical, 3231 ReleaseStringCritical, 3232 3233 NewWeakGlobalRef, 3234 DeleteWeakGlobalRef, 3235 3236 ExceptionCheck, 3237 3238 NewDirectByteBuffer, 3239 GetDirectBufferAddress, 3240 GetDirectBufferCapacity, 3241 3242 GetObjectRefType 3243}; 3244 3245static const struct JNIInvokeInterface gInvokeInterface = { 3246 NULL, 3247 NULL, 3248 NULL, 3249 3250 DestroyJavaVM, 3251 AttachCurrentThread, 3252 DetachCurrentThread, 3253 3254 GetEnv, 3255 3256 AttachCurrentThreadAsDaemon, 3257}; 3258 3259/* 3260 * =========================================================================== 3261 * VM/Env creation 3262 * =========================================================================== 3263 */ 3264 3265/* 3266 * Create a new JNIEnv struct and add it to the VM's list. 3267 * 3268 * "self" will be NULL for the main thread, since the VM hasn't started 3269 * yet; the value will be filled in later. 3270 */ 3271JNIEnv* dvmCreateJNIEnv(Thread* self) { 3272 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm; 3273 3274 //if (self != NULL) 3275 // LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self); 3276 3277 assert(vm != NULL); 3278 3279 JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt)); 3280 newEnv->funcTable = &gNativeInterface; 3281 if (self != NULL) { 3282 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self); 3283 assert(newEnv->envThreadId != 0); 3284 } else { 3285 /* make it obvious if we fail to initialize these later */ 3286 newEnv->envThreadId = 0x77777775; 3287 newEnv->self = (Thread*) 0x77777779; 3288 } 3289 if (gDvmJni.useCheckJni) { 3290 dvmUseCheckedJniEnv(newEnv); 3291 } 3292 3293 ScopedPthreadMutexLock lock(&vm->envListLock); 3294 3295 /* insert at head of list */ 3296 newEnv->next = vm->envList; 3297 assert(newEnv->prev == NULL); 3298 if (vm->envList == NULL) { 3299 // rare, but possible 3300 vm->envList = newEnv; 3301 } else { 3302 vm->envList->prev = newEnv; 3303 } 3304 vm->envList = newEnv; 3305 3306 //if (self != NULL) 3307 // LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self); 3308 return (JNIEnv*) newEnv; 3309} 3310 3311/* 3312 * Remove a JNIEnv struct from the list and free it. 3313 */ 3314void dvmDestroyJNIEnv(JNIEnv* env) { 3315 if (env == NULL) { 3316 return; 3317 } 3318 3319 //LOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self); 3320 3321 JNIEnvExt* extEnv = (JNIEnvExt*) env; 3322 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm; 3323 3324 ScopedPthreadMutexLock lock(&vm->envListLock); 3325 3326 if (extEnv == vm->envList) { 3327 assert(extEnv->prev == NULL); 3328 vm->envList = extEnv->next; 3329 } else { 3330 assert(extEnv->prev != NULL); 3331 extEnv->prev->next = extEnv->next; 3332 } 3333 if (extEnv->next != NULL) { 3334 extEnv->next->prev = extEnv->prev; 3335 } 3336 3337 free(env); 3338 //LOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self); 3339} 3340 3341/* 3342 * Enable "checked JNI" after the VM has partially started. This must 3343 * only be called in "zygote" mode, when we have one thread running. 3344 * 3345 * This doesn't attempt to rewrite the JNI call bridge associated with 3346 * native methods, so we won't get those checks for any methods that have 3347 * already been resolved. 3348 */ 3349void dvmLateEnableCheckedJni() { 3350 JNIEnvExt* extEnv = dvmGetJNIEnvForThread(); 3351 if (extEnv == NULL) { 3352 LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv"); 3353 return; 3354 } 3355 JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm; 3356 assert(extVm != NULL); 3357 3358 if (!gDvmJni.useCheckJni) { 3359 LOGD("Late-enabling CheckJNI"); 3360 dvmUseCheckedJniVm(extVm); 3361 dvmUseCheckedJniEnv(extEnv); 3362 } else { 3363 LOGD("Not late-enabling CheckJNI (already on)"); 3364 } 3365} 3366 3367/* 3368 * Not supported. 3369 */ 3370jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) { 3371 return JNI_ERR; 3372} 3373 3374/* 3375 * Return a buffer full of created VMs. 3376 * 3377 * We always have zero or one. 3378 */ 3379jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) { 3380 if (gDvmJni.jniVm != NULL) { 3381 *nVMs = 1; 3382 if (bufLen > 0) { 3383 *vmBuf++ = gDvmJni.jniVm; 3384 } 3385 } else { 3386 *nVMs = 0; 3387 } 3388 return JNI_OK; 3389} 3390 3391/* 3392 * Create a new VM instance. 3393 * 3394 * The current thread becomes the main VM thread. We return immediately, 3395 * which effectively means the caller is executing in a native method. 3396 */ 3397jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 3398 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args; 3399 if (args->version < JNI_VERSION_1_2) { 3400 return JNI_EVERSION; 3401 } 3402 3403 // TODO: don't allow creation of multiple VMs -- one per customer for now 3404 3405 /* zero globals; not strictly necessary the first time a VM is started */ 3406 memset(&gDvm, 0, sizeof(gDvm)); 3407 3408 /* 3409 * Set up structures for JNIEnv and VM. 3410 */ 3411 JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt)); 3412 memset(pVM, 0, sizeof(JavaVMExt)); 3413 pVM->funcTable = &gInvokeInterface; 3414 pVM->envList = NULL; 3415 dvmInitMutex(&pVM->envListLock); 3416 3417 UniquePtr<const char*[]> argv(new const char*[args->nOptions]); 3418 memset(argv.get(), 0, sizeof(char*) * (args->nOptions)); 3419 3420 /* 3421 * Convert JNI args to argv. 3422 * 3423 * We have to pull out vfprintf/exit/abort, because they use the 3424 * "extraInfo" field to pass function pointer "hooks" in. We also 3425 * look for the -Xcheck:jni stuff here. 3426 */ 3427 int argc = 0; 3428 bool sawJniOpts = false; 3429 for (int i = 0; i < args->nOptions; i++) { 3430 const char* optStr = args->options[i].optionString; 3431 if (optStr == NULL) { 3432 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i); 3433 return JNI_ERR; 3434 } else if (strcmp(optStr, "vfprintf") == 0) { 3435 gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo; 3436 } else if (strcmp(optStr, "exit") == 0) { 3437 gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo; 3438 } else if (strcmp(optStr, "abort") == 0) { 3439 gDvm.abortHook = (void (*)(void))args->options[i].extraInfo; 3440 } else if (strcmp(optStr, "sensitiveThread") == 0) { 3441 gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo; 3442 } else if (strcmp(optStr, "-Xcheck:jni") == 0) { 3443 gDvmJni.useCheckJni = true; 3444 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) { 3445 sawJniOpts = true; 3446 char* jniOpts = strdup(optStr + 10); 3447 size_t jniOptCount = 1; 3448 for (char* p = jniOpts; *p != 0; ++p) { 3449 if (*p == ',') { 3450 ++jniOptCount; 3451 *p = 0; 3452 } 3453 } 3454 char* jniOpt = jniOpts; 3455 for (size_t i = 0; i < jniOptCount; ++i) { 3456 if (strcmp(jniOpt, "warnonly") == 0) { 3457 gDvmJni.warnOnly = true; 3458 } else if (strcmp(jniOpt, "forcecopy") == 0) { 3459 gDvmJni.forceCopy = true; 3460 } else { 3461 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n", 3462 jniOpt); 3463 return JNI_ERR; 3464 } 3465 jniOpt += strlen(jniOpt) + 1; 3466 } 3467 free(jniOpts); 3468 } else { 3469 /* regular option */ 3470 argv[argc++] = optStr; 3471 } 3472 } 3473 3474 if (sawJniOpts && !gDvmJni.useCheckJni) { 3475 dvmFprintf(stderr, "ERROR: -Xjniopts only makes sense with -Xcheck:jni\n"); 3476 return JNI_ERR; 3477 } 3478 3479 if (gDvmJni.useCheckJni) { 3480 dvmUseCheckedJniVm(pVM); 3481 } 3482 3483 if (gDvmJni.jniVm != NULL) { 3484 dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n"); 3485 return JNI_ERR; 3486 } 3487 gDvmJni.jniVm = (JavaVM*) pVM; 3488 3489 /* 3490 * Create a JNIEnv for the main thread. We need to have something set up 3491 * here because some of the class initialization we do when starting 3492 * up the VM will call into native code. 3493 */ 3494 JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL); 3495 3496 /* Initialize VM. */ 3497 gDvm.initializing = true; 3498 int rc = dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv); 3499 gDvm.initializing = false; 3500 3501 if (rc != 0) { 3502 free(pEnv); 3503 free(pVM); 3504 LOGW("CreateJavaVM failed"); 3505 return JNI_ERR; 3506 } 3507 3508 /* 3509 * Success! Return stuff to caller. 3510 */ 3511 dvmChangeStatus(NULL, THREAD_NATIVE); 3512 *p_env = (JNIEnv*) pEnv; 3513 *p_vm = (JavaVM*) pVM; 3514 LOGV("CreateJavaVM succeeded"); 3515 return JNI_OK; 3516} 3517