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 * Resolve classes, methods, fields, and strings. 18 * 19 * According to the VM spec (v2 5.5), classes may be initialized by use 20 * of the "new", "getstatic", "putstatic", or "invokestatic" instructions. 21 * If we are resolving a static method or static field, we make the 22 * initialization check here. 23 * 24 * (NOTE: the verifier has its own resolve functions, which can be invoked 25 * if a class isn't pre-verified. Those functions must not update the 26 * "resolved stuff" tables for static fields and methods, because they do 27 * not perform initialization.) 28 */ 29 #include "Dalvik.h" 30 31 #include <stdlib.h> 32 33 34 /* 35 * Find the class corresponding to "classIdx", which maps to a class name 36 * string. It might be in the same DEX file as "referrer", in a different 37 * DEX file, generated by a class loader, or generated by the VM (e.g. 38 * array classes). 39 * 40 * Because the DexTypeId is associated with the referring class' DEX file, 41 * we may have to resolve the same class more than once if it's referred 42 * to from classes in multiple DEX files. This is a necessary property for 43 * DEX files associated with different class loaders. 44 * 45 * We cache a copy of the lookup in the DexFile's "resolved class" table, 46 * so future references to "classIdx" are faster. 47 * 48 * Note that "referrer" may be in the process of being linked. 49 * 50 * Traditional VMs might do access checks here, but in Dalvik the class 51 * "constant pool" is shared between all classes in the DEX file. We rely 52 * on the verifier to do the checks for us. 53 * 54 * Does not initialize the class. 55 * 56 * "fromUnverifiedConstant" should only be set if this call is the direct 57 * result of executing a "const-class" or "instance-of" instruction, which 58 * use class constants not resolved by the bytecode verifier. 59 * 60 * Returns NULL with an exception raised on failure. 61 */ 62 ClassObject* dvmResolveClass(const ClassObject* referrer, u4 classIdx, 63 bool fromUnverifiedConstant) 64 { 65 DvmDex* pDvmDex = referrer->pDvmDex; 66 ClassObject* resClass; 67 const char* className; 68 69 /* 70 * Check the table first -- this gets called from the other "resolve" 71 * methods. 72 */ 73 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx); 74 if (resClass != NULL) 75 return resClass; 76 77 LOGVV("--- resolving class %u (referrer=%s cl=%p)\n", 78 classIdx, referrer->descriptor, referrer->classLoader); 79 80 /* 81 * Class hasn't been loaded yet, or is in the process of being loaded 82 * and initialized now. Try to get a copy. If we find one, put the 83 * pointer in the DexTypeId. There isn't a race condition here -- 84 * 32-bit writes are guaranteed atomic on all target platforms. Worst 85 * case we have two threads storing the same value. 86 * 87 * If this is an array class, we'll generate it here. 88 */ 89 className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx); 90 if (className[0] != '\0' && className[1] == '\0') { 91 /* primitive type */ 92 resClass = dvmFindPrimitiveClass(className[0]); 93 } else { 94 resClass = dvmFindClassNoInit(className, referrer->classLoader); 95 } 96 97 if (resClass != NULL) { 98 /* 99 * If the referrer was pre-verified, the resolved class must come 100 * from the same DEX or from a bootstrap class. The pre-verifier 101 * makes assumptions that could be invalidated by a wacky class 102 * loader. (See the notes at the top of oo/Class.c.) 103 * 104 * The verifier does *not* fail a class for using a const-class 105 * or instance-of instruction referring to an unresolveable class, 106 * because the result of the instruction is simply a Class object 107 * or boolean -- there's no need to resolve the class object during 108 * verification. Instance field and virtual method accesses can 109 * break dangerously if we get the wrong class, but const-class and 110 * instance-of are only interesting at execution time. So, if we 111 * we got here as part of executing one of the "unverified class" 112 * instructions, we skip the additional check. 113 * 114 * Ditto for class references from annotations and exception 115 * handler lists. 116 */ 117 if (!fromUnverifiedConstant && 118 IS_CLASS_FLAG_SET(referrer, CLASS_ISPREVERIFIED)) 119 { 120 ClassObject* resClassCheck = resClass; 121 if (dvmIsArrayClass(resClassCheck)) 122 resClassCheck = resClassCheck->elementClass; 123 124 if (referrer->pDvmDex != resClassCheck->pDvmDex && 125 resClassCheck->classLoader != NULL) 126 { 127 LOGW("Class resolved by unexpected DEX:" 128 " %s(%p):%p ref [%s] %s(%p):%p\n", 129 referrer->descriptor, referrer->classLoader, 130 referrer->pDvmDex, 131 resClass->descriptor, resClassCheck->descriptor, 132 resClassCheck->classLoader, resClassCheck->pDvmDex); 133 LOGW("(%s had used a different %s during pre-verification)\n", 134 referrer->descriptor, resClass->descriptor); 135 dvmThrowException("Ljava/lang/IllegalAccessError;", 136 "Class ref in pre-verified class resolved to unexpected " 137 "implementation"); 138 return NULL; 139 } 140 } 141 142 LOGVV("##### +ResolveClass(%s): referrer=%s dex=%p ldr=%p ref=%d\n", 143 resClass->descriptor, referrer->descriptor, referrer->pDvmDex, 144 referrer->classLoader, classIdx); 145 146 /* 147 * Add what we found to the list so we can skip the class search 148 * next time through. 149 * 150 * TODO: should we be doing this when fromUnverifiedConstant==true? 151 * (see comments at top of oo/Class.c) 152 */ 153 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass); 154 } else { 155 /* not found, exception should be raised */ 156 LOGVV("Class not found: %s\n", 157 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx)); 158 assert(dvmCheckException(dvmThreadSelf())); 159 } 160 161 return resClass; 162 } 163 164 165 /* 166 * Find the method corresponding to "methodRef". 167 * 168 * We use "referrer" to find the DexFile with the constant pool that 169 * "methodRef" is an index into. We also use its class loader. The method 170 * being resolved may very well be in a different DEX file. 171 * 172 * If this is a static method, we ensure that the method's class is 173 * initialized. 174 */ 175 Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx, 176 MethodType methodType) 177 { 178 DvmDex* pDvmDex = referrer->pDvmDex; 179 ClassObject* resClass; 180 const DexMethodId* pMethodId; 181 Method* resMethod; 182 183 assert(methodType != METHOD_INTERFACE); 184 185 LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx, 186 referrer->descriptor); 187 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); 188 189 resClass = dvmResolveClass(referrer, pMethodId->classIdx, false); 190 if (resClass == NULL) { 191 /* can't find the class that the method is a part of */ 192 assert(dvmCheckException(dvmThreadSelf())); 193 return NULL; 194 } 195 if (dvmIsInterfaceClass(resClass)) { 196 /* method is part of an interface */ 197 dvmThrowExceptionWithClassMessage( 198 "Ljava/lang/IncompatibleClassChangeError;", 199 resClass->descriptor); 200 return NULL; 201 } 202 203 const char* name = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); 204 DexProto proto; 205 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); 206 207 /* 208 * We need to chase up the class hierarchy to find methods defined 209 * in super-classes. (We only want to check the current class 210 * if we're looking for a constructor; since DIRECT calls are only 211 * for constructors and private methods, we don't want to walk up.) 212 */ 213 if (methodType == METHOD_DIRECT) { 214 resMethod = dvmFindDirectMethod(resClass, name, &proto); 215 } else if (methodType == METHOD_STATIC) { 216 resMethod = dvmFindDirectMethodHier(resClass, name, &proto); 217 } else { 218 resMethod = dvmFindVirtualMethodHier(resClass, name, &proto); 219 } 220 221 if (resMethod == NULL) { 222 dvmThrowException("Ljava/lang/NoSuchMethodError;", name); 223 return NULL; 224 } 225 226 LOGVV("--- found method %d (%s.%s)\n", 227 methodIdx, resClass->descriptor, resMethod->name); 228 229 /* see if this is a pure-abstract method */ 230 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) { 231 dvmThrowException("Ljava/lang/AbstractMethodError;", name); 232 return NULL; 233 } 234 235 /* 236 * If we're the first to resolve this class, we need to initialize 237 * it now. Only necessary for METHOD_STATIC. 238 */ 239 if (methodType == METHOD_STATIC) { 240 if (!dvmIsClassInitialized(resMethod->clazz) && 241 !dvmInitClass(resMethod->clazz)) 242 { 243 assert(dvmCheckException(dvmThreadSelf())); 244 return NULL; 245 } else { 246 assert(!dvmCheckException(dvmThreadSelf())); 247 } 248 } else { 249 /* 250 * Edge case: if the <clinit> for a class creates an instance 251 * of itself, we will call <init> on a class that is still being 252 * initialized by us. 253 */ 254 assert(dvmIsClassInitialized(resMethod->clazz) || 255 dvmIsClassInitializing(resMethod->clazz)); 256 } 257 258 /* 259 * The class is initialized, the method has been found. Add a pointer 260 * to our data structure so we don't have to jump through the hoops again. 261 */ 262 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); 263 264 return resMethod; 265 } 266 267 /* 268 * Resolve an interface method reference. 269 * 270 * Returns NULL with an exception raised on failure. 271 */ 272 Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx) 273 { 274 DvmDex* pDvmDex = referrer->pDvmDex; 275 ClassObject* resClass; 276 const DexMethodId* pMethodId; 277 Method* resMethod; 278 int i; 279 280 LOGVV("--- resolving interface method %d (referrer=%s)\n", 281 methodIdx, referrer->descriptor); 282 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); 283 284 resClass = dvmResolveClass(referrer, pMethodId->classIdx, false); 285 if (resClass == NULL) { 286 /* can't find the class that the method is a part of */ 287 assert(dvmCheckException(dvmThreadSelf())); 288 return NULL; 289 } 290 if (!dvmIsInterfaceClass(resClass)) { 291 /* whoops */ 292 dvmThrowExceptionWithClassMessage( 293 "Ljava/lang/IncompatibleClassChangeError;", 294 resClass->descriptor); 295 return NULL; 296 } 297 298 /* 299 * This is the first time the method has been resolved. Set it in our 300 * resolved-method structure. It always resolves to the same thing, 301 * so looking it up and storing it doesn't create a race condition. 302 * 303 * If we scan into the interface's superclass -- which is always 304 * java/lang/Object -- we will catch things like: 305 * interface I ... 306 * I myobj = (something that implements I) 307 * myobj.hashCode() 308 * However, the Method->methodIndex will be an offset into clazz->vtable, 309 * rather than an offset into clazz->iftable. The invoke-interface 310 * code can test to see if the method returned is abstract or concrete, 311 * and use methodIndex accordingly. I'm not doing this yet because 312 * (a) we waste time in an unusual case, and (b) we're probably going 313 * to fix it in the DEX optimizer. 314 * 315 * We do need to scan the superinterfaces, in case we're invoking a 316 * superinterface method on an interface reference. The class in the 317 * DexTypeId is for the static type of the object, not the class in 318 * which the method is first defined. We have the full, flattened 319 * list in "iftable". 320 */ 321 const char* methodName = 322 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); 323 324 DexProto proto; 325 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); 326 327 LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n", 328 methodName, methodSig, resClass->descriptor); 329 resMethod = dvmFindVirtualMethod(resClass, methodName, &proto); 330 if (resMethod == NULL) { 331 LOGVV("+++ did not resolve immediately\n"); 332 for (i = 0; i < resClass->iftableCount; i++) { 333 resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz, 334 methodName, &proto); 335 if (resMethod != NULL) 336 break; 337 } 338 339 if (resMethod == NULL) { 340 dvmThrowException("Ljava/lang/NoSuchMethodError;", methodName); 341 return NULL; 342 } 343 } else { 344 LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name, 345 resMethod->clazz->descriptor, (u4) resMethod->methodIndex); 346 } 347 348 LOGVV("--- found interface method %d (%s.%s)\n", 349 methodIdx, resClass->descriptor, resMethod->name); 350 351 /* we're expecting this to be abstract */ 352 assert(dvmIsAbstractMethod(resMethod)); 353 354 /* interface methods are always public; no need to check access */ 355 356 /* 357 * The interface class *may* be initialized. According to VM spec 358 * v2 2.17.4, the interfaces a class refers to "need not" be initialized 359 * when the class is initialized. 360 * 361 * It isn't necessary for an interface class to be initialized before 362 * we resolve methods on that interface. 363 * 364 * We choose not to do the initialization now. 365 */ 366 //assert(dvmIsClassInitialized(resMethod->clazz)); 367 368 /* 369 * The class is initialized, the method has been found. Add a pointer 370 * to our data structure so we don't have to jump through the hoops again. 371 */ 372 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); 373 374 return resMethod; 375 } 376 377 /* 378 * Resolve an instance field reference. 379 * 380 * Returns NULL and throws an exception on error (no such field, illegal 381 * access). 382 */ 383 InstField* dvmResolveInstField(const ClassObject* referrer, u4 ifieldIdx) 384 { 385 DvmDex* pDvmDex = referrer->pDvmDex; 386 ClassObject* resClass; 387 const DexFieldId* pFieldId; 388 InstField* resField; 389 390 LOGVV("--- resolving field %u (referrer=%s cl=%p)\n", 391 ifieldIdx, referrer->descriptor, referrer->classLoader); 392 393 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx); 394 395 /* 396 * Find the field's class. 397 */ 398 resClass = dvmResolveClass(referrer, pFieldId->classIdx, false); 399 if (resClass == NULL) { 400 assert(dvmCheckException(dvmThreadSelf())); 401 return NULL; 402 } 403 404 resField = dvmFindInstanceFieldHier(resClass, 405 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), 406 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); 407 if (resField == NULL) { 408 dvmThrowException("Ljava/lang/NoSuchFieldError;", 409 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); 410 return NULL; 411 } 412 413 /* 414 * Class must be initialized by now (unless verifier is buggy). We 415 * could still be in the process of initializing it if the field 416 * access is from a static initializer. 417 */ 418 assert(dvmIsClassInitialized(resField->field.clazz) || 419 dvmIsClassInitializing(resField->field.clazz)); 420 421 /* 422 * The class is initialized, the method has been found. Add a pointer 423 * to our data structure so we don't have to jump through the hoops again. 424 */ 425 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*)resField); 426 LOGVV(" field %u is %s.%s\n", 427 ifieldIdx, resField->field.clazz->descriptor, resField->field.name); 428 429 return resField; 430 } 431 432 /* 433 * Resolve a static field reference. The DexFile format doesn't distinguish 434 * between static and instance field references, so the "resolved" pointer 435 * in the Dex struct will have the wrong type. We trivially cast it here. 436 * 437 * Causes the field's class to be initialized. 438 */ 439 StaticField* dvmResolveStaticField(const ClassObject* referrer, u4 sfieldIdx) 440 { 441 DvmDex* pDvmDex = referrer->pDvmDex; 442 ClassObject* resClass; 443 const DexFieldId* pFieldId; 444 StaticField* resField; 445 446 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx); 447 448 /* 449 * Find the field's class. 450 */ 451 resClass = dvmResolveClass(referrer, pFieldId->classIdx, false); 452 if (resClass == NULL) { 453 assert(dvmCheckException(dvmThreadSelf())); 454 return NULL; 455 } 456 457 resField = dvmFindStaticFieldHier(resClass, 458 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), 459 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); 460 if (resField == NULL) { 461 dvmThrowException("Ljava/lang/NoSuchFieldError;", 462 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); 463 return NULL; 464 } 465 466 /* 467 * If we're the first to resolve the field in which this class resides, 468 * we need to do it now. Note that, if the field was inherited from 469 * a superclass, it is not necessarily the same as "resClass". 470 */ 471 if (!dvmIsClassInitialized(resField->field.clazz) && 472 !dvmInitClass(resField->field.clazz)) 473 { 474 assert(dvmCheckException(dvmThreadSelf())); 475 return NULL; 476 } 477 478 /* 479 * The class is initialized, the method has been found. Add a pointer 480 * to our data structure so we don't have to jump through the hoops again. 481 */ 482 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField); 483 484 return resField; 485 } 486 487 488 /* 489 * Resolve a string reference. 490 * 491 * Finding the string is easy. We need to return a reference to a 492 * java/lang/String object, not a bunch of characters, which means the 493 * first time we get here we need to create an interned string. 494 */ 495 StringObject* dvmResolveString(const ClassObject* referrer, u4 stringIdx) 496 { 497 DvmDex* pDvmDex = referrer->pDvmDex; 498 StringObject* strObj; 499 StringObject* internStrObj; 500 const char* utf8; 501 u4 utf16Size; 502 503 LOGVV("+++ resolving string, referrer is %s\n", referrer->descriptor); 504 505 /* 506 * Create a UTF-16 version so we can trivially compare it to what's 507 * already interned. 508 */ 509 utf8 = dexStringAndSizeById(pDvmDex->pDexFile, stringIdx, &utf16Size); 510 strObj = dvmCreateStringFromCstrAndLength(utf8, utf16Size, 511 ALLOC_DEFAULT); 512 if (strObj == NULL) { 513 /* ran out of space in GC heap? */ 514 assert(dvmCheckException(dvmThreadSelf())); 515 goto bail; 516 } 517 518 /* 519 * Add it to the intern list. The return value is the one in the 520 * intern list, which (due to race conditions) may or may not be 521 * the one we just created. The intern list is synchronized, so 522 * there will be only one "live" version. 523 * 524 * By requesting an immortal interned string, we guarantee that 525 * the returned object will never be collected by the GC. 526 * 527 * A NULL return here indicates some sort of hashing failure. 528 */ 529 internStrObj = dvmLookupImmortalInternedString(strObj); 530 dvmReleaseTrackedAlloc((Object*) strObj, NULL); 531 strObj = internStrObj; 532 if (strObj == NULL) { 533 assert(dvmCheckException(dvmThreadSelf())); 534 goto bail; 535 } 536 537 /* save a reference so we can go straight to the object next time */ 538 dvmDexSetResolvedString(pDvmDex, stringIdx, strObj); 539 540 bail: 541 return strObj; 542 } 543 544 /* 545 * For debugging: return a string representing the methodType. 546 */ 547 const char* dvmMethodTypeStr(MethodType methodType) 548 { 549 switch (methodType) { 550 case METHOD_DIRECT: return "direct"; 551 case METHOD_STATIC: return "static"; 552 case METHOD_VIRTUAL: return "virtual"; 553 case METHOD_INTERFACE: return "interface"; 554 case METHOD_UNKNOWN: return "UNKNOWN"; 555 } 556 assert(false); 557 return "BOGUS"; 558 } 559