static void wrapClassNotFoundException(Env* env, const char* className) { Object* exception = rvmExceptionOccurred(env); if (exception && exception->clazz == java_lang_ClassNotFoundException) { // If ClassNotFoundException is thrown we have to wrap it in a NoClassDefFoundError exception = rvmExceptionClear(env); Method* constructor = rvmGetInstanceMethod(env, java_lang_NoClassDefFoundError, "<init>", "(Ljava/lang/String;)V"); if (!constructor) return; Object* message = rvmNewStringUTF(env, className, -1); if (!message) return; Object* wrappedException = rvmNewObject(env, java_lang_NoClassDefFoundError, constructor, message); if (!wrappedException) return; Class* java_lang_StackTraceElement = rvmFindClassUsingLoader(env, "java/lang/StackTraceElement", NULL); if (!java_lang_StackTraceElement) return; ObjectArray* stackTrace = rvmNewObjectArray(env, 0, java_lang_StackTraceElement, NULL, NULL); if (!stackTrace) return; Method* setStackTrace = rvmGetInstanceMethod(env, java_lang_Throwable, "setStackTrace", "([Ljava/lang/StackTraceElement;)V"); if (!setStackTrace) return; rvmCallVoidInstanceMethod(env, wrappedException, setStackTrace, stackTrace); if (rvmExceptionCheck(env)) return; Method* initCause = rvmGetInstanceMethod(env, java_lang_NoClassDefFoundError, "initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;"); if (!initCause) return; rvmCallObjectInstanceMethod(env, wrappedException, initCause, exception); if (!rvmExceptionCheck(env)) rvmThrow(env, wrappedException); } }
void* lookupInterfaceMethod(Env* env, ClassInfoHeader* header, Object* thiz, char* name, char* desc) { initializeClass(env, header); if (rvmExceptionCheck(env)) return NULL; Class* ownerInterface = header->clazz; if (!rvmIsInstanceOf(env, thiz, ownerInterface)) { char message[256]; snprintf(message, 256, "Class %s does not implement the requested interface %s", rvmToBinaryClassName(env, thiz->clazz->name), rvmToBinaryClassName(env, ownerInterface->name)); rvmThrowIncompatibleClassChangeError(env, message); return NULL; } Method* method = rvmGetInstanceMethod(env, thiz->clazz, name, desc); Object* throwable = rvmExceptionClear(env); if (!method && throwable->clazz != java_lang_NoSuchMethodError) { rvmThrow(env, throwable); return NULL; } if (!method || METHOD_IS_ABSTRACT(method)) { rvmThrowAbstractMethodError(env, ""); // TODO: Message return NULL; } if (!METHOD_IS_PUBLIC(method)) { rvmThrowIllegalAccessError(env, ""); // TODO: Message return NULL; } return method->synchronizedImpl ? method->synchronizedImpl : method->impl; }
void rvmRaiseException(Env* env, Object* e) { if (env->throwable != e) { rvmThrow(env, e); } jboolean (*exceptionMatch)(Env*, TrycatchContext*) = env->vm->options->exceptionMatch; TrycatchContext* tc = env->trycatchContext; while (tc) { if (tc->sel != 0 && (tc->sel == CATCH_ALL_SEL || exceptionMatch(env, tc))) { rvmRestoreThreadSignalMask(env); rvmHookExceptionRaised(env, e, tc->prev? TRUE: FALSE); rvmTrycatchJump(tc); // unreachable } rvmTrycatchLeave(env); tc = env->trycatchContext; } /* * We only end up here if Java was called into from native without a * TrycatchContext being set up first. This only happens for @Callback * methods. The only sane thing to do here is to terminate the app. But * first we want to detach the current thread which will report the * uncaught exception to the uncaught exception handler. */ env->gatewayFrames = NULL; // Needed to avoid the "Cannot detach thread when there are non native frames on the call stack" error rvmDetachCurrentThread(env->vm, TRUE, TRUE); rvmAbort("Unhandled exception (probably in a @Callback method called from native code): %s", e->clazz->name); }
jboolean rvmThrowOutOfMemoryError(Env* env) { // Don't run the constructor on OutOfMemoryError instances since that will // likely cause more OOM. Object* e = rvmAllocateObject(env, java_lang_OutOfMemoryError); if (!e) { return FALSE; } rvmThrow(env, e); return TRUE; }
jboolean rvmThrowNew(Env* env, Class* clazz, const char* message) { Method* constructor = rvmGetInstanceMethod(env, clazz, "<init>", "(Ljava/lang/String;)V"); if (!constructor) return FALSE; Object* string = NULL; // TODO: Check that clazz != NULL? if (message) { string = rvmNewStringUTF(env, message, -1); if (!string) return FALSE; } Object* e = rvmNewObject(env, clazz, constructor, string); if (!e) return FALSE; rvmThrow(env, e); return TRUE; }
void throwInvocationTargetException(Env* env, Object* throwable) { rvmExceptionClear(env); if (!java_lang_reflect_InvocationTargetException) { java_lang_reflect_InvocationTargetException = rvmFindClassUsingLoader(env, "java/lang/reflect/InvocationTargetException", NULL); if (!java_lang_reflect_InvocationTargetException) return; } if (!java_lang_reflect_InvocationTargetException_init) { java_lang_reflect_InvocationTargetException_init = rvmGetMethod(env, java_lang_reflect_InvocationTargetException, "<init>", "(Ljava/lang/Throwable;)V"); if (!java_lang_reflect_InvocationTargetException_init) return; } jvalue initArgs[1]; initArgs[0].l = (jobject) throwable; Object* exception = rvmNewObjectA(env, java_lang_reflect_InvocationTargetException, java_lang_reflect_InvocationTargetException_init, initArgs); if (!exception) return; rvmThrow(env, exception); }
void rvmRaiseException(Env* env, Object* e) { if (env->throwable != e) { rvmThrow(env, e); } jboolean (*exceptionMatch)(Env*, TrycatchContext*) = env->vm->options->exceptionMatch; TrycatchContext* tc = env->trycatchContext; while (tc) { if (tc->sel != 0 && (tc->sel == CATCH_ALL_SEL || exceptionMatch(env, tc))) { rvmRestoreSignalMask(env); rvmTrycatchJump(tc); // unreachable } rvmTrycatchLeave(env); tc = env->trycatchContext; } rvmAbort("Unhandled exception: %s", e->clazz->name); }
static jint Throw(JNIEnv* env, jthrowable obj) { rvmThrow((Env*) env, (Object*) obj); return 0; }
void rvmInitialize(Env* env, Class* clazz) { obtainClassLock(); // TODO: Throw java.lang.NoClassDefFoundError if state == CLASS_ERROR? if (CLASS_IS_STATE_ERROR(clazz)) { // TODO: Add the class' binary name in the message rvmThrowNew(env, java_lang_NoClassDefFoundError, "Could not initialize class ??"); releaseClassLock(); return; } if (!CLASS_IS_STATE_INITIALIZED(clazz) && !CLASS_IS_STATE_INITIALIZING(clazz)) { jint oldState = clazz->flags & CLASS_STATE_MASK; clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | CLASS_STATE_INITIALIZING; if (clazz->superclass) { rvmInitialize(env, clazz->superclass); if (rvmExceptionOccurred(env)) { clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | oldState; releaseClassLock(); return; } } TRACEF("Initializing class %s", clazz->name); void* initializer = clazz->initializer; if (!initializer) { if (!CLASS_IS_ARRAY(clazz) && !CLASS_IS_PROXY(clazz) && !CLASS_IS_PRIMITIVE(clazz)) { env->vm->options->classInitialized(env, clazz); } clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | CLASS_STATE_INITIALIZED; releaseClassLock(); return; } CallInfo* callInfo = call0AllocateCallInfo(env, initializer, 1, 0, 0, 0, 0); call0AddPtr(callInfo, env); void (*f)(CallInfo*) = (void (*)(CallInfo*)) _call0; rvmPushGatewayFrame(env); TrycatchContext tc = {0}; tc.sel = CATCH_ALL_SEL; if (!rvmTrycatchEnter(env, &tc)) { f(callInfo); } rvmTrycatchLeave(env); rvmPopGatewayFrame(env); Object* exception = rvmExceptionClear(env); if (exception) { clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | CLASS_STATE_ERROR; if (!rvmIsInstanceOf(env, exception, java_lang_Error)) { // If exception isn't an instance of java.lang.Error // we must wrap it in a java.lang.ExceptionInInitializerError Method* constructor = rvmGetInstanceMethod(env, java_lang_ExceptionInInitializerError, "<init>", "(Ljava/lang/Throwable;)V"); if (!constructor) return; Object* wrappedException = rvmNewObject(env, java_lang_ExceptionInInitializerError, constructor, exception); if (!wrappedException) return; exception = wrappedException; } rvmThrow(env, exception); releaseClassLock(); return; } if (!CLASS_IS_ARRAY(clazz) && !CLASS_IS_PROXY(clazz) && !CLASS_IS_PRIMITIVE(clazz)) { env->vm->options->classInitialized(env, clazz); } clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | CLASS_STATE_INITIALIZED; } releaseClassLock(); }