static jboolean parseElementValue(Env* env, void** attributes, Class* type, Object* classLoader, jvalue* result) { if (CLASS_IS_PRIMITIVE(type)) { switch (type->name[0]) { case 'Z': return parseBooleanElementValue(env, attributes, result); case 'B': return parseByteElementValue(env, attributes, result); case 'S': return parseShortElementValue(env, attributes, result); case 'C': return parseCharElementValue(env, attributes, result); case 'I': return parseIntElementValue(env, attributes, result); case 'J': return parseLongElementValue(env, attributes, result); case 'F': return parseFloatElementValue(env, attributes, result); case 'D': return parseDoubleElementValue(env, attributes, result); } } else if (CLASS_IS_ARRAY(type)) { return parseArrayElementValue(env, attributes, type, classLoader, result); } else if (type == java_lang_Class) { return parseClassElementValue(env, attributes, classLoader, result); } else if (type == java_lang_String) { return parseStringElementValue(env, attributes, result); } else if (CLASS_IS_ENUM(type) && type->superclass == java_lang_Enum) { return parseEnumElementValue(env, attributes, classLoader, result); } else if (CLASS_IS_ANNOTATION(type) && CLASS_IS_INTERFACE(type)) { return parseAnnotationElementValue(env, attributes, type, classLoader, result); } return FALSE; }
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; }
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; }
/** * Allocate an object and execute the constructor. * * @param cname the name of the class to be instantiated (may be 0 if cc is != 0) * @param loader the class loader that's to be used to lookup the class * @param cc the class to be instantiated (may be 0 if cname is != 0) * @param signature the signature of the constructor to be executed * @param argptr arguments to be passed to the constructor * * @throws InstantiationException if class is an interface or abstract * @throws NoSuchMethodError if the specified constructor cannot be found * * @return the newly allocated object */ Hjava_lang_Object* execute_java_constructor_v(const char* cname, Hjava_lang_ClassLoader* loader, Hjava_lang_Class* cc, const char* signature, va_list argptr) { Hjava_lang_Object* obj; Method* mb; jvalue retval; errorInfo info; Utf8Const* sig; if (cc == 0) { char *buf; /* Convert "." to "/" and lookup class */ buf = checkPtr(KMALLOC(strlen(cname) + 1)); classname2pathname(cname, buf); cc = lookupClass(buf, loader, &info); KFREE(buf); if (!cc) { throwError(&info); } } /* We cannot construct interfaces or abstract classes */ if (CLASS_IS_INTERFACE(cc) || CLASS_IS_ABSTRACT(cc)) { throwException(InstantiationException(cc->name->data)); } if (cc->state < CSTATE_USABLE) { if (processClass(cc, CSTATE_COMPLETE, &info) == false) { throwError(&info); } } sig = checkPtr(utf8ConstFromString(signature)); mb = findMethodLocal(cc, constructor_name, sig); utf8ConstRelease(sig); if (mb == 0) { throwException(NoSuchMethodError(constructor_name->data)); } obj = newObject(cc); assert(obj != 0); /* Make the call */ KaffeVM_callMethodV(mb, METHOD_NATIVECODE(mb), obj, argptr, &retval); return (obj); }
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; }
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; }
Class* rvmAllocateClass(Env* env, const char* className, Class* superclass, ClassLoader* classLoader, jint flags, jint classDataSize, jint instanceDataSize, jint instanceDataOffset, unsigned short classRefCount, unsigned short instanceRefCount, void* attributes, void* initializer) { if (superclass && CLASS_IS_INTERFACE(superclass)) { // TODO: Message should look like ? rvmThrowIncompatibleClassChangeError(env, ""); return NULL; } Class* clazz = rvmAllocateMemoryForClass(env, classDataSize); if (!clazz) return NULL; /* * NOTE: All classes we load before we have cached java.lang.Class will have NULL here so it is * important that we cache java.lang.Class as soon as possible. However, we have to cache * java.lang.Object first since it is the superclass of java.lang.Class. This means that * the java_lang_Object global variable will actually have NULL as clazz until we fix this in * rvmInitClasses(). */ clazz->object.clazz = java_lang_Class; clazz->name = className; clazz->superclass = superclass; clazz->classLoader = classLoader; clazz->flags = flags; clazz->classDataSize = classDataSize; clazz->instanceDataSize = instanceDataSize; clazz->instanceDataOffset = instanceDataOffset; clazz->classRefCount = classRefCount; clazz->instanceRefCount = instanceRefCount; clazz->_interfaces = &INTERFACES_NOT_LOADED; clazz->_fields = &FIELDS_NOT_LOADED; clazz->_methods = &METHODS_NOT_LOADED; clazz->attributes = attributes; clazz->initializer = initializer; // Inherit the CLASS_FLAG_FINALIZABLE flag from the superclass if (superclass && !CLASS_IS_FINALIZABLE(clazz) && CLASS_IS_FINALIZABLE(superclass)) { clazz->flags |= CLASS_FLAG_FINALIZABLE; } return clazz; }
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; }
jboolean Java_java_lang_Class_isInterface(Env* env, Class* thiz) { return CLASS_IS_INTERFACE(thiz) ? TRUE : FALSE; }