/** * 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; }
Class* rvmProxyCreateProxyClass(Env* env, Class* superclass, ClassLoader* classLoader, char* className, jint interfacesCount, Class** interfaces, jint instanceDataSize, jint instanceDataOffset, unsigned short instanceRefCount, ProxyHandler handler) { // Allocate the proxy class. Class* proxyClass = rvmAllocateClass(env, className, superclass, classLoader, CLASS_TYPE_PROXY | ACC_PUBLIC | ACC_FINAL, offsetof(Class, data) + sizeof(ProxyClassData), instanceDataSize, instanceDataOffset, 1, instanceRefCount, NULL, NULL); if (!proxyClass) return NULL; ProxyClassData* proxyClassData = (ProxyClassData*) proxyClass->data; proxyClassData->handler = handler; // Add interfaces jint i; for (i = 0; i < interfacesCount; i++) { if (!rvmAddInterface(env, proxyClass, (Class*) interfaces[i])) return NULL; } // Initialize methods to NULL to prevent rvmGetMethods() from trying to load the methods if called with this proxy class proxyClass->_methods = NULL; Class* c = proxyClass; while (c) { Interface* interface = rvmGetInterfaces(env, c); if (rvmExceptionCheck(env)) return NULL; if (!implementAbstractInterfaceMethods(env, proxyClass, interface, proxyClassData)) return NULL; c = c->superclass; } if (!addProxyMethods(env, proxyClass, superclass, proxyClassData)) return NULL; if (!rvmRegisterClass(env, proxyClass)) return NULL; return proxyClass; }
ObjectArray* Java_java_lang_Class_getInterfaces(Env* env, Class* thiz) { Interface* interfaces = rvmGetInterfaces(env, thiz); if (rvmExceptionCheck(env)) return NULL; Interface* interfaze; jint length = 0; LL_FOREACH(interfaces, interfaze) { length++; } ObjectArray* result = rvmNewObjectArray(env, length, java_lang_Class, NULL, NULL); if (!result) return NULL; jint i = 0; LL_FOREACH(interfaces, interfaze) { result->values[i++] = (Object*) interfaze->interfaze; } return result; }
jboolean rvmIsAssignableFrom(Env* env, Class* s, Class* t) { // TODO: What if s or t are NULL? if (s == t || t == java_lang_Object) { return TRUE; } if (CLASS_IS_ARRAY(s)) { if (t == java_io_Serializable) { return TRUE; } if (t == java_lang_Cloneable) { return TRUE; } if (!CLASS_IS_ARRAY(t)) { return FALSE; } Class* componentType = s->componentType; if (CLASS_IS_PRIMITIVE(componentType)) { // s is a primitive array and can only be assigned to // class t if s == t or t == (Object|Serializable|Cloneable). But we // already know that s != t and t != (Object|Serializable|Cloneable) return FALSE; } return rvmIsAssignableFrom(env, componentType, t->componentType); } if (CLASS_IS_INTERFACE(t)) { // s or any of its parents must implement the interface t for (; s; s = s->superclass) { Interface* interface = rvmGetInterfaces(env, s); if (rvmExceptionCheck(env)) return FALSE; for (; interface != NULL; interface = interface->next) { if (rvmIsAssignableFrom(env, interface->interface, t)) { return TRUE; } } } return FALSE; } while (s && s != t) { s = s->superclass; } return s ? TRUE : FALSE; }
static Method* getMethod(Env* env, Class* clazz, const char* name, const char* desc) { if (!strcmp("<init>", name) || !strcmp("<clinit>", name)) { // Constructors and static initializers are not inherited so we shouldn't check with the superclasses. return findMethod(env, clazz, name, desc); } Class* c = clazz; for (c = clazz; c != NULL; c = c->superclass) { Method* method = findMethod(env, c, name, desc); if (rvmExceptionCheck(env)) return NULL; if (method) return method; } /* * Check with interfaces. * TODO: Should we really do this? Does the JNI GetMethodID() function do this? */ for (c = clazz; c != NULL; c = c->superclass) { Interface* interfaze = rvmGetInterfaces(env, c); if (rvmExceptionCheck(env)) return NULL; for (; interfaze != NULL; interfaze = interfaze->next) { Method* method = getMethod(env, interfaze->interfaze, name, desc); if (rvmExceptionCheck(env)) return NULL; if (method) return method; } } if (CLASS_IS_INTERFACE(clazz)) { /* * Class is an interface so check with java.lang.Object. * TODO: Should we really do this? Does the JNI GetMethodID() function do this? */ return getMethod(env, java_lang_Object, name, desc); } return NULL; }