static jboolean parseStringElementValue(Env* env, void** attributes, jvalue* result) { jbyte tag = getByte(attributes); if (tag != 's') return throwFormatError(env, "java.lang.String"); char* s = getString(attributes); result->l = (jobject) rvmNewStringUTF(env, s, -1); return result->l ? 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 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); } }
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; }
static jboolean getSourceFileIterator(Env* env, jbyte type, void* attributes, void* data) { Object** result = (Object**) data; if (type == SOURCE_FILE) { *result = rvmNewStringUTF(env, getString(&attributes), -1); return FALSE; // Stop iterating } return TRUE; // Continue with next attribute }
ObjectArray* Java_java_lang_System_robovmSpecialProperties(Env* env, Class* c) { char* osArch = NULL; #if defined(RVM_X86) osArch = "os.arch=x86"; #elif defined(RVM_ARMV6) || defined(RVM_ARMV7) || defined(RVM_THUMBV6) || defined(RVM_THUMBV7) osArch = "os.arch=arm"; #endif #if defined(DARWIN) char* osName = NULL; # if defined(IOS) && defined(RVM_X86) osName = "os.name=iOS Simulator"; # elif defined(IOS) osName = "os.name=iOS"; # elif defined(MACOSX) osName = "os.name=Mac OS X"; # endif char osVersion[64]; memset(osVersion, 0, sizeof(osVersion)); strcat(osVersion, "os.version="); readDarwinOSVersionFromSystemVersionPList(osVersion); ObjectArray* result = rvmNewObjectArray(env, 3, java_lang_String, NULL, NULL); if (!result) return NULL; result->values[0] = rvmNewStringUTF(env, osName, -1); if (!result->values[0]) return NULL; result->values[1] = rvmNewStringUTF(env, osVersion, -1); if (!result->values[1]) return NULL; result->values[2] = rvmNewStringUTF(env, osArch, -1); if (!result->values[2]) return NULL; return result; #else ObjectArray* result = rvmNewObjectArray(env, 1, java_lang_String, NULL, NULL); if (!result) return NULL; result->values[0] = rvmNewStringUTF(env, osArch, -1); if (!result->values[0]) return NULL; return result; #endif }
Object* Java_java_lang_System_mapLibraryName0(Env* env, Class* c, Object* userLibName) { if (!userLibName) return NULL; char* libName = rvmGetStringUTFChars(env, userLibName); if (!libName) return NULL; char* result = rvmAllocateMemoryAtomic(env, strlen(libName) + strlen(DSO_PREFIX) + strlen(DSO_EXT) + 1); if (!result) return NULL; strcpy(result, DSO_PREFIX); strcat(result, libName); strcat(result, DSO_EXT); return rvmNewStringUTF(env, result, -1); }
ObjectArray* Java_java_lang_System_robovmSpecialProperties(Env* env, Class* c) { char* osArch = NULL; #if defined(RVM_X86) osArch = "os.arch=x86"; #elif defined(RVM_ARMV6) || defined(RVM_ARMV7) || defined(RVM_THUMBV6) || defined(RVM_THUMBV7) osArch = "os.arch=arm"; #endif #if defined(DARWIN) char* osName = NULL; # if defined(IOS) && defined(RVM_X86) osName = "os.name=iOS Simulator"; # elif defined(IOS) osName = "os.name=iOS"; # elif defined(MACOSX) osName = "os.name=Mac OS X"; # endif char osVersion[64]; memset(osVersion, 0, sizeof(osVersion)); strcat(osVersion, "os.version="); readDarwinOSVersionFromSystemVersionPList(osVersion); char userLanguage[64] = "user.language="; char userRegion[64] = "user.region="; char userVariant[64] = "user.variant="; getDarwinLocaleParts(userLanguage, userRegion, userVariant); jboolean hasLocale = strcmp(userLanguage, "user.language=") != 0; ObjectArray* result = rvmNewObjectArray(env, hasLocale ? 6 : 3, java_lang_String, NULL, NULL); if (!result) return NULL; result->values[0] = rvmNewStringUTF(env, osName, -1); if (!result->values[0]) return NULL; result->values[1] = rvmNewStringUTF(env, osVersion, -1); if (!result->values[1]) return NULL; result->values[2] = rvmNewStringUTF(env, osArch, -1); if (!result->values[2]) return NULL; if (hasLocale) { result->values[3] = rvmNewStringUTF(env, userLanguage, -1); if (!result->values[3]) return NULL; result->values[4] = rvmNewStringUTF(env, userRegion, -1); if (!result->values[4]) return NULL; result->values[5] = rvmNewStringUTF(env, userVariant, -1); if (!result->values[5]) return NULL; } return result; #else ObjectArray* result = rvmNewObjectArray(env, 1, java_lang_String, NULL, NULL); if (!result) return NULL; result->values[0] = rvmNewStringUTF(env, osArch, -1); if (!result->values[0]) return NULL; return result; #endif }
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; }
static jboolean getInnerClassIterator(Env* env, char* innerClass, char* outerClass, char* innerName, jint access, void* data) { GetInnerClassArgs* args = (GetInnerClassArgs*) data; Class* clazz = args->clazz; if (!innerClass || strcmp(innerClass, clazz->name)) { return TRUE; // Continue with next attribute } if (args->access) { *args->access = access; } if (innerName && args->innerClassName) { *args->innerClassName = rvmNewStringUTF(env, innerName, -1); } args->found = TRUE; return FALSE; // Stop iterating }
ObjectArray* rvmCallStackToStackTraceElements(Env* env, CallStack* callStack, jint first) { if (!callStack || callStack->length == 0) { return empty_java_lang_StackTraceElement_array; } // Count the number of methods jint index = first; jint length = 0; while (rvmGetNextCallStackMethod(env, callStack, &index)) { length++; } if (length == 0) { return empty_java_lang_StackTraceElement_array; } ObjectArray* array = rvmNewObjectArray(env, length, java_lang_StackTraceElement, NULL, NULL); if (!array) return NULL; if (length > 0) { jvalue args[4]; index = first; jint i; for (i = 0; i < length; i++) { Method* m = rvmGetNextCallStackMethod(env, callStack, &index); args[0].l = (jobject) m->clazz; args[1].l = (jobject) rvmNewStringUTF(env, m->name, -1); if (!args[1].l) return NULL; args[2].l = (jobject) rvmAttributeGetClassSourceFile(env, m->clazz); if (rvmExceptionOccurred(env)) { return NULL; } args[3].i = METHOD_IS_NATIVE(m) ? -2 : -1; // TODO: Line numbers array->values[i] = rvmNewObjectA(env, java_lang_StackTraceElement, java_lang_StackTraceElement_constructor, args); if (!array->values[i]) return NULL; } } return array; }
ObjectArray* Java_aura_rt_VM_staticLibs(Env* env, Class* c) { Options* options = env->vm->options; if (!options->staticLibs || options->staticLibs[0] == NULL) { return rvmNewObjectArray(env, 0, java_lang_String, NULL, NULL); } jint length = 0; while (options->staticLibs[length] != NULL) { length++; } ObjectArray* result = rvmNewObjectArray(env, length, java_lang_String, NULL, NULL); if (!result) return NULL; jint i; for (i = 0; i < length; i++) { Object* s = rvmNewStringUTF(env, options->staticLibs[i], -1); if (!s) return NULL; result->values[i] = s; } return result; }
ObjectArray* Java_java_net_NetworkInterface_getInterfaceNames(Env* env, JClass* cls) { if (!java_lang_String_array) { java_lang_String_array = rvmFindClassUsingLoader(env, "[Ljava/lang/String;", NULL); if (!java_lang_String_array) { return NULL; } } struct if_nameindex* ifs = if_nameindex(); if (!ifs) { // Assume out of memory rvmThrowOutOfMemoryError(env); return NULL; } jint count = 0; while (ifs[count].if_index > 0) { count++; } ObjectArray* result = rvmNewObjectArray(env, count, NULL, java_lang_String_array, NULL); if (!result) { goto done; } jint i = 0; for (i = 0; i < count; i++) { Object* name = rvmNewStringUTF(env, ifs[i].if_name, -1); if (!name) { goto done; } result->values[i] = name; } done: if_freenameindex(ifs); return result; }
static jint attachThread(VM* vm, Env** envPtr, char* name, Object* group, jboolean daemon) { Env* env = *envPtr; // env is NULL if rvmAttachCurrentThread() was called. If non NULL rvmInitThreads() was called. if (!env) { // If the thread was already attached there's an Env* associated with the thread. env = (Env*) pthread_getspecific(tlsEnvKey); if (env) { env->attachCount++; *envPtr = env; return JNI_OK; } } if (!env) { env = rvmCreateEnv(vm); if (!env) goto error; } setThreadEnv(env); if (rvmExceptionOccurred(env)) goto error; Thread* thread = allocThread(env); if (!thread) goto error; thread->stackAddr = getStackAddress(); thread->pThread = pthread_self(); env->currentThread = thread; rvmChangeThreadStatus(env, thread, THREAD_RUNNING); JavaThread* threadObj = (JavaThread*) rvmAllocateObject(env, java_lang_Thread); if (!threadObj) goto error; rvmLockThreadsList(); if (!initThread(env, thread, threadObj)) { rvmUnlockThreadsList(); goto error; } if (!rvmSetupSignals(env)) { rvmUnlockThreadsList(); goto error; } DL_PREPEND(threads, thread); pthread_cond_broadcast(&threadsChangedCond); rvmUnlockThreadsList(); Object* threadName = NULL; if (name) { threadName = rvmNewStringUTF(env, name, -1); if (!threadName) goto error_remove; } Method* threadConstructor = rvmGetInstanceMethod2(env, java_lang_Thread, "<init>", "(JLjava/lang/String;Ljava/lang/ThreadGroup;Z)V"); if (!threadConstructor) goto error_remove; rvmCallNonvirtualVoidInstanceMethod(env, (Object*) threadObj, threadConstructor, PTR_TO_LONG(thread), threadName, group, daemon); if (rvmExceptionOccurred(env)) goto error_remove; *envPtr = env; return JNI_OK; error_remove: rvmLockThreadsList(); DL_DELETE(threads, thread); pthread_cond_broadcast(&threadsChangedCond); rvmTearDownSignals(env); rvmUnlockThreadsList(); error: if (env) env->currentThread = NULL; clearThreadEnv(); return JNI_ERR; }
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; }
Object* Java_aura_rt_VM_imagePath(Env* env, Class* c) { return rvmNewStringUTF(env, env->vm->options->imagePath, -1); }
Object* Java_aura_rt_VM_classPath(Env* env, Class* c) { char* classpath = createClasspathFromClasspathEntries(env, env->vm->options->classpath); if (!classpath) return NULL; return rvmNewStringUTF(env, classpath, -1); }
Object* Java_aura_rt_VM_newStringUTF(Env* env, Class* c, jlong address) { return rvmNewStringUTF(env, (char*) LONG_TO_PTR(address), -1); }
Object* Java_java_lang_reflect_Method_getName(Env* env, Class* clazz, jlong methodPtr) { Method* method = (Method*) LONG_TO_PTR(methodPtr); return rvmNewStringUTF(env, method->name, -1); }
Object* Java_java_lang_Class_getName0(Env* env, Class* thiz) { return rvmNewStringUTF(env, thiz->name, -1); }
Object* Java_org_robovm_rt_VM_bootClassPath(Env* env, Class* c) { char* bootclasspath = createClasspathFromClasspathEntries(env, env->vm->options->bootclasspath); if (!bootclasspath) return NULL; return rvmNewStringUTF(env, bootclasspath, -1); }
Object* Java_org_robovm_rt_VM_basePath(Env* env, Class* c) { return rvmNewStringUTF(env, env->vm->options->basePath, -1); }
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; }
static jstring NewStringUTF(JNIEnv* env, const char* utf) { return (jstring) rvmNewStringUTF((Env*) env, (char*) utf, -1); }