This fixes a bug where a method may require other classes to load,
thereby compiling and executing _their_ <clinit> methods, which may
(compile and) call the same method we were trying to execute in the
first place.

Signed-off-by: Vegard Nossum <vegard.nos...@gmail.com>
---
 include/vm/classloader.h |    3 +-
 jit/trampoline.c         |    8 ++++++
 vm/class.c               |    2 +-
 vm/classloader.c         |   58 ++++++++++++++++++++++++++++++++++------------
 vm/jato.c                |    4 ++-
 5 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/include/vm/classloader.h b/include/vm/classloader.h
index 0fe25d6..e05feb9 100644
--- a/include/vm/classloader.h
+++ b/include/vm/classloader.h
@@ -8,6 +8,7 @@ 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);
+
+int synchronize_clinit(void);
 
 #endif
diff --git a/jit/trampoline.c b/jit/trampoline.c
index af3dae5..b912db2 100644
--- a/jit/trampoline.c
+++ b/jit/trampoline.c
@@ -120,6 +120,14 @@ void *jit_magic_trampoline(struct compilation_unit *cu)
 
        pthread_mutex_unlock(&cu->mutex);
 
+       /* XXX:
+        * 
+        * 09:58 < penberg> but you need to be careful
+        * 09:58 < penberg> not to allow any threads to run the jit'd code
+        *                  before classes are initialized
+        */
+       synchronize_clinit();
+
        return ret;
 }
 
diff --git a/vm/class.c b/vm/class.c
index cd19840..fcdc324 100644
--- a/vm/class.c
+++ b/vm/class.c
@@ -256,7 +256,7 @@ struct vm_class *vm_class_resolve_class(struct vm_class 
*vmc, uint16_t i)
                return NULL;
        }
 
-       struct vm_class *class = classloader_load_and_init(class_name_str);
+       struct vm_class *class = classloader_load(class_name_str);
        if (!class) {
                NOT_IMPLEMENTED;
                return NULL;
diff --git a/vm/classloader.c b/vm/classloader.c
index 1ce3cf9..6aebcff 100644
--- a/vm/classloader.c
+++ b/vm/classloader.c
@@ -421,6 +421,14 @@ out_filename:
        return result;
 }
 
+struct clinit {
+       struct list_head node;
+
+       struct vm_class *vmc;
+};
+
+static struct list_head clinits = LIST_HEAD_INIT(clinits);
+
 /* XXX: Should use hash table or tree, not linear search. -Vegard */
 struct vm_class *classloader_load(const char *class_name)
 {
@@ -462,31 +470,51 @@ struct vm_class *classloader_load(const char *class_name)
        class->class = vmc;
 
 out:
+       if (vmc && vmc->state < VM_CLASS_INITIALIZING) {
+               struct clinit *c = malloc(sizeof *c);
+               if (!c) {
+                       NOT_IMPLEMENTED;
+                       return NULL;
+               }
+
+               c->vmc = vmc;
+
+               list_add(&c->node, &clinits);
+       }
+
        trace_pop();
        return vmc;
 }
 
-struct vm_class *classloader_load_and_init(const char *class_name)
+int synchronize_clinit(void)
 {
-       struct vm_class *vmc;
+       while (!list_is_empty(&clinits)) {
+               struct clinit *c
+                       = list_first_entry(&clinits, struct clinit, node);
+               struct vm_class *vmc = c->vmc;
 
-       vmc = classloader_load(class_name);
-       if (!vmc)
-               return NULL;
+               list_del(&c->node);
+               free(c);
 
-       if (vmc->state < VM_CLASS_INITIALIZING) {
-               vmc->state = VM_CLASS_INITIALIZING;
+               /* Don't try to initialize classes without a backing class-
+                * file. */
+               if (!vmc->class)
+                       continue;
 
-               if (vm_class_init_object(vmc)) {
-                       NOT_IMPLEMENTED;
-                       return NULL;
-               }
+               if (vmc->state < VM_CLASS_INITIALIZING) {
+                       vmc->state = VM_CLASS_INITIALIZING;
 
-               if (vm_class_run_clinit(vmc)) {
-                       NOT_IMPLEMENTED;
-                       return NULL;
+                       if (vm_class_init_object(vmc)) {
+                               NOT_IMPLEMENTED;
+                               return -1;
+                       }
+
+                       if (vm_class_run_clinit(vmc)) {
+                               NOT_IMPLEMENTED;
+                               return -1;
+                       }
                }
        }
 
-       return vmc;
+       return 0;
 }
diff --git a/vm/jato.c b/vm/jato.c
index 0819fec..559b65e 100644
--- a/vm/jato.c
+++ b/vm/jato.c
@@ -306,12 +306,14 @@ 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;
        }
 
+       synchronize_clinit();
+
        struct vm_method *vmm = vm_class_get_method_recursive(vmc,
                "main", "([Ljava/lang/String;)V");
        if (!vmm) {
-- 
1.6.0.4


------------------------------------------------------------------------------
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to