We use the term "miranda method" here as a method which is omitted by
the compiler (because the method is declared in an interface and the
implementing class is abstract), and which needs to be inserted by the
VM.

Reported-by: Tomek Grabiec <tgrab...@gmail.com>
Signed-off-by: Vegard Nossum <vegard.nos...@gmail.com>
---
 include/vm/class.h  |    1 +
 include/vm/method.h |    3 ++
 vm/class.c          |   88 ++++++++++++++++++++++++++++++++++++++++++++++----
 vm/method.c         |   31 ++++++++++++++++++
 4 files changed, 116 insertions(+), 7 deletions(-)

diff --git a/include/vm/class.h b/include/vm/class.h
index 46b34b2..4451680 100644
--- a/include/vm/class.h
+++ b/include/vm/class.h
@@ -52,6 +52,7 @@ struct vm_class {
        unsigned int nr_interfaces;
        struct vm_class **interfaces;
        struct vm_field *fields;
+       unsigned int nr_methods;
        struct vm_method *methods;
 
        unsigned int object_size;
diff --git a/include/vm/method.h b/include/vm/method.h
index 90a4fef..54c2b94 100644
--- a/include/vm/method.h
+++ b/include/vm/method.h
@@ -53,6 +53,9 @@ struct vm_method {
 int vm_method_init(struct vm_method *vmm,
        struct vm_class *vmc, unsigned int method_index);
 
+int vm_method_init_from_interface(struct vm_method *vmm, struct vm_class *vmc,
+       unsigned int method_index, struct vm_method *interface_method);
+
 static inline bool vm_method_is_public(struct vm_method *vmm)
 {
        return vmm->method->access_flags & CAFEBABE_METHOD_ACC_PUBLIC;
diff --git a/vm/class.c b/vm/class.c
index 4c77dd3..87868e4 100644
--- a/vm/class.c
+++ b/vm/class.c
@@ -74,7 +74,7 @@ setup_vtable(struct vm_class *vmc)
        }
 
        vtable_size = 0;
-       for (uint16_t i = 0; i < vmc->class->methods_count; ++i) {
+       for (uint16_t i = 0; i < vmc->nr_methods; ++i) {
                struct vm_method *vmm = &vmc->methods[i];
 
                if (super) {
@@ -101,7 +101,7 @@ setup_vtable(struct vm_class *vmc)
                        super_vtable->native_ptr[i]);
 
        /* Our methods */
-       for (uint16_t i = 0; i < vmc->class->methods_count; ++i) {
+       for (uint16_t i = 0; i < vmc->nr_methods; ++i) {
                struct vm_method *vmm = &vmc->methods[i];
 
                vtable_setup_method(&vmc->vtable,
@@ -371,7 +371,56 @@ int vm_class_link(struct vm_class *vmc, const struct 
cafebabe_class *class)
                }
        }
 
-       vmc->methods = malloc(sizeof(*vmc->methods) * class->methods_count);
+       unsigned int nr_miranda_methods = 0;
+       struct vm_method **miranda_methods = NULL;
+
+       /* If in any of the superinterfaces we find a method which is not
+        * defined in this class file, we need to add a "miranda" method.
+        * Note that we don't need to do this recursively for all super-
+        * interfaces because they will have already done this very same
+        * procedure themselves. */
+       for (unsigned int i = 0; i < class->interfaces_count; ++i) {
+               struct vm_class *vmi = vmc->interfaces[i];
+
+               for (unsigned int j = 0; j < vmi->nr_methods; ++j) {
+                       struct vm_method *vmm = &vmi->methods[j];
+
+                       assert(vmm->name);
+                       assert(vmm->type);
+
+                       /* We need this "manual" recursive lookup because we
+                        * haven't initialized this class' list of methods
+                        * yet... */
+                       unsigned int index = 0;
+                       if (!cafebabe_class_get_method(vmc->class,
+                               vmm->name, vmm->type, &index))
+                       {
+                               continue;
+                       }
+
+                       if (!vmc->super)
+                               continue;
+
+                       if (vm_class_get_method_recursive(vmc->super,
+                               vmm->name, vmm->type))
+                       {
+                               continue;
+                       }
+
+                       /* XXX: Use generic resizable array? */
+                       miranda_methods = realloc(miranda_methods,
+                               sizeof(*miranda_methods)
+                               * (nr_miranda_methods + 1));
+
+                       miranda_methods[nr_miranda_methods] = vmm;
+
+                       ++nr_miranda_methods;
+               }
+       }
+
+       vmc->nr_methods = class->methods_count + nr_miranda_methods;
+
+       vmc->methods = malloc(sizeof(*vmc->methods) * vmc->nr_methods);
        if (!vmc->methods) {
                NOT_IMPLEMENTED;
                return -1;
@@ -387,7 +436,28 @@ int vm_class_link(struct vm_class *vmc, const struct 
cafebabe_class *class)
 
                vmm->itable_index = itable_hash(vmm);
 
-               if (vm_method_prepare_jit(&vmc->methods[i])) {
+               /* XXX: Only if the method actually has code. */
+               if (vm_method_prepare_jit(vmm)) {
+                       NOT_IMPLEMENTED;
+                       return -1;
+               }
+       }
+
+       for (uint16_t i = 0; i < nr_miranda_methods; ++i) {
+               struct vm_method *vmm = &vmc->methods[class->methods_count + i];
+
+               if (vm_method_init_from_interface(vmm, vmc,
+                       class->methods_count + i, miranda_methods[i]))
+               {
+                       NOT_IMPLEMENTED;
+                       return -1;
+               }
+
+               /* Share with above? */
+               vmm->itable_index = itable_hash(vmm);
+
+               /* XXX: We _know_ that this method doesn't have any code. */
+               if (vm_method_prepare_jit(vmm)) {
                        NOT_IMPLEMENTED;
                        return -1;
                }
@@ -829,9 +899,13 @@ struct vm_method *vm_class_get_method(const struct 
vm_class *vmc,
        if (vmc->kind != VM_CLASS_KIND_REGULAR)
                return NULL;
 
-       unsigned int index = 0;
-       if (!cafebabe_class_get_method(vmc->class, name, type, &index))
-               return &vmc->methods[index];
+       /* Could do binary search here if we wanted. */
+       for (unsigned int i = 0; i < vmc->nr_methods; ++i) {
+               struct vm_method *vmm = &vmc->methods[i];
+
+               if (!strcmp(vmm->name, name) && !strcmp(vmm->type, type))
+                       return vmm;
+       }
 
        return NULL;
 }
diff --git a/vm/method.c b/vm/method.c
index 095c1de..4be9c31 100644
--- a/vm/method.c
+++ b/vm/method.c
@@ -141,6 +141,37 @@ int vm_method_init(struct vm_method *vmm,
        return 0;
 }
 
+int vm_method_init_from_interface(struct vm_method *vmm, struct vm_class *vmc,
+       unsigned int method_index, struct vm_method *interface_method)
+{
+       /* NOTE: If we ever keep reference counts on loaded classes, we should
+        * perhaps _copy_ the interformation from the interface method instead
+        * of just grabbing a reference to the same information. */
+
+       vmm->class = vmc;
+       vmm->method_index = method_index;
+       vmm->method = interface_method->method;
+
+       vmm->name = interface_method->name;
+       vmm->type = interface_method->type;
+
+       vmm->args_count = interface_method->args_count;
+       vmm->is_vm_native = false;
+
+       /* XXX: Do we need to duplicate args_map? */
+
+       /* All interface methods are abstract. */
+       {
+               vmm->code_attribute.max_stack = 0;
+               vmm->code_attribute.max_locals = vmm->args_count;
+
+               vmm->line_number_table_attribute.line_number_table_length = 0;
+               vmm->line_number_table_attribute.line_number_table = NULL;
+       }
+
+       return 0;
+}
+
 int vm_method_prepare_jit(struct vm_method *vmm)
 {
        struct compilation_unit *cu;
-- 
1.6.0.4


------------------------------------------------------------------------------
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

Reply via email to