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 * Operations on an Object. 19 */ 20 #include "Dalvik.h" 21 22 /* 23 * Find a matching field, in the current class only. 24 * 25 * Returns NULL if the field can't be found. (Does not throw an exception.) 26 */ 27 InstField* dvmFindInstanceField(const ClassObject* clazz, 28 const char* fieldName, const char* signature) 29 { 30 InstField* pField; 31 int i; 32 33 assert(clazz != NULL); 34 35 /* 36 * Find a field with a matching name and signature. The Java programming 37 * language does not allow you to have two fields with the same name 38 * and different types, but the Java VM spec does allow it, so we can't 39 * bail out early when the name matches. 40 */ 41 pField = clazz->ifields; 42 for (i = 0; i < clazz->ifieldCount; i++, pField++) { 43 if (strcmp(fieldName, pField->field.name) == 0 && 44 strcmp(signature, pField->field.signature) == 0) 45 { 46 return pField; 47 } 48 } 49 50 return NULL; 51 } 52 53 /* 54 * Find a matching field, in this class or a superclass. 55 * 56 * Searching through interfaces isn't necessary, because interface fields 57 * are inherently public/static/final. 58 * 59 * Returns NULL if the field can't be found. (Does not throw an exception.) 60 */ 61 InstField* dvmFindInstanceFieldHier(const ClassObject* clazz, 62 const char* fieldName, const char* signature) 63 { 64 InstField* pField; 65 66 /* 67 * Search for a match in the current class. 68 */ 69 pField = dvmFindInstanceField(clazz, fieldName, signature); 70 if (pField != NULL) 71 return pField; 72 73 if (clazz->super != NULL) 74 return dvmFindInstanceFieldHier(clazz->super, fieldName, signature); 75 else 76 return NULL; 77 } 78 79 80 /* 81 * Find a matching field, in this class or an interface. 82 * 83 * Returns NULL if the field can't be found. (Does not throw an exception.) 84 */ 85 StaticField* dvmFindStaticField(const ClassObject* clazz, 86 const char* fieldName, const char* signature) 87 { 88 const StaticField* pField; 89 int i; 90 91 assert(clazz != NULL); 92 93 /* 94 * Find a field with a matching name and signature. As with instance 95 * fields, the VM allows you to have two fields with the same name so 96 * long as they have different types. 97 */ 98 pField = &clazz->sfields[0]; 99 for (i = 0; i < clazz->sfieldCount; i++, pField++) { 100 if (strcmp(fieldName, pField->field.name) == 0 && 101 strcmp(signature, pField->field.signature) == 0) 102 { 103 return (StaticField*) pField; 104 } 105 } 106 107 return NULL; 108 } 109 110 /* 111 * Find a matching field, in this class or a superclass. 112 * 113 * Returns NULL if the field can't be found. (Does not throw an exception.) 114 */ 115 StaticField* dvmFindStaticFieldHier(const ClassObject* clazz, 116 const char* fieldName, const char* signature) 117 { 118 StaticField* pField; 119 120 /* 121 * Search for a match in the current class. 122 */ 123 pField = dvmFindStaticField(clazz, fieldName, signature); 124 if (pField != NULL) 125 return pField; 126 127 /* 128 * See if it's in any of our interfaces. We don't check interfaces 129 * inherited from the superclass yet. 130 * 131 * (Note the set may have been stripped down because of redundancy with 132 * the superclass; see notes in createIftable.) 133 */ 134 int i = 0; 135 if (clazz->super != NULL) { 136 assert(clazz->iftableCount >= clazz->super->iftableCount); 137 i = clazz->super->iftableCount; 138 } 139 for ( ; i < clazz->iftableCount; i++) { 140 ClassObject* iface = clazz->iftable[i].clazz; 141 pField = dvmFindStaticField(iface, fieldName, signature); 142 if (pField != NULL) 143 return pField; 144 } 145 146 if (clazz->super != NULL) 147 return dvmFindStaticFieldHier(clazz->super, fieldName, signature); 148 else 149 return NULL; 150 } 151 152 /* 153 * Find a matching field, in this class or a superclass. 154 * 155 * We scan both the static and instance field lists in the class. If it's 156 * not found there, we check the direct interfaces, and then recursively 157 * scan the superclasses. This is the order prescribed in the VM spec 158 * (v2 5.4.3.2). 159 * 160 * In most cases we know that we're looking for either a static or an 161 * instance field and there's no value in searching through both types. 162 * During verification we need to recognize and reject certain unusual 163 * situations, and we won't see them unless we walk the lists this way. 164 */ 165 Field* dvmFindFieldHier(const ClassObject* clazz, const char* fieldName, 166 const char* signature) 167 { 168 Field* pField; 169 170 /* 171 * Search for a match in the current class. Which set we scan first 172 * doesn't really matter. 173 */ 174 pField = (Field*) dvmFindStaticField(clazz, fieldName, signature); 175 if (pField != NULL) 176 return pField; 177 pField = (Field*) dvmFindInstanceField(clazz, fieldName, signature); 178 if (pField != NULL) 179 return pField; 180 181 /* 182 * See if it's in any of our interfaces. We don't check interfaces 183 * inherited from the superclass yet. 184 */ 185 int i = 0; 186 if (clazz->super != NULL) { 187 assert(clazz->iftableCount >= clazz->super->iftableCount); 188 i = clazz->super->iftableCount; 189 } 190 for ( ; i < clazz->iftableCount; i++) { 191 ClassObject* iface = clazz->iftable[i].clazz; 192 pField = (Field*) dvmFindStaticField(iface, fieldName, signature); 193 if (pField != NULL) 194 return pField; 195 } 196 197 if (clazz->super != NULL) 198 return dvmFindFieldHier(clazz->super, fieldName, signature); 199 else 200 return NULL; 201 } 202 203 204 /* 205 * Compare the given name, return type, and argument types with the contents 206 * of the given method. This returns 0 if they are equal and non-zero if not. 207 */ 208 static inline int compareMethodHelper(Method* method, const char* methodName, 209 const char* returnType, size_t argCount, const char** argTypes) 210 { 211 DexParameterIterator iterator; 212 const DexProto* proto; 213 214 if (strcmp(methodName, method->name) != 0) { 215 return 1; 216 } 217 218 proto = &method->prototype; 219 220 if (strcmp(returnType, dexProtoGetReturnType(proto)) != 0) { 221 return 1; 222 } 223 224 if (dexProtoGetParameterCount(proto) != argCount) { 225 return 1; 226 } 227 228 dexParameterIteratorInit(&iterator, proto); 229 230 for (/*argCount*/; argCount != 0; argCount--, argTypes++) { 231 const char* argType = *argTypes; 232 const char* paramType = dexParameterIteratorNextDescriptor(&iterator); 233 234 if (paramType == NULL) { 235 /* Param list ended early; no match */ 236 break; 237 } else if (strcmp(argType, paramType) != 0) { 238 /* Types aren't the same; no match. */ 239 break; 240 } 241 } 242 243 if (argCount == 0) { 244 /* We ran through all the given arguments... */ 245 if (dexParameterIteratorNextDescriptor(&iterator) == NULL) { 246 /* ...and through all the method's arguments; success! */ 247 return 0; 248 } 249 } 250 251 return 1; 252 } 253 254 /* 255 * Get the count of arguments in the given method descriptor string, 256 * and also find a pointer to the return type. 257 */ 258 static inline size_t countArgsAndFindReturnType(const char* descriptor, 259 const char** pReturnType) 260 { 261 size_t count = 0; 262 bool bogus = false; 263 bool done = false; 264 265 assert(*descriptor == '('); 266 descriptor++; 267 268 while (!done) { 269 switch (*descriptor) { 270 case 'B': case 'C': case 'D': case 'F': 271 case 'I': case 'J': case 'S': case 'Z': { 272 count++; 273 break; 274 } 275 case '[': { 276 do { 277 descriptor++; 278 } while (*descriptor == '['); 279 /* 280 * Don't increment count, as it will be taken care of 281 * by the next iteration. Also, decrement descriptor 282 * to compensate for the increment below the switch. 283 */ 284 descriptor--; 285 break; 286 } 287 case 'L': { 288 do { 289 descriptor++; 290 } while ((*descriptor != ';') && (*descriptor != '\0')); 291 count++; 292 if (*descriptor == '\0') { 293 /* Bogus descriptor. */ 294 done = true; 295 bogus = true; 296 } 297 break; 298 } 299 case ')': { 300 /* 301 * Note: The loop will exit after incrementing descriptor 302 * one more time, so it then points at the return type. 303 */ 304 done = true; 305 break; 306 } 307 default: { 308 /* Bogus descriptor. */ 309 done = true; 310 bogus = true; 311 break; 312 } 313 } 314 315 descriptor++; 316 } 317 318 if (bogus) { 319 *pReturnType = NULL; 320 return 0; 321 } 322 323 *pReturnType = descriptor; 324 return count; 325 } 326 327 /* 328 * Copy the argument types into the given array using the given buffer 329 * for the contents. 330 */ 331 static inline void copyTypes(char* buffer, const char** argTypes, 332 size_t argCount, const char* descriptor) 333 { 334 size_t i; 335 char c; 336 337 /* Skip the '('. */ 338 descriptor++; 339 340 for (i = 0; i < argCount; i++) { 341 argTypes[i] = buffer; 342 343 /* Copy all the array markers and one extra character. */ 344 do { 345 c = *(descriptor++); 346 *(buffer++) = c; 347 } while (c == '['); 348 349 if (c == 'L') { 350 /* Copy the rest of a class name. */ 351 do { 352 c = *(descriptor++); 353 *(buffer++) = c; 354 } while (c != ';'); 355 } 356 357 *(buffer++) = '\0'; 358 } 359 } 360 361 /* 362 * Look for a match in the given class. Returns the match if found 363 * or NULL if not. 364 */ 365 static Method* findMethodInListByDescriptor(const ClassObject* clazz, 366 bool findVirtual, bool isHier, const char* name, const char* descriptor) 367 { 368 const char* returnType; 369 size_t argCount = countArgsAndFindReturnType(descriptor, &returnType); 370 371 if (returnType == NULL) { 372 LOGW("Bogus method descriptor: %s\n", descriptor); 373 return NULL; 374 } 375 376 /* 377 * Make buffer big enough for all the argument type characters and 378 * one '\0' per argument. The "- 2" is because "returnType - 379 * descriptor" includes two parens. 380 */ 381 char buffer[argCount + (returnType - descriptor) - 2]; 382 const char* argTypes[argCount]; 383 384 copyTypes(buffer, argTypes, argCount, descriptor); 385 386 while (clazz != NULL) { 387 Method* methods; 388 size_t methodCount; 389 size_t i; 390 391 if (findVirtual) { 392 methods = clazz->virtualMethods; 393 methodCount = clazz->virtualMethodCount; 394 } else { 395 methods = clazz->directMethods; 396 methodCount = clazz->directMethodCount; 397 } 398 399 for (i = 0; i < methodCount; i++) { 400 Method* method = &methods[i]; 401 if (compareMethodHelper(method, name, returnType, argCount, 402 argTypes) == 0) { 403 return method; 404 } 405 } 406 407 if (! isHier) { 408 break; 409 } 410 411 clazz = clazz->super; 412 } 413 414 return NULL; 415 } 416 417 /* 418 * Look for a match in the given clazz. Returns the match if found 419 * or NULL if not. 420 * 421 * "wantedType" should be METHOD_VIRTUAL or METHOD_DIRECT to indicate the 422 * list to search through. If the match can come from either list, use 423 * MATCH_UNKNOWN to scan both. 424 */ 425 static Method* findMethodInListByProto(const ClassObject* clazz, 426 MethodType wantedType, bool isHier, const char* name, const DexProto* proto) 427 { 428 while (clazz != NULL) { 429 int i; 430 431 /* 432 * Check the virtual and/or direct method lists. 433 */ 434 if (wantedType == METHOD_VIRTUAL || wantedType == METHOD_UNKNOWN) { 435 for (i = 0; i < clazz->virtualMethodCount; i++) { 436 Method* method = &clazz->virtualMethods[i]; 437 if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) { 438 return method; 439 } 440 } 441 } 442 if (wantedType == METHOD_DIRECT || wantedType == METHOD_UNKNOWN) { 443 for (i = 0; i < clazz->directMethodCount; i++) { 444 Method* method = &clazz->directMethods[i]; 445 if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) { 446 return method; 447 } 448 } 449 } 450 451 if (! isHier) { 452 break; 453 } 454 455 clazz = clazz->super; 456 } 457 458 return NULL; 459 } 460 461 /* 462 * Find a "virtual" method in a class. 463 * 464 * Does not chase into the superclass. 465 * 466 * Returns NULL if the method can't be found. (Does not throw an exception.) 467 */ 468 Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz, 469 const char* methodName, const char* descriptor) 470 { 471 return findMethodInListByDescriptor(clazz, true, false, 472 methodName, descriptor); 473 474 // TODO? - throw IncompatibleClassChangeError if a match is 475 // found in the directMethods list, rather than NotFoundError. 476 // Note we could have been called by dvmFindVirtualMethodHier though. 477 } 478 479 480 /* 481 * Find a "virtual" method in a class, knowing only the name. This is 482 * only useful in limited circumstances, e.g. when searching for a member 483 * of an annotation class. 484 * 485 * Does not chase into the superclass. 486 * 487 * Returns NULL if the method can't be found. (Does not throw an exception.) 488 */ 489 Method* dvmFindVirtualMethodByName(const ClassObject* clazz, 490 const char* methodName) 491 { 492 Method* methods = clazz->virtualMethods; 493 int methodCount = clazz->virtualMethodCount; 494 int i; 495 496 for (i = 0; i < methodCount; i++) { 497 if (strcmp(methods[i].name, methodName) == 0) 498 return &methods[i]; 499 } 500 501 return NULL; 502 } 503 504 /* 505 * Find a "virtual" method in a class. 506 * 507 * Does not chase into the superclass. 508 * 509 * Returns NULL if the method can't be found. (Does not throw an exception.) 510 */ 511 Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName, 512 const DexProto* proto) 513 { 514 return findMethodInListByProto(clazz, METHOD_VIRTUAL, false, methodName, 515 proto); 516 } 517 518 /* 519 * Find a "virtual" method in a class. If we don't find it, try the 520 * superclass. 521 * 522 * Returns NULL if the method can't be found. (Does not throw an exception.) 523 */ 524 Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz, 525 const char* methodName, const char* descriptor) 526 { 527 return findMethodInListByDescriptor(clazz, true, true, 528 methodName, descriptor); 529 } 530 531 /* 532 * Find a "virtual" method in a class. If we don't find it, try the 533 * superclass. 534 * 535 * Returns NULL if the method can't be found. (Does not throw an exception.) 536 */ 537 Method* dvmFindVirtualMethodHier(const ClassObject* clazz, 538 const char* methodName, const DexProto* proto) 539 { 540 return findMethodInListByProto(clazz, METHOD_VIRTUAL, true, methodName, 541 proto); 542 } 543 544 /* 545 * Find a "direct" method (static, private, or "<*init>"). 546 * 547 * Returns NULL if the method can't be found. (Does not throw an exception.) 548 */ 549 Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz, 550 const char* methodName, const char* descriptor) 551 { 552 return findMethodInListByDescriptor(clazz, false, false, 553 methodName, descriptor); 554 } 555 556 /* 557 * Find a "direct" method. If we don't find it, try the superclass. This 558 * is only appropriate for static methods, but will work for all direct 559 * methods. 560 * 561 * Returns NULL if the method can't be found. (Does not throw an exception.) 562 */ 563 Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz, 564 const char* methodName, const char* descriptor) 565 { 566 return findMethodInListByDescriptor(clazz, false, true, 567 methodName, descriptor); 568 } 569 570 /* 571 * Find a "direct" method (static or "<*init>"). 572 * 573 * Returns NULL if the method can't be found. (Does not throw an exception.) 574 */ 575 Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName, 576 const DexProto* proto) 577 { 578 return findMethodInListByProto(clazz, METHOD_DIRECT, false, methodName, 579 proto); 580 } 581 582 /* 583 * Find a "direct" method in a class. If we don't find it, try the 584 * superclass. 585 * 586 * Returns NULL if the method can't be found. (Does not throw an exception.) 587 */ 588 Method* dvmFindDirectMethodHier(const ClassObject* clazz, 589 const char* methodName, const DexProto* proto) 590 { 591 return findMethodInListByProto(clazz, METHOD_DIRECT, true, methodName, 592 proto); 593 } 594 595 /* 596 * Find a virtual or static method in a class. If we don't find it, try the 597 * superclass. This is compatible with the VM spec (v2 5.4.3.3) method 598 * search order, but it stops short of scanning through interfaces (which 599 * should be done after this function completes). 600 * 601 * In most cases we know that we're looking for either a static or an 602 * instance field and there's no value in searching through both types. 603 * During verification we need to recognize and reject certain unusual 604 * situations, and we won't see them unless we walk the lists this way. 605 * 606 * Returns NULL if the method can't be found. (Does not throw an exception.) 607 */ 608 Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName, 609 const DexProto* proto) 610 { 611 return findMethodInListByProto(clazz, METHOD_UNKNOWN, true, methodName, 612 proto); 613 } 614 615 616 /* 617 * We have a method pointer for a method in "clazz", but it might be 618 * pointing to a method in a derived class. We want to find the actual entry 619 * from the class' vtable. If "clazz" is an interface, we have to do a 620 * little more digging. 621 * 622 * (This is used for reflection and JNI "call method" calls.) 623 */ 624 const Method* dvmGetVirtualizedMethod(const ClassObject* clazz, 625 const Method* meth) 626 { 627 Method* actualMeth; 628 int methodIndex; 629 630 assert(!dvmIsStaticMethod(meth)); 631 632 if (dvmIsPrivateMethod(meth)) // no vtable entry for these 633 return meth; 634 635 /* 636 * If the method was declared in an interface, we need to scan through 637 * the class' list of interfaces for it, and find the vtable index 638 * from that. 639 * 640 * TODO: use the interface cache. 641 */ 642 if (dvmIsInterfaceClass(meth->clazz)) { 643 int i; 644 645 for (i = 0; i < clazz->iftableCount; i++) { 646 if (clazz->iftable[i].clazz == meth->clazz) 647 break; 648 } 649 if (i == clazz->iftableCount) { 650 dvmThrowException("Ljava/lang/IncompatibleClassChangeError;", 651 "invoking method from interface not implemented by class"); 652 return NULL; 653 } 654 655 methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex]; 656 } else { 657 methodIndex = meth->methodIndex; 658 } 659 660 assert(methodIndex >= 0 && methodIndex < clazz->vtableCount); 661 actualMeth = clazz->vtable[methodIndex]; 662 663 /* 664 * Make sure there's code to execute. 665 */ 666 if (dvmIsAbstractMethod(actualMeth)) { 667 dvmThrowException("Ljava/lang/AbstractMethodError;", NULL); 668 return NULL; 669 } 670 assert(!dvmIsMirandaMethod(actualMeth)); 671 672 return actualMeth; 673 } 674 675 /* 676 * Get the source file for a method. 677 */ 678 const char* dvmGetMethodSourceFile(const Method* meth) 679 { 680 /* 681 * TODO: A method's debug info can override the default source 682 * file for a class, so we should account for that possibility 683 * here. 684 */ 685 return meth->clazz->sourceFile; 686 } 687 688 /* 689 * Dump some information about an object. 690 */ 691 void dvmDumpObject(const Object* obj) 692 { 693 ClassObject* clazz; 694 int i; 695 696 if (obj == NULL || obj->clazz == NULL) { 697 LOGW("Null or malformed object not dumped"); 698 return; 699 } 700 701 clazz = obj->clazz; 702 LOGD("----- Object dump: %p (%s, %d bytes) -----", 703 obj, clazz->descriptor, (int) clazz->objectSize); 704 //printHexDump(obj, clazz->objectSize); 705 LOGD(" Fields:"); 706 while (clazz != NULL) { 707 LOGD(" -- %s", clazz->descriptor); 708 for (i = 0; i < clazz->ifieldCount; i++) { 709 const InstField* pField = &clazz->ifields[i]; 710 char type = pField->field.signature[0]; 711 712 if (type == 'F' || type == 'D') { 713 double dval; 714 715 if (type == 'F') 716 dval = dvmGetFieldFloat(obj, pField->byteOffset); 717 else 718 dval = dvmGetFieldDouble(obj, pField->byteOffset); 719 720 LOGD(" %2d: '%s' '%s' af=%04x off=%d %.3f", i, 721 pField->field.name, pField->field.signature, 722 pField->field.accessFlags, pField->byteOffset, dval); 723 } else { 724 u8 lval; 725 726 if (type == 'J') 727 lval = dvmGetFieldLong(obj, pField->byteOffset); 728 else if (type == 'Z') 729 lval = dvmGetFieldBoolean(obj, pField->byteOffset); 730 else 731 lval = dvmGetFieldInt(obj, pField->byteOffset); 732 733 LOGD(" %2d: '%s' '%s' af=%04x off=%d 0x%08llx", i, 734 pField->field.name, pField->field.signature, 735 pField->field.accessFlags, pField->byteOffset, lval); 736 } 737 } 738 739 clazz = clazz->super; 740 } 741 if (obj->clazz == gDvm.classJavaLangClass) { 742 LOGD(" Static fields:"); 743 const StaticField* sfields = &((ClassObject *)obj)->sfields[0]; 744 for (i = 0; i < ((ClassObject *)obj)->sfieldCount; ++i) { 745 const StaticField* pField = &sfields[i]; 746 size_t byteOffset = (size_t)pField - (size_t)sfields; 747 char type = pField->field.signature[0]; 748 749 if (type == 'F' || type == 'D') { 750 double dval; 751 752 if (type == 'F') 753 dval = pField->value.f; 754 else 755 dval = pField->value.d; 756 757 LOGD(" %2d: '%s' '%s' af=%04x off=%zd %.3f", i, 758 pField->field.name, pField->field.signature, 759 pField->field.accessFlags, byteOffset, dval); 760 } else { 761 u8 lval; 762 763 if (type == 'J') 764 lval = pField->value.j; 765 else if (type == 'Z') 766 lval = pField->value.z; 767 else 768 lval = pField->value.i; 769 770 LOGD(" %2d: '%s' '%s' af=%04x off=%zd 0x%08llx", i, 771 pField->field.name, pField->field.signature, 772 pField->field.accessFlags, byteOffset, lval); 773 } 774 } 775 } 776 } 777