/* * 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; /* 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; /* "ins" for new frame start at frame pointer plus locals */ ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize); 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; 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; 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 dvmThrowException("Ljava/lang/IllegalArgumentException;", "argument type mismatch"); goto bail_popped; } ins += width; verifyCount += width; } 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)) { #ifdef WITH_PROFILER TRACE_METHOD_ENTER(self, method); #endif /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)(self->curFrame, &retval, method, self); #ifdef WITH_PROFILER TRACE_METHOD_EXIT(self, method); #endif } else { dvmInterpret(self, method, &retval); } /* * 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); dvmReleaseTrackedAlloc(retObj, NULL); } } bail: dvmPopFrame(self); bail_popped: return retObj; }
/* * 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) { //salma // __android_log_print(ANDROID_LOG_DEBUG, "DVM DEBUG", "dvmInvokeMethod method name = %s\n,clazz name: %s", method->name, method->clazz->descriptor); //end salma 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; }
/* * 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; }