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); }
Env* _bcAttachThreadFromCallback(void) { Env* env = NULL; if (rvmAttachCurrentThread(vm, &env, NULL, NULL) != JNI_OK) { rvmAbort("Failed to attach thread in callback"); } return env; }
void __android_log_assert(const char *cond, const char *tag, const char *fmt, ...) { char realtag[128] = "android."; strcat(realtag, tag); va_list ap; va_start(ap, fmt); rvmLogfv(LOG_LEVEL_FATAL, realtag, fmt, ap); va_end(ap); rvmAbort(NULL); }
Env* _bcAttachThreadFromCallback(void) { Env* env = rvmGetEnv(); if (!env) { // This thread has never been attached or it has been // attached, then detached in the TLS destructor. In the // latter case, we are getting called back by native code // e.g. an auto-release pool, that is triggered after // the TLS destructor. if (rvmAttachCurrentThreadAsDaemon(vm, &env, NULL, NULL) != JNI_OK) { rvmAbort("Failed to attach thread in callback"); } } return env; }
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 detachThread(Env* env, jboolean ignoreAttachCount) { env->attachCount--; if (!ignoreAttachCount && env->attachCount > 0) { return JNI_OK; } if (env->gatewayFrames) { rvmAbort("Cannot detach thread when there are non native frames on the call stack"); } // TODO: Release all monitors still held by this thread (should only be monitors acquired from JNI code) Thread* thread = env->currentThread; if (rvmExceptionOccurred(env)) { threadExitUncaughtException(env, thread); } if (thread->threadObj->group) { rvmCallVoidInstanceMethod(env, thread->threadObj->group, removeThreadMethod, thread->threadObj); rvmExceptionClear(env); } // Set threadPtr to null rvmAtomicStoreLong(&thread->threadObj->threadPtr, 0); // Notify anyone waiting on this thread (using Thread.join()) rvmLockObject(env, thread->threadObj->lock); rvmObjectNotifyAll(env, thread->threadObj->lock); rvmUnlockObject(env, thread->threadObj->lock); rvmLockThreadsList(); thread->status = THREAD_ZOMBIE; DL_DELETE(threads, thread); pthread_cond_broadcast(&threadsChangedCond); rvmTearDownSignals(env); env->currentThread = NULL; pthread_setspecific(tlsEnvKey, NULL); rvmUnlockThreadsList(); return JNI_OK; }
void rvmThrow(Env* env, Object* e) { // TODO: Check that e != NULL? if (env->throwable) { rvmAbort("rvmThrow() called with env->throwable already set"); } if (IS_TRACE_ENABLED) { jlong stackState = rvmGetLongInstanceFieldValue(env, e, stackStateField); CallStack* callStack = (CallStack*) LONG_TO_PTR(stackState); if (!callStack || callStack->length == 0) { TRACEF("Throwing a %s with empty call stack", e->clazz->name); } else { TRACEF("Throwing a %s. Call stack:", e->clazz->name); Method* m; jint index = 0; while ((m = rvmGetNextCallStackMethod(env, callStack, &index)) != NULL) { TRACEF(" %s.%s%s", m->clazz->name, m->name, m->desc); } } } env->throwable = e; }
static Class* findClass(Env* env, const char* className, ClassLoader* classLoader, Class* (*loaderFunc)(Env*, const char*, ClassLoader*)) { obtainClassLock(); Class* clazz = getLoadedClass(env, className); if (clazz != NULL) { releaseClassLock(); return clazz; } if (className[0] == '[') { Class* componentType = findClassByDescriptor(env, &className[1], classLoader, loaderFunc); if (!componentType) { releaseClassLock(); return NULL; } clazz = createArrayClass(env, componentType); releaseClassLock(); return clazz; } TRACEF("Class '%s' not loaded", className); clazz = loaderFunc(env, className, classLoader); if (rvmExceptionOccurred(env)) { releaseClassLock(); return NULL; } if (clazz == NULL) { if (!strcmp(className, "java/lang/ClassNotFoundException")) { rvmAbort("Fatal error: java.lang.ClassNotFoundException not found!"); } rvmThrowClassNotFoundException(env, className); } TRACEF("Class '%s' loaded successfully", className); releaseClassLock(); return clazz; }
jboolean rvmInitOptions(int argc, char* argv[], Options* options, jboolean ignoreRvmArgs) { if (argc > 0) { // We're called from a RoboVM executable if (!realpath(argv[0], options->imagePath)) { return FALSE; } } else { // We're called via JNI. The caller could already have set // imagePath. If not we try to determine it via dladdr(). if (strlen(options->imagePath) == 0) { Dl_info dlinfo; if (dladdr(rvmInitOptions, &dlinfo) == 0 || dlinfo.dli_fname == NULL) { rvmAbort("Could not determine image path using dladdr()"); } strncpy(options->imagePath, dlinfo.dli_fname, sizeof(options->imagePath) - 1); } } if (strlen(options->resourcesPath) == 0) { strncpy(options->resourcesPath, options->imagePath, sizeof(options->resourcesPath) - 1); jint i = strlen(options->resourcesPath); while (i >= 0 && options->resourcesPath[i] != '/') { options->resourcesPath[i--] = '\0'; } if (i >= 0 && options->resourcesPath[i] == '/') { options->resourcesPath[i] = '\0'; } if (argc == 0) { #if defined(DARWIN) // Called via JNI and on Darwin. Assume this is a framework. Use the // Resources folder next to the image. strncat(options->resourcesPath, "/Resources", sizeof(options->resourcesPath) - strlen(options->resourcesPath) - 1); #endif } } // Look for a robovm.ini in the resources path parseRoboVMIni(options); if (argc > 0) { jint firstJavaArg = 1; for (jint i = 1; i < argc; i++) { if (startsWith(argv[i], "-rvm:")) { if (!ignoreRvmArgs) { char* arg = &argv[i][5]; rvmParseOption(arg, options); } firstJavaArg++; } else { break; } } options->commandLineArgs = NULL; options->commandLineArgsCount = argc - firstJavaArg; if (options->commandLineArgsCount > 0) { options->commandLineArgs = &argv[firstJavaArg]; } return options->mainClass != NULL; } return TRUE; }
static void FatalError(JNIEnv* env, const char* msg) { rvmAbort((char*) msg); }