예제 #1
0
파일: TypeCheck.cpp 프로젝트: handgod/soma
/*
 * 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);
}
예제 #2
0
파일: TypeCheck.cpp 프로젝트: handgod/soma
/*
 * 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);
    }
}
예제 #3
0
/*
 * 在'clazz'中,我们有一个方法指向另一个方法,但它可能指向派生类中的一个方法,我们想要从虚拟函数表中找到实际入口,如果'class'是一个接口,我们不得不在短时间内做更多的挖掘
 *
 * 对于'direct'方法(private / constructor).我们仅仅返回原生态方法
 *  
 * (这里被适用于反射和JNI调用)
 */
const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
    const Method* meth)
{
    Method* actualMeth;
    int methodIndex;

    if (dvmIsDirectMethod(meth)) {
        /* no vtable entry for these */
        assert(!dvmIsStaticMethod(meth));
        return meth;
    }

    /*
     * If the method was declared in an interface, we need to scan through
     * the class' list of interfaces for it, and find the vtable index
     * from that.
     *
     * TODO: use the interface cache.
     */
    if (dvmIsInterfaceClass(meth->clazz)) {
        int i;

        for (i = 0; i < clazz->iftableCount; i++) {
            if (clazz->iftable[i].clazz == meth->clazz)
                break;
        }
        if (i == clazz->iftableCount) {
            dvmThrowIncompatibleClassChangeError(
                "invoking method from interface not implemented by class");
            return NULL;
        }

        methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
    } else {
        methodIndex = meth->methodIndex;
    }

    assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
    actualMeth = clazz->vtable[methodIndex];

    /*
     * Make sure there's code to execute.
     */
    if (dvmIsAbstractMethod(actualMeth)) {
        dvmThrowAbstractMethodError(NULL);
        return NULL;
    }
    assert(!dvmIsMirandaMethod(actualMeth));

    return actualMeth;
}
예제 #4
0
파일: TypeCheck.cpp 프로젝트: handgod/soma
/*
 * 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;
    }
}
예제 #5
0
파일: TypeCheck.cpp 프로젝트: handgod/soma
/*
 * Returns 1 (true) if "clazz" is an implementation of "interface".
 *
 * "clazz" could be a class or an interface.
 */
int dvmImplements(const ClassObject* clazz, const ClassObject* interface)
{
    int i;

    assert(dvmIsInterfaceClass(interface));

    /*
     * All interfaces implemented directly and by our superclass, and
     * recursively all super-interfaces of those interfaces, are listed
     * in "iftable", so we can just do a linear scan through that.
     */
    for (i = 0; i < clazz->iftableCount; i++) {
        if (clazz->iftable[i].clazz == interface)
            return 1;
    }

    return 0;
}
/*
 * private Object invokeNative(Object obj, Object[] args, Class declaringClass,
 *   Class[] parameterTypes, Class returnType, int slot, boolean noAccessCheck)
 *
 * Invoke a static or virtual method via reflection.
 */
static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* methObj = (Object*) args[1];        // null for static methods
    ArrayObject* argList = (ArrayObject*) args[2];
    ClassObject* declaringClass = (ClassObject*) args[3];
    ArrayObject* params = (ArrayObject*) args[4];
    ClassObject* returnType = (ClassObject*) args[5];
    int slot = args[6];
    bool noAccessCheck = (args[7] != 0);
    const Method* meth;
    Object* result;

    /*
     * "If the underlying method is static, the class that declared the
     * method is initialized if it has not already been initialized."
     */
    meth = dvmSlotToMethod(declaringClass, slot);
    assert(meth != NULL);

    if (dvmIsStaticMethod(meth)) {
        if (!dvmIsClassInitialized(declaringClass)) {
            if (!dvmInitClass(declaringClass))
                goto init_failed;
        }
    } else {
        /* looks like interfaces need this too? */
        if (dvmIsInterfaceClass(declaringClass) &&
            !dvmIsClassInitialized(declaringClass))
        {
            if (!dvmInitClass(declaringClass))
                goto init_failed;
        }

        /* make sure the object is an instance of the expected class */
        if (!dvmVerifyObjectInClass(methObj, declaringClass)) {
            assert(dvmCheckException(dvmThreadSelf()));
            RETURN_VOID();
        }

        /* do the virtual table lookup for the method */
        meth = dvmGetVirtualizedMethod(methObj->clazz, meth);
        if (meth == NULL) {
            assert(dvmCheckException(dvmThreadSelf()));
            RETURN_VOID();
        }
    }

    /*
     * If the method has a return value, "result" will be an object or
     * a boxed primitive.
     */
    result = dvmInvokeMethod(methObj, meth, argList, params, returnType,
                noAccessCheck);

    RETURN_PTR(result);

init_failed:
    /*
     * If initialization failed, an exception will be raised.
     */
    ALOGD("Method.invoke() on bad class %s failed",
        declaringClass->descriptor);
    assert(dvmCheckException(dvmThreadSelf()));
    RETURN_VOID();
}
예제 #7
0
/*
 * Resolve an interface method reference.
 *
 * Returns NULL with an exception raised on failure.
 */
Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx)
{
    DvmDex* pDvmDex = referrer->pDvmDex;
    ClassObject* resClass;
    const DexMethodId* pMethodId;
    Method* resMethod;
    int i;

    LOGVV("--- resolving interface method %d (referrer=%s)\n",
          methodIdx, referrer->descriptor);
    pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);

    resClass = dvmResolveClass(referrer, pMethodId->classIdx, false);
    if (resClass == NULL) {
        /* can't find the class that the method is a part of */
        assert(dvmCheckException(dvmThreadSelf()));
        return NULL;
    }
    if (!dvmIsInterfaceClass(resClass)) {
        /* whoops */
        dvmThrowExceptionWithClassMessage(
            "Ljava/lang/IncompatibleClassChangeError;",
            resClass->descriptor);
        return NULL;
    }

    /*
     * This is the first time the method has been resolved.  Set it in our
     * resolved-method structure.  It always resolves to the same thing,
     * so looking it up and storing it doesn't create a race condition.
     *
     * If we scan into the interface's superclass -- which is always
     * java/lang/Object -- we will catch things like:
     *   interface I ...
     *   I myobj = (something that implements I)
     *   myobj.hashCode()
     * However, the Method->methodIndex will be an offset into clazz->vtable,
     * rather than an offset into clazz->iftable.  The invoke-interface
     * code can test to see if the method returned is abstract or concrete,
     * and use methodIndex accordingly.  I'm not doing this yet because
     * (a) we waste time in an unusual case, and (b) we're probably going
     * to fix it in the DEX optimizer.
     *
     * We do need to scan the superinterfaces, in case we're invoking a
     * superinterface method on an interface reference.  The class in the
     * DexTypeId is for the static type of the object, not the class in
     * which the method is first defined.  We have the full, flattened
     * list in "iftable".
     */
    const char* methodName =
        dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);

    DexProto proto;
    dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);

    LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
          methodName, methodSig, resClass->descriptor);
    resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
    if (resMethod == NULL) {
        LOGVV("+++ did not resolve immediately\n");
        for (i = 0; i < resClass->iftableCount; i++) {
            resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
                                             methodName, &proto);
            if (resMethod != NULL)
                break;
        }

        if (resMethod == NULL) {
            dvmThrowException("Ljava/lang/NoSuchMethodError;", methodName);
            return NULL;
        }
    } else {
        LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
              resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
    }

    LOGVV("--- found interface method %d (%s.%s)\n",
          methodIdx, resClass->descriptor, resMethod->name);

    /* we're expecting this to be abstract */
    assert(dvmIsAbstractMethod(resMethod));

    /* interface methods are always public; no need to check access */

    /*
     * The interface class *may* be initialized.  According to VM spec
     * v2 2.17.4, the interfaces a class refers to "need not" be initialized
     * when the class is initialized.
     *
     * It isn't necessary for an interface class to be initialized before
     * we resolve methods on that interface.
     *
     * We choose not to do the initialization now.
     */
    //assert(dvmIsClassInitialized(resMethod->clazz));

    /*
     * The class is initialized, the method has been found.  Add a pointer
     * to our data structure so we don't have to jump through the hoops again.
     */
    dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);

    return resMethod;
}
예제 #8
0
/*
 * Find the method corresponding to "methodRef".
 *
 * We use "referrer" to find the DexFile with the constant pool that
 * "methodRef" is an index into.  We also use its class loader.  The method
 * being resolved may very well be in a different DEX file.
 *
 * If this is a static method, we ensure that the method's class is
 * initialized.
 */
Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx,
                         MethodType methodType)
{
    DvmDex* pDvmDex = referrer->pDvmDex;
    ClassObject* resClass;
    const DexMethodId* pMethodId;
    Method* resMethod;

    assert(methodType != METHOD_INTERFACE);

    LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
          referrer->descriptor);
    pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);

    resClass = dvmResolveClass(referrer, pMethodId->classIdx, false);
    if (resClass == NULL) {
        /* can't find the class that the method is a part of */
        assert(dvmCheckException(dvmThreadSelf()));
        return NULL;
    }
    if (dvmIsInterfaceClass(resClass)) {
        /* method is part of an interface */
        dvmThrowExceptionWithClassMessage(
            "Ljava/lang/IncompatibleClassChangeError;",
            resClass->descriptor);
        return NULL;
    }

    const char* name = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
    DexProto proto;
    dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);

    /*
     * We need to chase up the class hierarchy to find methods defined
     * in super-classes.  (We only want to check the current class
     * if we're looking for a constructor; since DIRECT calls are only
     * for constructors and private methods, we don't want to walk up.)
     */
    if (methodType == METHOD_DIRECT) {
        resMethod = dvmFindDirectMethod(resClass, name, &proto);
    } else if (methodType == METHOD_STATIC) {
        resMethod = dvmFindDirectMethodHier(resClass, name, &proto);
    } else {
        resMethod = dvmFindVirtualMethodHier(resClass, name, &proto);
    }

    if (resMethod == NULL) {
        dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
        return NULL;
    }

    LOGVV("--- found method %d (%s.%s)\n",
          methodIdx, resClass->descriptor, resMethod->name);

    /* see if this is a pure-abstract method */
    if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
        dvmThrowException("Ljava/lang/AbstractMethodError;", name);
        return NULL;
    }

    /*
     * If we're the first to resolve this class, we need to initialize
     * it now.  Only necessary for METHOD_STATIC.
     */
    if (methodType == METHOD_STATIC) {
        if (!dvmIsClassInitialized(resMethod->clazz) &&
                !dvmInitClass(resMethod->clazz))
        {
            assert(dvmCheckException(dvmThreadSelf()));
            return NULL;
        } else {
            assert(!dvmCheckException(dvmThreadSelf()));
        }
    } else {
        /*
         * Edge case: if the <clinit> for a class creates an instance
         * of itself, we will call <init> on a class that is still being
         * initialized by us.
         */
        assert(dvmIsClassInitialized(resMethod->clazz) ||
               dvmIsClassInitializing(resMethod->clazz));
    }

    /*
     * The class is initialized, the method has been found.  Add a pointer
     * to our data structure so we don't have to jump through the hoops again.
     */
    dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);

    return resMethod;
}
예제 #9
0
/*
 * Alternate version of dvmResolveMethod().
 *
 * Doesn't throw exceptions, and checks access on every lookup.
 *
 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
 */
Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
    MethodType methodType, VerifyError* pFailure)
{
    DvmDex* pDvmDex = referrer->pDvmDex;
    Method* resMethod;

    assert(methodType == METHOD_DIRECT ||
           methodType == METHOD_VIRTUAL ||
           methodType == METHOD_STATIC);

    LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
        referrer->descriptor);

    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
    if (resMethod == NULL) {
        const DexMethodId* pMethodId;
        ClassObject* resClass;

        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);

        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
        if (resClass == NULL) {
            /*
             * Can't find the class that the method is a part of, or don't
             * have permission to access the class.
             */
            ALOGV("DexOpt: can't find called method's class (?.%s)",
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
            return NULL;
        }
        if (dvmIsInterfaceClass(resClass)) {
            /* method is part of an interface; this is wrong method for that */
            ALOGW("DexOpt: method is in an interface");
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_GENERIC;
            return NULL;
        }

        /*
         * We need to chase up the class hierarchy to find methods defined
         * in super-classes.  (We only want to check the current class
         * if we're looking for a constructor.)
         */
        DexProto proto;
        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);

        if (methodType == METHOD_DIRECT) {
            resMethod = dvmFindDirectMethod(resClass,
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
        } else {
            /* METHOD_STATIC or METHOD_VIRTUAL */
            resMethod = dvmFindMethodHier(resClass,
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
        }

        if (resMethod == NULL) {
            ALOGV("DexOpt: couldn't find method '%s'",
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_NO_METHOD;
            return NULL;
        }
        if (methodType == METHOD_STATIC) {
            if (!dvmIsStaticMethod(resMethod)) {
                ALOGD("DexOpt: wanted static, got instance for method %s.%s",
                    resClass->descriptor, resMethod->name);
                if (pFailure != NULL)
                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
                return NULL;
            }
        } else if (methodType == METHOD_VIRTUAL) {
            if (dvmIsStaticMethod(resMethod)) {
                ALOGD("DexOpt: wanted instance, got static for method %s.%s",
                    resClass->descriptor, resMethod->name);
                if (pFailure != NULL)
                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
                return NULL;
            }
        }

        /* see if this is a pure-abstract method */
        if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
            ALOGW("DexOpt: pure-abstract method '%s' in %s",
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
                resClass->descriptor);
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_GENERIC;
            return NULL;
        }

        /*
         * Add it to the resolved table so we're faster on the next lookup.
         *
         * We can only do this for static methods if we're not in "dexopt",
         * because the presence of a valid value in the resolution table
         * implies that the class containing the static field has been
         * initialized.
         */
        if (methodType != METHOD_STATIC || gDvm.optimizing)
            dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
    }

    LOGVV("--- found method %d (%s.%s)",
        methodIdx, resMethod->clazz->descriptor, resMethod->name);

    /* access allowed? */
    tweakLoader(referrer, resMethod->clazz);
    bool allowed = dvmCheckMethodAccess(referrer, resMethod);
    untweakLoader(referrer, resMethod->clazz);
    if (!allowed) {
        IF_ALOGI() {
            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
            ALOGI("DexOpt: illegal method access (call %s.%s %s from %s)",
                resMethod->clazz->descriptor, resMethod->name, desc,
                referrer->descriptor);
            free(desc);
        }