Exemplo n.º 1
0
static bool performanceTest()
{
    static const int kTableMax = 100;
    IndirectRefTable irt;
    IndirectRef manyRefs[kTableMax];
    ClassObject* clazz = dvmFindClass("Ljava/lang/Object;", NULL);
    Object* obj0 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    const u4 cookie = IRT_FIRST_SEGMENT;
    const int kLoops = 100000;
    Stopwatch stopwatch;

    DBUG_MSG("+++ START performance\n");

    if (!irt.init(kTableMax, kTableMax, kIndirectKindGlobal)) {
        return false;
    }

    stopwatch.reset();
    for (int loop = 0; loop < kLoops; loop++) {
        for (int i = 0; i < kTableMax; i++) {
            manyRefs[i] = irt.add(cookie, obj0);
        }
        for (int i = 0; i < kTableMax; i++) {
            irt.remove(cookie, manyRefs[i]);
        }
    }
    DBUG_MSG("Add/remove %d objects FIFO order, %d iterations, %0.3fms / iteration",
            kTableMax, kLoops, stopwatch.elapsedSeconds() * 1000 / kLoops);

    stopwatch.reset();
    for (int loop = 0; loop < kLoops; loop++) {
        for (int i = 0; i < kTableMax; i++) {
            manyRefs[i] = irt.add(cookie, obj0);
        }
        for (int i = kTableMax; i-- > 0; ) {
            irt.remove(cookie, manyRefs[i]);
        }
    }
    DBUG_MSG("Add/remove %d objects LIFO order, %d iterations, %0.3fms / iteration",
            kTableMax, kLoops, stopwatch.elapsedSeconds() * 1000  / kLoops);

    for (int i = 0; i < kTableMax; i++) {
        manyRefs[i] = irt.add(cookie, obj0);
    }
    stopwatch.reset();
    for (int loop = 0; loop < kLoops; loop++) {
        for (int i = 0; i < kTableMax; i++) {
            irt.get(manyRefs[i]);
        }
    }
    DBUG_MSG("Get %d objects, %d iterations, %0.3fms / iteration",
            kTableMax, kLoops, stopwatch.elapsedSeconds() * 1000  / kLoops);
    for (int i = kTableMax; i-- > 0; ) {
        irt.remove(cookie, manyRefs[i]);
    }

    irt.destroy();
    return true;
}
Exemplo n.º 2
0
/*
 * Create a "stock instance" of an exception class.
 */
static Object* createStockException(const char* descriptor, const char* msg)
{
    Thread* self = dvmThreadSelf();
    StringObject* msgStr = NULL;
    ClassObject* clazz;
    Method* init;
    Object* obj;

    /* find class, initialize if necessary */
    clazz = dvmFindSystemClass(descriptor);
    if (clazz == NULL) {
        LOGE("Unable to find %s", descriptor);
        return NULL;
    }

    init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
            "(Ljava/lang/String;)V");
    if (init == NULL) {
        LOGE("Unable to find String-arg constructor for %s", descriptor);
        return NULL;
    }

    obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
    if (obj == NULL)
        return NULL;

    if (msg == NULL) {
        msgStr = NULL;
    } else {
        msgStr = dvmCreateStringFromCstr(msg);
        if (msgStr == NULL) {
            LOGW("Could not allocate message string \"%s\"", msg);
            dvmReleaseTrackedAlloc(obj, self);
            return NULL;
        }
    }

    JValue unused;
    dvmCallMethod(self, init, obj, &unused, msgStr);
    if (dvmCheckException(self)) {
        dvmReleaseTrackedAlloc((Object*) msgStr, self);
        dvmReleaseTrackedAlloc(obj, self);
        return NULL;
    }

    dvmReleaseTrackedAlloc((Object*) msgStr, self);     // okay if msgStr NULL
    return obj;
}
Exemplo n.º 3
0
/*
 * Create a new java.lang.reflect.Field object from "field".
 *
 * The Field spec doesn't specify the constructor.  We're going to use the
 * one from our existing class libs:
 *
 *  private Field(Class declaringClass, Class type, String name, int slot)
 */
static Object* createFieldObject(Field* field, const ClassObject* clazz)
{
    Object* result = NULL;
    Object* fieldObj = NULL;
    StringObject* nameObj = NULL;
    ClassObject* type;
    char* mangle;
    char* cp;
    int slot, field_idx;

    assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField));

    fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT);
    if (fieldObj == NULL)
        goto bail;

    cp = mangle = strdup(field->signature);
    type = convertSignaturePartToClass(&cp, clazz);
    free(mangle);
    if (type == NULL)
        goto bail;

    nameObj = dvmCreateStringFromCstr(field->name);
    if (nameObj == NULL)
        goto bail;

    slot = fieldToSlot(field, clazz);
    field_idx = dvmGetFieldIdx(field);

    JValue unused;
    dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init,
        fieldObj, &unused, clazz, type, nameObj, slot, field_idx);
    if (dvmCheckException(dvmThreadSelf())) {
        ALOGD("Field class init threw exception");
        goto bail;
    }

    result = fieldObj;

bail:
    dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
    if (result == NULL)
        dvmReleaseTrackedAlloc((Object*) fieldObj, NULL);
    /* caller must dvmReleaseTrackedAlloc(result) */
    return result;
}
Exemplo n.º 4
0
/*
 * Wrap the now-pending exception in a different exception.  This is useful
 * for reflection stuff that wants to hand a checked exception back from a
 * method that doesn't declare it.
 *
 * If something fails, an (unchecked) exception related to that failure
 * will be pending instead.
 */
void dvmWrapException(const char* newExcepStr)
{
    Thread* self = dvmThreadSelf();
    Object* origExcep;
    ClassObject* iteClass;

    origExcep = dvmGetException(self);
    dvmAddTrackedAlloc(origExcep, self);    // don't let the GC free it

    dvmClearException(self);                // clear before class lookup
    iteClass = dvmFindSystemClass(newExcepStr);
    if (iteClass != NULL) {
        Object* iteExcep;
        Method* initMethod;

        iteExcep = dvmAllocObject(iteClass, ALLOC_DEFAULT);
        if (iteExcep != NULL) {
            initMethod = dvmFindDirectMethodByDescriptor(iteClass, "<init>",
                            "(Ljava/lang/Throwable;)V");
            if (initMethod != NULL) {
                JValue unused;
                dvmCallMethod(self, initMethod, iteExcep, &unused,
                    origExcep);

                /* if <init> succeeded, replace the old exception */
                if (!dvmCheckException(self))
                    dvmSetException(self, iteExcep);
            }
            dvmReleaseTrackedAlloc(iteExcep, NULL);

            /* if initMethod doesn't exist, or failed... */
            if (!dvmCheckException(self))
                dvmSetException(self, origExcep);
        } else {
            /* leave OutOfMemoryError pending */
        }
    } else {
        /* leave ClassNotFoundException pending */
    }

    assert(dvmCheckException(self));
    dvmReleaseTrackedAlloc(origExcep, self);
}
Exemplo n.º 5
0
/*
 * Create a wrapper object for a primitive data type.  If "returnType" is
 * not primitive, this just casts "value" to an object and returns it.
 *
 * We could invoke the "toValue" method on the box types to take
 * advantage of pre-created values, but running that through the
 * interpreter is probably less efficient than just allocating storage here.
 *
 * The caller must call dvmReleaseTrackedAlloc on the result.
 */
DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType)
{
    ClassObject* wrapperClass;
    DataObject* wrapperObj;
    s4* dataPtr;
    PrimitiveType typeIndex = returnType->primitiveType;
    const char* classDescriptor;

    if (typeIndex == PRIM_NOT) {
        /* add to tracking table so return value is always in table */
        if (value.l != NULL)
            dvmAddTrackedAlloc((Object*)value.l, NULL);
        return (DataObject*) value.l;
    }

    classDescriptor = dexGetBoxedTypeDescriptor(typeIndex);
    if (classDescriptor == NULL) {
        return NULL;
    }

    wrapperClass = dvmFindSystemClass(classDescriptor);
    if (wrapperClass == NULL) {
        ALOGW("Unable to find '%s'", classDescriptor);
        assert(dvmCheckException(dvmThreadSelf()));
        return NULL;
    }

    wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT);
    if (wrapperObj == NULL)
        return NULL;
    dataPtr = (s4*) wrapperObj->instanceData;

    /* assumes value is stored in first instance field */
    /* (see dvmValidateBoxClasses) */
    if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE)
        *(s8*)dataPtr = value.j;
    else
        *dataPtr = value.i;

    return wrapperObj;
}
/*
 * public int constructNative(Object[] args, Class declaringClass,
 *     Class[] parameterTypes, int slot, boolean noAccessCheck)
 *
 * We get here through Constructor.newInstance().  The Constructor object
 * would not be available if the constructor weren't public (per the
 * definition of Class.getConstructor), so we can skip the method access
 * check.  We can also safely assume the constructor isn't associated
 * with an interface, array, or primitive class.
 */
static void Dalvik_java_lang_reflect_Constructor_constructNative(
    const u4* args, JValue* pResult)
{
    // ignore thisPtr in args[0]
    ArrayObject* argList = (ArrayObject*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ArrayObject* params = (ArrayObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    Object* newObj;
    Method* meth;

    if (dvmIsAbstractClass(declaringClass)) {
        dvmThrowInstantiationException(declaringClass, NULL);
        RETURN_VOID();
    }

    /* initialize the class if it hasn't been already */
    if (!dvmIsClassInitialized(declaringClass)) {
        if (!dvmInitClass(declaringClass)) {
            ALOGW("Class init failed in Constructor.constructNative (%s)",
                declaringClass->descriptor);
            assert(dvmCheckException(dvmThreadSelf()));
            RETURN_VOID();
        }
    }

    newObj = dvmAllocObject(declaringClass, ALLOC_DEFAULT);
    if (newObj == NULL)
        RETURN_PTR(NULL);

    meth = dvmSlotToMethod(declaringClass, slot);
    assert(meth != NULL);

    (void) dvmInvokeMethod(newObj, meth, argList, params, NULL, noAccessCheck);
    dvmReleaseTrackedAlloc(newObj, NULL);
    RETURN_PTR(newObj);
}
Exemplo n.º 7
0
/*
 * Allocate a new instance of the class String, performing first-use
 * initialization of the class if necessary. Upon success, the
 * returned value will have all its fields except hashCode already
 * filled in, including a reference to a newly-allocated char[] for
 * the contents, sized as given. Additionally, a reference to the
 * chars array is stored to the pChars pointer. Callers must
 * subsequently call dvmReleaseTrackedAlloc() on the result pointer.
 * This function returns NULL on failure.
 */
static StringObject* makeStringObject(u4 charsLength, ArrayObject** pChars)
{
    /*
     * The String class should have already gotten found (but not
     * necessarily initialized) before making it here. We assert it
     * explicitly, since historically speaking, we have had bugs with
     * regard to when the class String gets set up. The assert helps
     * make any regressions easier to diagnose.
     */
    assert(gDvm.classJavaLangString != NULL);

    if (!dvmIsClassInitialized(gDvm.classJavaLangString)) {
        /* Perform first-time use initialization of the class. */
        if (!dvmInitClass(gDvm.classJavaLangString)) {
            LOGE("FATAL: Could not initialize class String");
            dvmAbort();
        }
    }

    Object* result = dvmAllocObject(gDvm.classJavaLangString, ALLOC_DEFAULT);
    if (result == NULL) {
        return NULL;
    }

    ArrayObject* chars = dvmAllocPrimitiveArray('C', charsLength, ALLOC_DEFAULT);
    if (chars == NULL) {
        dvmReleaseTrackedAlloc(result, NULL);
        return NULL;
    }

    dvmSetFieldInt(result, STRING_FIELDOFF_COUNT, charsLength);
    dvmSetFieldObject(result, STRING_FIELDOFF_VALUE, (Object*) chars);
    dvmReleaseTrackedAlloc((Object*) chars, NULL);
    /* Leave offset and hashCode set to zero. */

    *pChars = chars;
    return (StringObject*) result;
}
/*
 * public int constructNative(Object[] args, Class declaringClass,
 *     Class[] parameterTypes, int slot, boolean noAccessCheck)
 */
static void Dalvik_java_lang_reflect_Constructor_constructNative(
    const u4* args, JValue* pResult)
{
    // ignore thisPtr in args[0]
    ArrayObject* argList = (ArrayObject*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ArrayObject* params = (ArrayObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    Object* newObj;
    Method* meth;

    newObj = dvmAllocObject(declaringClass, ALLOC_DEFAULT);
    if (newObj == NULL)
        RETURN_PTR(NULL);

    meth = dvmSlotToMethod(declaringClass, slot);
    assert(meth != NULL);

    (void) dvmInvokeMethod(newObj, meth, argList, params, NULL, noAccessCheck);
    dvmReleaseTrackedAlloc(newObj, NULL);
    RETURN_PTR(newObj);
}
Exemplo n.º 9
0
/*
 * Basic add/get/delete tests in an unsegmented table.
 */
static bool basicTest()
{
    static const int kTableMax = 20;
    IndirectRefTable irt;
    IndirectRef iref0, iref1, iref2, iref3;
    IndirectRef manyRefs[kTableMax];
    ClassObject* clazz = dvmFindClass("Ljava/lang/Object;", NULL);
    Object* obj0 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    Object* obj1 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    Object* obj2 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    Object* obj3 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    const u4 cookie = IRT_FIRST_SEGMENT;
    bool result = false;

    if (!irt.init(kTableMax/2, kTableMax, kIndirectKindGlobal)) {
        return false;
    }

    iref0 = (IndirectRef) 0x11110;
    if (irt.remove(cookie, iref0)) {
        ALOGE("unexpectedly successful removal");
        goto bail;
    }

    /*
     * Add three, check, remove in the order in which they were added.
     */
    DBUG_MSG("+++ START fifo\n");
    iref0 = irt.add(cookie, obj0);
    iref1 = irt.add(cookie, obj1);
    iref2 = irt.add(cookie, obj2);
    if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
        ALOGE("trivial add1 failed");
        goto bail;
    }

    if (irt.get(iref0) != obj0 ||
            irt.get(iref1) != obj1 ||
            irt.get(iref2) != obj2) {
        ALOGE("objects don't match expected values %p %p %p vs. %p %p %p",
                irt.get(iref0), irt.get(iref1), irt.get(iref2),
                obj0, obj1, obj2);
        goto bail;
    } else {
        DBUG_MSG("+++ obj1=%p --> iref1=%p\n", obj1, iref1);
    }

    if (!irt.remove(cookie, iref0) ||
            !irt.remove(cookie, iref1) ||
            !irt.remove(cookie, iref2))
    {
        ALOGE("fifo deletion failed");
        goto bail;
    }

    /* table should be empty now */
    if (irt.capacity() != 0) {
        ALOGE("fifo del not empty");
        goto bail;
    }

    /* get invalid entry (off the end of the list) */
    if (irt.get(iref0) != kInvalidIndirectRefObject) {
        ALOGE("stale entry get succeeded unexpectedly");
        goto bail;
    }

    /*
     * Add three, remove in the opposite order.
     */
    DBUG_MSG("+++ START lifo\n");
    iref0 = irt.add(cookie, obj0);
    iref1 = irt.add(cookie, obj1);
    iref2 = irt.add(cookie, obj2);
    if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
        ALOGE("trivial add2 failed");
        goto bail;
    }

    if (!irt.remove(cookie, iref2) ||
            !irt.remove(cookie, iref1) ||
            !irt.remove(cookie, iref0))
    {
        ALOGE("lifo deletion failed");
        goto bail;
    }

    /* table should be empty now */
    if (irt.capacity() != 0) {
        ALOGE("lifo del not empty");
        goto bail;
    }

    /*
     * Add three, remove middle / middle / bottom / top.  (Second attempt
     * to remove middle should fail.)
     */
    DBUG_MSG("+++ START unorder\n");
    iref0 = irt.add(cookie, obj0);
    iref1 = irt.add(cookie, obj1);
    iref2 = irt.add(cookie, obj2);
    if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
        ALOGE("trivial add3 failed");
        goto bail;
    }

    if (irt.capacity() != 3) {
        ALOGE("expected 3 entries, found %d", irt.capacity());
        goto bail;
    }

    if (!irt.remove(cookie, iref1) || irt.remove(cookie, iref1)) {
        ALOGE("unorder deletion1 failed");
        goto bail;
    }

    /* get invalid entry (from hole) */
    if (irt.get(iref1) != kInvalidIndirectRefObject) {
        ALOGE("hole get succeeded unexpectedly");
        goto bail;
    }

    if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
        ALOGE("unorder deletion2 failed");
        goto bail;
    }

    /* table should be empty now */
    if (irt.capacity() != 0) {
        ALOGE("unorder del not empty");
        goto bail;
    }

    /*
     * Add four entries.  Remove #1, add new entry, verify that table size
     * is still 4 (i.e. holes are getting filled).  Remove #1 and #3, verify
     * that we delete one and don't hole-compact the other.
     */
    DBUG_MSG("+++ START hole fill\n");
    iref0 = irt.add(cookie, obj0);
    iref1 = irt.add(cookie, obj1);
    iref2 = irt.add(cookie, obj2);
    iref3 = irt.add(cookie, obj3);
    if (iref0 == NULL || iref1 == NULL || iref2 == NULL || iref3 == NULL) {
        ALOGE("trivial add4 failed");
        goto bail;
    }
    if (!irt.remove(cookie, iref1)) {
        ALOGE("remove 1 of 4 failed");
        goto bail;
    }
    iref1 = irt.add(cookie, obj1);
    if (irt.capacity() != 4) {
        ALOGE("hole not filled");
        goto bail;
    }
    if (!irt.remove(cookie, iref1) || !irt.remove(cookie, iref3)) {
        ALOGE("remove 1/3 failed");
        goto bail;
    }
    if (irt.capacity() != 3) {
        ALOGE("should be 3 after two deletions");
        goto bail;
    }
    if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
        ALOGE("remove 2/0 failed");
        goto bail;
    }
    if (irt.capacity() != 0) {
        ALOGE("not empty after split remove");
        goto bail;
    }

    /*
     * Add an entry, remove it, add a new entry, and try to use the original
     * iref.  They have the same slot number but are for different objects.
     * With the extended checks in place, this should fail.
     */
    DBUG_MSG("+++ START switched\n");
    iref0 = irt.add(cookie, obj0);
    irt.remove(cookie, iref0);
    iref1 = irt.add(cookie, obj1);
    if (irt.remove(cookie, iref0)) {
        ALOGE("mismatched del succeeded (%p vs %p)", iref0, iref1);
        goto bail;
    }
    if (!irt.remove(cookie, iref1)) {
        ALOGE("switched del failed");
        goto bail;
    }
    if (irt.capacity() != 0) {
        ALOGE("switching del not empty");
        goto bail;
    }

    /*
     * Same as above, but with the same object.  A more rigorous checker
     * (e.g. with slot serialization) will catch this.
     */
    DBUG_MSG("+++ START switched same object\n");
    iref0 = irt.add(cookie, obj0);
    irt.remove(cookie, iref0);
    iref1 = irt.add(cookie, obj0);
    if (iref0 != iref1) {
        /* try 0, should not work */
        if (irt.remove(cookie, iref0)) {
            ALOGE("temporal del succeeded (%p vs %p)", iref0, iref1);
            goto bail;
        }
    }
    if (!irt.remove(cookie, iref1)) {
        ALOGE("temporal cleanup failed");
        goto bail;
    }
    if (irt.capacity() != 0) {
        ALOGE("temporal del not empty");
        goto bail;
    }

    DBUG_MSG("+++ START null lookup\n");
    if (irt.get(NULL) != kInvalidIndirectRefObject) {
        ALOGE("null lookup succeeded");
        goto bail;
    }

    DBUG_MSG("+++ START stale lookup\n");
    iref0 = irt.add(cookie, obj0);
    irt.remove(cookie, iref0);
    if (irt.get(iref0) != kInvalidIndirectRefObject) {
        ALOGE("stale lookup succeeded");
        goto bail;
    }

    /*
     * Test table overflow.
     */
    DBUG_MSG("+++ START overflow\n");
    int i;
    for (i = 0; i < kTableMax; i++) {
        manyRefs[i] = irt.add(cookie, obj0);
        if (manyRefs[i] == NULL) {
            ALOGE("Failed adding %d of %d", i, kTableMax);
            goto bail;
        }
    }
    if (irt.add(cookie, obj0) != NULL) {
        ALOGE("Table overflow succeeded");
        goto bail;
    }
    if (irt.capacity() != (size_t)kTableMax) {
        ALOGE("Expected %d entries, found %d", kTableMax, irt.capacity());
        goto bail;
    }
    irt.dump("table with 20 entries, all filled");
    for (i = 0; i < kTableMax-1; i++) {
        if (!irt.remove(cookie, manyRefs[i])) {
            ALOGE("multi-remove failed at %d", i);
            goto bail;
        }
    }
    irt.dump("table with 20 entries, 19 of them holes");
    /* because of removal order, should have 20 entries, 19 of them holes */
    if (irt.capacity() != (size_t)kTableMax) {
        ALOGE("Expected %d entries (with holes), found %d",
                kTableMax, irt.capacity());
        goto bail;
    }
    if (!irt.remove(cookie, manyRefs[kTableMax-1])) {
        ALOGE("multi-remove final failed");
        goto bail;
    }
    if (irt.capacity() != 0) {
        ALOGE("multi-del not empty");
        goto bail;
    }

    /* Done */
    DBUG_MSG("+++ basic test complete\n");
    result = true;

bail:
    irt.destroy();
    return result;
}
Exemplo n.º 10
0
/*
 * Create a new java/lang/reflect/Method object, using the contents of
 * "meth" to construct it.
 *
 * The spec doesn't specify the constructor.  We're going to use the
 * one from our existing class libs:
 *
 *  private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes,
 *      Class returnType, String name, int slot)
 *
 * The caller must call dvmReleaseTrackedAlloc() on the result.
 */
Object* dvmCreateReflectMethodObject(const Method* meth)
{
    Object* result = NULL;
    ArrayObject* params = NULL;
    ArrayObject* exceptions = NULL;
    StringObject* nameObj = NULL;
    Object* methObj;
    ClassObject* returnType;
    DexStringCache mangle;
    char* cp;
    int slot, method_idx;

    if (dvmCheckException(dvmThreadSelf())) {
        ALOGW("WARNING: dvmCreateReflectMethodObject called with "
             "exception pending");
        return NULL;
    }

    dexStringCacheInit(&mangle);

    /* parent should guarantee init so we don't have to check on every call */
    assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod));

    methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT);
    if (methObj == NULL)
        goto bail;

    /*
     * Convert the signature string into an array of classes representing
     * the arguments, and a class for the return type.
     */
    cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
    params = convertSignatureToClassArray(&cp, meth->clazz);
    if (params == NULL)
        goto bail;
    assert(*cp == ')');
    cp++;
    returnType = convertSignaturePartToClass(&cp, meth->clazz);
    if (returnType == NULL)
        goto bail;

    /*
     * Create an array with one entry for every exception that the class
     * is declared to throw.
     */
    exceptions = dvmGetMethodThrows(meth);
    if (dvmCheckException(dvmThreadSelf()))
        goto bail;

    /* method name */
    nameObj = dvmCreateStringFromCstr(meth->name);
    if (nameObj == NULL)
        goto bail;

    slot = methodToSlot(meth);
    method_idx = dvmGetMethodIdx(meth);

    JValue unused;
    dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init,
        methObj, &unused, meth->clazz, params, exceptions, returnType,
        nameObj, slot, method_idx);
    if (dvmCheckException(dvmThreadSelf())) {
        ALOGD("Method class init threw exception");
        goto bail;
    }

    result = methObj;

bail:
    dexStringCacheRelease(&mangle);
    if (result == NULL) {
        assert(dvmCheckException(dvmThreadSelf()));
    }
    dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
    dvmReleaseTrackedAlloc((Object*) params, NULL);
    dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
    if (result == NULL)
        dvmReleaseTrackedAlloc(methObj, NULL);
    return result;
}
Exemplo n.º 11
0
/*
 * Create a new java/lang/reflect/Constructor object, using the contents of
 * "meth" to construct it.
 *
 * The spec doesn't specify the constructor.  We're going to use the
 * one from our existing class libs:
 *
 *  private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes,
 *      int slot)
 */
static Object* createConstructorObject(Method* meth)
{
    Object* result = NULL;
    ArrayObject* params = NULL;
    ArrayObject* exceptions = NULL;
    Object* consObj;
    DexStringCache mangle;
    char* cp;
    int slot, method_idx;

    dexStringCacheInit(&mangle);

    /* parent should guarantee init so we don't have to check on every call */
    assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor));

    consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor,
                ALLOC_DEFAULT);
    if (consObj == NULL)
        goto bail;

    /*
     * Convert the signature string into an array of classes representing
     * the arguments.
     */
    cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
    params = convertSignatureToClassArray(&cp, meth->clazz);
    if (params == NULL)
        goto bail;
    assert(*cp == ')');
    assert(*(cp+1) == 'V');

    /*
     * Create an array with one entry for every exception that the class
     * is declared to throw.
     */
    exceptions = dvmGetMethodThrows(meth);
    if (dvmCheckException(dvmThreadSelf()))
        goto bail;

    slot = methodToSlot(meth);
    method_idx = dvmGetMethodIdx(meth);

    JValue unused;
    dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init,
        consObj, &unused, meth->clazz, params, exceptions, slot, method_idx);
    if (dvmCheckException(dvmThreadSelf())) {
        ALOGD("Constructor class init threw exception");
        goto bail;
    }

    result = consObj;

bail:
    dexStringCacheRelease(&mangle);
    dvmReleaseTrackedAlloc((Object*) params, NULL);
    dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
    if (result == NULL) {
        assert(dvmCheckException(dvmThreadSelf()));
        dvmReleaseTrackedAlloc(consObj, NULL);
    }
    /* caller must dvmReleaseTrackedAlloc(result) */
    return result;
}
/*
 * Test operations on a segmented table.
 */
static bool segmentTest(void)
{
    static const int kTableMax = 20;
    IndirectRefTable irt;
    IndirectRef iref0, iref1, iref2, iref3;
    ClassObject* clazz = dvmFindClass("Ljava/lang/Object;", NULL);
    Object* obj0 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    Object* obj1 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    Object* obj2 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    Object* obj3 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
    u4 cookie;
    u4 segmentState[4];
    bool result = false;

    if (!dvmInitIndirectRefTable(&irt, kTableMax, kTableMax,
            kIndirectKindLocal))
    {
        return false;
    }
    cookie = segmentState[0] = IRT_FIRST_SEGMENT;
    DBUG_MSG("+++ objs %p %p %p %p\n", obj0, obj1, obj2, obj3);

    /*
     * Push two, create new segment, push two more, try to get all four,
     * try to delete all 4.  All four should be accessible, but only the
     * last two should be deletable.
     */
    DBUG_MSG("+++ START basic segment\n");
    iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
    iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
    cookie = segmentState[1] = dvmPushIndirectRefTableSegment(&irt);
    DBUG_MSG("+++ pushed, cookie is 0x%08x\n", cookie);
    iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
    iref3 = dvmAddToIndirectRefTable(&irt, cookie, obj3);

    if (dvmRemoveFromIndirectRefTable(&irt, cookie, iref0) ||
        dvmRemoveFromIndirectRefTable(&irt, cookie, iref1))
    {
        LOGE("removed values from earlier segment\n");
        goto bail;
    }
    if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref2) ||
        !dvmRemoveFromIndirectRefTable(&irt, cookie, iref3))
    {
        LOGE("unable to remove values from current segment\n");
        goto bail;
    }
    if (dvmIndirectRefTableEntries(&irt) != 2) {
        LOGE("wrong total entries\n");
        goto bail;
    }
    dvmPopIndirectRefTableSegment(&irt, segmentState[1]);
    cookie = segmentState[0];
    if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref0) ||
        !dvmRemoveFromIndirectRefTable(&irt, cookie, iref1))
    {
        LOGE("unable to remove values from first segment\n");
        goto bail;
    }
    if (dvmIndirectRefTableEntries(&irt) != 0) {
        LOGE("basic push/pop not empty\n");
        goto bail;
    }

    /*
     * Push two, delete first, segment, push two more, pop segment, verify
     * the last two are no longer present and hole count is right.  The
     * adds after the segment pop should not be filling in the hole.
     */
    DBUG_MSG("+++ START segment pop\n");
    iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
    iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
    dvmRemoveFromIndirectRefTable(&irt, cookie, iref0);
    cookie = segmentState[1] = dvmPushIndirectRefTableSegment(&irt);
    iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
    iref3 = dvmAddToIndirectRefTable(&irt, cookie, obj3);
    dvmPopIndirectRefTableSegment(&irt, segmentState[1]);
    cookie = segmentState[0];
    if (dvmIndirectRefTableEntries(&irt) != 2) {
        LOGE("wrong total entries after pop\n");
        goto bail;
    }
    dvmRemoveFromIndirectRefTable(&irt, cookie, iref1);
    if (dvmIndirectRefTableEntries(&irt) != 0) {
        LOGE("not back to zero after pop + del\n");
        goto bail;
    }

    /*
     * Multiple segments, some empty.
     */
    DBUG_MSG("+++ START multiseg\n");
    iref0 = dvmAppendToIndirectRefTable(&irt, cookie, obj0);
    iref1 = dvmAppendToIndirectRefTable(&irt, cookie, obj1);
    cookie = segmentState[1] = dvmPushIndirectRefTableSegment(&irt);
    cookie = segmentState[2] = dvmPushIndirectRefTableSegment(&irt);
    iref3 = dvmAppendToIndirectRefTable(&irt, cookie, obj3);
    iref2 = dvmAppendToIndirectRefTable(&irt, cookie, obj2);
    dvmRemoveFromIndirectRefTable(&irt, cookie, iref3);
    cookie = segmentState[3] = dvmPushIndirectRefTableSegment(&irt);
    iref3 = dvmAppendToIndirectRefTable(&irt, cookie, obj3);

    if (dvmGetFromIndirectRefTable(&irt, iref0) != obj0 ||
        dvmGetFromIndirectRefTable(&irt, iref1) != obj1 ||
        dvmGetFromIndirectRefTable(&irt, iref2) != obj2 ||
        dvmGetFromIndirectRefTable(&irt, iref3) != obj3)
    {
        LOGE("Unable to retrieve all multiseg objects\n");
        goto bail;
    }

    dvmDumpIndirectRefTable(&irt, "test");

    //int i;
    //for (i = 0; i < sizeof(segmentState) / sizeof(segmentState[0]); i++) {
    //    DBUG_MSG("+++  segment %d = 0x%08x\n", i, segmentState[i]);
    //}

    dvmRemoveFromIndirectRefTable(&irt, cookie, iref3);
    if (dvmRemoveFromIndirectRefTable(&irt, cookie, iref2)) {
        LOGE("multiseg del2 worked\n");
        goto bail;
    }
    dvmPopIndirectRefTableSegment(&irt, segmentState[3]);
    cookie = segmentState[2];
    if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref2)) {
        LOGE("multiseg del2b failed (cookie=0x%08x ref=%p)\n", cookie, iref2);
        goto bail;
    }
    iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);

    /* pop two off at once */
    dvmPopIndirectRefTableSegment(&irt, segmentState[1]);
    cookie = segmentState[0];

    if (dvmIndirectRefTableEntries(&irt) != 2) {
        LOGE("Unexpected entry count in multiseg\n");
        goto bail;
    }
    dvmRemoveFromIndirectRefTable(&irt, cookie, iref0);
    dvmRemoveFromIndirectRefTable(&irt, cookie, iref1);
    if (dvmIndirectRefTableEntries(&irt) != 0) {
        LOGE("Unexpected entry count at multiseg end\n");
        goto bail;
    }

    DBUG_MSG("+++ segment test complete\n");
    result = true;

bail:
    dvmClearIndirectRefTable(&irt);
    return result;
}
Exemplo n.º 13
0
/*
 * Start/continue throwing process now that we have a class reference.
 */
void dvmThrowChainedExceptionByClass(ClassObject* excepClass, const char* msg,
    Object* cause)
{
    Thread* self = dvmThreadSelf();
    Object* exception;

    /* make sure the exception is initialized */
    if (!dvmIsClassInitialized(excepClass) && !dvmInitClass(excepClass)) {
        LOGE("ERROR: unable to initialize exception class '%s'\n",
            excepClass->descriptor);
        if (strcmp(excepClass->descriptor, "Ljava/lang/InternalError;") == 0)
            dvmAbort();
        dvmThrowChainedException("Ljava/lang/InternalError;",
            "failed to init original exception class", cause);
        return;
    }

    exception = dvmAllocObject(excepClass, ALLOC_DEFAULT);
    if (exception == NULL) {
        /*
         * We're in a lot of trouble.  We might be in the process of
         * throwing an out-of-memory exception, in which case the
         * pre-allocated object will have been thrown when our object alloc
         * failed.  So long as there's an exception raised, return and
         * allow the system to try to recover.  If not, something is broken
         * and we need to bail out.
         */
        if (dvmCheckException(self))
            goto bail;
        LOGE("FATAL: unable to allocate exception '%s' '%s'\n",
            excepClass->descriptor, msg != NULL ? msg : "(no msg)");
        dvmAbort();
    }

    /*
     * Init the exception.
     */
    if (gDvm.optimizing) {
        /* need the exception object, but can't invoke interpreted code */
        LOGV("Skipping init of exception %s '%s'\n",
            excepClass->descriptor, msg);
    } else {
        assert(excepClass == exception->clazz);
        if (!initException(exception, msg, cause, self)) {
            /*
             * Whoops.  If we can't initialize the exception, we can't use
             * it.  If there's an exception already set, the constructor
             * probably threw an OutOfMemoryError.
             */
            if (!dvmCheckException(self)) {
                /*
                 * We're required to throw something, so we just
                 * throw the pre-constructed internal error.
                 */
                self->exception = gDvm.internalErrorObj;
            }
            goto bail;
        }
    }

    self->exception = exception;

bail:
    dvmReleaseTrackedAlloc(exception, self);
}
Exemplo n.º 14
0
/*
 * Generate an array of StackTraceElement objects from the raw integer
 * data encoded by dvmFillInStackTrace().
 *
 * "intVals" points to the first {method,pc} pair.
 *
 * The returned array is not added to the "local refs" list.
 */
ArrayObject* dvmGetStackTraceRaw(const int* intVals, int stackDepth)
{
    ArrayObject* steArray = NULL;
    int i;

    /* init this if we haven't yet */
    if (!dvmIsClassInitialized(gDvm.classJavaLangStackTraceElement))
        dvmInitClass(gDvm.classJavaLangStackTraceElement);

    /* allocate a StackTraceElement array */
    steArray = dvmAllocArray(gDvm.classJavaLangStackTraceElementArray,
                    stackDepth, kObjectArrayRefWidth, ALLOC_DEFAULT);
    if (steArray == NULL)
        goto bail;

    /*
     * Allocate and initialize a StackTraceElement for each stack frame.
     * We use the standard constructor to configure the object.
     */
    for (i = 0; i < stackDepth; i++) {
        Object* ste;
        Method* meth;
        StringObject* className;
        StringObject* methodName;
        StringObject* fileName;
        int lineNumber, pc;
        const char* sourceFile;
        char* dotName;

        ste = dvmAllocObject(gDvm.classJavaLangStackTraceElement,ALLOC_DEFAULT);
        if (ste == NULL)
            goto bail;

        meth = (Method*) *intVals++;
        pc = *intVals++;

        if (pc == -1)      // broken top frame?
            lineNumber = 0;
        else
            lineNumber = dvmLineNumFromPC(meth, pc);

        dotName = dvmDescriptorToDot(meth->clazz->descriptor);
        className = dvmCreateStringFromCstr(dotName);
        free(dotName);

        methodName = dvmCreateStringFromCstr(meth->name);
        sourceFile = dvmGetMethodSourceFile(meth);
        if (sourceFile != NULL)
            fileName = dvmCreateStringFromCstr(sourceFile);
        else
            fileName = NULL;

        /*
         * Invoke:
         *  public StackTraceElement(String declaringClass, String methodName,
         *      String fileName, int lineNumber)
         * (where lineNumber==-2 means "native")
         */
        JValue unused;
        dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangStackTraceElement_init,
            ste, &unused, className, methodName, fileName, lineNumber);

        dvmReleaseTrackedAlloc(ste, NULL);
        dvmReleaseTrackedAlloc((Object*) className, NULL);
        dvmReleaseTrackedAlloc((Object*) methodName, NULL);
        dvmReleaseTrackedAlloc((Object*) fileName, NULL);

        if (dvmCheckException(dvmThreadSelf()))
            goto bail;

        dvmSetObjectArrayElement(steArray, i, ste);
    }

bail:
    dvmReleaseTrackedAlloc((Object*) steArray, NULL);
    return steArray;
}