static jint GetEnv(JavaVM* vm, void** penv, jint ver) { // TODO: Check version? Env* env = rvmGetEnv(); if (env) { *penv = env; return JNI_OK; } return JNI_EDETACHED; }
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; }
static void signalHandler_npe_so(int signum, siginfo_t* info, void* context) { // rvmGetEnv() uses pthread_getspecific() which isn't listed as // async-signal-safe. Others (e.g. mono) do this too so we assume it is safe // in practice. Env* env = rvmGetEnv(); if (env && rvmIsNonNativeFrame(env)) { // We now know the fault occurred in non-native code and not in our // native code or in any non-async-signal-safe system function. It // should be safe to do things here that would normally be unsafe to do // in a signal handler. void* faultAddr = info->si_addr; void* stackAddr = env->currentThread->stackAddr; Class* exClass = NULL; if (faultAddr < stackAddr && faultAddr >= (void*) (stackAddr - THREAD_STACK_GUARD_SIZE)) { // StackOverflowError exClass = java_lang_StackOverflowError; } else { // At least on Linux x86 it seems like si_addr isn't always 0x0 even // if a read of address 0x0 triggered SIGSEGV so we assume // everything that isn't a stack overflow is a read of address 0x0 // and throw NullPointerException. exClass = java_lang_NullPointerException; } if (exClass) { Object* throwable = rvmAllocateObject(env, exClass); if (!throwable) { throwable = rvmExceptionClear(env); } Frame fakeFrame; fakeFrame.prev = (Frame*) getFramePointer((ucontext_t*) context); fakeFrame.returnAddress = getPC((ucontext_t*) context); CallStack* callStack = captureCallStackFromFrame(env, &fakeFrame); rvmSetLongInstanceFieldValue(env, throwable, stackStateField, PTR_TO_LONG(callStack)); rvmRaiseException(env, throwable); } } struct sigaction sa; sa.sa_flags = 0; sa.sa_handler = SIG_DFL; sigaction(signum, &sa, NULL); kill(0, signum); }
static void signalHandler_npe_so(int signum, siginfo_t* info, void* context) { // SIGSEGV/SIGBUS are synchronous signals so we shouldn't have to worry about only calling // async-signal-safe functions here. Env* env = rvmGetEnv(); if (env && rvmIsNonNativeFrame(env)) { // We now know the fault occurred in non-native code. void* faultAddr = info->si_addr; void* stackAddr = env->currentThread->stackAddr; Class* exClass = NULL; if (faultAddr < stackAddr && faultAddr >= (void*) (stackAddr - THREAD_STACK_GUARD_SIZE)) { // StackOverflowError exClass = java_lang_StackOverflowError; } else { // At least on Linux x86 it seems like si_addr isn't always 0x0 even // if a read of address 0x0 triggered SIGSEGV so we assume // everything that isn't a stack overflow is a read of address 0x0 // and throw NullPointerException. exClass = java_lang_NullPointerException; } if (exClass) { Frame fakeFrame; fakeFrame.prev = (Frame*) getFramePointer((ucontext_t*) context); fakeFrame.returnAddress = getPC((ucontext_t*) context); Object* throwable = NULL; CallStack* callStack = captureCallStackFromFrame(env, &fakeFrame); if (callStack) { throwable = rvmAllocateObject(env, exClass); if (throwable) { rvmCallVoidClassMethod(env, exClass, throwableInitMethod, throwable, PTR_TO_LONG(callStack)); if (rvmExceptionCheck(env)) { throwable = NULL; } } } if (!throwable) { throwable = rvmExceptionClear(env); } rvmRaiseException(env, throwable); // Never returns! } } }
static void signalHandler_dump_thread(int signum, siginfo_t* info, void* context) { Env* env = rvmGetEnv(); if (env) { Frame fakeFrame; if (rvmIsNonNativeFrame(env)) { // Signalled in non-native code fakeFrame.prev = (Frame*) getFramePointer((ucontext_t*) context); fakeFrame.returnAddress = getPC((ucontext_t*) context); } else { // The thread was signalled while in native code, possibly a system // function. We cannot trust that this code uses proper frame // pointers so we cannot use the context's frame pointer. The top // most GatewayFrame in env was pushed when native code was entered. // Use its frame as frame pointer. fakeFrame = *(Frame*) env->gatewayFrames->frameAddress; } captureCallStack(env, &fakeFrame, dumpThreadStackTraceCallStack, MAX_CALL_STACK_LENGTH); } sem_post(&dumpThreadStackTraceCallSemaphore); }
static void _finalizeObject(GC_PTR addr, GC_PTR client_data) { Object* obj = (Object*) addr; Env* env = rvmGetEnv(); assert(env != NULL); finalizeObject(env, obj); }
jint rvmDetachCurrentThread(VM* vm, jboolean ignoreAttachCount) { Env* env = rvmGetEnv(); if (!env) return JNI_EDETACHED; return detachThread(env, ignoreAttachCount); }