/** * Implements all abstract methods in {@code proxyClass}. This should be called after * {@link #addProxyMethods()} which will override all methods defined by the proxy's * ancestor classes (abstract or concrete). */ static jboolean implementAbstractInterfaceMethods(Env* env, Class* proxyClass, Interface* interface, ProxyClassData* proxyClassData) { if (!interface) return TRUE; Method* method = rvmGetMethods(env, interface->interface); if (rvmExceptionOccurred(env)) return FALSE; for (; method != NULL; method = method->next) { if (!METHOD_IS_CLASS_INITIALIZER(method)) { ProxyMethod* proxyMethod = hasMethod(env, proxyClass, method->name, method->desc); if (rvmExceptionOccurred(env)) return FALSE; if (!proxyMethod) { jint access = (method->access & (~ACC_ABSTRACT)) | ACC_FINAL; proxyMethod = addProxyMethod(env, proxyClass, method, access, _proxy0); if (!proxyMethod) return FALSE; } // Record the lookup function in proxyClassData LookupEntry* entry = rvmAllocateMemory(env, sizeof(LookupEntry)); if (!entry) return FALSE; entry->key.name = method->name; entry->key.desc = method->desc; entry->method = proxyMethod; HASH_ADD(hh, proxyClassData->lookupsHash, key, sizeof(LookupKey), entry); } } if (!implementAbstractInterfaceMethods(env, proxyClass, interface->next, proxyClassData)) return FALSE; Interface* interfaceInterfaces = rvmGetInterfaces(env, interface->interface); if (rvmExceptionCheck(env)) return FALSE; if (!implementAbstractInterfaceMethods(env, proxyClass, interfaceInterfaces, proxyClassData)) return FALSE; return TRUE; }
CallStack* captureCallStackFromFrame(Env* env, Frame* fp) { jint count = countCallStackFrames(env, fp); if (rvmExceptionOccurred(env)) return NULL; CallStack* data = allocateCallStackFrames(env, count); if (!data) return NULL; captureCallStack(env, fp, data, count); if (rvmExceptionOccurred(env)) return NULL; return data; }
jboolean rvmLoadNativeLibrary(Env* env, const char* path, ClassLoader* classLoader) { DynamicLib** nativeLibs = NULL; if (!classLoader || classLoader->parent == NULL) { // This is the bootstrap classloader nativeLibs = &bootNativeLibs; } else if (classLoader->parent->parent == NULL && classLoader->object.clazz->classLoader == NULL) { // This is the system classloader nativeLibs = &mainNativeLibs; } else { // Unknown classloader rvmThrowUnsatisfiedLinkError(env, "Unknown classloader"); return FALSE; } char* errorMsg = NULL; DynamicLib* lib = rvmOpenDynamicLib(env, path, &errorMsg); if (!lib) { if (!rvmExceptionOccurred(env)) { rvmThrowUnsatisfiedLinkError(env, errorMsg); } return FALSE; } obtainNativeLibsLock(); if (rvmHasDynamicLib(env, lib, *nativeLibs)) { // The lib is already in nativeLibs rvmCloseDynamicLib(env, lib); releaseNativeLibsLock(); return TRUE; } jint (*JNI_OnLoad)(JavaVM*, void*) = rvmFindDynamicLibSymbol(env, lib, "JNI_OnLoad", FALSE); if (JNI_OnLoad) { // TODO: Check that JNI_OnLoad returns a supported JNI version? JNI_OnLoad(&env->vm->javaVM, NULL); if (rvmExceptionOccurred(env)) { releaseNativeLibsLock(); return FALSE; } } rvmAddDynamicLib(env, lib, nativeLibs); releaseNativeLibsLock(); return TRUE; }
Object* rvmNewObjectV(Env* env, Class* clazz, Method* method, va_list args) { Object* obj = rvmAllocateObject(env, clazz); if (!obj) return NULL; rvmCallNonvirtualVoidInstanceMethodV(env, obj, method, args); if (rvmExceptionOccurred(env)) return NULL; return obj; }
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); } }
CallStack* rvmCaptureCallStackForThread(Env* env, Thread* thread) { if (thread == env->currentThread) { return rvmCaptureCallStack(env); } // dumpThreadStackTrace() must not be called concurrently obtainThreadStackTraceLock(); if (!shared_callStack) { shared_callStack = rvmAllocateMemoryAtomicUncollectable(env, sizeof(CallStack) + sizeof(CallStackFrame) * MAX_CALL_STACK_LENGTH); if (!shared_callStack) { releaseThreadStackTraceLock(); return NULL; } } memset(shared_callStack, 0, sizeof(CallStack) + sizeof(CallStackFrame) * MAX_CALL_STACK_LENGTH); dumpThreadStackTrace(env, thread, shared_callStack); if (rvmExceptionOccurred(env)) { releaseThreadStackTraceLock(); return NULL; } // Make a copy of the CallStack that is just big enough CallStack* copy = allocateCallStackFrames(env, shared_callStack->length); if (!copy) { releaseThreadStackTraceLock(); return NULL; } memcpy(copy, shared_callStack, sizeof(CallStack) + sizeof(CallStackFrame) * shared_callStack->length); releaseThreadStackTraceLock(); return copy; }
jdouble rvmCallDoubleClassMethodA(Env* env, Class* clazz, Method* method, jvalue* args) { CallInfo* callInfo = INIT_CALL_INFO(env, NULL, method, FALSE, args); if (!callInfo) return 0.0; rvmInitialize(env, method->clazz); if (rvmExceptionOccurred(env)) return 0.0; return callDoubleMethod(env, callInfo); }
jboolean exceptionMatch(Env* env, TrycatchContext* _tc) { BcTrycatchContext* tc = (BcTrycatchContext*) _tc; LandingPad* lps = tc->landingPads[tc->tc.sel - 1]; Object* throwable = rvmExceptionOccurred(env); jint i; for (i = 0; lps[i].landingPadId > 0; i++) { ClassInfoHeader* header = lps[i].exHeader; if (!header) { // NULL means java.lang.Throwable which always matches tc->tc.sel = lps[i].landingPadId; return TRUE; } if (!header->clazz) { // Exception class not yet loaded so it cannot match. continue; } Class* clazz = header->clazz; Class* c = throwable->clazz; while (c && c != clazz) { c = c->superclass; } if (c == clazz) { tc->tc.sel = lps[i].landingPadId; return TRUE; } } return FALSE; }
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 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 jboolean addProxyMethods(Env* env, Class* proxyClass, Class* clazz, ProxyClassData* proxyClassData) { // Add constructors from the super class and override all overridable methods. Constructors will use // the same impl as the superclass. Overridden methods will have _rvmProxy0 as its impl. if (clazz->superclass) { if (!addProxyMethods(env, proxyClass, clazz->superclass, proxyClassData)) return FALSE; } Method* method = rvmGetMethods(env, clazz); if (rvmExceptionOccurred(env)) return FALSE; for (; method != NULL; method = method->next) { if (!METHOD_IS_STATIC(method) && !METHOD_IS_PRIVATE(method) && !METHOD_IS_FINAL(method) && (!METHOD_IS_CONSTRUCTOR(method) || clazz == proxyClass->superclass)) { void* impl = NULL; jint access = (method->access & (~ACC_ABSTRACT & ~ACC_NATIVE)) | ACC_FINAL; if (METHOD_IS_CONSTRUCTOR(method)) { impl = method->impl; // TODO: For now we make all constructors public to satisfy java.lang.reflect.Proxy. access = ACC_PUBLIC; if (!addProxyMethod(env, proxyClass, method, access, impl)) return FALSE; } else { impl = _proxy0; if (METHOD_IS_PUBLIC(method)) { ProxyMethod* proxyMethod = hasMethod(env, proxyClass, method->name, method->desc); if (rvmExceptionOccurred(env)) return FALSE; if (!proxyMethod) { proxyMethod = addProxyMethod(env, proxyClass, method, access, impl); if (!proxyMethod) return FALSE; } // Record the lookup function in proxyClassData LookupEntry* entry = rvmAllocateMemory(env, sizeof(LookupEntry)); if (!entry) return FALSE; entry->key.name = method->name; entry->key.desc = method->desc; entry->method = proxyMethod; HASH_ADD(hh, proxyClassData->lookupsHash, key, sizeof(LookupKey), entry); } } } } return TRUE; }
Class* Java_java_lang_Class_getEnclosingClass(Env* env, Class* thiz) { Class* enclosingClass = rvmAttributeGetEnclosingClass(env, thiz); if (rvmExceptionCheck(env) && rvmExceptionOccurred(env)->clazz != java_lang_ClassNotFoundException) { return NULL; } if (!enclosingClass) { rvmExceptionClear(env); return rvmAttributeGetDeclaringClass(env, thiz); } return enclosingClass; }
static Class* findType(Env* env, const char* classDesc, Object* loader) { Class* c = rvmFindClassByDescriptor(env, classDesc, loader); if (!c) { if (rvmExceptionOccurred(env)->clazz == java_lang_ClassNotFoundException) { rvmExceptionClear(env); char* className = rvmCopyMemoryAtomicZ(env, classDesc); className[strlen(className)] = 0; rvmThrowNew(env, java_lang_TypeNotPresentException, rvmFromBinaryClassName(env, &className[1])); } } return c; }
static Class* findBootClass(Env* env, const char* className) { Class* clazz = findClass(env, className, NULL, env->vm->options->loadBootClass); if (rvmExceptionOccurred(env)) return NULL; if (clazz != NULL) { if (clazz->classLoader != NULL) { // Not a boot class rvmThrowClassNotFoundException(env, className); return NULL; } } return clazz; }
Object* rvmAllocateObject(Env* env, Class* clazz) { if (CLASS_IS_ABSTRACT(clazz) || CLASS_IS_INTERFACE(clazz)) { // TODO: Message rvmThrowNew(env, java_lang_InstantiationException, ""); return NULL; } rvmInitialize(env, clazz); if (rvmExceptionOccurred(env)) return NULL; Object* obj = rvmAllocateMemoryForObject(env, clazz); if (!obj) return NULL; obj->clazz = clazz; return obj; }
Object* Java_java_lang_reflect_Constructor_internalNewInstance(Env* env, JClass* clazz, jlong methodPtr, ObjectArray* parameterTypes, ObjectArray* args) { Method* method = (Method*) LONG_TO_PTR(methodPtr); /* * The Java code has already checked that the constructor is accessible * to the the caller, that the class can be instatiated and that the number * of arguments are correct. The args array is never null. */ jvalue* jvalueArgs = validateAndUnwrapArgs(env, parameterTypes, args); if (!jvalueArgs) return NULL; Object* o = rvmNewObjectA(env, method->clazz, method, jvalueArgs); if (!o) { Object* exception = rvmExceptionOccurred(env); if (exception->clazz != java_lang_ExceptionInInitializerError) { throwInvocationTargetException(env, rvmExceptionOccurred(env)); } return NULL; } return o; }
jboolean rvmDestroyVM(VM* vm) { Env* env; if (JNI_OK != rvmAttachCurrentThread(vm, &env, NULL, NULL) ) { WARN("rvmDestroy() failed to attach current thread."); return FALSE; } Object* throwable = rvmExceptionOccurred(env); rvmDetachCurrentThread(env->vm, TRUE, FALSE); rvmJoinNonDaemonThreads(env); return throwable == NULL ? TRUE : FALSE; }
Class* rvmFindClassInClasspathForLoader(Env* env, const char* className, ClassLoader* classLoader) { if (!classLoader || classLoader->parent == NULL) { // This is the bootstrap classloader return findBootClass(env, className); } if (classLoader->parent->parent == NULL && classLoader->object.clazz->classLoader == NULL) { // This is the system classloader Class* clazz = findClass(env, className, classLoader, env->vm->options->loadUserClass); if (rvmExceptionOccurred(env)) return NULL; return clazz; } rvmThrowClassNotFoundException(env, className); return NULL; }
Class* rvmFindClassUsingLoader(Env* env, const char* className, ClassLoader* classLoader) { if (!classLoader || classLoader->parent == NULL) { // This is the bootstrap classloader. No need to call ClassLoader.loadClass() return findBootClass(env, className); } char* binaryClassName = rvmToBinaryClassName(env, className); if (!binaryClassName) return NULL; Object* binaryClassNameString = rvmNewInternedStringUTF(env, binaryClassName, -1); if (!binaryClassNameString) return NULL; Method* loadClassMethod = rvmGetInstanceMethod(env, java_lang_ClassLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); if (!loadClassMethod) return NULL; Object* clazz = rvmCallObjectInstanceMethod(env, (Object*) classLoader, loadClassMethod, binaryClassNameString); if (rvmExceptionOccurred(env)) return NULL; return (Class*) clazz; }
jboolean rvmInitMemory(Env* env) { vm = env->vm; java_lang_ref_Reference = rvmFindClassUsingLoader(env, "java/lang/ref/Reference", NULL); if (!java_lang_ref_Reference) return FALSE; java_lang_ref_Reference_referent = rvmGetInstanceField(env, java_lang_ref_Reference, "referent", "Ljava/lang/Object;"); if (!java_lang_ref_Reference_referent) return FALSE; java_lang_ref_Reference_pendingNext = rvmGetInstanceField(env, java_lang_ref_Reference, "pendingNext", "Ljava/lang/ref/Reference;"); if (!java_lang_ref_Reference_pendingNext) return FALSE; java_lang_ref_Reference_queue = rvmGetInstanceField(env, java_lang_ref_Reference, "queue", "Ljava/lang/ref/ReferenceQueue;"); if (!java_lang_ref_Reference_queue) return FALSE; java_lang_ref_Reference_queueNext = rvmGetInstanceField(env, java_lang_ref_Reference, "queueNext", "Ljava/lang/ref/Reference;"); if (!java_lang_ref_Reference_queueNext) return FALSE; java_lang_ref_PhantomReference = rvmFindClassUsingLoader(env, "java/lang/ref/PhantomReference", NULL); if (!java_lang_ref_PhantomReference) return FALSE; java_lang_ref_WeakReference = rvmFindClassUsingLoader(env, "java/lang/ref/WeakReference", NULL); if (!java_lang_ref_WeakReference) return FALSE; java_lang_ref_SoftReference = rvmFindClassUsingLoader(env, "java/lang/ref/SoftReference", NULL); if (!java_lang_ref_SoftReference) return FALSE; java_lang_ref_FinalizerReference = rvmFindClassUsingLoader(env, "java/lang/ref/FinalizerReference", NULL); if (!java_lang_ref_FinalizerReference) return FALSE; java_lang_ref_FinalizerReference_add = rvmGetClassMethod(env, java_lang_ref_FinalizerReference, "add", "(Ljava/lang/Object;)V"); if (!java_lang_ref_FinalizerReference_add) return FALSE; java_lang_ref_FinalizerReference_zombie = rvmGetInstanceField(env, java_lang_ref_FinalizerReference, "zombie", "Ljava/lang/Object;"); if (!java_lang_ref_FinalizerReference_zombie) return FALSE; java_lang_ref_ReferenceQueue = rvmFindClassUsingLoader(env, "java/lang/ref/ReferenceQueue", NULL); if (!java_lang_ref_ReferenceQueue) return FALSE; java_lang_ref_ReferenceQueue_add = rvmGetClassMethod(env, java_lang_ref_ReferenceQueue, "add", "(Ljava/lang/ref/Reference;)V"); if (!java_lang_ref_ReferenceQueue_add) return FALSE; java_nio_ReadWriteDirectByteBuffer = rvmFindClassUsingLoader(env, "java/nio/ReadWriteDirectByteBuffer", NULL); if (!java_nio_ReadWriteDirectByteBuffer) return FALSE; java_nio_ReadWriteDirectByteBuffer_init = rvmGetInstanceMethod(env, java_nio_ReadWriteDirectByteBuffer, "<init>", "(II)V"); if (!java_nio_ReadWriteDirectByteBuffer_init) return FALSE; Class* java_nio_Buffer = rvmFindClassUsingLoader(env, "java/nio/Buffer", NULL); if (!java_nio_Buffer) return FALSE; java_nio_Buffer_effectiveDirectAddress = rvmGetInstanceField(env, java_nio_Buffer, "effectiveDirectAddress", "I"); if (!java_nio_Buffer_effectiveDirectAddress) return FALSE; java_nio_Buffer_capacity = rvmGetInstanceField(env, java_nio_Buffer, "capacity", "I"); if (!java_nio_Buffer_capacity) return FALSE; // Make sure that java.lang.ReferenceQueue is initialized now to prevent deadlocks during finalization // when both holding the referentsLock and the classLock. rvmInitialize(env, java_lang_ref_ReferenceQueue); if (rvmExceptionOccurred(env)) return FALSE; return TRUE; }
jvalue* validateAndUnwrapArgs(Env* env, ObjectArray* parameterTypes, ObjectArray* args) { jint length = args->length; jvalue* jvalueArgs = length > 0 ? (jvalue*) rvmAllocateMemory(env, sizeof(jvalue) * length) : emptyJValueArgs; if (!jvalueArgs) return NULL; jint i; for (i = 0; i < length; i++) { Object* arg = args->values[i]; Class* type = (Class*) parameterTypes->values[i]; if (CLASS_IS_PRIMITIVE(type)) { if (arg == NULL) { const char* typeName = rvmGetHumanReadableClassName(env, type); if (typeName) { rvmThrowNewf(env, java_lang_IllegalArgumentException, "argument %d should have type %s, got null", i + 1, typeName); } return NULL; } if (!rvmUnbox(env, arg, type, &jvalueArgs[i])) { if (rvmExceptionOccurred(env)->clazz == java_lang_ClassCastException) { rvmExceptionClear(env); const char* argTypeName = rvmGetHumanReadableClassName(env, arg->clazz); const char* typeName = argTypeName ? rvmGetHumanReadableClassName(env, type) : NULL; if (argTypeName && typeName) { rvmThrowNewf(env, java_lang_IllegalArgumentException, "argument %d should have type %s, got %s", i + 1, typeName, argTypeName); } } return NULL; } } else { if (arg && !rvmIsInstanceOf(env, arg, type)) { const char* argTypeName = rvmGetHumanReadableClassName(env, arg->clazz); const char* typeName = argTypeName ? rvmGetHumanReadableClassName(env, type) : NULL; if (argTypeName && typeName) { rvmThrowNewf(env, java_lang_IllegalArgumentException, "argument %d should have type %s, got %s", i + 1, typeName, argTypeName); } return NULL; } jvalueArgs[i].l = (jobject) arg; } } return jvalueArgs; }
static ObjectArray* listClasses(Env* env, Class* instanceofClazz, ClassLoader* classLoader, void* hash) { if (instanceofClazz && (CLASS_IS_ARRAY(instanceofClazz) || CLASS_IS_PRIMITIVE(instanceofClazz))) { return NULL; } ClassInfoHeader** base = getClassInfosBase(hash); uint32_t count = getClassInfosCount(hash); uint32_t i = 0; jint matches = count; TypeInfo* instanceofTypeInfo = instanceofClazz ? instanceofClazz->typeInfo : NULL; if (instanceofTypeInfo) { matches = 0; for (i = 0; i < count; i++) { ClassInfoHeader* header = base[i]; if ((header->flags & CI_ERROR) == 0) { if ((!CLASS_IS_INTERFACE(instanceofClazz) && rvmIsClassTypeInfoAssignable(env, header->typeInfo, instanceofTypeInfo)) || (CLASS_IS_INTERFACE(instanceofClazz) && rvmIsInterfaceTypeInfoAssignable(env, header->typeInfo, instanceofTypeInfo))) { matches++; } } } } if (matches == 0) return NULL; ObjectArray* result = rvmNewObjectArray(env, matches, java_lang_Class, NULL, NULL); if (!result) return NULL; jint j = 0; for (i = 0; i < count; i++) { ClassInfoHeader* header = base[i]; if ((header->flags & CI_ERROR) == 0) { if (!instanceofTypeInfo || ((!CLASS_IS_INTERFACE(instanceofClazz) && rvmIsClassTypeInfoAssignable(env, header->typeInfo, instanceofTypeInfo)) || (CLASS_IS_INTERFACE(instanceofClazz) && rvmIsInterfaceTypeInfoAssignable(env, header->typeInfo, instanceofTypeInfo)))) { result->values[j++] = (Object*) (header->clazz ? header->clazz : createClass(env, header, classLoader)); if (rvmExceptionOccurred(env)) return NULL; } } } return result; }
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; }
static void* startThreadEntryPoint(void* _args) { ThreadEntryPointArgs* args = (ThreadEntryPointArgs*) _args; Env* env = args->env; Thread* thread = args->thread; JavaThread* threadObj = args->threadObj; rvmLockThreadsList(); jboolean failure = TRUE; setThreadEnv(env); if (!rvmExceptionOccurred(env)) { if (initThread(env, thread, threadObj)) { if (rvmSetupSignals(env)) { failure = FALSE; thread->stackAddr = getStackAddress(); } } } thread->status = THREAD_STARTING; pthread_cond_broadcast(&threadStartCond); while (thread->status != THREAD_VMWAIT) { pthread_cond_wait(&threadStartCond, &threadsLock); } rvmUnlockThreadsList(); if (!failure) { rvmChangeThreadStatus(env, thread, THREAD_RUNNING); rvmChangeThreadPriority(env, thread, thread->threadObj->priority); Method* run = rvmGetInstanceMethod2(env, java_lang_Thread, "run", "()V"); if (run) { jvalue emptyArgs[0]; rvmCallVoidInstanceMethodA(env, (Object*) threadObj, run, emptyArgs); } } detachThread(env, TRUE); return NULL; }
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; }
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; }
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; }
void _bcThrowIfExceptionOccurred(Env* env) { Object* throwable = rvmExceptionOccurred(env); if (throwable) rvmRaiseException(env, throwable); }
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; }
static jboolean getAnnotationValue(Env* env, void** attributes, Class* expectedAnnotationClass, Object* classLoader, jvalue* result, jboolean ignoreClassNotFound) { char* annotationTypeName = getString(attributes); if (expectedAnnotationClass && strncmp(&annotationTypeName[1], expectedAnnotationClass->name, strlen(expectedAnnotationClass->name))) { return throwFormatError(env, rvmFromBinaryClassName(env, expectedAnnotationClass->name)); } Class* annotationClass = expectedAnnotationClass; if (!annotationClass) { annotationClass = rvmFindClassByDescriptor(env, annotationTypeName, classLoader); if (!annotationClass) { if (ignoreClassNotFound && rvmExceptionOccurred(env)->clazz == java_lang_ClassNotFoundException) { rvmExceptionClear(env); jint length = getInt(attributes); for (jint i = 0; i < length; i++) { getString(attributes); skipElementValue(attributes); } } return FALSE; } } // Find the annotation impl class Class* annotationImplClass = findAnnotationImplClass(env, annotationClass, classLoader); if (rvmExceptionCheck(env)) return FALSE; jint length = getInt(attributes); if (length == 0) { // No member values specified. Use a singleton instance. Method* factoryMethod = rvmGetClassMethod(env, annotationImplClass, "$createSingleton", "()Ljava/lang/Object;"); if (rvmExceptionCheck(env)) return FALSE; Object* annotationObject = rvmCallObjectClassMethod(env, annotationImplClass, factoryMethod); if (rvmExceptionCheck(env)) return FALSE; result->l = (jobject) annotationObject; return TRUE; } // Call the annotation impl $create() method Method* factoryMethod = rvmGetClassMethod(env, annotationImplClass, "$create", "()Ljava/lang/Object;"); if (rvmExceptionCheck(env)) return FALSE; Object* annotationObject = rvmCallObjectClassMethod(env, annotationImplClass, factoryMethod); if (rvmExceptionCheck(env)) return FALSE; jint i = 0; for (i = 0; i < length; i++) { char* name = getString(attributes); Method* method = getAnnotationValueMethod(env, annotationClass, name); if (rvmExceptionCheck(env)) return FALSE; if (!method) { skipElementValue(attributes); } else { const char* memberDesc = rvmGetReturnType(method->desc); Class* type = findType(env, memberDesc, method->clazz->classLoader); Object* value = NULL; if (!type) { value = rvmExceptionClear(env); } else { jvalue v = {0}; if (!parseElementValue(env, attributes, type, classLoader, &v)) { value = rvmExceptionClear(env); } else { value = rvmBox(env, type, &v); } } InstanceField* field = getAnnotationMemberField(env, annotationImplClass, method->name); if (!field) return FALSE; rvmSetObjectInstanceFieldValue(env, annotationObject, field, value); if (rvmExceptionCheck(env)) return FALSE; } } result->l = (jobject) annotationObject; return TRUE; }