/* * Determine whether "sub" is a sub-class of "clazz", where "sub" is an * array class. * * "clazz" could be an array class, interface, or simple class. */ static int isArrayInstanceOf(const ClassObject* sub, const ClassObject* clazz) { assert(dvmIsArrayClass(sub)); /* "If T is an interface type, T must be one of the interfaces * implemented by arrays." * * I'm not checking that here, because dvmInstanceof tests for * interfaces first, and the generic dvmImplements stuff should * work correctly. */ assert(!dvmIsInterfaceClass(clazz)); /* make sure */ /* "If T is a class type, then T must be Object." * * The superclass of an array is always java.lang.Object, so just * compare against that. */ if (!dvmIsArrayClass(clazz)) return BOOL_TO_INT(clazz == sub->super); /* * If T is an array type TC[] ... */ return isArrayInstanceOfArray(sub->elementClass, sub->arrayDim, clazz); }
/* * Undo the effects of tweakLoader. */ static void untweakLoader(ClassObject* referrer, ClassObject* resClass) { if (!gDvm.optimizing || gDvm.optimizingBootstrapClass) return; if (dvmIsArrayClass(resClass)) resClass = resClass->elementClass; resClass->classLoader = NULL; }
/* * Perform the instanceof calculation. */ static inline int isInstanceof(const ClassObject* instance, const ClassObject* clazz) { if (dvmIsInterfaceClass(clazz)) { return dvmImplements(instance, clazz); } else if (dvmIsArrayClass(instance)) { return isArrayInstanceOf(instance, clazz); } else { return dvmIsSubClass(instance, clazz); } }
/* * Determine whether "sub" is an instance of "clazz", where both of these * are array classes. * * Consider an array class, e.g. Y[][], where Y is a subclass of X. * Y[][] instanceof Y[][] --> true (identity) * Y[][] instanceof X[][] --> true (element superclass) * Y[][] instanceof Y --> false * Y[][] instanceof Y[] --> false * Y[][] instanceof Object --> true (everything is an object) * Y[][] instanceof Object[] --> true * Y[][] instanceof Object[][] --> true * Y[][] instanceof Object[][][] --> false (too many []s) * Y[][] instanceof Serializable --> true (all arrays are Serializable) * Y[][] instanceof Serializable[] --> true * Y[][] instanceof Serializable[][] --> false (unless Y is Serializable) * * Don't forget about primitive types. * int[] instanceof Object[] --> false * * "subElemClass" is sub->elementClass. * * "subDim" is usually just sub->dim, but for some kinds of checks we want * to pass in a non-array class and pretend that it's an array. */ static int isArrayInstanceOfArray(const ClassObject* subElemClass, int subDim, const ClassObject* clazz) { //assert(dvmIsArrayClass(sub)); assert(dvmIsArrayClass(clazz)); /* "If T is an array type TC[]... one of the following must be true: * TC and SC are the same primitive type. * TC and SC are reference types and type SC can be cast to TC [...]." * * We need the class objects for the array elements. For speed we * tucked them into the class object. */ assert(subDim > 0 && clazz->arrayDim > 0); if (subDim == clazz->arrayDim) { /* * See if "sub" is an instance of "clazz". This handles the * interfaces, java.lang.Object, superclassing, etc. */ return dvmInstanceof(subElemClass, clazz->elementClass); } else if (subDim > clazz->arrayDim) { /* * The thing we might be an instance of has fewer dimensions. It * must be an Object or array of Object, or a standard array * interface or array of standard array interfaces (the standard * interfaces being java/lang/Cloneable and java/io/Serializable). */ if (dvmIsInterfaceClass(clazz->elementClass)) { /* * See if the class implements its base element. We know the * base element is an interface; if the array class implements * it, we know it's a standard array interface. */ return dvmImplements(clazz, clazz->elementClass); } else { /* * See if this is an array of Object, Object[], etc. We know * that the superclass of an array is always Object, so we * just compare the element type to that. */ return (clazz->elementClass == clazz->super); } } else { /* * Too many []s. */ return false; } }
/* * If "referrer" and "resClass" don't come from the same DEX file, and * the DEX we're working on is not destined for the bootstrap class path, * tweak the class loader so package-access checks work correctly. * * Only do this if we're doing pre-verification or optimization. */ static void tweakLoader(ClassObject* referrer, ClassObject* resClass) { if (!gDvm.optimizing) return; assert(referrer->classLoader == NULL); assert(resClass->classLoader == NULL); if (!gDvm.optimizingBootstrapClass) { /* class loader for an array class comes from element type */ if (dvmIsArrayClass(resClass)) resClass = resClass->elementClass; if (referrer->pDvmDex != resClass->pDvmDex) resClass->classLoader = (Object*) 0xdead3333; } }
/* * Determine whether or not we can put an object into an array, based on * the class hierarchy. The object might itself by an array, which means * we have to pay attention to the array instanceof rules. * * Note that "objectClass" could be an array, but objectClass->elementClass * is always a non-array type. */ bool dvmCanPutArrayElement(const ClassObject* objectClass, const ClassObject* arrayClass) { if (dvmIsArrayClass(objectClass)) { /* * We're stuffing an array into an array. We want to see if the * elements of "arrayClass" are compatible with "objectClass". * We bump up the number of dimensions in "objectClass" so that we * can compare the two directly. */ return isArrayInstanceOfArray(objectClass->elementClass, objectClass->arrayDim + 1, arrayClass); } else { /* * We're putting a non-array element into an array. We need to * test to see if the elements are compatible. The easiest way * to do that is to "arrayify" it and use the standard array * compatibility check. */ return isArrayInstanceOfArray(objectClass, 1, arrayClass); } }
GOTO_TARGET(filledNewArray, bool methodCallRange) { ClassObject* arrayClass; ArrayObject* newArray; u4* contents; char typeCh; int i; u4 arg5; EXPORT_PC(); ref = FETCH(1); /* class ref */ vdst = FETCH(2); /* first 4 regs -or- range base */ if (methodCallRange) { vsrc1 = INST_AA(inst); /* #of elements */ arg5 = -1; /* silence compiler warning */ ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}", vsrc1, ref, vdst, vdst+vsrc1-1); } else { arg5 = INST_A(inst); vsrc1 = INST_B(inst); /* #of elements */ ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}", vsrc1, ref, vdst, arg5); } /* * Resolve the array class. */ arrayClass = dvmDexGetResolvedClass(methodClassDex, ref); if (arrayClass == NULL) { arrayClass = dvmResolveClass(curMethod->clazz, ref, false); if (arrayClass == NULL) GOTO_exceptionThrown(); } /* if (!dvmIsArrayClass(arrayClass)) { dvmThrowException("Ljava/lang/RuntimeError;", "filled-new-array needs array class"); GOTO_exceptionThrown(); } */ /* verifier guarantees this is an array class */ assert(dvmIsArrayClass(arrayClass)); assert(dvmIsClassInitialized(arrayClass)); /* * Create an array of the specified type. */ LOGVV("+++ filled-new-array type is '%s'\n", arrayClass->descriptor); typeCh = arrayClass->descriptor[1]; if (typeCh == 'D' || typeCh == 'J') { /* category 2 primitives not allowed */ dvmThrowException("Ljava/lang/RuntimeError;", "bad filled array req"); GOTO_exceptionThrown(); } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') { /* TODO: requires multiple "fill in" loops with different widths */ LOGE("non-int primitives not implemented\n"); dvmThrowException("Ljava/lang/InternalError;", "filled-new-array not implemented for anything but 'int'"); GOTO_exceptionThrown(); } newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK); if (newArray == NULL) GOTO_exceptionThrown(); /* * Fill in the elements. It's legal for vsrc1 to be zero. */ contents = (u4*) newArray->contents; if (methodCallRange) { for (i = 0; i < vsrc1; i++) contents[i] = GET_REGISTER(vdst+i); } else { assert(vsrc1 <= 5); if (vsrc1 == 5) { contents[4] = GET_REGISTER(arg5); vsrc1--; } for (i = 0; i < vsrc1; i++) { contents[i] = GET_REGISTER(vdst & 0x0f); vdst >>= 4; } } retval.l = newArray; }
/* * Find the class corresponding to "classIdx", which maps to a class name * string. It might be in the same DEX file as "referrer", in a different * DEX file, generated by a class loader, or generated by the VM (e.g. * array classes). * * Because the DexTypeId is associated with the referring class' DEX file, * we may have to resolve the same class more than once if it's referred * to from classes in multiple DEX files. This is a necessary property for * DEX files associated with different class loaders. * * We cache a copy of the lookup in the DexFile's "resolved class" table, * so future references to "classIdx" are faster. * * Note that "referrer" may be in the process of being linked. * * Traditional VMs might do access checks here, but in Dalvik the class * "constant pool" is shared between all classes in the DEX file. We rely * on the verifier to do the checks for us. * * Does not initialize the class. * * "fromUnverifiedConstant" should only be set if this call is the direct * result of executing a "const-class" or "instance-of" instruction, which * use class constants not resolved by the bytecode verifier. * * Returns NULL with an exception raised on failure. */ ClassObject* dvmResolveClass(const ClassObject* referrer, u4 classIdx, bool fromUnverifiedConstant) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const char* className; /* * Check the table first -- this gets called from the other "resolve" * methods. */ resClass = dvmDexGetResolvedClass(pDvmDex, classIdx); if (resClass != NULL) return resClass; LOGVV("--- resolving class %u (referrer=%s cl=%p)\n", classIdx, referrer->descriptor, referrer->classLoader); /* * Class hasn't been loaded yet, or is in the process of being loaded * and initialized now. Try to get a copy. If we find one, put the * pointer in the DexTypeId. There isn't a race condition here -- * 32-bit writes are guaranteed atomic on all target platforms. Worst * case we have two threads storing the same value. * * If this is an array class, we'll generate it here. */ className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx); if (className[0] != '\0' && className[1] == '\0') { /* primitive type */ resClass = dvmFindPrimitiveClass(className[0]); } else { resClass = dvmFindClassNoInit(className, referrer->classLoader); } if (resClass != NULL) { /* * If the referrer was pre-verified, the resolved class must come * from the same DEX or from a bootstrap class. The pre-verifier * makes assumptions that could be invalidated by a wacky class * loader. (See the notes at the top of oo/Class.c.) * * The verifier does *not* fail a class for using a const-class * or instance-of instruction referring to an unresolveable class, * because the result of the instruction is simply a Class object * or boolean -- there's no need to resolve the class object during * verification. Instance field and virtual method accesses can * break dangerously if we get the wrong class, but const-class and * instance-of are only interesting at execution time. So, if we * we got here as part of executing one of the "unverified class" * instructions, we skip the additional check. * * Ditto for class references from annotations and exception * handler lists. */ if (!fromUnverifiedConstant && IS_CLASS_FLAG_SET(referrer, CLASS_ISPREVERIFIED)) { ClassObject* resClassCheck = resClass; if (dvmIsArrayClass(resClassCheck)) resClassCheck = resClassCheck->elementClass; if (referrer->pDvmDex != resClassCheck->pDvmDex && resClassCheck->classLoader != NULL) { LOGW("Class resolved by unexpected DEX:" " %s(%p):%p ref [%s] %s(%p):%p\n", referrer->descriptor, referrer->classLoader, referrer->pDvmDex, resClass->descriptor, resClassCheck->descriptor, resClassCheck->classLoader, resClassCheck->pDvmDex); LOGW("(%s had used a different %s during pre-verification)\n", referrer->descriptor, resClass->descriptor); dvmThrowException("Ljava/lang/IllegalAccessError;", "Class ref in pre-verified class resolved to unexpected " "implementation"); return NULL; } } LOGVV("##### +ResolveClass(%s): referrer=%s dex=%p ldr=%p ref=%d\n", resClass->descriptor, referrer->descriptor, referrer->pDvmDex, referrer->classLoader, classIdx); /* * Add what we found to the list so we can skip the class search * next time through. * * TODO: should we be doing this when fromUnverifiedConstant==true? * (see comments at top of oo/Class.c) */ dvmDexSetResolvedClass(pDvmDex, classIdx, resClass); } else { /* not found, exception should be raised */ LOGVV("Class not found: %s\n", dexStringByTypeIdx(pDvmDex->pDexFile, classIdx)); assert(dvmCheckException(dvmThreadSelf())); } return resClass; }