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 ALOGE("Couldn't find '%s'", *ccp); 53 return false; 54 } 55 56 if (clazz->ifieldCount != 1) { 57 ALOGE("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 ALOGW("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 ALOGD("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 ALOGD("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 ALOGW("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 ALOGD("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 #ifdef ARCH_HAVE_ALIGNED_DOUBLES 905 double ret; 906 #endif 907 908 assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT)); 909 assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT)); 910 911 switch (dstType) { 912 case PRIM_BOOLEAN: 913 case PRIM_CHAR: 914 case PRIM_BYTE: { 915 conv = (srcType == dstType) ? OK4 : bad; 916 break; 917 } 918 case PRIM_SHORT: { 919 switch (srcType) { 920 case PRIM_BYTE: 921 case PRIM_SHORT: conv = OK4; break; 922 default: conv = bad; break; 923 } 924 break; 925 } 926 case PRIM_INT: { 927 switch (srcType) { 928 case PRIM_BYTE: 929 case PRIM_CHAR: 930 case PRIM_SHORT: 931 case PRIM_INT: conv = OK4; break; 932 default: conv = bad; break; 933 } 934 break; 935 } 936 case PRIM_LONG: { 937 switch (srcType) { 938 case PRIM_BYTE: 939 case PRIM_CHAR: 940 case PRIM_SHORT: 941 case PRIM_INT: conv = ItoJ; break; 942 case PRIM_LONG: conv = OK8; break; 943 default: conv = bad; break; 944 } 945 break; 946 } 947 case PRIM_FLOAT: { 948 switch (srcType) { 949 case PRIM_BYTE: 950 case PRIM_CHAR: 951 case PRIM_SHORT: 952 case PRIM_INT: conv = ItoF; break; 953 case PRIM_LONG: conv = JtoF; break; 954 case PRIM_FLOAT: conv = OK4; break; 955 default: conv = bad; break; 956 } 957 break; 958 } 959 case PRIM_DOUBLE: { 960 switch (srcType) { 961 case PRIM_BYTE: 962 case PRIM_CHAR: 963 case PRIM_SHORT: 964 case PRIM_INT: conv = ItoD; break; 965 case PRIM_LONG: conv = JtoD; break; 966 case PRIM_FLOAT: conv = FtoD; break; 967 case PRIM_DOUBLE: conv = OK8; break; 968 default: conv = bad; break; 969 } 970 break; 971 } 972 case PRIM_VOID: 973 case PRIM_NOT: 974 default: { 975 conv = bad; 976 break; 977 } 978 } 979 980 switch (conv) { 981 case OK4: *dstPtr = *srcPtr; return 1; 982 case OK8: *(s8*) dstPtr = *(s8*)srcPtr; return 2; 983 case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr); return 2; 984 #ifndef ARCH_HAVE_ALIGNED_DOUBLES 985 case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr); return 2; 986 case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2; 987 case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr); return 2; 988 #else 989 case ItoD: ret = (double) (*(s4*) srcPtr); memcpy(dstPtr, &ret, 8); return 2; 990 case JtoD: ret = (double) (*(long long*) srcPtr); memcpy(dstPtr, &ret, 8); return 2; 991 case FtoD: ret = (double) (*(float*) srcPtr); memcpy(dstPtr, &ret, 8); return 2; 992 #endif 993 case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr); return 1; 994 case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr); return 1; 995 case bad: { 996 ALOGV("illegal primitive conversion: '%s' to '%s'", 997 dexGetPrimitiveTypeDescriptor(srcType), 998 dexGetPrimitiveTypeDescriptor(dstType)); 999 return -1; 1000 } 1001 default: { 1002 dvmAbort(); 1003 return -1; // Keep the compiler happy. 1004 } 1005 } 1006 } 1007 1008 /* 1009 * Convert types and widen primitives. Puts the value of "arg" into 1010 * "destPtr". 1011 * 1012 * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error. 1013 */ 1014 int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr) 1015 { 1016 int retVal; 1017 1018 if (dvmIsPrimitiveClass(type)) { 1019 /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */ 1020 PrimitiveType srcType; 1021 s4* valuePtr; 1022 1023 srcType = getBoxedType(arg); 1024 if (srcType == PRIM_NOT) { // didn't pass a boxed primitive in 1025 LOGVV("conv arg: type '%s' not boxed primitive", 1026 arg->clazz->descriptor); 1027 return -1; 1028 } 1029 1030 /* assumes value is stored in first instance field */ 1031 valuePtr = (s4*) arg->instanceData; 1032 1033 retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType, 1034 valuePtr, destPtr); 1035 } else { 1036 /* verify object is compatible */ 1037 if ((arg == NULL) || dvmInstanceof(arg->clazz, type)) { 1038 *destPtr = (s4) arg; 1039 retVal = 1; 1040 } else { 1041 LOGVV("Arg %p (%s) not compatible with %s", 1042 arg, arg->clazz->descriptor, type->descriptor); 1043 retVal = -1; 1044 } 1045 } 1046 1047 return retVal; 1048 } 1049 1050 /* 1051 * Create a wrapper object for a primitive data type. If "returnType" is 1052 * not primitive, this just casts "value" to an object and returns it. 1053 * 1054 * We could invoke the "toValue" method on the box types to take 1055 * advantage of pre-created values, but running that through the 1056 * interpreter is probably less efficient than just allocating storage here. 1057 * 1058 * The caller must call dvmReleaseTrackedAlloc on the result. 1059 */ 1060 DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType) 1061 { 1062 ClassObject* wrapperClass; 1063 DataObject* wrapperObj; 1064 s4* dataPtr; 1065 PrimitiveType typeIndex = returnType->primitiveType; 1066 const char* classDescriptor; 1067 1068 if (typeIndex == PRIM_NOT) { 1069 /* add to tracking table so return value is always in table */ 1070 if (value.l != NULL) 1071 dvmAddTrackedAlloc((Object*)value.l, NULL); 1072 return (DataObject*) value.l; 1073 } 1074 1075 classDescriptor = dexGetBoxedTypeDescriptor(typeIndex); 1076 if (classDescriptor == NULL) { 1077 return NULL; 1078 } 1079 1080 wrapperClass = dvmFindSystemClass(classDescriptor); 1081 if (wrapperClass == NULL) { 1082 ALOGW("Unable to find '%s'", classDescriptor); 1083 assert(dvmCheckException(dvmThreadSelf())); 1084 return NULL; 1085 } 1086 1087 wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT); 1088 if (wrapperObj == NULL) 1089 return NULL; 1090 dataPtr = (s4*) wrapperObj->instanceData; 1091 1092 /* assumes value is stored in first instance field */ 1093 /* (see dvmValidateBoxClasses) */ 1094 if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE) 1095 *(s8*)dataPtr = value.j; 1096 else 1097 *dataPtr = value.i; 1098 1099 return wrapperObj; 1100 } 1101 1102 /* 1103 * Unwrap a primitive data type, if necessary. 1104 * 1105 * If "returnType" is not primitive, we just tuck "value" into JValue and 1106 * return it after verifying that it's the right type of object. 1107 * 1108 * Fails if the field is primitive and "value" is either not a boxed 1109 * primitive or is of a type that cannot be converted. 1110 * 1111 * Returns "true" on success, "false" on failure. 1112 */ 1113 bool dvmUnboxPrimitive(Object* value, ClassObject* returnType, 1114 JValue* pResult) 1115 { 1116 PrimitiveType typeIndex = returnType->primitiveType; 1117 PrimitiveType valueIndex; 1118 1119 if (typeIndex == PRIM_NOT) { 1120 if (value != NULL && !dvmInstanceof(value->clazz, returnType)) { 1121 ALOGD("wrong object type: %s %s", 1122 value->clazz->descriptor, returnType->descriptor); 1123 return false; 1124 } 1125 pResult->l = value; 1126 return true; 1127 } else if (typeIndex == PRIM_VOID) { 1128 /* can't put anything into a void */ 1129 return false; 1130 } 1131 1132 valueIndex = getBoxedType((DataObject*)value); 1133 if (valueIndex == PRIM_NOT) 1134 return false; 1135 1136 /* assumes value is stored in first instance field of "value" */ 1137 /* (see dvmValidateBoxClasses) */ 1138 if (dvmConvertPrimitiveValue(valueIndex, typeIndex, 1139 (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0) 1140 { 1141 ALOGV("Prim conversion failed"); 1142 return false; 1143 } 1144 1145 return true; 1146 } 1147 1148 1149 /* 1150 * Find the return type in the signature, and convert it to a class 1151 * object. For primitive types we use a boxed class, for reference types 1152 * we do a name lookup. 1153 * 1154 * On failure, we return NULL with an exception raised. 1155 */ 1156 ClassObject* dvmGetBoxedReturnType(const Method* meth) 1157 { 1158 const char* sig = dexProtoGetReturnType(&meth->prototype); 1159 1160 switch (*sig) { 1161 case 'Z': 1162 case 'C': 1163 case 'F': 1164 case 'D': 1165 case 'B': 1166 case 'S': 1167 case 'I': 1168 case 'J': 1169 case 'V': 1170 return dvmFindPrimitiveClass(*sig); 1171 case '[': 1172 case 'L': 1173 return dvmFindClass(sig, meth->clazz->classLoader); 1174 default: { 1175 /* should not have passed verification */ 1176 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); 1177 ALOGE("Bad return type in signature '%s'", desc); 1178 free(desc); 1179 dvmThrowInternalError(NULL); 1180 return NULL; 1181 } 1182 } 1183 } 1184 1185 1186 /* 1187 * JNI reflection support: convert reflection object to Field ptr. 1188 */ 1189 Field* dvmGetFieldFromReflectObj(Object* obj) 1190 { 1191 ClassObject* clazz; 1192 int slot; 1193 1194 assert(obj->clazz == gDvm.classJavaLangReflectField); 1195 clazz = (ClassObject*)dvmGetFieldObject(obj, 1196 gDvm.offJavaLangReflectField_declClass); 1197 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot); 1198 1199 /* must initialize the class before returning a field ID */ 1200 if (!dvmInitClass(clazz)) 1201 return NULL; 1202 1203 return dvmSlotToField(clazz, slot); 1204 } 1205 1206 /* 1207 * JNI reflection support: convert reflection object to Method ptr. 1208 */ 1209 Method* dvmGetMethodFromReflectObj(Object* obj) 1210 { 1211 ClassObject* clazz; 1212 int slot; 1213 1214 if (obj->clazz == gDvm.classJavaLangReflectConstructor) { 1215 clazz = (ClassObject*)dvmGetFieldObject(obj, 1216 gDvm.offJavaLangReflectConstructor_declClass); 1217 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot); 1218 } else if (obj->clazz == gDvm.classJavaLangReflectMethod) { 1219 clazz = (ClassObject*)dvmGetFieldObject(obj, 1220 gDvm.offJavaLangReflectMethod_declClass); 1221 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot); 1222 } else { 1223 assert(false); 1224 return NULL; 1225 } 1226 1227 /* must initialize the class before returning a method ID */ 1228 if (!dvmInitClass(clazz)) 1229 return NULL; 1230 1231 return dvmSlotToMethod(clazz, slot); 1232 } 1233 1234 /* 1235 * JNI reflection support: convert Field to reflection object. 1236 * 1237 * The return value is a java.lang.reflect.Field. 1238 * 1239 * Caller must call dvmReleaseTrackedAlloc(). 1240 */ 1241 Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field) 1242 { 1243 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) 1244 dvmInitClass(gDvm.classJavaLangReflectField); 1245 1246 /* caller must dvmReleaseTrackedAlloc(result) */ 1247 return createFieldObject(field, clazz); 1248 } 1249 1250 /* 1251 * JNI reflection support: convert Method to reflection object. 1252 * 1253 * The returned object will be either a java.lang.reflect.Method or 1254 * .Constructor, depending on whether "method" is a constructor. 1255 * 1256 * This is also used for certain "system" annotations. 1257 * 1258 * Caller must call dvmReleaseTrackedAlloc(). 1259 */ 1260 Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method) 1261 { 1262 UNUSED_PARAMETER(clazz); 1263 1264 if (strcmp(method->name, "<init>") == 0) { 1265 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) 1266 dvmInitClass(gDvm.classJavaLangReflectConstructor); 1267 1268 return createConstructorObject(method); 1269 } else { 1270 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 1271 dvmInitClass(gDvm.classJavaLangReflectMethod); 1272 1273 return dvmCreateReflectMethodObject(method); 1274 } 1275 } 1276