void rvmRegisterReference(Env* env, Object* reference, Object* referent) { if (referent) { // Add 'reference' to the references list for 'referent' in the referents hashtable rvmLockMutex(&referentsLock); ReferenceList* l = rvmAllocateMemory(env, sizeof(ReferenceList)); if (!l) goto done; // OOM thrown l->reference = reference; void* key = (void*) GC_HIDE_POINTER(referent); // Hide the pointer from the GC so that it doesn't prevent the referent from being GCed. ReferentEntry* referentEntry; HASH_FIND_PTR(referents, &key, referentEntry); if (!referentEntry) { // referent is not in the hashtable. Add it. referentEntry = rvmAllocateMemory(env, sizeof(ReferentEntry)); if (!referentEntry) goto done; // OOM thrown referentEntry->key = key; HASH_ADD_PTR(referents, key, referentEntry); } // Add the reference to the referent's list of references LL_PREPEND(referentEntry->references, l); // Register the referent for finalization GC_REGISTER_FINALIZER_NO_ORDER(referent, _finalizeObject, NULL, NULL, NULL); done: rvmUnlockMutex(&referentsLock); } }
/** * 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; }
void rvmPushShadowFrame(Env* env, void* functionAddress) { ShadowFrame* frame = rvmAllocateMemory(env, sizeof(ShadowFrame)); frame->functionAddress = functionAddress; frame->prev = env->shadowFrame; env->shadowFrame = frame; }
static jboolean addLoadedClass(Env* env, Class* clazz) { LoadedClassEntry* entry = rvmAllocateMemory(env, sizeof(LoadedClassEntry)); if (!entry) return FALSE; entry->key = clazz->name; entry->clazz = clazz; HASH_ADD_KEYPTR(hh, loadedClasses, entry->key, strlen(entry->key), entry); return TRUE; }
static jboolean initClasspathEntries(Env* env, char* basePath, char** raw, ClasspathEntry** first) { jint i = 0; while (raw[i]) { ClasspathEntry* entry = rvmAllocateMemory(env, sizeof(ClasspathEntry)); if (!entry) return FALSE; absolutize(basePath, raw[i], entry->jarPath); LL_APPEND(*first, entry); i++; } return TRUE; }
jboolean rvmAddInterface(Env* env, Class* clazz, Class* interf) { if (!CLASS_IS_INTERFACE(interf)) { // TODO: Message should look like ? rvmThrowIncompatibleClassChangeError(env, ""); return FALSE; } Interface* interface = rvmAllocateMemory(env, sizeof(Interface)); if (!interface) return FALSE; interface->interface = interf; if (clazz->_interfaces == &INTERFACES_NOT_LOADED) { clazz->_interfaces = NULL; } LL_APPEND(clazz->_interfaces, interface); return TRUE; }
void registerCleanupHandler(Env* env, Object* object, CleanupHandler handler) { rvmLockMutex(&referentsLock); CleanupHandlerList* l = rvmAllocateMemory(env, sizeof(CleanupHandlerList)); if (!l) goto done; // OOM thrown l->handler = handler; ReferentEntry* referentEntry = getReferentEntryForObject(env, object); if (!referentEntry) goto done; // Add the handler to the object's list of cleanup handlers LL_PREPEND(referentEntry->cleanupHandlers, l); // Register the referent for finalization GC_REGISTER_FINALIZER_NO_ORDER(object, _finalizeObject, NULL, NULL, NULL); done: rvmUnlockMutex(&referentsLock); }
static jvalue* va_list2jargs(Env* env, Method* method, va_list args) { jint argsCount = rvmGetParameterCount(method); if (argsCount == 0) { return emptyJValueArgs; } jvalue *jvalueArgs = (jvalue*) rvmAllocateMemory(env, sizeof(jvalue) * argsCount); if (!jvalueArgs) return NULL; const char* desc = method->desc; const char* c; jint i = 0; while ((c = rvmGetNextParameterType(&desc))) { switch (c[0]) { case 'B': jvalueArgs[i++].b = (jbyte) va_arg(args, jint); break; case 'Z': jvalueArgs[i++].z = (jboolean) va_arg(args, jint); break; case 'S': jvalueArgs[i++].s = (jshort) va_arg(args, jint); break; case 'C': jvalueArgs[i++].c = (jchar) va_arg(args, jint); break; case 'I': jvalueArgs[i++].i = va_arg(args, jint); break; case 'J': jvalueArgs[i++].j = va_arg(args, jlong); break; case 'F': jvalueArgs[i++].f = (jfloat) va_arg(args, jdouble); break; case 'D': jvalueArgs[i++].d = va_arg(args, jdouble); break; case '[': case 'L': jvalueArgs[i++].l = va_arg(args, jobject); break; } } return jvalueArgs; }
static AddressClassLookup* getAddressClassLookups(Env* env) { if (!addressClassLookups) { jint count = 0; iterateClassInfos(env, countClassesWithConcreteMethodsCallback, _bcBootClassesHash, &count); iterateClassInfos(env, countClassesWithConcreteMethodsCallback, _bcClassesHash, &count); AddressClassLookup* lookups = rvmAllocateMemory(env, sizeof(AddressClassLookup) * count); if (!lookups) return NULL; AddressClassLookup* _lookups = lookups; iterateClassInfos(env, initAddressClassLookupsCallback, _bcBootClassesHash, &_lookups); iterateClassInfos(env, initAddressClassLookupsCallback, _bcClassesHash, &_lookups); qsort(lookups, count, sizeof(AddressClassLookup), addressClassLookupCompareQSort); addressClassLookupsCount = count; addressClassLookups = lookups; } return addressClassLookups; }
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 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; }
void rvmRegisterReference(Env* env, Object* reference, Object* referent) { if (referent) { // Add 'reference' to the references list for 'referent' in the referents hashtable rvmLockMutex(&referentsLock); ReferenceList* l = rvmAllocateMemory(env, sizeof(ReferenceList)); if (!l) goto done; // OOM thrown l->reference = reference; ReferentEntry* referentEntry = getReferentEntryForObject(env, referent); if (!referentEntry) goto done; // Add the reference to the referent's list of references LL_PREPEND(referentEntry->references, l); // Register the referent for finalization GC_REGISTER_FINALIZER_NO_ORDER(referent, _finalizeObject, NULL, NULL, NULL); done: rvmUnlockMutex(&referentsLock); } }
ProxyMethod* addProxyMethod(Env* env, Class* clazz, Method* proxiedMethod, jint access, void* impl) { ProxyMethod* method = rvmAllocateMemory(env, sizeof(ProxyMethod)); if (!method) return NULL; method->method.clazz = clazz; method->method.name = proxiedMethod->name; method->method.desc = proxiedMethod->desc; method->method.access = access | METHOD_TYPE_PROXY; method->method.impl = impl; method->method.synchronizedImpl = NULL; method->proxiedMethod = proxiedMethod; if (clazz->_methods == &METHODS_NOT_LOADED) { clazz->_methods = NULL; } method->method.next = clazz->_methods; clazz->_methods = (Method*) method; return method; }
Method* rvmAddMethod(Env* env, Class* clazz, const char* name, const char* desc, jint access, jint size, void* impl, void* synchronizedImpl, void* attributes) { Method* method = rvmAllocateMemory(env, IS_NATIVE(access) ? sizeof(NativeMethod) : sizeof(Method)); if (!method) return NULL; method->clazz = clazz; method->name = name; method->desc = desc; method->access = access; method->size = size; method->impl = impl; method->synchronizedImpl = synchronizedImpl; method->attributes = attributes; if (clazz->_methods == &METHODS_NOT_LOADED) { clazz->_methods = NULL; } method->next = clazz->_methods; clazz->_methods = method; return method; }
DynamicLib* rvmOpenDynamicLib(Env* env, const char* file, char** errorMsg) { *errorMsg = NULL; DynamicLib* dlib = NULL; void* handle = dlopen(file, RTLD_LOCAL | RTLD_LAZY); if (!handle) { *errorMsg = dlerror(); TRACEF("Failed to load dynamic library '%s': %s", file, *errorMsg); return NULL; } TRACEF("Opening dynamic library '%s'", file); dlib = rvmAllocateMemory(env, sizeof(DynamicLib)); if (!dlib) { dlclose(handle); return NULL; } dlib->handle = handle; return dlib; }
Field* rvmAddField(Env* env, Class* clazz, const char* name, const char* desc, jint access, jint offset, void* attributes) { Field* field = rvmAllocateMemory(env, IS_STATIC(access) ? sizeof(ClassField) : sizeof(InstanceField)); if (!field) return NULL; field->clazz = clazz; field->name = name; field->desc = desc; field->access = access; field->attributes = attributes; if (clazz->_fields == &FIELDS_NOT_LOADED) { clazz->_fields = NULL; } field->next = clazz->_fields; clazz->_fields = field; if (access & ACC_STATIC) { ((ClassField*) field)->address = ((jbyte*) clazz) + offset; } else { ((InstanceField*) field)->offset = offset; } return field; }
BridgeMethod* rvmAddBridgeMethod(Env* env, Class* clazz, const char* name, const char* desc, jint access, jint size, void* impl, void* synchronizedImpl, void** targetFnPtr, void* attributes) { BridgeMethod* method = rvmAllocateMemory(env, sizeof(BridgeMethod)); if (!method) return NULL; method->method.clazz = clazz; method->method.name = name; method->method.desc = desc; method->method.access = access | METHOD_TYPE_BRIDGE; method->method.size = size; method->method.impl = impl; method->method.synchronizedImpl = synchronizedImpl; method->method.attributes = attributes; method->targetFnPtr = targetFnPtr; if (clazz->_methods == &METHODS_NOT_LOADED) { clazz->_methods = NULL; } method->method.next = clazz->_methods; clazz->_methods = (Method*) method; return method; }
CallbackMethod* rvmAddCallbackMethod(Env* env, Class* clazz, const char* name, const char* desc, jint access, jint size, void* impl, void* synchronizedImpl, void* callbackImpl, void* attributes) { CallbackMethod* method = rvmAllocateMemory(env, sizeof(CallbackMethod)); if (!method) return NULL; method->method.clazz = clazz; method->method.name = name; method->method.desc = desc; method->method.access = access | METHOD_TYPE_CALLBACK; method->method.size = size; method->method.impl = impl; method->method.synchronizedImpl = synchronizedImpl; method->method.attributes = attributes; method->callbackImpl = callbackImpl; if (clazz->_methods == &METHODS_NOT_LOADED) { clazz->_methods = NULL; } method->method.next = clazz->_methods; clazz->_methods = (Method*) method; return method; }
jlong Java_aura_rt_VM_allocateMemory(Env* env, Class* c, jint size) { return PTR_TO_LONG(rvmAllocateMemory(env, size)); }
void _rvmProxyHandler(CallInfo* callInfo) { Env* env = (Env*) proxy0NextPtr(callInfo); Object* receiver = (Object*) proxy0NextPtr(callInfo); Class* proxyClass = receiver->clazz; ProxyClassData* proxyClassData = (ProxyClassData*) proxyClass->data; LookupKey key; memset(&key, 0, sizeof(LookupKey)); key.name = (char*) env->reserved0; key.desc = (char*) env->reserved1; LookupEntry* entry; HASH_FIND(hh, proxyClassData->lookupsHash, &key, sizeof(LookupKey), entry); if (!entry) { rvmThrowNoSuchMethodError(env, "Failed to determine which method was called on proxy class"); goto error; } ProxyMethod* method = entry->method; rvmPushGatewayFrameProxy(env, method); jint argsCount = rvmGetParameterCount((Method*) method); jvalue *jvalueArgs = NULL; if (argsCount > 0) { jvalueArgs = (jvalue*) rvmAllocateMemory(env, sizeof(jvalue) * argsCount); if (!jvalueArgs) goto errorPop; const char* desc = method->method.desc; const char* c; jint i = 0; while ((c = rvmGetNextParameterType(&desc))) { switch (c[0]) { case 'B': jvalueArgs[i++].b = (jbyte) proxy0NextInt(callInfo); break; case 'Z': jvalueArgs[i++].z = (jboolean) proxy0NextInt(callInfo); break; case 'S': jvalueArgs[i++].s = (jshort) proxy0NextInt(callInfo); break; case 'C': jvalueArgs[i++].c = (jchar) proxy0NextInt(callInfo); break; case 'I': jvalueArgs[i++].i = proxy0NextInt(callInfo); break; case 'J': jvalueArgs[i++].j = proxy0NextLong(callInfo); break; case 'F': jvalueArgs[i++].f = proxy0NextFloat(callInfo); break; case 'D': jvalueArgs[i++].d = proxy0NextDouble(callInfo); break; case '[': case 'L': jvalueArgs[i++].l = (jobject) proxy0NextPtr(callInfo); break; } } } jvalue returnValue; proxyClassData->handler(env, receiver, method, jvalueArgs, &returnValue); rvmPopGatewayFrame(env); if (rvmExceptionCheck(env)) goto error; proxy0ReturnInt(callInfo, 0); switch (rvmGetReturnType(method->method.desc)[0]) { case 'B': proxy0ReturnInt(callInfo, (jint) returnValue.b); break; case 'Z': proxy0ReturnInt(callInfo, (jint) returnValue.z); break; case 'S': proxy0ReturnInt(callInfo, (jint) returnValue.s); break; case 'C': proxy0ReturnInt(callInfo, (jint) returnValue.c); break; case 'I': proxy0ReturnInt(callInfo, returnValue.i); break; case 'J': proxy0ReturnLong(callInfo, returnValue.j); break; case 'F': proxy0ReturnFloat(callInfo, returnValue.f); break; case 'D': proxy0ReturnDouble(callInfo, returnValue.d); break; case '[': case 'L': proxy0ReturnPtr(callInfo, returnValue.l); break; } return; errorPop: rvmPopGatewayFrame(env); error: rvmRaiseException(env, rvmExceptionOccurred(env)); }
void* rvmCopyMemory(Env* env, const void* src, jint size) { void* dest = rvmAllocateMemory(env, size); if (!dest) return NULL; memcpy(dest, src, size); return dest; }
static Thread* allocThread(Env* env) { Thread* thread = (Thread*) rvmAllocateMemory(env, sizeof(Thread)); if (!thread) return NULL; thread->status = THREAD_INITIALIZING; return thread; }