const char* rvmGetNextParameterType(const char** desc) { const char* s = *desc; (*desc)++; switch (s[0]) { case 'B': case 'Z': case 'S': case 'C': case 'I': case 'J': case 'F': case 'D': return s; case '[': rvmGetNextParameterType(desc); return s; case 'L': while (**desc != ';') (*desc)++; (*desc)++; return s; case '(': return rvmGetNextParameterType(desc); } return 0; }
jint rvmGetParameterCount(Method* method) { const char* desc = method->desc; jint count = 0; while (rvmGetNextParameterType(&desc)) { count++; } return count; }
static jvalue* va_list2jargs(Env* env, Method* method, va_list args) { jint argsCount = rvmGetParameterCount(method); if (argsCount == 0) { return emptyJValueArgs; } jvalue *jvalueArgs = (jvalue*) rvmAllocateMemory(env, sizeof(jvalue) * argsCount); if (!jvalueArgs) return NULL; const char* desc = method->desc; const char* c; jint i = 0; while ((c = rvmGetNextParameterType(&desc))) { switch (c[0]) { case 'B': jvalueArgs[i++].b = (jbyte) va_arg(args, jint); break; case 'Z': jvalueArgs[i++].z = (jboolean) va_arg(args, jint); break; case 'S': jvalueArgs[i++].s = (jshort) va_arg(args, jint); break; case 'C': jvalueArgs[i++].c = (jchar) va_arg(args, jint); break; case 'I': jvalueArgs[i++].i = va_arg(args, jint); break; case 'J': jvalueArgs[i++].j = va_arg(args, jlong); break; case 'F': jvalueArgs[i++].f = (jfloat) va_arg(args, jdouble); break; case 'D': jvalueArgs[i++].d = va_arg(args, jdouble); break; case '[': case 'L': jvalueArgs[i++].l = va_arg(args, jobject); break; } } return jvalueArgs; }
static void setArgs(Env* env, Object* obj, Method* method, CallInfo* callInfo, jvalue* args) { call0AddPtr(callInfo, env); if (!(method->access & ACC_STATIC)) { call0AddPtr(callInfo, obj); } const char* desc = method->desc; const char* c; jint i = 0; while ((c = rvmGetNextParameterType(&desc))) { switch (c[0]) { case 'Z': call0AddInt(callInfo, (jint) args[i++].z); break; case 'B': call0AddInt(callInfo, (jint) args[i++].b); break; case 'S': call0AddInt(callInfo, (jint) args[i++].s); break; case 'C': call0AddInt(callInfo, (jint) args[i++].c); break; case 'I': call0AddInt(callInfo, args[i++].i); break; case 'J': call0AddLong(callInfo, args[i++].j); break; case 'F': call0AddFloat(callInfo, args[i++].f); break; case 'D': call0AddDouble(callInfo, args[i++].d); break; case 'L': case '[': call0AddPtr(callInfo, args[i++].l); break; } } }
static void countArgs(Env* env, Method* method, ArgsCount* argsCount) { jint ptrArgsCount = 0, intArgsCount = 0, longArgsCount = 0, floatArgsCount = 0, doubleArgsCount = 0; ptrArgsCount = 1; // First arg is always the Env* if (!(method->access & ACC_STATIC)) { // Non-static methods takes the receiver object (this) as arg 2 ptrArgsCount++; } const char* desc = method->desc; const char* c; while ((c = rvmGetNextParameterType(&desc))) { switch (c[0]) { case 'Z': case 'B': case 'S': case 'C': case 'I': intArgsCount++; break; case 'J': longArgsCount++; break; case 'F': floatArgsCount++; break; case 'D': doubleArgsCount++; break; case 'L': case '[': ptrArgsCount++; break; } } argsCount->ptrArgsCount = ptrArgsCount; argsCount->intArgsCount = intArgsCount; argsCount->longArgsCount = longArgsCount; argsCount->floatArgsCount = floatArgsCount; argsCount->doubleArgsCount = doubleArgsCount; }
ObjectArray* Java_java_lang_reflect_Method_getParameterTypes(Env* env, Class* clazz, jlong methodPtr) { Method* method = (Method*) LONG_TO_PTR(methodPtr); jint argsCount = rvmGetParameterCount(method); Class* array_java_lang_Class = rvmFindClassUsingLoader(env, "[Ljava/lang/Class;", NULL); if (!array_java_lang_Class) return NULL; ObjectArray* paramTypes = rvmNewObjectArray(env, argsCount, NULL, array_java_lang_Class, NULL); if (!paramTypes) return NULL; const char* desc = method->desc; const char* s; jint i = 0; while ((s = rvmGetNextParameterType(&desc))) { char* paramTypeName = rvmAllocateMemoryAtomic(env, desc - s + 1); if (!paramTypeName) return NULL; strncpy(paramTypeName, s, desc - s); Class* paramType = rvmFindClassByDescriptor(env, paramTypeName, method->clazz->classLoader); if (!paramType) return NULL; paramTypes->values[i++] = (Object*) paramType; } return paramTypes; }
void _rvmProxyHandler(CallInfo* callInfo) { Env* env = (Env*) proxy0NextPtr(callInfo); Object* receiver = (Object*) proxy0NextPtr(callInfo); Class* proxyClass = receiver->clazz; ProxyClassData* proxyClassData = (ProxyClassData*) proxyClass->data; LookupKey key; memset(&key, 0, sizeof(LookupKey)); key.name = (char*) env->reserved0; key.desc = (char*) env->reserved1; LookupEntry* entry; HASH_FIND(hh, proxyClassData->lookupsHash, &key, sizeof(LookupKey), entry); if (!entry) { rvmThrowNoSuchMethodError(env, "Failed to determine which method was called on proxy class"); goto error; } ProxyMethod* method = entry->method; rvmPushGatewayFrameProxy(env, method); jint argsCount = rvmGetParameterCount((Method*) method); jvalue *jvalueArgs = NULL; if (argsCount > 0) { jvalueArgs = (jvalue*) rvmAllocateMemory(env, sizeof(jvalue) * argsCount); if (!jvalueArgs) goto errorPop; const char* desc = method->method.desc; const char* c; jint i = 0; while ((c = rvmGetNextParameterType(&desc))) { switch (c[0]) { case 'B': jvalueArgs[i++].b = (jbyte) proxy0NextInt(callInfo); break; case 'Z': jvalueArgs[i++].z = (jboolean) proxy0NextInt(callInfo); break; case 'S': jvalueArgs[i++].s = (jshort) proxy0NextInt(callInfo); break; case 'C': jvalueArgs[i++].c = (jchar) proxy0NextInt(callInfo); break; case 'I': jvalueArgs[i++].i = proxy0NextInt(callInfo); break; case 'J': jvalueArgs[i++].j = proxy0NextLong(callInfo); break; case 'F': jvalueArgs[i++].f = proxy0NextFloat(callInfo); break; case 'D': jvalueArgs[i++].d = proxy0NextDouble(callInfo); break; case '[': case 'L': jvalueArgs[i++].l = (jobject) proxy0NextPtr(callInfo); break; } } } jvalue returnValue; proxyClassData->handler(env, receiver, method, jvalueArgs, &returnValue); rvmPopGatewayFrame(env); if (rvmExceptionCheck(env)) goto error; proxy0ReturnInt(callInfo, 0); switch (rvmGetReturnType(method->method.desc)[0]) { case 'B': proxy0ReturnInt(callInfo, (jint) returnValue.b); break; case 'Z': proxy0ReturnInt(callInfo, (jint) returnValue.z); break; case 'S': proxy0ReturnInt(callInfo, (jint) returnValue.s); break; case 'C': proxy0ReturnInt(callInfo, (jint) returnValue.c); break; case 'I': proxy0ReturnInt(callInfo, returnValue.i); break; case 'J': proxy0ReturnLong(callInfo, returnValue.j); break; case 'F': proxy0ReturnFloat(callInfo, returnValue.f); break; case 'D': proxy0ReturnDouble(callInfo, returnValue.d); break; case '[': case 'L': proxy0ReturnPtr(callInfo, returnValue.l); break; } return; errorPop: rvmPopGatewayFrame(env); error: rvmRaiseException(env, rvmExceptionOccurred(env)); }