struct vm_type_info is introduced to fully describe a java type of a
call argument, return type, field type, etc. Method's and field's type
strings are parsed on initialization and type information is put to
appropriate struct vm_type_infos. Type information for method
arguments is encapsulated in struct vm_method_arg and linked in a list
pointed by struct vm_method.args.

This change removes plenty of calls to type string parsing which
should not be done at run-time but rather on method or field
initialization.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 include/jit/expression.h     |   13 ---
 include/vm/field.h           |    4 +-
 include/vm/method.h          |    7 ++
 include/vm/types.h           |   32 +++++++-
 jit/invoke-bc.c              |    3 +-
 jit/trace-jit.c              |   14 ++--
 test/jit/invoke-bc-test.c    |   11 ++-
 test/jit/object-bc-test.c    |    8 +-
 test/jit/tree-printer-test.c |    4 +-
 vm/class.c                   |    4 +-
 vm/field.c                   |   18 ++--
 vm/jni-interface.c           |    9 +-
 vm/method.c                  |   12 +++-
 vm/reflection.c              |   51 ++++---------
 vm/types.c                   |  173 ++++++++++++++++++++++++++++++------------
 15 files changed, 224 insertions(+), 139 deletions(-)

diff --git a/include/jit/expression.h b/include/jit/expression.h
index d89ff92..6fc87e8 100644
--- a/include/jit/expression.h
+++ b/include/jit/expression.h
@@ -349,17 +349,4 @@ unsigned long nr_args(struct expression *);
 int expr_nr_kids(struct expression *);
 int expr_is_pure(struct expression *);
 
-static inline enum vm_type mimic_stack_type(enum vm_type type)
-{
-       switch (type) {
-       case J_BOOLEAN:
-       case J_BYTE:
-       case J_CHAR:
-       case J_SHORT:
-               return J_INT;
-       default:
-               return type;
-       }
-}
-
 #endif
diff --git a/include/vm/field.h b/include/vm/field.h
index aa4a25d..0c9d150 100644
--- a/include/vm/field.h
+++ b/include/vm/field.h
@@ -20,6 +20,8 @@ struct vm_field {
        char *name;
        char *type;
 
+       struct vm_type_info type_info;
+
        unsigned int offset;
 };
 
@@ -45,7 +47,7 @@ static inline bool vm_field_is_public(const struct vm_field 
*vmf)
 
 static inline enum vm_type vm_field_type(const struct vm_field *vmf)
 {
-       return str_to_type(vmf->type);
+       return vmf->type_info.vm_type;
 }
 
 #endif
diff --git a/include/vm/method.h b/include/vm/method.h
index 54c2b94..ccf1db8 100644
--- a/include/vm/method.h
+++ b/include/vm/method.h
@@ -26,6 +26,11 @@ struct vm_args_map {
 };
 #endif
 
+struct vm_method_arg {
+       struct vm_type_info type_info;
+       struct list_head list_node;
+};
+
 struct vm_method {
        struct vm_class *class;
        unsigned int method_index;
@@ -40,6 +45,8 @@ struct vm_method {
        struct vm_args_map *args_map;
        int reg_args_count;
 #endif
+       struct list_head args;
+       struct vm_type_info return_type;
 
        struct cafebabe_code_attribute code_attribute;
        struct cafebabe_line_number_table_attribute line_number_table_attribute;
diff --git a/include/vm/types.h b/include/vm/types.h
index ae32f69..4695d9c 100644
--- a/include/vm/types.h
+++ b/include/vm/types.h
@@ -4,6 +4,11 @@
 #include <assert.h>
 #include <stdbool.h>
 
+#include "lib/list.h"
+
+struct vm_method;
+struct vm_field;
+
 enum vm_type {
        J_VOID,
        J_REFERENCE,
@@ -25,19 +30,25 @@ enum vm_type {
 #  define J_NATIVE_PTR J_LONG
 #endif
 
+struct vm_type_info {
+       enum vm_type vm_type;
+       char *class_name;
+};
+
 extern enum vm_type str_to_type(const char *);
 extern enum vm_type get_method_return_type(char *);
 extern unsigned int vm_type_size(enum vm_type);
 
 int skip_type(const char **type);
-int count_arguments(const char *);
+int count_arguments(const struct vm_method *);
 enum vm_type bytecode_type_to_vmtype(int);
 int vmtype_to_bytecode_type(enum vm_type);
 int get_vmtype_size(enum vm_type);
 const char *get_vm_type_name(enum vm_type);
-const char *parse_method_args(const char *, enum vm_type *, char **);
-const char *parse_type(const char *, enum vm_type *, char **);
-unsigned int count_java_arguments(const char *);
+int parse_type(char **, struct vm_type_info *);
+unsigned int count_java_arguments(const struct vm_method *);
+int parse_method_type(struct vm_method *);
+int parse_field_type(struct vm_field *);
 
 static inline bool vm_type_is_float(enum vm_type type)
 {
@@ -51,4 +62,17 @@ static inline int vm_type_slot_size(enum vm_type type)
        return 1;
 }
 
+static inline enum vm_type mimic_stack_type(enum vm_type type)
+{
+       switch (type) {
+       case J_BOOLEAN:
+       case J_BYTE:
+       case J_CHAR:
+       case J_SHORT:
+               return J_INT;
+       default:
+               return type;
+       }
+}
+
 #endif
diff --git a/jit/invoke-bc.c b/jit/invoke-bc.c
index 698dd36..45a51f1 100644
--- a/jit/invoke-bc.c
+++ b/jit/invoke-bc.c
@@ -56,8 +56,7 @@ static unsigned int method_real_argument_count(struct 
vm_method *invoke_target)
 {
        int argc;
 
-       argc = count_java_arguments(invoke_target->type);
-
+       argc = count_java_arguments(invoke_target);
        if (!vm_method_is_static(invoke_target))
                argc++;
 
diff --git a/jit/trace-jit.c b/jit/trace-jit.c
index 57c7a46..4282d12 100644
--- a/jit/trace-jit.c
+++ b/jit/trace-jit.c
@@ -564,8 +564,7 @@ static void print_arg(enum vm_type arg_type, const unsigned 
long *args,
 static void trace_invoke_args(struct vm_method *vmm,
                              struct jit_stack_frame *frame)
 {
-       enum vm_type arg_type;
-       const char *type_str;
+       struct vm_method_arg *arg;
        int arg_index;
 
        if (vm_method_is_jni(vmm))
@@ -578,18 +577,17 @@ static void trace_invoke_args(struct vm_method *vmm,
                print_arg(J_REFERENCE, frame->args, &arg_index);
        }
 
-       type_str = vmm->type;
-
-       if (!strncmp(type_str, "()", 2)) {
+       if (list_is_empty(&vmm->args)) {
                trace_printf("\targs\t: none\n");
                return;
        }
 
        trace_printf("\targs\t:\n");
 
-       while ((type_str = parse_method_args(type_str, &arg_type, NULL))) {
-               trace_printf("\t   %-12s: ", get_vm_type_name(arg_type));
-               print_arg(arg_type, frame->args, &arg_index);
+       list_for_each_entry(arg, &vmm->args, list_node) {
+               trace_printf("\t   %-12s: ",
+                            get_vm_type_name(arg->type_info.vm_type));
+               print_arg(arg->type_info.vm_type, frame->args, &arg_index);
        }
 }
 
diff --git a/test/jit/invoke-bc-test.c b/test/jit/invoke-bc-test.c
index 7428644..371621b 100644
--- a/test/jit/invoke-bc-test.c
+++ b/test/jit/invoke-bc-test.c
@@ -9,6 +9,7 @@
 #include "jit/statement.h"
 #include "lib/stack.h"
 #include "lib/string.h"
+#include "vm/method.h"
 #include <args-test-utils.h>
 
 #include <libharness.h>
@@ -113,6 +114,8 @@ build_invoke_bb(unsigned char invoke_opc,
        struct expression *objectref_expr;
        struct basic_block *bb;
 
+       assert_int_equals(0, parse_method_type(&target_method));
+
        bb = __alloc_simple_bb(&method);
 
        objectref_expr = value_expr(J_REFERENCE, objectref);
@@ -215,7 +218,7 @@ static void assert_converts_to_invoke_stmt(enum vm_type 
expected_result_type, un
        struct statement *stmt;
 
        bb = __alloc_simple_bb(&method);
-
+       assert_int_equals(0, parse_method_type(&target_method));
        create_args(args, nr_args);
        push_args(bb, args, nr_args);
        convert_ir_invoke(bb->b_parent, &target_method, 0);
@@ -270,7 +273,7 @@ void test_invokespecial_should_parse_return_type(void)
        assert_invoke_return_type(OPC_INVOKESPECIAL, J_INT, "()C");
        assert_invoke_return_type(OPC_INVOKESPECIAL, J_INT, "()S");
        assert_invoke_return_type(OPC_INVOKESPECIAL, J_INT, "()I");
-       assert_invoke_return_type(OPC_INVOKESPECIAL, J_LONG, "()L");
+       assert_invoke_return_type(OPC_INVOKESPECIAL, J_LONG, "()J");
        assert_invoke_return_type(OPC_INVOKESPECIAL, J_FLOAT, "()F");
        assert_invoke_return_type(OPC_INVOKESPECIAL, J_DOUBLE, "()D");
 }
@@ -299,7 +302,7 @@ void test_invokevirtual_should_parse_return_type(void)
        assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_INT, "()C");
        assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_INT, "()S");
        assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_INT, "()I");
-       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_LONG, "()L");
+       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_LONG, "()J");
        assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_FLOAT, "()F");
        assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_DOUBLE, "()D");
 }
@@ -315,7 +318,7 @@ void test_convert_invokestatic(void)
        assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "()C", 0);
        assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "()S", 0);
        assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "()I", 0);
-       assert_converts_to_invoke_stmt(J_LONG, OPC_INVOKESTATIC, "()L", 0);
+       assert_converts_to_invoke_stmt(J_LONG, OPC_INVOKESTATIC, "()J", 0);
        assert_converts_to_invoke_stmt(J_VOID, OPC_INVOKESTATIC, "()V", 0);
        assert_converts_to_invoke_stmt(J_FLOAT, OPC_INVOKESTATIC, "()F", 0);
        assert_converts_to_invoke_stmt(J_DOUBLE, OPC_INVOKESTATIC, "()D", 0);
diff --git a/test/jit/object-bc-test.c b/test/jit/object-bc-test.c
index 76107da..a19f8e6 100644
--- a/test/jit/object-bc-test.c
+++ b/test/jit/object-bc-test.c
@@ -55,7 +55,7 @@ static void __assert_convert_getstatic(unsigned char opc,
        };
        struct basic_block *bb;
 
-       fb.type = field_type;
+       assert_int_equals(0, parse_type(&field_type, &fb.type_info));
 
        bb = __alloc_simple_bb(&method);
 
@@ -97,7 +97,7 @@ static void __assert_convert_getfield(unsigned char opc,
        };
        struct basic_block *bb;
 
-       fb.type = field_type;
+       assert_int_equals(0, parse_type(&field_type, &fb.type_info));
 
        bb = __alloc_simple_bb(&method);
 
@@ -142,7 +142,7 @@ static void __assert_convert_putstatic(unsigned char opc,
        struct basic_block *bb;
        struct expression *value;
 
-       fb.type = field_type;
+       assert_int_equals(0, parse_type(&field_type, &fb.type_info));
        value = value_expr(expected_vm_type, 0xdeadbeef);
        bb = __alloc_simple_bb(&method);
        stack_push(bb->mimic_stack, value);
@@ -187,7 +187,7 @@ static void __assert_convert_putfield(unsigned char opc,
        struct expression *objectref;
        struct expression *value;
 
-       fb.type = field_type;
+       assert_int_equals(0, parse_type(&field_type, &fb.type_info));
        bb = __alloc_simple_bb(&method);
 
        objectref = value_expr(J_REFERENCE, 0xdeadbeef);
diff --git a/test/jit/tree-printer-test.c b/test/jit/tree-printer-test.c
index 66e8b05..9ea9634 100644
--- a/test/jit/tree-printer-test.c
+++ b/test/jit/tree-printer-test.c
@@ -22,7 +22,7 @@ static struct vm_class vmc = {
 static struct vm_field vmf = {
        .class = &vmc,
        .name = "field",
-       .type = "I",
+       .type_info = { .vm_type = J_INT, .class_name = "I" }
 };
 
 static struct vm_method vmm = {
@@ -415,7 +415,7 @@ void test_should_print_class_field_expression(void)
 {
        assert_printed_class_field_expr(str_aprintf(
                "[class_field int %p '%s.%s']",
-               &vmf, vmf.class->name, vmf.name, vmf.type), J_INT, &vmf);
+               &vmf, vmf.class->name, vmf.name, "I"), J_INT, &vmf);
 }
 
 void assert_printed_instance_field_expr(struct string *expected, enum vm_type 
type,
diff --git a/vm/class.c b/vm/class.c
index f53f112..6edf2e4 100644
--- a/vm/class.c
+++ b/vm/class.c
@@ -360,7 +360,7 @@ int vm_class_link(struct vm_class *vmc, const struct 
cafebabe_class *class)
        for (uint16_t i = 0; i < class->fields_count; ++i) {
                struct vm_field *vmf = &vmc->fields[i];
                unsigned int stat = vm_field_is_static(vmf) ? 0 : 1;
-               enum vm_type type = str_to_type(vmf->type);
+               enum vm_type type = vmf->type_info.vm_type;
                struct field_bucket *bucket = &field_buckets[stat][type];
 
                ++bucket->nr;
@@ -380,7 +380,7 @@ int vm_class_link(struct vm_class *vmc, const struct 
cafebabe_class *class)
        for (uint16_t i = 0; i < class->fields_count; ++i) {
                struct vm_field *vmf = &vmc->fields[i];
                unsigned int stat = vm_field_is_static(vmf) ? 0 : 1;
-               enum vm_type type = str_to_type(vmf->type);
+               enum vm_type type = vmf->type_info.vm_type;
                struct field_bucket *bucket = &field_buckets[stat][type];
 
                bucket->fields[bucket->nr++] = vmf;
diff --git a/vm/field.c b/vm/field.c
index 5755d7f..604f7b3 100644
--- a/vm/field.c
+++ b/vm/field.c
@@ -46,7 +46,10 @@ int vm_field_init(struct vm_field *vmf,
        }
 
        vmf->type = strndup((char *) type->bytes, type->length);
-       if (!vmf->type) {
+       if (!vmf->type)
+               return -ENOMEM;
+
+       if (parse_field_type(vmf)) {
                NOT_IMPLEMENTED;
                return -1;
        }
@@ -103,10 +106,7 @@ int vm_field_init_static(struct vm_field *vmf)
         * should write a test case in Jasmine or something, I guess. */
        switch (cp->tag) {
        case CAFEBABE_CONSTANT_TAG_INTEGER:
-               if (strcmp(vmf->type, "I") && strcmp(vmf->type, "S")
-                       && strcmp(vmf->type, "C") && strcmp(vmf->type, "B")
-                       && strcmp(vmf->type, "Z"))
-               {
+               if (mimic_stack_type(vmf->type_info.vm_type) != J_INT) {
                        NOT_IMPLEMENTED;
                        return -1;
                }
@@ -114,7 +114,7 @@ int vm_field_init_static(struct vm_field *vmf)
                static_field_set_int(vmf, cp->integer_.bytes);
                break;
        case CAFEBABE_CONSTANT_TAG_FLOAT:
-               if (strcmp(vmf->type, "F")) {
+               if (vmf->type_info.vm_type != J_FLOAT) {
                        NOT_IMPLEMENTED;
                        return -1;
                }
@@ -122,7 +122,7 @@ int vm_field_init_static(struct vm_field *vmf)
                static_field_set_float(vmf, cp->float_.bytes);
                break;
        case CAFEBABE_CONSTANT_TAG_STRING: {
-               if (strcmp(vmf->type, "Ljava/lang/String;")) {
+               if (strcmp(vmf->type_info.class_name, "java/lang/String")) {
                        NOT_IMPLEMENTED;
                        return -1;
                }
@@ -147,7 +147,7 @@ int vm_field_init_static(struct vm_field *vmf)
                break;
        }
        case CAFEBABE_CONSTANT_TAG_LONG:
-               if (strcmp(vmf->type, "J")) {
+               if (vmf->type_info.vm_type != J_LONG) {
                        NOT_IMPLEMENTED;
                        return -1;
                }
@@ -157,7 +157,7 @@ int vm_field_init_static(struct vm_field *vmf)
                        + (uint64_t) cp->long_.low_bytes);
                break;
        case CAFEBABE_CONSTANT_TAG_DOUBLE:
-               if (strcmp(vmf->type, "D")) {
+               if (vmf->type_info.vm_type != J_DOUBLE) {
                        NOT_IMPLEMENTED;
                        return -1;
                }
diff --git a/vm/jni-interface.c b/vm/jni-interface.c
index 21d7ed9..73cfba2 100644
--- a/vm/jni-interface.c
+++ b/vm/jni-interface.c
@@ -904,17 +904,16 @@ static inline void pack_args(struct vm_method *vmm, 
unsigned long *packed_args,
                             uint64_t *args)
 {
 #ifdef CONFIG_32_BIT
-       const char *type_str;
-       enum vm_type type;
+       struct vm_method_arg *arg;
        int packed_idx;
        int idx;
 
-       type_str = vmm->type;
        packed_idx = 0;
        idx = 0;
 
-       while ((type_str = parse_method_args(type_str, &type, NULL))) {
-               if (type != J_LONG && type != J_DOUBLE) {
+       list_for_each_entry(arg, &vmm->args, list_node) {
+               if (arg->type_info.vm_type != J_LONG &&
+                   arg->type_info.vm_type != J_DOUBLE) {
                        packed_args[packed_idx++] = low_64(args[idx]);
                        packed_args[packed_idx++] = high_64(args[idx++]);
                } else {
diff --git a/vm/method.c b/vm/method.c
index bfb8948..1d6e231 100644
--- a/vm/method.c
+++ b/vm/method.c
@@ -67,12 +67,17 @@ int vm_method_init(struct vm_method *vmm,
                return -1;
        }
 
+       if (parse_method_type(vmm)) {
+               warn("method type parsing failed for: %s", vmm->type);
+               return -1;
+       }
+
        /*
         * XXX: Jam VM legacy? It seems that JamVM counts the number of
         * _32-bit_ arguments. This probably needs some fixing. What do we do
         * on x86_64?
         */
-       vmm->args_count = count_arguments(vmm->type);
+       vmm->args_count = count_arguments(vmm);
        if (vmm->args_count < 0) {
                NOT_IMPLEMENTED;
                return -1;
@@ -164,6 +169,11 @@ int vm_method_init_from_interface(struct vm_method *vmm, 
struct vm_class *vmc,
        vmm->args_count = interface_method->args_count;
        vmm->is_vm_native = false;
 
+       if (parse_method_type(vmm)) {
+               warn("method type parsing failed for: %s", vmm->type);
+               return -1;
+       }
+
        init_abstract_method(vmm);
 
        return 0;
diff --git a/vm/reflection.c b/vm/reflection.c
index 178fb92..d180634 100644
--- a/vm/reflection.c
+++ b/vm/reflection.c
@@ -300,10 +300,9 @@ native_vmclass_get_declared_constructors(struct vm_object 
*clazz,
 }
 
 static struct vm_class *
-vm_type_to_class(struct vm_object *classloader, char *type_name,
-                enum vm_type type)
+vm_type_to_class(struct vm_object *classloader, struct vm_type_info *type_info)
 {
-       switch (type) {
+       switch (type_info->vm_type) {
        case J_BOOLEAN:
                return vm_boolean_class;
        case J_CHAR:
@@ -323,7 +322,7 @@ vm_type_to_class(struct vm_object *classloader, char 
*type_name,
        case J_VOID:
                return vm_void_class;
        case J_REFERENCE:
-               return classloader_load(classloader, type_name);
+               return classloader_load(classloader, type_info->class_name);
        case J_RETURN_ADDRESS:
        case VM_TYPE_MAX:
                error("invalid type");
@@ -333,31 +332,25 @@ vm_type_to_class(struct vm_object *classloader, char 
*type_name,
 }
 
 static struct vm_object *get_method_parameter_types(struct vm_method *vmm)
+
 {
+       struct vm_method_arg *arg;
        struct vm_object *array;
        unsigned int count;
-       enum vm_type type;
-       const char *type_str;
-       char *type_name;
        int i;
 
-       count = count_java_arguments(vmm->type);
+       count = count_java_arguments(vmm);
        array = vm_object_alloc_array(vm_array_of_java_lang_Class, count);
        if (!array) {
                NOT_IMPLEMENTED;
                return NULL;
        }
 
-       type_str = vmm->type;
        i = 0;
-
-       while ((type_str = parse_method_args(type_str, &type, &type_name))) {
+       list_for_each_entry(arg, &vmm->args, list_node) {
                struct vm_class *class;
 
-               class = vm_type_to_class(vmm->class->classloader, type_name,
-                                        type);
-               free(type_name);
-
+               class = vm_type_to_class(vmm->class->classloader, 
&arg->type_info);
                if (class)
                        vm_class_ensure_init(class);
 
@@ -716,25 +709,21 @@ void native_field_set(struct vm_object *this, struct 
vm_object *o,
 static int marshall_call_arguments(struct vm_method *vmm, unsigned long *args,
                                   struct vm_object *args_array)
 {
-       enum vm_type type;
-       const char *type_str;
-       char *type_name;
+       struct vm_method_arg *arg;
        int args_array_idx;
        int idx;
 
-       type_str = vmm->type;
-       idx = 0;
        args_array_idx = 0;
+       idx = 0;
 
        if (args_array == NULL)
                return 0;
 
-       while ((type_str = parse_method_args(type_str, &type, &type_name))) {
-               struct vm_object *arg;
+       list_for_each_entry(arg, &vmm->args, list_node) {
+               struct vm_object *arg_obj;
 
-               arg = array_get_field_ptr(args_array, args_array_idx++);
-
-               if (unwrap_and_set_field(&args[idx++], type, arg))
+               arg_obj = array_get_field_ptr(args_array, args_array_idx++);
+               if (unwrap_and_set_field(&args[idx++], arg->type_info.vm_type, 
arg_obj))
                        return -1;
        }
 
@@ -804,8 +793,6 @@ 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);
@@ -816,14 +803,8 @@ struct vm_object *native_field_gettype(struct vm_object 
*this)
        if (!vmf)
                return 0;
 
-       if (!parse_type(vmf->type, &vmtype, &type_name)) {
-               warn("type parsing failed");
-               return NULL;
-       }
-
-       struct vm_class *vmc =
-               vm_type_to_class(vmf->class->classloader, type_name, vmtype);
-
+       struct vm_class *vmc = vm_type_to_class(vmf->class->classloader,
+                                               &vmf->type_info);
        if (vm_class_ensure_init(vmc))
                return NULL;
 
diff --git a/vm/types.c b/vm/types.c
index 08a2e4a..e20aecf 100644
--- a/vm/types.c
+++ b/vm/types.c
@@ -2,6 +2,8 @@
 
 #include "vm/system.h"
 #include "vm/types.h"
+#include "vm/method.h"
+#include "vm/field.h"
 #include "vm/die.h"
 #include "vm/vm.h"
 
@@ -63,15 +65,15 @@ unsigned int vm_type_size(enum vm_type type)
        return size[type];
 }
 
-int count_arguments(const char *type)
+int count_arguments(const struct vm_method *vmm)
 {
-       enum vm_type vmtype;
+       struct vm_method_arg *arg;
        int count;
 
        count = 0;
-
-       while ((type = parse_method_args(type, &vmtype, NULL))) {
-               if (vmtype == J_LONG || vmtype == J_DOUBLE)
+       list_for_each_entry(arg, &vmm->args, list_node) {
+               if (arg->type_info.vm_type == J_LONG ||
+                   arg->type_info.vm_type == J_DOUBLE)
                        count += 2;
                else
                        count++;
@@ -154,82 +156,155 @@ static const char *vm_type_names[] = {
        [J_RETURN_ADDRESS] = "J_RETURN_ADDRESS"
 };
 
-const char *get_vm_type_name(enum vm_type type) {
+const char *get_vm_type_name(enum vm_type type)
+{
        if (type < 0 || type >= ARRAY_SIZE(vm_type_names))
                return NULL;
 
        return vm_type_names[type];
 }
 
-const char *parse_type(const char *type_str, enum vm_type *vmtype,
-                      char **name_p)
+static int parse_class_name(char **type_str)
 {
-       const char *type_name_start = type_str;
+       do {
+               if (**type_str == 0)
+                       return -1;
+
+               (*type_str)++;
+       } while (**type_str != ';');
 
-       if (name_p)
-               *name_p = NULL;
+       (*type_str)++;
+       return 0;
+}
 
-       if (!type_str || *type_str == ')')
+static int parse_array_element_type(char **type_str)
+{
+       switch (**type_str) {
+       case '[':
+               (*type_str)++;
+               return parse_array_element_type(type_str);
+       case 'L':
+               (*type_str)++;
+               return parse_class_name(type_str);
+       case 'V':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'F':
+       case 'I':
+       case 'J':
+       case 'S':
+       case 'Z':
+               (*type_str)++;
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+int parse_type(char **type_str, struct vm_type_info *type_info)
+{
+       char *name_start;
+
+       switch (**type_str) {
+       case '[':
+               name_start = (*type_str)++;
+               if (parse_array_element_type(type_str))
+                       return -1;
+
+               type_info->vm_type = J_REFERENCE;
+               type_info->class_name = strndup(name_start,
+                       (size_t) *type_str - (size_t) name_start);
+               return 0;
+       case 'L':
+               name_start = ++(*type_str);
+               if (parse_class_name(type_str))
+                       return -1;
+
+               type_info->vm_type = J_REFERENCE;
+               type_info->class_name = strndup(name_start,
+                       (size_t) *type_str - (size_t) name_start - 1);
+               return 0;
+       case 'V':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'F':
+       case 'I':
+       case 'J':
+       case 'S':
+       case 'Z':
+               type_info->class_name = strndup(*type_str, 1);
+               type_info->vm_type = str_to_type(type_info->class_name);
+               (*type_str)++;
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+static struct vm_method_arg *alloc_method_arg(void)
+{
+       struct vm_method_arg *arg;
+
+       arg = malloc(sizeof(*arg));
+       if (!arg)
                return NULL;
 
-       if (*type_str == '[') {
-               *vmtype = J_REFERENCE;
+       INIT_LIST_HEAD(&arg->list_node);
+       return arg;
+}
+
+int parse_method_type(struct vm_method *vmm)
+{
+       char *type_str;
 
-               while (*type_str == '[')
-                       type_str++;
+       INIT_LIST_HEAD(&vmm->args);
+       type_str = vmm->type;
 
-               if (*type_str != 'L') {
-                       type_str++;
-                       goto out;
-               }
-       }
+       if (*type_str++ != '(')
+               return -1;
 
-       if (*type_str == 'L') {
-               ++type_name_start;
-               ++type_str;
-               while (*(type_str++) != ';')
-                       ;
-               *vmtype = J_REFERENCE;
-       } else {
-               char primitive_name[2];
+       while (*type_str != ')') {
+               struct vm_method_arg *arg = alloc_method_arg();
+               if (!arg)
+                       return -ENOMEM;
 
-               primitive_name[0] = *(type_str++);
-               primitive_name[1] = 0;
+               if (parse_type(&type_str, &arg->type_info))
+                       return -1;
 
-               *vmtype = str_to_type(primitive_name);
+               list_add(&arg->list_node, &vmm->args);
        }
 
- out:
-       if (name_p) {
-               size_t size = (size_t) type_str - (size_t) type_name_start;
+       type_str++;
 
-               if (*vmtype == J_REFERENCE)
-                       size--;
+       /* parse return type */
+       if (parse_type(&type_str, &vmm->return_type))
+               return -1;
 
-               *name_p = strndup(type_name_start, size);
-       }
+       if (*type_str != 0)
+               return -1; /* junk after return type */
 
-       return type_str;
+       return 0;
 }
 
-const char *parse_method_args(const char *type_str, enum vm_type *vmtype,
-                             char **name_p)
+int parse_field_type(struct vm_field *vmf)
 {
-       if (*type_str == '(')
-               type_str++;
+       char *type_str;
 
-       return parse_type(type_str, vmtype, name_p);
+       type_str = vmf->type;
+       return parse_type(&type_str, &vmf->type_info);
 }
 
-unsigned int count_java_arguments(const char *type)
+unsigned int count_java_arguments(const struct vm_method *vmm)
 {
+       struct vm_method_arg *arg;
        unsigned int count;
-       enum vm_type vmtype;
 
        count = 0;
-
-       while ((type = parse_method_args(type, &vmtype, NULL)))
+       list_for_each_entry(arg, &vmm->args, list_node) {
                count ++;
+       }
 
        return count;
 }
-- 
1.6.0.4


------------------------------------------------------------------------------
Come build with us! The BlackBerry&reg; Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9&#45;12, 2009. Register now&#33;
http://p.sf.net/sfu/devconf
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to