Example #1
0
/*
 * Invoke a method, using the specified arguments and return type, through
 * one of the reflection interfaces.  Could be a virtual or direct method
 * (including constructors).  Used for reflection.
 *
 * Deals with boxing/unboxing primitives and performs widening conversions.
 *
 * "invokeObj" will be null for a static method.
 *
 * If the invocation returns with an exception raised, we have to wrap it.
 */
Object* dvmInvokeMethod(Object* obj, const Method* method,
    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
    bool noAccessCheck)
{
    ClassObject* clazz;
    Object* retObj = NULL;
    Thread* self = dvmThreadSelf();
    s4* ins;
    int verifyCount, argListLength;
    JValue retval;
    bool needPop = false;

    /* verify arg count */
    if (argList != NULL)
        argListLength = argList->length;
    else
        argListLength = 0;
    if (argListLength != (int) params->length) {
        dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
            "wrong number of arguments; expected %d, got %d",
            params->length, argListLength);
        return NULL;
    }

    clazz = callPrep(self, method, obj, !noAccessCheck);
    if (clazz == NULL)
        return NULL;
    needPop = true;

    /* "ins" for new frame start at frame pointer plus locals */
    ins = ((s4*)self->interpSave.curFrame) +
        (method->registersSize - method->insSize);
    verifyCount = 0;

    //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
        assert(obj != NULL);
        *ins++ = (s4) obj;
        verifyCount++;
    }

    /*
     * Copy the args onto the stack.  Primitive types are converted when
     * necessary, and object types are verified.
     */
    DataObject** args = (DataObject**)(void*)argList->contents;
    ClassObject** types = (ClassObject**)(void*)params->contents;
    for (int i = 0; i < argListLength; i++) {
        int width = dvmConvertArgument(*args++, *types++, ins);
        if (width < 0) {
            dvmPopFrame(self);      // throw wants to pull PC out of stack
            needPop = false;
            throwArgumentTypeMismatch(i, *(types-1), *(args-1));
            goto bail;
        }

        ins += width;
        verifyCount += width;
    }

#ifndef NDEBUG
    if (verifyCount != method->insSize) {
        ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
            method->insSize, clazz->descriptor, method->name);
        assert(false);
        goto bail;
    }
#endif

    if (dvmIsNativeMethod(method)) {
        TRACE_METHOD_ENTER(self, method);
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval,
                              method, self);
        TRACE_METHOD_EXIT(self, method);
    } else {
        dvmInterpret(self, method, &retval);
    }

    /*
     * Pop the frame immediately.  The "wrap" calls below can cause
     * allocations, and we don't want the GC to walk the now-dead frame.
     */
    dvmPopFrame(self);
    needPop = false;

    /*
     * If an exception is raised, wrap and replace.  This is necessary
     * because the invoked method could have thrown a checked exception
     * that the caller wasn't prepared for.
     *
     * We might be able to do this up in the interpreted code, but that will
     * leave us with a shortened stack trace in the top-level exception.
     */
    if (dvmCheckException(self)) {
        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
    } else {
        /*
         * If this isn't a void method or constructor, convert the return type
         * to an appropriate object.
         *
         * We don't do this when an exception is raised because the value
         * in "retval" is undefined.
         */
        if (returnType != NULL) {
            retObj = (Object*)dvmBoxPrimitive(retval, returnType);
            dvmReleaseTrackedAlloc(retObj, NULL);
        }
    }

bail:
    if (needPop) {
        dvmPopFrame(self);
    }
    return retObj;
}
Example #2
0
/*
 * Issue a method call with arguments provided in an array.  We process
 * the contents of "args" by scanning the method signature.
 *
 * The values were likely placed into an uninitialized jvalue array using
 * the field specifiers, which means that sub-32-bit fields (e.g. short,
 * boolean) may not have 32 or 64 bits of valid data.  This is different
 * from the varargs invocation where the C compiler does a widening
 * conversion when calling a function.  As a result, we have to be a
 * little more precise when pulling stuff out.
 *
 * "args" may be NULL if the method has no arguments.
 */
void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
    bool fromJni, JValue* pResult, const jvalue* args)
{
    const char* desc = &(method->shorty[1]); // [0] is the return type.
    int verifyCount = 0;
    ClassObject* clazz;
    u4* ins;

    clazz = callPrep(self, method, obj, false);
    if (clazz == NULL)
        return;

    /* "ins" for new frame start at frame pointer plus locals */
    ins = ((u4*)self->interpSave.curFrame) +
        (method->registersSize - method->insSize);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
        assert(obj != NULL);
        *ins++ = (u4) obj;              /* obj is a "real" ref */
        verifyCount++;
    }

    while (*desc != '\0') {
        switch (*desc++) {
        case 'D':                       /* 64-bit quantity; have to use */
        case 'J':                       /*  memcpy() in case of mis-alignment */
            memcpy(ins, &args->j, 8);
            ins += 2;
            verifyCount++;              /* this needs an extra push */
            break;
        case 'L':                       /* includes array refs */
            if (fromJni)
                *ins++ = (u4) dvmDecodeIndirectRef(self, args->l);
            else
                *ins++ = (u4) args->l;
            break;
        case 'F':
        case 'I':
            *ins++ = args->i;           /* full 32 bits */
            break;
        case 'S':
            *ins++ = args->s;           /* 16 bits, sign-extended */
            break;
        case 'C':
            *ins++ = args->c;           /* 16 bits, unsigned */
            break;
        case 'B':
            *ins++ = args->b;           /* 8 bits, sign-extended */
            break;
        case 'Z':
            *ins++ = args->z;           /* 8 bits, zero or non-zero */
            break;
        default:
            ALOGE("Invalid char %c in short signature of %s.%s",
                *(desc-1), clazz->descriptor, method->name);
            assert(false);
            goto bail;
        }

        verifyCount++;
        args++;
    }

#ifndef NDEBUG
    if (verifyCount != method->insSize) {
        ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
            method->insSize, clazz->descriptor, method->name);
        assert(false);
        goto bail;
    }
#endif

    if (dvmIsNativeMethod(method)) {
        TRACE_METHOD_ENTER(self, method);
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
                              method, self);
        TRACE_METHOD_EXIT(self, method);
    } else {
        dvmInterpret(self, method, pResult);
    }

bail:
    dvmPopFrame(self);
}
Example #3
0
/*
 * Issue a method call with a variable number of arguments.  We process
 * the contents of "args" by scanning the method signature.
 *
 * Pass in NULL for "obj" on calls to static methods.
 *
 * We don't need to take the class as an argument because, in Dalvik,
 * we don't need to worry about static synchronized methods.
 */
void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
    bool fromJni, JValue* pResult, va_list args)
{
    const char* desc = &(method->shorty[1]); // [0] is the return type.
    int verifyCount = 0;
    ClassObject* clazz;
    u4* ins;

    clazz = callPrep(self, method, obj, false);
    if (clazz == NULL)
        return;

    /* "ins" for new frame start at frame pointer plus locals */
    ins = ((u4*)self->interpSave.curFrame) +
           (method->registersSize - method->insSize);

    //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
#ifdef WITH_EXTRA_OBJECT_VALIDATION
        assert(obj != NULL && dvmIsHeapAddress(obj));
#endif
        *ins++ = (u4) obj;
        verifyCount++;
    }

    while (*desc != '\0') {
        switch (*(desc++)) {
            case 'D': case 'J': {
                u8 val = va_arg(args, u8);
                memcpy(ins, &val, 8);       // EABI prevents direct store
                ins += 2;
                verifyCount += 2;
                break;
            }
            case 'F': {
                /* floats were normalized to doubles; convert back */
                float f = (float) va_arg(args, double);
                *ins++ = dvmFloatToU4(f);
                verifyCount++;
                break;
            }
            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
                void* arg = va_arg(args, void*);
                assert(obj == NULL || dvmIsHeapAddress(obj));
                jobject argObj = reinterpret_cast<jobject>(arg);
                if (fromJni)
                    *ins++ = (u4) dvmDecodeIndirectRef(self, argObj);
                else
                    *ins++ = (u4) argObj;
                verifyCount++;
                break;
            }
            default: {
                /* Z B C S I -- all passed as 32-bit integers */
                *ins++ = va_arg(args, u4);
                verifyCount++;
                break;
            }
        }
    }

#ifndef NDEBUG
    if (verifyCount != method->insSize) {
        ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
            method->insSize, clazz->descriptor, method->name);
        assert(false);
        goto bail;
    }
#endif

    //dvmDumpThreadStack(dvmThreadSelf());

    if (dvmIsNativeMethod(method)) {
        TRACE_METHOD_ENTER(self, method);
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
                              method, self);
        TRACE_METHOD_EXIT(self, method);
    } else {
        dvmInterpret(self, method, pResult);
    }

#ifndef NDEBUG
bail:
#endif
    dvmPopFrame(self);
}
Example #4
0
/*
 * Invoke a method, using the specified arguments and return type, through
 * one of the reflection interfaces.  Could be a virtual or direct method
 * (including constructors).  Used for reflection.
 *
 * Deals with boxing/unboxing primitives and performs widening conversions.
 *
 * "invokeObj" will be null for a static method.
 *
 * If the invocation returns with an exception raised, we have to wrap it.
 */
Object* dvmInvokeMethod(Object* obj, const Method* method,
    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
    bool noAccessCheck)
{
    ClassObject* clazz;
    Object* retObj = NULL;
    Thread* self = dvmThreadSelf();
    s4* ins;
    int verifyCount, argListLength;
    JValue retval;
    bool needPop = false;

#ifdef WITH_TAINT_TRACKING
    u4 rtaint = TAINT_CLEAR;
    int slot_cnt = 0;
    bool nativeTarget = dvmIsNativeMethod(method);
    /* For simplicity, argument tags for native targets
     * are unioned. This may cause false positives, but
     * it is the easiest way to handle this for now.
     */
    u4 nativeTag = TAINT_CLEAR;
#endif

    /* verify arg count */
    if (argList != NULL)
        argListLength = argList->length;
    else
        argListLength = 0;
    if (argListLength != (int) params->length) {
        LOGI("invoke: expected %d args, received %d args\n",
            params->length, argListLength);
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "wrong number of arguments");
        return NULL;
    }

    clazz = callPrep(self, method, obj, !noAccessCheck);
    if (clazz == NULL)
        return NULL;
    needPop = true;

    /* "ins" for new frame start at frame pointer plus locals */
#ifdef WITH_TAINT_TRACKING
    if (nativeTarget) {
	/* native target, no taint tag interleaving */
	ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize);
    } else {
	/* interpreted target, taint tags are interleaved */
	ins = ((s4*)self->curFrame) + 
	    ((method->registersSize - method->insSize) << 1);
    }
#else
    ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize);
#endif
    verifyCount = 0;

    //LOGD("  FP is %p, INs live at >= %p\n", self->curFrame, ins);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
        assert(obj != NULL);
        *ins++ = (s4) obj;
#ifdef WITH_TAINT_TRACKING
	if (!nativeTarget) {
	    *ins++ = TAINT_CLEAR;
	}
	slot_cnt++;
#endif
        verifyCount++;
    }

    /*
     * Copy the args onto the stack.  Primitive types are converted when
     * necessary, and object types are verified.
     */
    DataObject** args;
    ClassObject** types;
    int i;

    args = (DataObject**) argList->contents;
    types = (ClassObject**) params->contents;
    for (i = 0; i < argListLength; i++) {
        int width;
#ifdef WITH_TAINT_TRACKING
	int tag = dvmGetPrimitiveTaint(*args, *types);
#endif
        width = dvmConvertArgument(*args++, *types++, ins);
        if (width < 0) {
            if (*(args-1) != NULL) {
                LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n",
                    i, (*(args-1))->obj.clazz->descriptor,
                    (*(types-1))->descriptor);
            }
            dvmPopFrame(self);      // throw wants to pull PC out of stack
            needPop = false;
            dvmThrowException("Ljava/lang/IllegalArgumentException;",
                "argument type mismatch");
            goto bail;
        }

#ifdef WITH_TAINT_TRACKING
	/* dvmConvertArgument() returns -1, 1, or 2 */
	if (nativeTarget) {
	    nativeTag |= tag; /* TODO: is there a better way to do this?*/
	    ins += width;
	} else {
	    if (width == 2) {
		ins[2] = ins[1];
		ins[1] = tag;
		ins[3] = tag;
		ins += 4;
	    } else if (width == 1) {
		ins[1] = tag;
		ins += 2;
	    } else { /* error condition duplicated from above */
		dvmPopFrame(self);
		dvmThrowException("Ljava/lang/IllegalArgumentException;",
		    "argument type mismatch");
		goto bail_popped;
	    }
	}
	slot_cnt += width;
#else
        ins += width;
#endif
        verifyCount += width;
    }

#ifdef WITH_TAINT_TRACKING
    /* native hack spacer */
    *ins++ = TAINT_CLEAR; /* if nativeTarget, this is return taint */
    {
	int i;
	if (nativeTarget) {
	    for (i = 0; i < slot_cnt; i++) {
		*ins++ = nativeTag; /* TODO: better way? */
	    }
	}
    }
#endif

    if (verifyCount != method->insSize) {
        LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
            method->insSize, clazz->descriptor, method->name);
        assert(false);
        goto bail;
    }
    //dvmDumpThreadStack(dvmThreadSelf());

    if (dvmIsNativeMethod(method)) {
        TRACE_METHOD_ENTER(self, method);
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)(self->curFrame, &retval, method, self);
        TRACE_METHOD_EXIT(self, method);
#ifdef WITH_TAINT_TRACKING
	rtaint = ((u4*)self->curFrame)[slot_cnt];
#endif
    } else {
#ifdef WITH_TAINT_TRACKING
        dvmInterpret(self, method, &retval, &rtaint);
#else
        dvmInterpret(self, method, &retval);
#endif
    }

    /*
     * Pop the frame immediately.  The "wrap" calls below can cause
     * allocations, and we don't want the GC to walk the now-dead frame.
     */
    dvmPopFrame(self);
    needPop = false;

    /*
     * If an exception is raised, wrap and replace.  This is necessary
     * because the invoked method could have thrown a checked exception
     * that the caller wasn't prepared for.
     *
     * We might be able to do this up in the interpreted code, but that will
     * leave us with a shortened stack trace in the top-level exception.
     */
    if (dvmCheckException(self)) {
        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
    } else {
        /*
         * If this isn't a void method or constructor, convert the return type
         * to an appropriate object.
         *
         * We don't do this when an exception is raised because the value
         * in "retval" is undefined.
         */
        if (returnType != NULL) {
            retObj = (Object*)dvmWrapPrimitive(retval, returnType);
#ifdef WITH_TAINT_TRACKING
	    dvmSetPrimitiveTaint((DataObject *)retObj, returnType, rtaint);
#endif
            dvmReleaseTrackedAlloc(retObj, NULL);
        }
    }

bail:
    if (needPop) {
        dvmPopFrame(self);
    }
bail_popped:
    return retObj;
}
Example #5
0
/*
 * Issue a method call with arguments provided in an array.  We process
 * the contents of "args" by scanning the method signature.
 *
 * The values were likely placed into an uninitialized jvalue array using
 * the field specifiers, which means that sub-32-bit fields (e.g. short,
 * boolean) may not have 32 or 64 bits of valid data.  This is different
 * from the varargs invocation where the C compiler does a widening
 * conversion when calling a function.  As a result, we have to be a
 * little more precise when pulling stuff out.
 *
 * "args" may be NULL if the method has no arguments.
 */
void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
    bool fromJni, JValue* pResult, const jvalue* args)
{
    const char* desc = &(method->shorty[1]); // [0] is the return type.
    int verifyCount = 0;
    ClassObject* clazz;
    u4* ins;

#ifdef WITH_TAINT_TRACKING
    int slot_cnt = 0;
    bool nativeTarget = dvmIsNativeMethod(method);
#endif

    clazz = callPrep(self, method, obj, false);
    if (clazz == NULL)
        return;

    /* "ins" for new frame start at frame pointer plus locals */
#ifdef WITH_TAINT_TRACKING
    if (nativeTarget) {
	/* native target, no taint tag interleaving */
	ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
    } else {
	/* interpreted target, taint tags are interleaved */
	ins = ((u4*)self->curFrame) +
	    ((method->registersSize - method->insSize) << 1);
    }
#else
    ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
#endif

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
        assert(obj != NULL);
        *ins++ = (u4) obj;              /* obj is a "real" ref */
#ifdef WITH_TAINT_TRACKING
	if (!nativeTarget) {
	    *ins++ = TAINT_CLEAR;
	}
	slot_cnt++;
#endif
        verifyCount++;
    }

    JNIEnv* env = self->jniEnv;
    while (*desc != '\0') {
        switch (*desc++) {
        case 'D':                       /* 64-bit quantity; have to use */
        case 'J':                       /*  memcpy() in case of mis-alignment */
            memcpy(ins, &args->j, 8);
#ifdef WITH_TAINT_TRACKING
	    if (nativeTarget) {
		ins += 2;
	    } else { /* adjust for taint tag interleaving */
		ins[2] = ins[1];
		ins[1] = TAINT_CLEAR;
		ins[3] = TAINT_CLEAR;
		ins += 4;
	    }
	    slot_cnt += 2;
#else
	    ins += 2;
#endif
            verifyCount++;              /* this needs an extra push */
            break;
        case 'L':                       /* includes array refs */
            if (fromJni)
                *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
            else
                *ins++ = (u4) args->l;
#ifdef WITH_TAINT_TRACKING
	    if (!nativeTarget) {
		*ins++ = TAINT_CLEAR;
	    }
	    slot_cnt++;
#endif
            break;
        case 'F':
        case 'I':
            *ins++ = args->i;           /* full 32 bits */
#ifdef WITH_TAINT_TRACKING
	    if (!nativeTarget) {
		*ins++ = TAINT_CLEAR;
	    }
	    slot_cnt++;
#endif
            break;
        case 'S':
            *ins++ = args->s;           /* 16 bits, sign-extended */
#ifdef WITH_TAINT_TRACKING
	    if (!nativeTarget) {
		*ins++ = TAINT_CLEAR;
	    }
	    slot_cnt++;
#endif
            break;
        case 'C':
            *ins++ = args->c;           /* 16 bits, unsigned */
#ifdef WITH_TAINT_TRACKING
	    if (!nativeTarget) {
		*ins++ = TAINT_CLEAR;
	    }
	    slot_cnt++;
#endif
            break;
        case 'B':
            *ins++ = args->b;           /* 8 bits, sign-extended */
#ifdef WITH_TAINT_TRACKING
	    if (!nativeTarget) {
		*ins++ = TAINT_CLEAR;
	    }
	    slot_cnt++;
#endif
            break;
        case 'Z':
            *ins++ = args->z;           /* 8 bits, zero or non-zero */
#ifdef WITH_TAINT_TRACKING
	    if (!nativeTarget) {
		*ins++ = TAINT_CLEAR;
	    }
	    slot_cnt++;
#endif
            break;
        default:
            LOGE("Invalid char %c in short signature of %s.%s\n",
                *(desc-1), clazz->descriptor, method->name);
            assert(false);
            goto bail;
        }

        verifyCount++;
        args++;
    }

#ifdef WITH_TAINT_TRACKING
    /* native hack spacer */
    *ins++ = TAINT_CLEAR; /* if nativeTarget, this is return taint */
    {
	int i;
	if (nativeTarget) {
	    for (i = 0; i < slot_cnt; i++) {
		*ins++ = TAINT_CLEAR;
	    }
	}
    }
#endif

#ifndef NDEBUG
    if (verifyCount != method->insSize) {
        LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
            method->insSize, clazz->descriptor, method->name);
        assert(false);
        goto bail;
    }
#endif

    if (dvmIsNativeMethod(method)) {
        TRACE_METHOD_ENTER(self, method);
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)(self->curFrame, pResult, method, self);
        TRACE_METHOD_EXIT(self, method);
    } else {
#ifdef WITH_TAINT_TRACKING
	u4 rtaint; /* not used */
        dvmInterpret(self, method, pResult, &rtaint);
#else
        dvmInterpret(self, method, pResult);
#endif
    }

bail:
    dvmPopFrame(self);
}
Example #6
0
/*
 * Issue a method call with a variable number of arguments.  We process
 * the contents of "args" by scanning the method signature.
 *
 * Pass in NULL for "obj" on calls to static methods.
 *
 * We don't need to take the class as an argument because, in Dalvik,
 * we don't need to worry about static synchronized methods.
 */
void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
    bool fromJni, JValue* pResult, va_list args)
{
    const char* desc = &(method->shorty[1]); // [0] is the return type.
    int verifyCount = 0;
    ClassObject* clazz;
    u4* ins;

#ifdef WITH_TAINT_TRACKING
    int slot_cnt = 0;
    bool nativeTarget = dvmIsNativeMethod(method);
#endif

    clazz = callPrep(self, method, obj, false);
    if (clazz == NULL)
        return;

    /* "ins" for new frame start at frame pointer plus locals */
#ifdef WITH_TAINT_TRACKING
    if (nativeTarget) {
	/* native target, no taint tag interleaving */
	ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
    } else {
	/* interpreted target, taint tags are interleaved */
	ins = ((u4*)self->curFrame) +
	    ((method->registersSize - method->insSize) << 1);
    }
#else
    ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
#endif

    //LOGD("  FP is %p, INs live at >= %p\n", self->curFrame, ins);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
#ifdef WITH_EXTRA_OBJECT_VALIDATION
        assert(obj != NULL && dvmIsValidObject(obj));
#endif
        *ins++ = (u4) obj;
#ifdef WITH_TAINT_TRACKING
	if (!nativeTarget) {
	    *ins++ = TAINT_CLEAR;
	}
	slot_cnt++;
#endif
        verifyCount++;
    }

    JNIEnv* env = self->jniEnv;
    while (*desc != '\0') {
        switch (*(desc++)) {
            case 'D': case 'J': {
                u8 val = va_arg(args, u8);
                memcpy(ins, &val, 8);       // EABI prevents direct store
#ifdef WITH_TAINT_TRACKING
		if (nativeTarget) {
		    ins += 2;
		} else { /* adjust for taint tag interleaving */
		    ins[2] = ins[1];
		    ins[1] = TAINT_CLEAR;
		    ins[3] = TAINT_CLEAR;
		    ins += 4;
		}
		slot_cnt += 2;
#else
                ins += 2;
#endif
                verifyCount += 2;
                break;
            }
            case 'F': {
                /* floats were normalized to doubles; convert back */
                float f = (float) va_arg(args, double);
                *ins++ = dvmFloatToU4(f);
#ifdef WITH_TAINT_TRACKING
		if (!nativeTarget) {
		    *ins++ = TAINT_CLEAR;
		}
		slot_cnt++;
#endif
                verifyCount++;
                break;
            }
            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
                void* argObj = va_arg(args, void*);
                assert(obj == NULL || dvmIsValidObject(obj));
                if (fromJni)
                    *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
                else
                    *ins++ = (u4) argObj;
#ifdef WITH_TAINT_TRACKING
		if (!nativeTarget) {
		    *ins++ = TAINT_CLEAR;
		}
		slot_cnt++;
#endif
                verifyCount++;
                break;
            }
            default: {
                /* Z B C S I -- all passed as 32-bit integers */
                *ins++ = va_arg(args, u4);
#ifdef WITH_TAINT_TRACKING
		if (!nativeTarget) {
		    *ins++ = TAINT_CLEAR;
		}
		slot_cnt++;
#endif
                verifyCount++;
                break;
            }
        }
    }

#ifdef WITH_TAINT_TRACKING
    /* native hack spacer */
    *ins++ = TAINT_CLEAR; /* if nativeTarget, this is return taint */
    {
	int i;
	if (nativeTarget) {
	    for (i = 0; i < slot_cnt; i++) {
		*ins++ = TAINT_CLEAR;
	    }
	}
    }
#endif

#ifndef NDEBUG
    if (verifyCount != method->insSize) {
        LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
            method->insSize, clazz->descriptor, method->name);
        assert(false);
        goto bail;
    }
#endif

    //dvmDumpThreadStack(dvmThreadSelf());

    if (dvmIsNativeMethod(method)) {
        TRACE_METHOD_ENTER(self, method);
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)(self->curFrame, pResult, method, self);
        TRACE_METHOD_EXIT(self, method);
    } else {
#ifdef WITH_TAINT_TRACKING
	u4 rtaint; /* not used */
        dvmInterpret(self, method, pResult, &rtaint);
#else
        dvmInterpret(self, method, pResult);
#endif
    }

#ifndef NDEBUG
bail:
#endif
    dvmPopFrame(self);
}