This is closer to the JVM spec. In particular, classes are immediately loaded and linked by the class loader, but initialized only on demand, i.e. when we need to call a method.
Signed-off-by: Vegard Nossum <vegard.nos...@gmail.com> --- include/vm/class.h | 10 +++++++- include/vm/classloader.h | 1 - jit/trampoline.c | 5 ++++ vm/class.c | 49 +++++++++++++++++++++++++++------------------ vm/classloader.c | 23 --------------------- vm/jato.c | 22 ++++++++++---------- vm/object.c | 28 +++++++++++++++++++++++-- 7 files changed, 78 insertions(+), 60 deletions(-) diff --git a/include/vm/class.h b/include/vm/class.h index cb4060d..a03db0e 100644 --- a/include/vm/class.h +++ b/include/vm/class.h @@ -37,9 +37,15 @@ struct vm_class { }; int vm_class_link(struct vm_class *vmc, const struct cafebabe_class *class); +int vm_class_init(struct vm_class *vmc); -int vm_class_init_object(struct vm_class *vmc); -int vm_class_run_clinit(struct vm_class *vmc); +static inline int vm_class_ensure_init(struct vm_class *vmc) +{ + if (vmc->state == VM_CLASS_INITIALIZED) + return 0; + + return vm_class_init(vmc); +} static inline bool vm_class_is_interface(const struct vm_class *vmc) { diff --git a/include/vm/classloader.h b/include/vm/classloader.h index 0fe25d6..885e588 100644 --- a/include/vm/classloader.h +++ b/include/vm/classloader.h @@ -8,6 +8,5 @@ struct vm_class; int classloader_add_to_classpath(const char *classpath); struct vm_class *classloader_load(const char *class_name); -struct vm_class *classloader_load_and_init(const char *class_name); #endif diff --git a/jit/trampoline.c b/jit/trampoline.c index af3dae5..cc27ed3 100644 --- a/jit/trampoline.c +++ b/jit/trampoline.c @@ -99,6 +99,11 @@ void *jit_magic_trampoline(struct compilation_unit *cu) if (opt_trace_magic_trampoline) trace_magic_trampoline(cu); + if (vm_class_ensure_init(method->class)) { + NOT_IMPLEMENTED; + return NULL; + } + pthread_mutex_lock(&cu->mutex); if (vm_method_is_native(cu->method)) diff --git a/vm/class.c b/vm/class.c index b0dc205..8e9a71e 100644 --- a/vm/class.c +++ b/vm/class.c @@ -195,37 +195,46 @@ int vm_class_link(struct vm_class *vmc, const struct cafebabe_class *class) return 0; } -/* - * This function sets the .object member of struct vm_class to point to - * the object (of type java.lang.Class) for this class. - */ -int vm_class_init_object(struct vm_class *vmc) +int vm_class_init(struct vm_class *vmc) { + assert(vmc->state == VM_CLASS_LINKED); + + /* XXX: Not entirely true, but we need it to break the recursion. */ + vmc->state = VM_CLASS_INITIALIZED; + + /* JVM spec, 2nd. ed., 2.17.1: "But before Terminator can be + * initialized, its direct superclass must be initialized, as well + * as the direct superclass of its direct superclass, and so on, + * recursively." */ + if (vmc->super) { + int ret = vm_class_ensure_init(vmc->super); + if (ret) + return ret; + } + + /* + * Set the .object member of struct vm_class to point to + * the object (of type java.lang.Class) for this class. + */ vmc->object = vm_object_alloc(vm_java_lang_Class); if (!vmc->object) { NOT_IMPLEMENTED; return -1; } - return 0; -} + if (vmc->class) { + /* XXX: Make sure there's at most one of these. */ + for (uint16_t i = 0; i < vmc->class->methods_count; ++i) { + if (strcmp(vmc->methods[i].name, "<clinit>")) + continue; -int vm_class_run_clinit(struct vm_class *vmc) -{ - assert(vmc->state == VM_CLASS_LINKED); + void (*clinit_trampoline)(void) + = vm_method_trampoline_ptr(&vmc->methods[i]); - /* XXX: Make sure there's at most one of these. */ - for (uint16_t i = 0; i < vmc->class->methods_count; ++i) { - if (strcmp(vmc->methods[i].name, "<clinit>")) - continue; - - void (*clinit_trampoline)(void) - = vm_method_trampoline_ptr(&vmc->methods[i]); - - clinit_trampoline(); + clinit_trampoline(); + } } - vmc->state = VM_CLASS_INITIALIZED; return 0; } diff --git a/vm/classloader.c b/vm/classloader.c index 05ffc16..917d7c2 100644 --- a/vm/classloader.c +++ b/vm/classloader.c @@ -465,26 +465,3 @@ out: trace_pop(); return vmc; } - -struct vm_class *classloader_load_and_init(const char *class_name) -{ - struct vm_class *vmc; - - vmc = classloader_load(class_name); - if (!vmc) - return NULL; - - if (vmc->state != VM_CLASS_INITIALIZED) { - if (vm_class_init_object(vmc)) { - NOT_IMPLEMENTED; - return NULL; - } - - if (vm_class_run_clinit(vmc)) { - NOT_IMPLEMENTED; - return NULL; - } - } - - return vmc; -} diff --git a/vm/jato.c b/vm/jato.c index 163968b..3a42b62 100644 --- a/vm/jato.c +++ b/vm/jato.c @@ -182,15 +182,6 @@ static int preload_vm_classes(void) *pe->class = class; } - for (unsigned int i = 0; i < ARRAY_SIZE(preload_entries); ++i) { - const struct preload_entry *pe = &preload_entries[i]; - - if (vm_class_init_object(*pe->class)) { - NOT_IMPLEMENTED; - return 1; - } - } - for (unsigned int i = 0; i < ARRAY_SIZE(field_preload_entries); ++i) { const struct field_preload_entry *pe = &field_preload_entries[i]; @@ -205,6 +196,15 @@ static int preload_vm_classes(void) *pe->field = field; } + for (unsigned int i = 0; i < ARRAY_SIZE(preload_entries); ++i) { + const struct preload_entry *pe = &preload_entries[i]; + + if (vm_class_ensure_init(*pe->class)) { + NOT_IMPLEMENTED; + return 1; + } + } + return 0; } @@ -308,7 +308,7 @@ main(int argc, char *argv[]) init_stack_trace_printing(); - struct vm_class *vmc = classloader_load_and_init(classname); + struct vm_class *vmc = classloader_load(classname); if (!vmc) { fprintf(stderr, "error: %s: could not load\n", classname); goto out; @@ -322,7 +322,7 @@ main(int argc, char *argv[]) } if (!vm_method_is_static(vmm)) { - fprintf(stderr, "errror: %s: main method not static\n", + fprintf(stderr, "error: %s: main method not static\n", classname); goto out; } diff --git a/vm/object.c b/vm/object.c index 9f0b58a..2776ab2 100644 --- a/vm/object.c +++ b/vm/object.c @@ -19,11 +19,19 @@ struct vm_object *vm_object_alloc(struct vm_class *class) { struct vm_object *res; + if (vm_class_ensure_init(class)) { + NOT_IMPLEMENTED; + return NULL; + } + res = zalloc(sizeof(*res) + class->object_size); - if (res) { - res->class = class; + if (!res) { + NOT_IMPLEMENTED; + return NULL; } + res->class = class; + if (pthread_mutex_init(&res->mutex, NULL)) NOT_IMPLEMENTED; @@ -75,6 +83,11 @@ struct vm_object *vm_object_alloc_native_array(int type, int count) return NULL; } + if (vm_class_ensure_init(res->class)) { + NOT_IMPLEMENTED; + return NULL; + } + res->array_length = count; if (pthread_mutex_init(&res->mutex, NULL)) @@ -88,6 +101,11 @@ struct vm_object *vm_object_alloc_multi_array(struct vm_class *class, { assert(nr_dimensions > 0); + if (vm_class_ensure_init(class)) { + NOT_IMPLEMENTED; + return NULL; + } + struct vm_object *res; res = zalloc(sizeof(*res) + sizeof(struct vm_object *) * counts[0]); @@ -122,6 +140,11 @@ struct vm_object *vm_object_alloc_array(struct vm_class *class, int count) { struct vm_object *res; + if (vm_class_ensure_init(class)) { + NOT_IMPLEMENTED; + return NULL; + } + res = zalloc(sizeof(*res) + sizeof(struct vm_object *) * count); if (!res) { NOT_IMPLEMENTED; @@ -186,7 +209,6 @@ struct vm_object *new_exception(const char *class_name, const char *message) struct vm_object *obj; struct vm_class *e_class; - /* XXX: load_and_init? We'd better preload exception classes. */ e_class = classloader_load(class_name); if (!e_class) return NULL; -- 1.6.0.4 ------------------------------------------------------------------------------ _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel