jboolean rvmRun(Env* env) { Options* options = env->vm->options; Class* clazz = NULL; clazz = rvmFindClassUsingLoader(env, options->mainClass, systemClassLoader); if (clazz) { Method* method = rvmGetClassMethod(env, clazz, "main", "([Ljava/lang/String;)V"); if (method) { ObjectArray* args = rvmNewObjectArray(env, options->commandLineArgsCount, java_lang_String, NULL, NULL); if (args) { jint i = 0; for (i = 0; i < args->length; i++) { // TODO: Don't assume modified UTF-8 args->values[i] = rvmNewStringUTF(env, options->commandLineArgs[i], -1); if (!args->values[i]) { args = NULL; break; } } if (args) rvmCallVoidClassMethod(env, clazz, method, args); } } } Object* throwable = rvmExceptionOccurred(env); rvmDetachCurrentThread(env->vm, TRUE); return throwable == NULL ? TRUE : FALSE; }
jboolean rvmRun(Env* env) { Options* options = env->vm->options; Class* clazz = NULL; rvmHookBeforeAppEntryPoint(env, options->mainClass); clazz = rvmFindClassUsingLoader(env, options->mainClass, systemClassLoader); if (clazz) { Method* method = rvmGetClassMethod(env, clazz, "main", "([Ljava/lang/String;)V"); if (method) { ObjectArray* args = rvmNewObjectArray(env, options->commandLineArgsCount, java_lang_String, NULL, NULL); if (args) { jint i = 0; for (i = 0; i < args->length; i++) { // TODO: Don't assume modified UTF-8 args->values[i] = rvmNewStringUTF(env, options->commandLineArgs[i], -1); if (!args->values[i]) { args = NULL; break; } } if (args) { rvmCallVoidClassMethod(env, clazz, method, args); } } } } return rvmDestroyVM(env->vm); }
static void finalizeObject(Env* env, Object* obj) { // TRACEF("finalizeObject: %p (%s)\n", obj, obj->clazz->name); rvmLockMutex(&referentsLock); void* key = (void*) GC_HIDE_POINTER(obj); ReferentEntry* referentEntry; HASH_FIND_PTR(referents, &key, referentEntry); assert(referentEntry != NULL); if (referentEntry->references == NULL) { // The object is not referenced by any type of reference and can never be resurrected. HASH_DEL(referents, referentEntry); rvmUnlockMutex(&referentsLock); return; } Object* softReferences = NULL; Object* weakReferences = NULL; Object* finalizerReferences = NULL; Object* phantomReferences = NULL; Object* clearedReferences = NULL; ReferenceList* refNode; while (referentEntry->references != NULL) { refNode = referentEntry->references; LL_DELETE(referentEntry->references, refNode); Object** list = NULL; Object* reference = refNode->reference; if (rvmIsSubClass(java_lang_ref_SoftReference, reference->clazz)) { list = &softReferences; } else if (rvmIsSubClass(java_lang_ref_WeakReference, reference->clazz)) { list = &weakReferences; } else if (rvmIsSubClass(java_lang_ref_FinalizerReference, reference->clazz)) { list = &finalizerReferences; } else if (rvmIsSubClass(java_lang_ref_PhantomReference, reference->clazz)) { list = &phantomReferences; } enqueuePendingReference(env, reference, list); } assert(referentEntry->references == NULL); clearAndEnqueueReferences(env, &softReferences, &clearedReferences); clearAndEnqueueReferences(env, &weakReferences, &clearedReferences); enqueueFinalizerReferences(env, &finalizerReferences, &clearedReferences); clearAndEnqueueReferences(env, &phantomReferences, &clearedReferences); // Reregister for finalization. If no new references have been added to the list of references for the referent the // next time it gets finalized we know it will never be resurrected. GC_REGISTER_FINALIZER_NO_ORDER(obj, _finalizeObject, NULL, NULL, NULL); rvmUnlockMutex(&referentsLock); if (clearedReferences != NULL) { rvmCallVoidClassMethod(env, java_lang_ref_ReferenceQueue, java_lang_ref_ReferenceQueue_add, clearedReferences); assert(rvmExceptionOccurred(env) == NULL); } }
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! } } }
void rvmRegisterFinalizer(Env* env, Object* obj) { // Call java.lang.FinalizerReference.add(obj) // A FinalizerReference will be created for obj and that reference will be registered using rvmRegisterReference(). rvmCallVoidClassMethod(env, java_lang_ref_FinalizerReference, java_lang_ref_FinalizerReference_add, obj); }
Env* rvmStartup(Options* options) { // TODO: Error handling TRACE("Initializing logging"); if (!rvmInitLog(options)) return NULL; #if defined(IOS) && (defined(RVM_ARMV7) || defined(RVM_THUMBV7)) // Enable IEEE-754 denormal support. // Without this the VFP treats numbers that are close to zero as zero itself. // See http://developer.apple.com/library/ios/#technotes/tn2293/_index.html. fenv_t fenv; fegetenv(&fenv); fenv.__fpscr &= ~__fpscr_flush_to_zero; fesetenv(&fenv); #endif // print PID if it was requested if(options->printPID) { pid_t pid = getpid(); if(options->pidFile) { FILE* f = fopen(options->pidFile, "w"); if (!f) return NULL; fprintf(f, "%d", pid); fclose(f); } else { fprintf(stderr, "[DEBUG] %s: pid=%d\n", LOG_TAG, pid); } } // setup the TCP channel socket and wait // for the debugger to connect if(options->enableHooks) { if(!rvmHookSetupTCPChannel(options)) return NULL; if(!rvmHookHandshake(options)) return NULL; } TRACE("Initializing GC"); if (!initGC(options)) return NULL; // Ignore SIGPIPE signals. SIGPIPE interrupts write() calls which we don't // want. Dalvik does this too in dalvikvm/Main.cpp. if (!ignoreSignal(SIGPIPE)) return NULL; // Ignore SIGXFSZ signals. SIGXFSZ is raised when writing beyond the RLIMIT_FSIZE // of the current process (at least on Darwin) using pwrite(). if (!ignoreSignal(SIGXFSZ)) return NULL; VM* vm = rvmCreateVM(options); if (!vm) return NULL; Env* env = rvmCreateEnv(vm); if (!env) return NULL; // TODO: What if we can't allocate Env? if (!initClasspathEntries(env, options->resourcesPath, options->rawBootclasspath, &options->bootclasspath)) return NULL; if (!initClasspathEntries(env, options->resourcesPath, options->rawClasspath, &options->classpath)) return NULL; // Call init on modules TRACE("Initializing classes"); if (!rvmInitClasses(env)) return NULL; TRACE("Initializing memory"); if (!rvmInitMemory(env)) return NULL; TRACE("Initializing methods"); if (!rvmInitMethods(env)) return NULL; TRACE("Initializing strings"); if (!rvmInitStrings(env)) return NULL; TRACE("Initializing monitors"); if (!rvmInitMonitors(env)) return NULL; TRACE("Initializing proxy"); if (!rvmInitProxy(env)) return NULL; TRACE("Initializing threads"); if (!rvmInitThreads(env)) return NULL; TRACE("Initializing attributes"); if (!rvmInitAttributes(env)) return NULL; TRACE("Initializing primitive wrapper classes"); if (!rvmInitPrimitiveWrapperClasses(env)) return NULL; TRACE("Initializing exceptions"); if (!rvmInitExceptions(env)) return NULL; TRACE("Initializing signals"); if (!rvmInitSignals(env)) return NULL; TRACE("Initializing JNI"); if (!rvmInitJNI(env)) return NULL; // Initialize the RoboVM rt JNI code // RT_JNI_OnLoad(&vm->javaVM, NULL); // Initialize the dalvik rt JNI code TRACE("Initializing dalvik's runtime JNI code"); registerCoreLibrariesJni((JNIEnv*) env); #ifdef DARWIN TRACE("Initializing JAR NSURLProtocol"); registerJARURLProtocol(); #endif TRACE("Creating system ClassLoader"); systemClassLoader = rvmGetSystemClassLoader(env); if (rvmExceptionOccurred(env)) goto error_system_ClassLoader; env->currentThread->threadObj->contextClassLoader = systemClassLoader; TRACE("Initialization done"); env->vm->initialized = TRUE; // Start Daemons TRACE("Starting Daemons"); java_lang_Daemons = rvmFindClassUsingLoader(env, "java/lang/Daemons", NULL); if (!java_lang_Daemons) goto error_daemons; java_lang_Daemons_start = rvmGetClassMethod(env, java_lang_Daemons, "start", "()V"); if (!java_lang_Daemons_start) goto error_daemons; rvmCallVoidClassMethod(env, java_lang_Daemons, java_lang_Daemons_start); if (rvmExceptionCheck(env)) goto error_daemons; TRACE("Daemons started"); jboolean errorDuringSetup = FALSE; //If our options has any properties, let's set them before we call our main. if (options->properties) { //First, find java.lang.System, which has the setProperty method. Class* clazz = rvmFindClassUsingLoader(env, "java/lang/System", NULL); if (clazz) { //Get the setProperty method. Method* method = rvmGetClassMethod(env, clazz, "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); if (method) { SystemProperty* property = options->properties; //Go through all of our properties and add each one in turn by calling setProperty. while (property != NULL) { Object* key = NULL; Object* value = NULL; //The key is not allowed to be an empty string, so don't set it if we don't get a key. if(property->key && strlen(property->key) > 0) { key = rvmNewStringUTF(env, property->key, -1); } else { FATAL("Cannot have empty key in system property."); errorDuringSetup = TRUE; break; } if (property->value) { value = rvmNewStringUTF(env, property->value, -1); } else { value = rvmNewStringUTF(env, "", -1); } if (key && value) { rvmCallObjectClassMethod(env, clazz, method, key, value); } else { if (!key) { FATALF("Error creating string from system property key: %s", property->key); } if (!value) { FATALF("Error creating string from system property value: %s", property->value); } errorDuringSetup = TRUE; break; } property = property->next; //Advance to the next property. } } } } return (errorDuringSetup) ? NULL : env; error_daemons: error_system_ClassLoader: rvmDetachCurrentThread(env->vm, TRUE, FALSE); return NULL; }
Env* rvmStartup(Options* options) { // TODO: Error handling TRACE("Initializing GC"); if (!initGC(options)) return NULL; VM* vm = rvmCreateVM(options); if (!vm) return NULL; Env* env = rvmCreateEnv(vm); if (!env) return NULL; // TODO: What if we can't allocate Env? if (!initClasspathEntries(env, options->basePath, options->rawBootclasspath, &options->bootclasspath)) return NULL; if (!initClasspathEntries(env, options->basePath, options->rawClasspath, &options->classpath)) return NULL; // Call init on modules TRACE("Initializing logging"); if (!rvmInitLog(env)) return NULL; TRACE("Initializing classes"); if (!rvmInitClasses(env)) return NULL; TRACE("Initializing methods"); if (!rvmInitMethods(env)) return NULL; TRACE("Initializing strings"); if (!rvmInitStrings(env)) return NULL; TRACE("Initializing monitors"); if (!rvmInitMonitors(env)) return NULL; TRACE("Initializing threads"); if (!rvmInitThreads(env)) return NULL; TRACE("Initializing attributes"); if (!rvmInitAttributes(env)) return NULL; TRACE("Initializing primitive wrapper classes"); if (!rvmInitPrimitiveWrapperClasses(env)) return NULL; TRACE("Initializing exceptions"); if (!rvmInitExceptions(env)) return NULL; TRACE("Initializing signals"); if (!rvmInitSignals(env)) return NULL; TRACE("Initializing memory"); if (!rvmInitMemory(env)) return NULL; // Initialize the RoboVM rt JNI code // RT_JNI_OnLoad(&vm->javaVM, NULL); // Initialize dalvik's JNIHelp code in libnativehelper TRACE("Initializing dalvik's libnativehelper"); registerJniHelp((JNIEnv*) env); // Initialize the dalvik rt JNI code TRACE("Initializing dalvik's runtime JNI code"); registerCoreLibrariesJni((JNIEnv*) env); TRACE("Creating system ClassLoader"); systemClassLoader = rvmGetSystemClassLoader(env); if (rvmExceptionOccurred(env)) goto error_system_ClassLoader; env->currentThread->threadObj->contextClassLoader = systemClassLoader; TRACE("Initialization done"); // Start Daemons TRACE("Starting Daemons"); java_lang_Daemons = rvmFindClassUsingLoader(env, "java/lang/Daemons", NULL); if (!java_lang_Daemons) goto error_daemons; java_lang_Daemons_start = rvmGetClassMethod(env, java_lang_Daemons, "start", "()V"); if (!java_lang_Daemons_start) goto error_daemons; rvmCallVoidClassMethod(env, java_lang_Daemons, java_lang_Daemons_start); if (rvmExceptionCheck(env)) goto error_daemons; TRACE("Daemons started"); return env; error_daemons: error_system_ClassLoader: rvmDetachCurrentThread(env->vm, TRUE); return NULL; }
jboolean rvmRun(Env* env) { Options* options = env->vm->options; Class* clazz = NULL; jboolean errorDuringSetup = FALSE; //If our options has any properties, let's set them before we call our main. if (options->properties) { //First, find java.lang.System, which has the setProperty method. clazz = rvmFindClassUsingLoader(env, "java/lang/System", NULL); if (clazz) { //Get the setProperty method. Method* method = rvmGetClassMethod(env, clazz, "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); if (method) { SystemProperty* property = options->properties; //Go through all of our properties and add each one in turn by calling setProperty. while (property != NULL) { Object* key = NULL; Object* value = NULL; //The key is not allowed to be an empty string, so don't set it if we don't get a key. if(property->key && strlen(property->key) > 0) { key = rvmNewStringUTF(env, property->key, -1); } else { FATAL("Cannot have empty key in system property."); errorDuringSetup = TRUE; break; } if (property->value) { value = rvmNewStringUTF(env, property->value, -1); } else { value = rvmNewStringUTF(env, "", -1); } if (key && value) { rvmCallObjectClassMethod(env, clazz, method, key, value); } else { if (!key) { FATALF("Error creating string from system property key: %s", property->key); } if (!value) { FATALF("Error creating string from system property value: %s", property->value); } errorDuringSetup = TRUE; break; } property = property->next; //Advance to the next property. } } } } if (!errorDuringSetup) { clazz = rvmFindClassUsingLoader(env, options->mainClass, systemClassLoader); if (clazz) { Method* method = rvmGetClassMethod(env, clazz, "main", "([Ljava/lang/String;)V"); if (method) { ObjectArray* args = rvmNewObjectArray(env, options->commandLineArgsCount, java_lang_String, NULL, NULL); if (args) { jint i = 0; for (i = 0; i < args->length; i++) { // TODO: Don't assume modified UTF-8 args->values[i] = rvmNewStringUTF(env, options->commandLineArgs[i], -1); if (!args->values[i]) { args = NULL; break; } } if (args) rvmCallVoidClassMethod(env, clazz, method, args); } } } } Object* throwable = rvmExceptionOccurred(env); rvmDetachCurrentThread(env->vm, TRUE, FALSE); rvmJoinNonDaemonThreads(env); return throwable == NULL ? TRUE : FALSE; }
Env* rvmStartup(Options* options) { // TODO: Error handling #if defined(IOS) && (defined(RVM_ARMV7) || defined(RVM_THUMBV7)) // Enable IEEE-754 denormal support. // Without this the VFP treats numbers that are close to zero as zero itself. // See http://developer.apple.com/library/ios/#technotes/tn2293/_index.html. fenv_t fenv; fegetenv(&fenv); fenv.__fpscr &= ~__fpscr_flush_to_zero; fesetenv(&fenv); #endif TRACE("Initializing GC"); if (!initGC(options)) return NULL; // Ignore SIGPIPE signals. SIGPIPE interrupts write() calls which we don't // want. Dalvik does this too in dalvikvm/Main.cpp. if (!ignoreSignal(SIGPIPE)) return NULL; // Ignore SIGXFSZ signals. SIGXFSZ is raised when writing beyond the RLIMIT_FSIZE // of the current process (at least on Darwin) using pwrite(). if (!ignoreSignal(SIGXFSZ)) return NULL; VM* vm = rvmCreateVM(options); if (!vm) return NULL; Env* env = rvmCreateEnv(vm); if (!env) return NULL; // TODO: What if we can't allocate Env? if (!initClasspathEntries(env, options->basePath, options->rawBootclasspath, &options->bootclasspath)) return NULL; if (!initClasspathEntries(env, options->basePath, options->rawClasspath, &options->classpath)) return NULL; // Call init on modules TRACE("Initializing logging"); if (!rvmInitLog(env)) return NULL; TRACE("Initializing classes"); if (!rvmInitClasses(env)) return NULL; TRACE("Initializing memory"); if (!rvmInitMemory(env)) return NULL; TRACE("Initializing methods"); if (!rvmInitMethods(env)) return NULL; TRACE("Initializing strings"); if (!rvmInitStrings(env)) return NULL; TRACE("Initializing monitors"); if (!rvmInitMonitors(env)) return NULL; TRACE("Initializing proxy"); if (!rvmInitProxy(env)) return NULL; TRACE("Initializing threads"); if (!rvmInitThreads(env)) return NULL; TRACE("Initializing attributes"); if (!rvmInitAttributes(env)) return NULL; TRACE("Initializing primitive wrapper classes"); if (!rvmInitPrimitiveWrapperClasses(env)) return NULL; TRACE("Initializing exceptions"); if (!rvmInitExceptions(env)) return NULL; TRACE("Initializing signals"); if (!rvmInitSignals(env)) return NULL; // Initialize the RoboVM rt JNI code // RT_JNI_OnLoad(&vm->javaVM, NULL); // Initialize the dalvik rt JNI code TRACE("Initializing dalvik's runtime JNI code"); registerCoreLibrariesJni((JNIEnv*) env); TRACE("Creating system ClassLoader"); systemClassLoader = rvmGetSystemClassLoader(env); if (rvmExceptionOccurred(env)) goto error_system_ClassLoader; env->currentThread->threadObj->contextClassLoader = systemClassLoader; TRACE("Initialization done"); env->vm->initialized = TRUE; // Start Daemons TRACE("Starting Daemons"); java_lang_Daemons = rvmFindClassUsingLoader(env, "java/lang/Daemons", NULL); if (!java_lang_Daemons) goto error_daemons; java_lang_Daemons_start = rvmGetClassMethod(env, java_lang_Daemons, "start", "()V"); if (!java_lang_Daemons_start) goto error_daemons; rvmCallVoidClassMethod(env, java_lang_Daemons, java_lang_Daemons_start); if (rvmExceptionCheck(env)) goto error_daemons; TRACE("Daemons started"); return env; error_daemons: error_system_ClassLoader: rvmDetachCurrentThread(env->vm, TRUE, FALSE); return NULL; }