This adds support for delegating class loading to other class loaders. While resolving a class, we must use the class loader of the class from which resolving originates.
Signed-off-by: Tomek Grabiec <tgrab...@gmail.com> --- include/vm/classloader.h | 4 ++- jit/object-bc.c | 5 +--- vm/class.c | 15 +++++++---- vm/classloader.c | 59 +++++++++++++++++++++++++++++++++++++++------ vm/jato.c | 56 +++++++++++-------------------------------- vm/jni-interface.c | 3 +- vm/object.c | 16 ++++++------ vm/preload.c | 2 +- vm/reflection.c | 17 +++++++----- 9 files changed, 99 insertions(+), 78 deletions(-) diff --git a/include/vm/classloader.h b/include/vm/classloader.h index 505b3db..fe2556f 100644 --- a/include/vm/classloader.h +++ b/include/vm/classloader.h @@ -6,13 +6,15 @@ extern bool opt_trace_classloader; struct vm_class; +struct vm_object; int classloader_add_to_classpath(const char *classpath); int try_to_add_zip_to_classpath(const char *zip); char *get_classpath(void); void classloader_init(void); -struct vm_class *classloader_load(const char *class_name); +struct vm_class *classloader_load(struct vm_object *loader, + const char *class_name); struct vm_class *classloader_load_primitive(const char *class_name); struct vm_class *classloader_find_class(const char *name); diff --git a/jit/object-bc.c b/jit/object-bc.c index 25b4847..154213c 100644 --- a/jit/object-bc.c +++ b/jit/object-bc.c @@ -46,11 +46,8 @@ static struct vm_class *class_to_array_class(struct vm_class *class) struct vm_class *array_class; char *array_class_name; - /* XXX: This is not entirely right. We need to make sure that we're - * using the same class loader as the original class. We don't support - * multiple (different) class loaders yet. */ array_class_name = class_name_to_array_name(class->name); - array_class = classloader_load(array_class_name); + array_class = classloader_load(class->classloader, array_class_name); free(array_class_name); return array_class; diff --git a/vm/class.c b/vm/class.c index e4e099d..e00d7a4 100644 --- a/vm/class.c +++ b/vm/class.c @@ -123,6 +123,7 @@ static int vm_class_link_common(struct vm_class *vmc) return -err; vmc->object = NULL; + vmc->classloader = NULL; return 0; } @@ -237,7 +238,7 @@ int vm_class_link(struct vm_class *vmc, const struct cafebabe_class *class) super_name->length); /* XXX: Circularity check */ - vmc->super = classloader_load(super_name_str); + vmc->super = classloader_load(NULL, super_name_str); if (!vmc->super) { NOT_IMPLEMENTED; return -1; @@ -284,7 +285,7 @@ int vm_class_link(struct vm_class *vmc, const struct cafebabe_class *class) return -1; } - struct vm_class *vmi = classloader_load(c_name); + struct vm_class *vmi = classloader_load(NULL, c_name); free(c_name); if (!vmi) return -1; @@ -635,7 +636,8 @@ struct vm_class *vm_class_resolve_class(const struct vm_class *vmc, uint16_t i) return NULL; } - struct vm_class *class = classloader_load(class_name_str); + struct vm_class *class + = classloader_load(vmc->classloader, class_name_str); if (!class) { NOT_IMPLEMENTED; return NULL; @@ -1063,11 +1065,12 @@ struct vm_class *vm_class_get_array_class(struct vm_class *element_class) struct vm_class *result; char *name; - if (!asprintf(&name, "[%s", element_class->name)) + if (!asprintf(&name, "[%s", element_class->name)) { + signal_new_exception(vm_java_lang_OutOfMemoryError, NULL); return NULL; + } - result = classloader_load(name); - + result = classloader_load(element_class->classloader, name); free(name); return result; } diff --git a/vm/classloader.c b/vm/classloader.c index 73bfcd7..fecb48f 100644 --- a/vm/classloader.c +++ b/vm/classloader.c @@ -8,8 +8,10 @@ #include "cafebabe/class.h" #include "cafebabe/stream.h" +#include "vm/call.h" #include "vm/classloader.h" #include "vm/preload.h" +#include "vm/reflection.h" #include "vm/class.h" #include "vm/die.h" #include "vm/backtrace.h" @@ -18,6 +20,8 @@ #include "lib/string.h" #include "lib/hash-map.h" +#include "jit/exception.h" + bool opt_trace_classloader; static __thread int trace_classloader_level = 0; @@ -406,7 +410,8 @@ struct vm_class *classloader_load_primitive(const char *class_name) return class; } -static struct vm_class *load_array_class(const char *class_name) +static struct vm_class * +load_array_class(struct vm_object *loader, const char *class_name) { struct vm_class *array_class; char *elem_class_name; @@ -436,7 +441,7 @@ static struct vm_class *load_array_class(const char *class_name) classloader_load_primitive(elem_class_name); } else { array_class->array_element_class = - classloader_load(elem_class_name); + classloader_load(loader, elem_class_name); } free(elem_class_name); @@ -444,13 +449,44 @@ static struct vm_class *load_array_class(const char *class_name) return array_class; } -static struct vm_class *load_class(const char *class_name) +static struct vm_class * +load_class_with(struct vm_object *loader, const char *name) +{ + struct vm_object *name_string; + struct vm_object *clazz; + struct vm_class *vmc; + + name_string = vm_object_alloc_string_from_c(name); + if (!name_string) { + signal_new_exception(vm_java_lang_OutOfMemoryError, NULL); + return NULL; + } + + clazz = vm_call_method_this_object(vm_java_lang_ClassLoader_loadClass, + loader, name_string); + if (!clazz || exception_occurred()) + return NULL; + + vmc = vm_object_to_vm_class(clazz); + if (!vmc) + return NULL; + + vmc->classloader = loader; + + return vmc; +} + +static struct vm_class *load_class(struct vm_object *loader, + const char *class_name) { struct vm_class *result; char *filename; if (class_name[0] == '[') - return load_array_class(class_name); + return load_array_class(loader, class_name); + + if (loader) + return load_class_with(loader, class_name); filename = class_name_to_file_name(class_name); if (!filename) { @@ -501,8 +537,15 @@ static struct classloader_class *find_class(const char *name) return class; } -/* XXX: Should use hash table or tree, not linear search. -Vegard */ -struct vm_class *classloader_load(const char *class_name) +/** + * Loads a class of given name. if @loader is not NULL then + * loading of a class will be delegated to @loader. + * + * If @class_name refers to an array class then @loader + * will be called only for array element class. + */ +struct vm_class * +classloader_load(struct vm_object *loader, const char *class_name) { struct vm_class *vmc; struct classloader_class *class; @@ -542,7 +585,7 @@ struct vm_class *classloader_load(const char *class_name) * load_class() because for example vm_class_init() might call * classloader_load() for superclasses. */ - vmc = load_class(slash_class_name); + vmc = load_class(loader, slash_class_name); if (!vmc) { pthread_mutex_lock(&classloader_mutex); @@ -565,7 +608,7 @@ struct vm_class *classloader_load(const char *class_name) pthread_mutex_lock(&classloader_mutex); - vmc->classloader = NULL; + vmc->classloader = loader; class->class = vmc; class->status = CLASS_LOADED; diff --git a/vm/jato.c b/vm/jato.c index 4d959cd..9c5e0c9 100644 --- a/vm/jato.c +++ b/vm/jato.c @@ -144,8 +144,6 @@ static struct vm_object *native_vmstackwalker_getclasscontext(void) if (vm_class_ensure_init(vmc)) return NULL; - printf("%d: %s.%s\n", idx, vmc->name, cu->method->name); - array_set_field_object(res, idx++, vmc->object); } @@ -541,53 +539,27 @@ native_vmclass_forname(struct vm_object *name, jboolean initialize, if (!name) { signal_new_exception(vm_java_lang_NullPointerException, NULL); - goto throw; + return NULL; } - if (loader != NULL) { - struct vm_object *obj; - - obj = vm_call_method_object(vm_java_lang_ClassLoader_loadClass, - loader, name); - if (exception_occurred()) - return NULL; - - if (!obj) - goto throw; - - class = vm_class_get_class_from_class_object(obj); - } else { - class_name = vm_string_to_cstr(name); - if (!class_name) { - NOT_IMPLEMENTED; - return NULL; - } - - class = classloader_load(class_name); - free(class_name); + class_name = vm_string_to_cstr(name); + if (!class_name) { + signal_new_exception(vm_java_lang_OutOfMemoryError, NULL); + return NULL; } + class = classloader_load(loader, class_name); if (!class) - goto throw; + goto throw_cnf; if (initialize) { - vm_class_ensure_init(class); - if (exception_occurred()) - goto throw; + if (vm_class_ensure_init(class)) + goto throw_cnf; } return class->object; - - throw: - class_name = vm_string_to_cstr(name); - - if (!class_name) { - NOT_IMPLEMENTED; - return NULL; - } - - signal_new_exception(vm_java_lang_ClassNotFoundException, - class_name); + throw_cnf: + signal_new_exception(vm_java_lang_ClassNotFoundException, class_name); free(class_name); return NULL; } @@ -823,7 +795,7 @@ native_vmclassloader_loadclass(struct vm_object *name, jboolean resolve) if (!c_name) return NULL; - vmc = classloader_load(c_name); + vmc = classloader_load(NULL, c_name); free(c_name); if (!vmc) return NULL; @@ -1218,7 +1190,7 @@ static void parse_options(int argc, char *argv[]) static int do_main_class(void) { - struct vm_class *vmc = classloader_load(classname); + struct vm_class *vmc = classloader_load(NULL, classname); if (!vmc) { fprintf(stderr, "error: %s: could not load\n", classname); return -1; @@ -1274,7 +1246,7 @@ do_jar_file(void) static int do_method_trace(void) { - struct vm_class *vmc = classloader_load(method_trace_class_name); + struct vm_class *vmc = classloader_load(NULL, method_trace_class_name); if (!vmc) { NOT_IMPLEMENTED; return -1; diff --git a/vm/jni-interface.c b/vm/jni-interface.c index 2e35439..d961c52 100644 --- a/vm/jni-interface.c +++ b/vm/jni-interface.c @@ -141,7 +141,8 @@ vm_jni_find_class(struct vm_jni_env *env, const char *name) enter_vm_from_jni(); - class = classloader_load(name); + /* XXX: which classloader should we use here? */ + class = classloader_load(NULL, name); if (!class) { signal_new_exception(vm_java_lang_NoClassDefFoundError, name); diff --git a/vm/object.c b/vm/object.c index c8ed0fe..1baa966 100644 --- a/vm/object.c +++ b/vm/object.c @@ -78,28 +78,28 @@ struct vm_object *vm_object_alloc_primitive_array(int type, int count) switch (type) { case T_BOOLEAN: - res->class = classloader_load("[Z"); + res->class = classloader_load(NULL, "[Z"); break; case T_CHAR: - res->class = classloader_load("[C"); + res->class = classloader_load(NULL, "[C"); break; case T_FLOAT: - res->class = classloader_load("[F"); + res->class = classloader_load(NULL, "[F"); break; case T_DOUBLE: - res->class = classloader_load("[D"); + res->class = classloader_load(NULL, "[D"); break; case T_BYTE: - res->class = classloader_load("[B"); + res->class = classloader_load(NULL, "[B"); break; case T_SHORT: - res->class = classloader_load("[S"); + res->class = classloader_load(NULL, "[S"); break; case T_INT: - res->class = classloader_load("[I"); + res->class = classloader_load(NULL, "[I"); break; case T_LONG: - res->class = classloader_load("[J"); + res->class = classloader_load(NULL, "[J"); break; default: NOT_IMPLEMENTED; diff --git a/vm/preload.c b/vm/preload.c index 8f83aa1..84bea01 100644 --- a/vm/preload.c +++ b/vm/preload.c @@ -437,7 +437,7 @@ int preload_vm_classes(void) for (unsigned int i = 0; i < ARRAY_SIZE(preload_entries); ++i) { const struct preload_entry *pe = &preload_entries[i]; - struct vm_class *class = classloader_load(pe->name); + struct vm_class *class = classloader_load(NULL, pe->name); if (!class) { printf("%s\n", pe->name); NOT_IMPLEMENTED; diff --git a/vm/reflection.c b/vm/reflection.c index dd53135..178fb92 100644 --- a/vm/reflection.c +++ b/vm/reflection.c @@ -299,7 +299,9 @@ native_vmclass_get_declared_constructors(struct vm_object *clazz, return array; } -static struct vm_class *vm_type_to_class(char *type_name, enum vm_type type) +static struct vm_class * +vm_type_to_class(struct vm_object *classloader, char *type_name, + enum vm_type type) { switch (type) { case J_BOOLEAN: @@ -321,7 +323,7 @@ static struct vm_class *vm_type_to_class(char *type_name, enum vm_type type) case J_VOID: return vm_void_class; case J_REFERENCE: - return classloader_load(type_name); + return classloader_load(classloader, type_name); case J_RETURN_ADDRESS: case VM_TYPE_MAX: error("invalid type"); @@ -352,7 +354,8 @@ static struct vm_object *get_method_parameter_types(struct vm_method *vmm) while ((type_str = parse_method_args(type_str, &type, &type_name))) { struct vm_class *class; - class = vm_type_to_class(type_name, type); + class = vm_type_to_class(vmm->class->classloader, type_name, + type); free(type_name); if (class) @@ -801,6 +804,8 @@ native_method_invokenative(struct vm_object *method, struct vm_object *o, struct vm_object *native_field_gettype(struct vm_object *this) { struct vm_field *vmf; + enum vm_type vmtype; + char *type_name; if (!this) { signal_new_exception(vm_java_lang_NullPointerException, NULL); @@ -811,15 +816,13 @@ struct vm_object *native_field_gettype(struct vm_object *this) if (!vmf) return 0; - enum vm_type vmtype; - char *type_name; - if (!parse_type(vmf->type, &vmtype, &type_name)) { warn("type parsing failed"); return NULL; } - struct vm_class *vmc = vm_type_to_class(type_name, vmtype); + struct vm_class *vmc = + vm_type_to_class(vmf->class->classloader, type_name, vmtype); if (vm_class_ensure_init(vmc)) return NULL; -- 1.6.0.6 ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel