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 * Basic reflection calls and utility functions. 18 */ 19 #include "Dalvik.h" 20 21 #include <stdlib.h> 22 23 /* 24 * For some of the reflection stuff we need to un-box primitives, e.g. 25 * convert a java/lang/Integer to int or even a float. We assume that 26 * the first instance field holds the value. 27 * 28 * To verify this, we either need to ensure that the class has only one 29 * instance field, or we need to look up the field by name and verify 30 * that it comes first. The former is simpler, and should work. 31 */ 32 bool dvmValidateBoxClasses() 33 { 34 static const char* classes[] = { 35 "Ljava/lang/Boolean;", 36 "Ljava/lang/Character;", 37 "Ljava/lang/Float;", 38 "Ljava/lang/Double;", 39 "Ljava/lang/Byte;", 40 "Ljava/lang/Short;", 41 "Ljava/lang/Integer;", 42 "Ljava/lang/Long;", 43 NULL 44 }; 45 const char** ccp; 46 47 for (ccp = classes; *ccp != NULL; ccp++) { 48 ClassObject* clazz; 49 50 clazz = dvmFindClassNoInit(*ccp, NULL); 51 if (clazz == NULL) { 52 LOGE("Couldn't find '%s'", *ccp); 53 return false; 54 } 55 56 if (clazz->ifieldCount != 1) { 57 LOGE("Found %d instance fields in '%s'", 58 clazz->ifieldCount, *ccp); 59 return false; 60 } 61 } 62 63 return true; 64 } 65 66 67 /* 68 * Find the named class object. We have to trim "*pSignature" down to just 69 * the first token, do the lookup, and then restore anything important 70 * that we've stomped on. 71 * 72 * "pSig" will be advanced to the start of the next token. 73 */ 74 static ClassObject* convertSignaturePartToClass(char** pSignature, 75 const ClassObject* defClass) 76 { 77 ClassObject* clazz = NULL; 78 char* signature = *pSignature; 79 80 if (*signature == '[') { 81 /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */ 82 char savedChar; 83 84 while (*++signature == '[') 85 ; 86 if (*signature == 'L') { 87 while (*++signature != ';') 88 ; 89 } 90 91 /* advance past ';', and stomp on whatever comes next */ 92 savedChar = *++signature; 93 *signature = '\0'; 94 clazz = dvmFindArrayClass(*pSignature, defClass->classLoader); 95 *signature = savedChar; 96 } else if (*signature == 'L') { 97 /* looks like 'Landroid/debug/Stuff;"; we want the whole thing */ 98 char savedChar; 99 while (*++signature != ';') 100 ; 101 savedChar = *++signature; 102 *signature = '\0'; 103 clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader); 104 *signature = savedChar; 105 } else { 106 clazz = dvmFindPrimitiveClass(*signature++); 107 } 108 109 if (clazz == NULL) { 110 LOGW("Unable to match class for part: '%s'", *pSignature); 111 } 112 *pSignature = signature; 113 return clazz; 114 } 115 116 /* 117 * Convert the method signature to an array of classes. 118 * 119 * The tokenization process may mangle "*pSignature". On return, it will 120 * be pointing at the closing ')'. 121 * 122 * "defClass" is the method's class, which is needed to make class loaders 123 * happy. 124 */ 125 static ArrayObject* convertSignatureToClassArray(char** pSignature, 126 ClassObject* defClass) 127 { 128 char* signature = *pSignature; 129 130 assert(*signature == '('); 131 signature++; 132 133 /* count up the number of parameters */ 134 size_t count = 0; 135 char* cp = signature; 136 while (*cp != ')') { 137 count++; 138 139 if (*cp == '[') { 140 while (*++cp == '[') 141 ; 142 } 143 if (*cp == 'L') { 144 while (*++cp != ';') 145 ; 146 } 147 cp++; 148 } 149 LOGVV("REFLECT found %d parameters in '%s'", count, *pSignature); 150 151 /* create an array to hold them */ 152 ArrayObject* classArray = dvmAllocArrayByClass(gDvm.classJavaLangClassArray, 153 count, ALLOC_DEFAULT); 154 if (classArray == NULL) 155 return NULL; 156 157 /* fill it in */ 158 cp = signature; 159 for (size_t i = 0; i < count; i++) { 160 ClassObject* clazz = convertSignaturePartToClass(&cp, defClass); 161 if (clazz == NULL) { 162 assert(dvmCheckException(dvmThreadSelf())); 163 return NULL; 164 } 165 LOGVV("REFLECT %d: '%s'", i, clazz->descriptor); 166 dvmSetObjectArrayElement(classArray, i, (Object *)clazz); 167 } 168 169 *pSignature = cp; 170 171 /* caller must call dvmReleaseTrackedAlloc */ 172 return classArray; 173 } 174 175 176 /* 177 * Convert a field pointer to a slot number. 178 * 179 * We use positive values starting from 0 for instance fields, negative 180 * values starting from -1 for static fields. 181 */ 182 static int fieldToSlot(const Field* field, const ClassObject* clazz) 183 { 184 int slot; 185 186 if (dvmIsStaticField(field)) { 187 slot = (StaticField*)field - &clazz->sfields[0]; 188 assert(slot >= 0 && slot < clazz->sfieldCount); 189 slot = -(slot+1); 190 } else { 191 slot = (InstField*)field - clazz->ifields; 192 assert(slot >= 0 && slot < clazz->ifieldCount); 193 } 194 195 return slot; 196 } 197 198 /* 199 * Convert a slot number to a field pointer. 200 */ 201 Field* dvmSlotToField(ClassObject* clazz, int slot) 202 { 203 if (slot < 0) { 204 slot = -(slot+1); 205 assert(slot < clazz->sfieldCount); 206 return (Field*)(void*)&clazz->sfields[slot]; 207 } else { 208 assert(slot < clazz->ifieldCount); 209 return (Field*)(void*)&clazz->ifields[slot]; 210 } 211 } 212 213 /* 214 * Create a new java.lang.reflect.Field object from "field". 215 * 216 * The Field spec doesn't specify the constructor. We're going to use the 217 * one from our existing class libs: 218 * 219 * private Field(Class declaringClass, Class type, String name, int slot) 220 */ 221 static Object* createFieldObject(Field* field, const ClassObject* clazz) 222 { 223 Object* result = NULL; 224 Object* fieldObj = NULL; 225 StringObject* nameObj = NULL; 226 ClassObject* type; 227 char* mangle; 228 char* cp; 229 int slot; 230 231 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField)); 232 233 fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT); 234 if (fieldObj == NULL) 235 goto bail; 236 237 cp = mangle = strdup(field->signature); 238 type = convertSignaturePartToClass(&cp, clazz); 239 free(mangle); 240 if (type == NULL) 241 goto bail; 242 243 nameObj = dvmCreateStringFromCstr(field->name); 244 if (nameObj == NULL) 245 goto bail; 246 247 slot = fieldToSlot(field, clazz); 248 249 JValue unused; 250 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init, 251 fieldObj, &unused, clazz, type, nameObj, slot); 252 if (dvmCheckException(dvmThreadSelf())) { 253 LOGD("Field class init threw exception"); 254 goto bail; 255 } 256 257 result = fieldObj; 258 259 bail: 260 dvmReleaseTrackedAlloc((Object*) nameObj, NULL); 261 if (result == NULL) 262 dvmReleaseTrackedAlloc((Object*) fieldObj, NULL); 263 /* caller must dvmReleaseTrackedAlloc(result) */ 264 return result; 265 } 266 267 /* 268 * 269 * Get an array with all fields declared by a class. 270 * 271 * This includes both static and instance fields. 272 */ 273 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly) 274 { 275 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) 276 dvmInitClass(gDvm.classJavaLangReflectField); 277 278 /* count #of fields */ 279 size_t count; 280 if (!publicOnly) 281 count = clazz->sfieldCount + clazz->ifieldCount; 282 else { 283 count = 0; 284 for (int i = 0; i < clazz->sfieldCount; i++) { 285 if ((clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0) 286 count++; 287 } 288 for (int i = 0; i < clazz->ifieldCount; i++) { 289 if ((clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0) 290 count++; 291 } 292 } 293 294 /* create the Field[] array */ 295 ArrayObject* fieldArray = 296 dvmAllocArrayByClass(gDvm.classJavaLangReflectFieldArray, count, ALLOC_DEFAULT); 297 if (fieldArray == NULL) 298 return NULL; 299 300 /* populate */ 301 size_t fieldCount = 0; 302 for (int i = 0; i < clazz->sfieldCount; i++) { 303 if (!publicOnly || 304 (clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0) 305 { 306 Object* field = createFieldObject(&clazz->sfields[i], clazz); 307 if (field == NULL) { 308 goto fail; 309 } 310 dvmSetObjectArrayElement(fieldArray, fieldCount, field); 311 dvmReleaseTrackedAlloc(field, NULL); 312 ++fieldCount; 313 } 314 } 315 for (int i = 0; i < clazz->ifieldCount; i++) { 316 if (!publicOnly || 317 (clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0) 318 { 319 Object* field = createFieldObject(&clazz->ifields[i], clazz); 320 if (field == NULL) { 321 goto fail; 322 } 323 dvmSetObjectArrayElement(fieldArray, fieldCount, field); 324 dvmReleaseTrackedAlloc(field, NULL); 325 ++fieldCount; 326 } 327 } 328 329 assert(fieldCount == fieldArray->length); 330 331 /* caller must call dvmReleaseTrackedAlloc */ 332 return fieldArray; 333 334 fail: 335 dvmReleaseTrackedAlloc((Object*) fieldArray, NULL); 336 return NULL; 337 } 338 339 340 /* 341 * Convert a method pointer to a slot number. 342 * 343 * We use positive values starting from 0 for virtual methods, negative 344 * values starting from -1 for static methods. 345 */ 346 static int methodToSlot(const Method* meth) 347 { 348 ClassObject* clazz = meth->clazz; 349 int slot; 350 351 if (dvmIsDirectMethod(meth)) { 352 slot = meth - clazz->directMethods; 353 assert(slot >= 0 && slot < clazz->directMethodCount); 354 slot = -(slot+1); 355 } else { 356 slot = meth - clazz->virtualMethods; 357 assert(slot >= 0 && slot < clazz->virtualMethodCount); 358 } 359 360 return slot; 361 } 362 363 /* 364 * Convert a slot number to a method pointer. 365 */ 366 Method* dvmSlotToMethod(ClassObject* clazz, int slot) 367 { 368 if (slot < 0) { 369 slot = -(slot+1); 370 assert(slot < clazz->directMethodCount); 371 return &clazz->directMethods[slot]; 372 } else { 373 assert(slot < clazz->virtualMethodCount); 374 return &clazz->virtualMethods[slot]; 375 } 376 } 377 378 /* 379 * Create a new java/lang/reflect/Constructor object, using the contents of 380 * "meth" to construct it. 381 * 382 * The spec doesn't specify the constructor. We're going to use the 383 * one from our existing class libs: 384 * 385 * private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes, 386 * int slot) 387 */ 388 static Object* createConstructorObject(Method* meth) 389 { 390 Object* result = NULL; 391 ArrayObject* params = NULL; 392 ArrayObject* exceptions = NULL; 393 Object* consObj; 394 DexStringCache mangle; 395 char* cp; 396 int slot; 397 398 dexStringCacheInit(&mangle); 399 400 /* parent should guarantee init so we don't have to check on every call */ 401 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)); 402 403 consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor, 404 ALLOC_DEFAULT); 405 if (consObj == NULL) 406 goto bail; 407 408 /* 409 * Convert the signature string into an array of classes representing 410 * the arguments. 411 */ 412 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle); 413 params = convertSignatureToClassArray(&cp, meth->clazz); 414 if (params == NULL) 415 goto bail; 416 assert(*cp == ')'); 417 assert(*(cp+1) == 'V'); 418 419 /* 420 * Create an array with one entry for every exception that the class 421 * is declared to throw. 422 */ 423 exceptions = dvmGetMethodThrows(meth); 424 if (dvmCheckException(dvmThreadSelf())) 425 goto bail; 426 427 slot = methodToSlot(meth); 428 429 JValue unused; 430 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init, 431 consObj, &unused, meth->clazz, params, exceptions, slot); 432 if (dvmCheckException(dvmThreadSelf())) { 433 LOGD("Constructor class init threw exception"); 434 goto bail; 435 } 436 437 result = consObj; 438 439 bail: 440 dexStringCacheRelease(&mangle); 441 dvmReleaseTrackedAlloc((Object*) params, NULL); 442 dvmReleaseTrackedAlloc((Object*) exceptions, NULL); 443 if (result == NULL) { 444 assert(dvmCheckException(dvmThreadSelf())); 445 dvmReleaseTrackedAlloc(consObj, NULL); 446 } 447 /* caller must dvmReleaseTrackedAlloc(result) */ 448 return result; 449 } 450 451 /* 452 * Get an array with all constructors declared by a class. 453 */ 454 ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly) 455 { 456 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) 457 dvmInitClass(gDvm.classJavaLangReflectConstructor); 458 459 /* 460 * Ordinarily we init the class the first time we resolve a method. 461 * We're bypassing the normal resolution mechanism, so we init it here. 462 */ 463 if (!dvmIsClassInitialized(clazz)) 464 dvmInitClass(clazz); 465 466 /* 467 * Count up the #of relevant methods. 468 */ 469 size_t count = 0; 470 for (int i = 0; i < clazz->directMethodCount; ++i) { 471 Method* meth = &clazz->directMethods[i]; 472 if ((!publicOnly || dvmIsPublicMethod(meth)) && 473 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth)) 474 { 475 count++; 476 } 477 } 478 479 /* 480 * Create an array of Constructor objects. 481 */ 482 ClassObject* arrayClass = gDvm.classJavaLangReflectConstructorArray; 483 ArrayObject* ctorArray = dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT); 484 if (ctorArray == NULL) 485 return NULL; 486 487 /* 488 * Fill out the array. 489 */ 490 size_t ctorObjCount = 0; 491 for (int i = 0; i < clazz->directMethodCount; ++i) { 492 Method* meth = &clazz->directMethods[i]; 493 if ((!publicOnly || dvmIsPublicMethod(meth)) && 494 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth)) 495 { 496 Object* ctorObj = createConstructorObject(meth); 497 if (ctorObj == NULL) { 498 dvmReleaseTrackedAlloc((Object*) ctorArray, NULL); 499 return NULL; 500 } 501 dvmSetObjectArrayElement(ctorArray, ctorObjCount, ctorObj); 502 ++ctorObjCount; 503 dvmReleaseTrackedAlloc(ctorObj, NULL); 504 } 505 } 506 507 assert(ctorObjCount == ctorArray->length); 508 509 /* caller must call dvmReleaseTrackedAlloc */ 510 return ctorArray; 511 } 512 513 /* 514 * Create a new java/lang/reflect/Method object, using the contents of 515 * "meth" to construct it. 516 * 517 * The spec doesn't specify the constructor. We're going to use the 518 * one from our existing class libs: 519 * 520 * private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes, 521 * Class returnType, String name, int slot) 522 * 523 * The caller must call dvmReleaseTrackedAlloc() on the result. 524 */ 525 Object* dvmCreateReflectMethodObject(const Method* meth) 526 { 527 Object* result = NULL; 528 ArrayObject* params = NULL; 529 ArrayObject* exceptions = NULL; 530 StringObject* nameObj = NULL; 531 Object* methObj; 532 ClassObject* returnType; 533 DexStringCache mangle; 534 char* cp; 535 int slot; 536 537 if (dvmCheckException(dvmThreadSelf())) { 538 LOGW("WARNING: dvmCreateReflectMethodObject called with " 539 "exception pending"); 540 return NULL; 541 } 542 543 dexStringCacheInit(&mangle); 544 545 /* parent should guarantee init so we don't have to check on every call */ 546 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)); 547 548 methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT); 549 if (methObj == NULL) 550 goto bail; 551 552 /* 553 * Convert the signature string into an array of classes representing 554 * the arguments, and a class for the return type. 555 */ 556 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle); 557 params = convertSignatureToClassArray(&cp, meth->clazz); 558 if (params == NULL) 559 goto bail; 560 assert(*cp == ')'); 561 cp++; 562 returnType = convertSignaturePartToClass(&cp, meth->clazz); 563 if (returnType == NULL) 564 goto bail; 565 566 /* 567 * Create an array with one entry for every exception that the class 568 * is declared to throw. 569 */ 570 exceptions = dvmGetMethodThrows(meth); 571 if (dvmCheckException(dvmThreadSelf())) 572 goto bail; 573 574 /* method name */ 575 nameObj = dvmCreateStringFromCstr(meth->name); 576 if (nameObj == NULL) 577 goto bail; 578 579 slot = methodToSlot(meth); 580 581 JValue unused; 582 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init, 583 methObj, &unused, meth->clazz, params, exceptions, returnType, 584 nameObj, slot); 585 if (dvmCheckException(dvmThreadSelf())) { 586 LOGD("Method class init threw exception"); 587 goto bail; 588 } 589 590 result = methObj; 591 592 bail: 593 dexStringCacheRelease(&mangle); 594 if (result == NULL) { 595 assert(dvmCheckException(dvmThreadSelf())); 596 } 597 dvmReleaseTrackedAlloc((Object*) nameObj, NULL); 598 dvmReleaseTrackedAlloc((Object*) params, NULL); 599 dvmReleaseTrackedAlloc((Object*) exceptions, NULL); 600 if (result == NULL) 601 dvmReleaseTrackedAlloc(methObj, NULL); 602 return result; 603 } 604 605 /* 606 * Get an array with all methods declared by a class. 607 * 608 * This includes both static and virtual methods, and can include private 609 * members if "publicOnly" is false. It does not include Miranda methods, 610 * since those weren't declared in the class, or constructors. 611 */ 612 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly) 613 { 614 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 615 dvmInitClass(gDvm.classJavaLangReflectMethod); 616 617 /* 618 * Count up the #of relevant methods. 619 * 620 * Ignore virtual Miranda methods and direct class/object constructors. 621 */ 622 size_t count = 0; 623 Method* meth = clazz->virtualMethods; 624 for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) { 625 if ((!publicOnly || dvmIsPublicMethod(meth)) && 626 !dvmIsMirandaMethod(meth)) 627 { 628 count++; 629 } 630 } 631 meth = clazz->directMethods; 632 for (int i = 0; i < clazz->directMethodCount; i++, meth++) { 633 if ((!publicOnly || dvmIsPublicMethod(meth)) && meth->name[0] != '<') { 634 count++; 635 } 636 } 637 638 /* 639 * Create an array of Method objects. 640 */ 641 ArrayObject* methodArray = 642 dvmAllocArrayByClass(gDvm.classJavaLangReflectMethodArray, count, ALLOC_DEFAULT); 643 if (methodArray == NULL) 644 return NULL; 645 646 /* 647 * Fill out the array. 648 */ 649 meth = clazz->virtualMethods; 650 size_t methObjCount = 0; 651 for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) { 652 if ((!publicOnly || dvmIsPublicMethod(meth)) && 653 !dvmIsMirandaMethod(meth)) 654 { 655 Object* methObj = dvmCreateReflectMethodObject(meth); 656 if (methObj == NULL) 657 goto fail; 658 dvmSetObjectArrayElement(methodArray, methObjCount, methObj); 659 ++methObjCount; 660 dvmReleaseTrackedAlloc(methObj, NULL); 661 } 662 } 663 meth = clazz->directMethods; 664 for (int i = 0; i < clazz->directMethodCount; i++, meth++) { 665 if ((!publicOnly || dvmIsPublicMethod(meth)) && 666 meth->name[0] != '<') 667 { 668 Object* methObj = dvmCreateReflectMethodObject(meth); 669 if (methObj == NULL) 670 goto fail; 671 dvmSetObjectArrayElement(methodArray, methObjCount, methObj); 672 ++methObjCount; 673 dvmReleaseTrackedAlloc(methObj, NULL); 674 } 675 } 676 677 assert(methObjCount == methodArray->length); 678 679 /* caller must call dvmReleaseTrackedAlloc */ 680 return methodArray; 681 682 fail: 683 dvmReleaseTrackedAlloc((Object*) methodArray, NULL); 684 return NULL; 685 } 686 687 /* 688 * Fills targetDescriptorCache with the descriptors of the classes in args. 689 * This is the concatenation of the descriptors with no other adornment, 690 * consistent with dexProtoGetParameterDescriptors. 691 */ 692 static void createTargetDescriptor(ArrayObject* args, 693 DexStringCache* targetDescriptorCache) 694 { 695 ClassObject** argsArray = (ClassObject**)(void*)args->contents; 696 size_t length = 1; /* +1 for the terminating '\0' */ 697 for (size_t i = 0; i < args->length; ++i) { 698 length += strlen(argsArray[i]->descriptor); 699 } 700 701 dexStringCacheAlloc(targetDescriptorCache, length); 702 703 char* at = (char*) targetDescriptorCache->value; 704 for (size_t i = 0; i < args->length; ++i) { 705 const char* descriptor = argsArray[i]->descriptor; 706 strcpy(at, descriptor); 707 at += strlen(descriptor); 708 } 709 } 710 711 static Object* findConstructorOrMethodInArray(int methodsCount, Method* methods, 712 const char* name, const char* parameterDescriptors) 713 { 714 Method* method = NULL; 715 Method* result = NULL; 716 int i; 717 718 for (i = 0; i < methodsCount; ++i) { 719 method = &methods[i]; 720 if (strcmp(name, method->name) != 0 721 || dvmIsMirandaMethod(method) 722 || dexProtoCompareToParameterDescriptors(&method->prototype, 723 parameterDescriptors) != 0) { 724 continue; 725 } 726 727 result = method; 728 729 /* 730 * Covariant return types permit the class to define multiple 731 * methods with the same name and parameter types. Prefer to return 732 * a non-synthetic method in such situations. We may still return 733 * a synthetic method to handle situations like escalated visibility. 734 */ 735 if (!dvmIsSyntheticMethod(method)) { 736 break; 737 } 738 } 739 740 if (result != NULL) { 741 return dvmCreateReflectObjForMethod(result->clazz, result); 742 } 743 744 return NULL; 745 } 746 747 /* 748 * Get the named method. 749 */ 750 Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz, 751 StringObject* nameObj, ArrayObject* args) 752 { 753 Object* result = NULL; 754 DexStringCache targetDescriptorCache; 755 char* name; 756 const char* targetDescriptor; 757 758 dexStringCacheInit(&targetDescriptorCache); 759 760 name = dvmCreateCstrFromString(nameObj); 761 createTargetDescriptor(args, &targetDescriptorCache); 762 targetDescriptor = targetDescriptorCache.value; 763 764 result = findConstructorOrMethodInArray(clazz->directMethodCount, 765 clazz->directMethods, name, targetDescriptor); 766 if (result == NULL) { 767 result = findConstructorOrMethodInArray(clazz->virtualMethodCount, 768 clazz->virtualMethods, name, targetDescriptor); 769 } 770 771 free(name); 772 dexStringCacheRelease(&targetDescriptorCache); 773 return result; 774 } 775 776 /* 777 * Get the named field. 778 */ 779 Object* dvmGetDeclaredField(ClassObject* clazz, StringObject* nameObj) 780 { 781 int i; 782 Object* fieldObj = NULL; 783 char* name = dvmCreateCstrFromString(nameObj); 784 785 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) 786 dvmInitClass(gDvm.classJavaLangReflectField); 787 788 for (i = 0; i < clazz->sfieldCount; i++) { 789 Field* field = &clazz->sfields[i]; 790 if (strcmp(name, field->name) == 0) { 791 fieldObj = createFieldObject(field, clazz); 792 break; 793 } 794 } 795 if (fieldObj == NULL) { 796 for (i = 0; i < clazz->ifieldCount; i++) { 797 Field* field = &clazz->ifields[i]; 798 if (strcmp(name, field->name) == 0) { 799 fieldObj = createFieldObject(field, clazz); 800 break; 801 } 802 } 803 } 804 805 free(name); 806 return fieldObj; 807 } 808 809 /* 810 * Get all interfaces a class implements. If this is unable to allocate 811 * the result array, this raises an OutOfMemoryError and returns NULL. 812 */ 813 ArrayObject* dvmGetInterfaces(ClassObject* clazz) 814 { 815 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 816 dvmInitClass(gDvm.classJavaLangReflectMethod); 817 818 /* 819 * Create an array of Class objects. 820 */ 821 size_t count = clazz->interfaceCount; 822 ArrayObject* interfaceArray = 823 dvmAllocArrayByClass(gDvm.classJavaLangClassArray, count, ALLOC_DEFAULT); 824 if (interfaceArray == NULL) 825 return NULL; 826 827 /* 828 * Fill out the array. 829 */ 830 memcpy(interfaceArray->contents, clazz->interfaces, 831 count * sizeof(Object *)); 832 dvmWriteBarrierArray(interfaceArray, 0, count); 833 834 /* caller must call dvmReleaseTrackedAlloc */ 835 return interfaceArray; 836 } 837 838 /* 839 * Given a boxed primitive type, such as java/lang/Integer, return the 840 * primitive type index. 841 * 842 * Returns PRIM_NOT for void, since we never "box" that. 843 */ 844 static PrimitiveType getBoxedType(DataObject* arg) 845 { 846 static const int kJavaLangLen = 11; // strlen("Ljava/lang/") 847 848 if (arg == NULL) 849 return PRIM_NOT; 850 851 const char* name = arg->clazz->descriptor; 852 853 if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0) 854 return PRIM_NOT; 855 856 if (strcmp(name + kJavaLangLen, "Boolean;") == 0) 857 return PRIM_BOOLEAN; 858 if (strcmp(name + kJavaLangLen, "Character;") == 0) 859 return PRIM_CHAR; 860 if (strcmp(name + kJavaLangLen, "Float;") == 0) 861 return PRIM_FLOAT; 862 if (strcmp(name + kJavaLangLen, "Double;") == 0) 863 return PRIM_DOUBLE; 864 if (strcmp(name + kJavaLangLen, "Byte;") == 0) 865 return PRIM_BYTE; 866 if (strcmp(name + kJavaLangLen, "Short;") == 0) 867 return PRIM_SHORT; 868 if (strcmp(name + kJavaLangLen, "Integer;") == 0) 869 return PRIM_INT; 870 if (strcmp(name + kJavaLangLen, "Long;") == 0) 871 return PRIM_LONG; 872 return PRIM_NOT; 873 } 874 875 /* 876 * Convert primitive, boxed data from "srcPtr" to "dstPtr". 877 * 878 * Section v2 2.6 lists the various conversions and promotions. We 879 * allow the "widening" and "identity" conversions, but don't allow the 880 * "narrowing" conversions. 881 * 882 * Allowed: 883 * byte to short, int, long, float, double 884 * short to int, long, float double 885 * char to int, long, float, double 886 * int to long, float, double 887 * long to float, double 888 * float to double 889 * Values of types byte, char, and short are "internally" widened to int. 890 * 891 * Returns the width in 32-bit words of the destination primitive, or 892 * -1 if the conversion is not allowed. 893 * 894 * TODO? use JValue rather than u4 pointers 895 */ 896 int dvmConvertPrimitiveValue(PrimitiveType srcType, 897 PrimitiveType dstType, const s4* srcPtr, s4* dstPtr) 898 { 899 enum Conversion { 900 OK4, OK8, ItoJ, ItoD, JtoD, FtoD, ItoF, JtoF, bad 901 }; 902 903 enum Conversion conv; 904 905 assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT)); 906 assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT)); 907 908 switch (dstType) { 909 case PRIM_BOOLEAN: 910 case PRIM_CHAR: 911 case PRIM_BYTE: { 912 conv = (srcType == dstType) ? OK4 : bad; 913 break; 914 } 915 case PRIM_SHORT: { 916 switch (srcType) { 917 case PRIM_BYTE: 918 case PRIM_SHORT: conv = OK4; break; 919 default: conv = bad; break; 920 } 921 break; 922 } 923 case PRIM_INT: { 924 switch (srcType) { 925 case PRIM_BYTE: 926 case PRIM_CHAR: 927 case PRIM_SHORT: 928 case PRIM_INT: conv = OK4; break; 929 default: conv = bad; break; 930 } 931 break; 932 } 933 case PRIM_LONG: { 934 switch (srcType) { 935 case PRIM_BYTE: 936 case PRIM_CHAR: 937 case PRIM_SHORT: 938 case PRIM_INT: conv = ItoJ; break; 939 case PRIM_LONG: conv = OK8; break; 940 default: conv = bad; break; 941 } 942 break; 943 } 944 case PRIM_FLOAT: { 945 switch (srcType) { 946 case PRIM_BYTE: 947 case PRIM_CHAR: 948 case PRIM_SHORT: 949 case PRIM_INT: conv = ItoF; break; 950 case PRIM_LONG: conv = JtoF; break; 951 case PRIM_FLOAT: conv = OK4; break; 952 default: conv = bad; break; 953 } 954 break; 955 } 956 case PRIM_DOUBLE: { 957 switch (srcType) { 958 case PRIM_BYTE: 959 case PRIM_CHAR: 960 case PRIM_SHORT: 961 case PRIM_INT: conv = ItoD; break; 962 case PRIM_LONG: conv = JtoD; break; 963 case PRIM_FLOAT: conv = FtoD; break; 964 case PRIM_DOUBLE: conv = OK8; break; 965 default: conv = bad; break; 966 } 967 break; 968 } 969 case PRIM_VOID: 970 case PRIM_NOT: 971 default: { 972 conv = bad; 973 break; 974 } 975 } 976 977 switch (conv) { 978 case OK4: *dstPtr = *srcPtr; return 1; 979 case OK8: *(s8*) dstPtr = *(s8*)srcPtr; return 2; 980 case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr); return 2; 981 case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr); return 2; 982 case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2; 983 case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr); return 2; 984 case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr); return 1; 985 case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr); return 1; 986 case bad: { 987 LOGV("illegal primitive conversion: '%s' to '%s'", 988 dexGetPrimitiveTypeDescriptor(srcType), 989 dexGetPrimitiveTypeDescriptor(dstType)); 990 return -1; 991 } 992 default: { 993 dvmAbort(); 994 return -1; // Keep the compiler happy. 995 } 996 } 997 } 998 999 /* 1000 * Convert types and widen primitives. Puts the value of "arg" into 1001 * "destPtr". 1002 * 1003 * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error. 1004 */ 1005 int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr) 1006 { 1007 int retVal; 1008 1009 if (dvmIsPrimitiveClass(type)) { 1010 /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */ 1011 PrimitiveType srcType; 1012 s4* valuePtr; 1013 1014 srcType = getBoxedType(arg); 1015 if (srcType == PRIM_NOT) { // didn't pass a boxed primitive in 1016 LOGVV("conv arg: type '%s' not boxed primitive", 1017 arg->clazz->descriptor); 1018 return -1; 1019 } 1020 1021 /* assumes value is stored in first instance field */ 1022 valuePtr = (s4*) arg->instanceData; 1023 1024 retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType, 1025 valuePtr, destPtr); 1026 } else { 1027 /* verify object is compatible */ 1028 if ((arg == NULL) || dvmInstanceof(arg->clazz, type)) { 1029 *destPtr = (s4) arg; 1030 retVal = 1; 1031 } else { 1032 LOGVV("Arg %p (%s) not compatible with %s", 1033 arg, arg->clazz->descriptor, type->descriptor); 1034 retVal = -1; 1035 } 1036 } 1037 1038 return retVal; 1039 } 1040 1041 /* 1042 * Create a wrapper object for a primitive data type. If "returnType" is 1043 * not primitive, this just casts "value" to an object and returns it. 1044 * 1045 * We could invoke the "toValue" method on the box types to take 1046 * advantage of pre-created values, but running that through the 1047 * interpreter is probably less efficient than just allocating storage here. 1048 * 1049 * The caller must call dvmReleaseTrackedAlloc on the result. 1050 */ 1051 DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType) 1052 { 1053 ClassObject* wrapperClass; 1054 DataObject* wrapperObj; 1055 s4* dataPtr; 1056 PrimitiveType typeIndex = returnType->primitiveType; 1057 const char* classDescriptor; 1058 1059 if (typeIndex == PRIM_NOT) { 1060 /* add to tracking table so return value is always in table */ 1061 if (value.l != NULL) 1062 dvmAddTrackedAlloc((Object*)value.l, NULL); 1063 return (DataObject*) value.l; 1064 } 1065 1066 classDescriptor = dexGetBoxedTypeDescriptor(typeIndex); 1067 if (classDescriptor == NULL) { 1068 return NULL; 1069 } 1070 1071 wrapperClass = dvmFindSystemClass(classDescriptor); 1072 if (wrapperClass == NULL) { 1073 LOGW("Unable to find '%s'", classDescriptor); 1074 assert(dvmCheckException(dvmThreadSelf())); 1075 return NULL; 1076 } 1077 1078 wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT); 1079 if (wrapperObj == NULL) 1080 return NULL; 1081 dataPtr = (s4*) wrapperObj->instanceData; 1082 1083 /* assumes value is stored in first instance field */ 1084 /* (see dvmValidateBoxClasses) */ 1085 if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE) 1086 *(s8*)dataPtr = value.j; 1087 else 1088 *dataPtr = value.i; 1089 1090 return wrapperObj; 1091 } 1092 1093 /* 1094 * Unwrap a primitive data type, if necessary. 1095 * 1096 * If "returnType" is not primitive, we just tuck "value" into JValue and 1097 * return it after verifying that it's the right type of object. 1098 * 1099 * Fails if the field is primitive and "value" is either not a boxed 1100 * primitive or is of a type that cannot be converted. 1101 * 1102 * Returns "true" on success, "false" on failure. 1103 */ 1104 bool dvmUnboxPrimitive(Object* value, ClassObject* returnType, 1105 JValue* pResult) 1106 { 1107 PrimitiveType typeIndex = returnType->primitiveType; 1108 PrimitiveType valueIndex; 1109 1110 if (typeIndex == PRIM_NOT) { 1111 if (value != NULL && !dvmInstanceof(value->clazz, returnType)) { 1112 LOGD("wrong object type: %s %s", 1113 value->clazz->descriptor, returnType->descriptor); 1114 return false; 1115 } 1116 pResult->l = value; 1117 return true; 1118 } else if (typeIndex == PRIM_VOID) { 1119 /* can't put anything into a void */ 1120 return false; 1121 } 1122 1123 valueIndex = getBoxedType((DataObject*)value); 1124 if (valueIndex == PRIM_NOT) 1125 return false; 1126 1127 /* assumes value is stored in first instance field of "value" */ 1128 /* (see dvmValidateBoxClasses) */ 1129 if (dvmConvertPrimitiveValue(valueIndex, typeIndex, 1130 (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0) 1131 { 1132 LOGV("Prim conversion failed"); 1133 return false; 1134 } 1135 1136 return true; 1137 } 1138 1139 1140 /* 1141 * Find the return type in the signature, and convert it to a class 1142 * object. For primitive types we use a boxed class, for reference types 1143 * we do a name lookup. 1144 * 1145 * On failure, we return NULL with an exception raised. 1146 */ 1147 ClassObject* dvmGetBoxedReturnType(const Method* meth) 1148 { 1149 const char* sig = dexProtoGetReturnType(&meth->prototype); 1150 1151 switch (*sig) { 1152 case 'Z': 1153 case 'C': 1154 case 'F': 1155 case 'D': 1156 case 'B': 1157 case 'S': 1158 case 'I': 1159 case 'J': 1160 case 'V': 1161 return dvmFindPrimitiveClass(*sig); 1162 case '[': 1163 case 'L': 1164 return dvmFindClass(sig, meth->clazz->classLoader); 1165 default: { 1166 /* should not have passed verification */ 1167 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); 1168 LOGE("Bad return type in signature '%s'", desc); 1169 free(desc); 1170 dvmThrowInternalError(NULL); 1171 return NULL; 1172 } 1173 } 1174 } 1175 1176 1177 /* 1178 * JNI reflection support: convert reflection object to Field ptr. 1179 */ 1180 Field* dvmGetFieldFromReflectObj(Object* obj) 1181 { 1182 ClassObject* clazz; 1183 int slot; 1184 1185 assert(obj->clazz == gDvm.classJavaLangReflectField); 1186 clazz = (ClassObject*)dvmGetFieldObject(obj, 1187 gDvm.offJavaLangReflectField_declClass); 1188 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot); 1189 1190 /* must initialize the class before returning a field ID */ 1191 if (!dvmInitClass(clazz)) 1192 return NULL; 1193 1194 return dvmSlotToField(clazz, slot); 1195 } 1196 1197 /* 1198 * JNI reflection support: convert reflection object to Method ptr. 1199 */ 1200 Method* dvmGetMethodFromReflectObj(Object* obj) 1201 { 1202 ClassObject* clazz; 1203 int slot; 1204 1205 if (obj->clazz == gDvm.classJavaLangReflectConstructor) { 1206 clazz = (ClassObject*)dvmGetFieldObject(obj, 1207 gDvm.offJavaLangReflectConstructor_declClass); 1208 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot); 1209 } else if (obj->clazz == gDvm.classJavaLangReflectMethod) { 1210 clazz = (ClassObject*)dvmGetFieldObject(obj, 1211 gDvm.offJavaLangReflectMethod_declClass); 1212 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot); 1213 } else { 1214 assert(false); 1215 return NULL; 1216 } 1217 1218 /* must initialize the class before returning a method ID */ 1219 if (!dvmInitClass(clazz)) 1220 return NULL; 1221 1222 return dvmSlotToMethod(clazz, slot); 1223 } 1224 1225 /* 1226 * JNI reflection support: convert Field to reflection object. 1227 * 1228 * The return value is a java.lang.reflect.Field. 1229 * 1230 * Caller must call dvmReleaseTrackedAlloc(). 1231 */ 1232 Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field) 1233 { 1234 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) 1235 dvmInitClass(gDvm.classJavaLangReflectField); 1236 1237 /* caller must dvmReleaseTrackedAlloc(result) */ 1238 return createFieldObject(field, clazz); 1239 } 1240 1241 /* 1242 * JNI reflection support: convert Method to reflection object. 1243 * 1244 * The returned object will be either a java.lang.reflect.Method or 1245 * .Constructor, depending on whether "method" is a constructor. 1246 * 1247 * This is also used for certain "system" annotations. 1248 * 1249 * Caller must call dvmReleaseTrackedAlloc(). 1250 */ 1251 Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method) 1252 { 1253 UNUSED_PARAMETER(clazz); 1254 1255 if (strcmp(method->name, "<init>") == 0) { 1256 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) 1257 dvmInitClass(gDvm.classJavaLangReflectConstructor); 1258 1259 return createConstructorObject(method); 1260 } else { 1261 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 1262 dvmInitClass(gDvm.classJavaLangReflectMethod); 1263 1264 return dvmCreateReflectMethodObject(method); 1265 } 1266 } 1267