Support for loading objects with native code, invoking JNI native methods.
Few JNI native interface functions implemented.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 Makefile                      |    4 +-
 arch/x86/emit-code.c          |   24 +++
 arch/x86/insn-selector_32.brg |    3 +-
 include/jit/compiler.h        |    7 +
 include/jit/emit-code.h       |    3 +
 include/vm/class.h            |    1 +
 include/vm/jni.h              |   56 +++++
 include/vm/method.h           |    1 +
 include/vm/preload.h          |    2 +
 jit/emit.c                    |   29 +++-
 jit/trampoline.c              |   28 +++-
 vm/class.c                    |    6 +
 vm/jato.c                     |    6 +-
 vm/jni-interface.c            |  447 +++++++++++++++++++++++++++++++++++++++++
 vm/jni.c                      |  162 +++++++++++++++
 vm/method.c                   |    2 +
 vm/preload.c                  |    4 +
 vm/signal.c                   |    3 +
 18 files changed, 779 insertions(+), 9 deletions(-)
 create mode 100644 include/vm/jni.h
 create mode 100644 vm/jni-interface.c
 create mode 100644 vm/jni.c

diff --git a/Makefile b/Makefile
index f776180..5ba6712 100644
--- a/Makefile
+++ b/Makefile
@@ -109,7 +109,9 @@ VM_OBJS = \
        vm/utf8.o               \
        vm/zalloc.o             \
        vm/preload.o            \
-       vm/fault-inject.o
+       vm/fault-inject.o       \
+       vm/jni.o                \
+       vm/jni-interface.o
 
 LIB_OBJS = \
        lib/bitset.o            \
diff --git a/arch/x86/emit-code.c b/arch/x86/emit-code.c
index 38f080d..236ba0e 100644
--- a/arch/x86/emit-code.c
+++ b/arch/x86/emit-code.c
@@ -20,6 +20,8 @@
 
 #include "lib/list.h"
 #include "lib/buffer.h"
+
+#include "vm/jni.h"
 #include "vm/method.h"
 #include "vm/object.h"
 
@@ -1386,6 +1388,28 @@ void emit_trampoline(struct compilation_unit *cu,
        jit_text_unlock();
 }
 
+void emit_jni_trampoline(struct buffer *buf, struct vm_jni_env *jni_env,
+                        void *target)
+{
+       jit_text_lock();
+
+       buf->buf = jit_text_ptr();
+
+       /* save return address into caller-saved register */
+       __emit_pop_reg(buf, REG_ESI);
+
+       __emit_push_imm(buf, (unsigned long) jni_env);
+       __emit_call(buf, target);
+       __emit_add_imm_reg(buf, 4, REG_ESP);
+
+       /* return to caller*/
+       __emit_push_reg(buf, REG_ESI);
+       emit_ret(buf);
+
+       jit_text_reserve(buffer_offset(buf));
+       jit_text_unlock();
+}
+
 /* Note: a < b, always */
 static void emit_itable_bsearch(struct buffer *buf,
        struct itable_entry **table, unsigned int a, unsigned int b)
diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg
index 0f87aa0..6c9840f 100644
--- a/arch/x86/insn-selector_32.brg
+++ b/arch/x86/insn-selector_32.brg
@@ -1917,7 +1917,7 @@ static void invoke(struct basic_block *s, struct 
tree_node *tree, struct compila
        struct insn *call_insn;
        void *target;
 
-       if (cu == s->b_parent) {
+       if (pthread_mutex_trylock(&cu->mutex)) {
                /*
                 * This is a recursive method invocation. Threfore, we are
                 * already holding cu->mutex here because we entered
@@ -1926,7 +1926,6 @@ static void invoke(struct basic_block *s, struct 
tree_node *tree, struct compila
                is_compiled = false;
                target = vm_method_trampoline_ptr(method);
        } else {
-               pthread_mutex_lock(&cu->mutex);
                is_compiled = cu->is_compiled;
 
                if (is_compiled)
diff --git a/include/jit/compiler.h b/include/jit/compiler.h
index 0999e5d..8584954 100644
--- a/include/jit/compiler.h
+++ b/include/jit/compiler.h
@@ -31,6 +31,10 @@ struct jit_trampoline {
        pthread_mutex_t mutex;
 };
 
+struct jni_trampoline {
+       struct buffer *objcode;
+};
+
 struct parse_context {
        struct compilation_unit *cu;
        struct basic_block *bb;
@@ -56,8 +60,11 @@ int emit_machine_code(struct compilation_unit *);
 void *jit_magic_trampoline(struct compilation_unit *);
 
 struct jit_trampoline *alloc_jit_trampoline(void);
+struct jni_trampoline *alloc_jni_trampoline(void);
 struct jit_trampoline *build_jit_trampoline(struct compilation_unit *);
+struct jni_trampoline *build_jni_trampoline(void *);
 void free_jit_trampoline(struct jit_trampoline *);
+void free_jni_trampoline(struct jni_trampoline *);
 
 struct fixup_site *alloc_fixup_site(void);
 void free_fixup_site(struct fixup_site *);
diff --git a/include/jit/emit-code.h b/include/jit/emit-code.h
index 266da19..07c41bf 100644
--- a/include/jit/emit-code.h
+++ b/include/jit/emit-code.h
@@ -7,6 +7,7 @@ struct basic_block;
 struct buffer;
 struct insn;
 struct vm_object;
+struct vm_jni_env;
 
 enum emitter_type {
        NO_OPERANDS = 1,
@@ -37,5 +38,7 @@ extern void emit_unlock_this(struct buffer *);
 extern void emit_body(struct basic_block *, struct buffer *);
 extern void backpatch_branch_target(struct buffer *buf, struct insn *insn,
                                    unsigned long target_offset);
+extern void emit_jni_trampoline(struct buffer *buf, struct vm_jni_env *jni_env,
+                               void *target);
 
 #endif /* JATO_EMIT_CODE_H */
diff --git a/include/vm/class.h b/include/vm/class.h
index 5de981d..7705861 100644
--- a/include/vm/class.h
+++ b/include/vm/class.h
@@ -128,5 +128,6 @@ bool vm_class_is_primitive_type_name(const char 
*class_name);
 char *vm_class_get_array_element_class_name(const char *class_name);
 struct vm_class *vm_class_get_array_element_class(const struct vm_class 
*array_class);
 enum vm_type vm_class_get_storage_vmtype(const struct vm_class *class);
+struct vm_class *vm_class_get_class_from_class_object(struct vm_object *clazz);
 
 #endif /* __CLASS_H */
diff --git a/include/vm/jni.h b/include/vm/jni.h
new file mode 100644
index 0000000..04d987b
--- /dev/null
+++ b/include/vm/jni.h
@@ -0,0 +1,56 @@
+#ifndef JATO_VM_JNI_H
+#define JATO_VM_JNI_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define JNI_FALSE  0
+#define JNI_TRUE   1
+
+struct vm_object;
+struct vm_class;
+struct vm_method;
+
+typedef uint8_t jboolean;
+typedef int8_t jbyte;
+typedef uint16_t jchar;
+typedef int16_t jshort;
+typedef int32_t jint;
+typedef int64_t jlong;
+typedef uint32_t jfloat;
+typedef uint64_t jdouble;
+
+typedef jint jsize;
+
+typedef struct vm_object *jobject;
+typedef jobject jclass;
+typedef struct vm_field *jfieldID;
+typedef struct vm_method *jmethodID;
+
+union jvalue {
+       jboolean z;
+       jbyte    b;
+       jchar    c;
+       jshort   s;
+       jint     i;
+       jlong    j;
+       jfloat   f;
+       jdouble  d;
+       jobject  l;
+};
+
+int vm_jni_nr_loaded_objects;
+void **vm_jni_loaded_objects;
+
+struct vm_jni_env {
+       void **jni_table;
+};
+
+void vm_jni_init(void);
+struct vm_jni_env *vm_jni_get_jni_env();
+int vm_jni_load_object(const char *name);
+void *vm_jni_lookup_method(const char *class_name, const char *method_name,
+                          const char *method_type);
+bool vm_jni_check_trap(void *ptr);
+
+#endif
diff --git a/include/vm/method.h b/include/vm/method.h
index 0b38905..ebea698 100644
--- a/include/vm/method.h
+++ b/include/vm/method.h
@@ -35,6 +35,7 @@ struct vm_method {
 
        struct compilation_unit *compilation_unit;
        struct jit_trampoline *trampoline;
+       struct jni_trampoline *jni_trampoline;
 
        void *jit_code;
 };
diff --git a/include/vm/preload.h b/include/vm/preload.h
index 1f3a2e9..d083411 100644
--- a/include/vm/preload.h
+++ b/include/vm/preload.h
@@ -20,6 +20,8 @@ extern struct vm_class 
*vm_java_lang_ArrayIndexOutOfBoundsException;
 extern struct vm_class *vm_java_lang_ArrayStoreException;
 extern struct vm_class *vm_java_lang_RuntimeException;
 extern struct vm_class *vm_java_lang_ExceptionInInitializerError;
+extern struct vm_class *vm_java_lang_NoSuchFieldError;
+extern struct vm_class *vm_java_lang_NoSuchMethodError;
 extern struct vm_class *vm_boolean_class;
 extern struct vm_class *vm_char_class;
 extern struct vm_class *vm_float_class;
diff --git a/jit/emit.c b/jit/emit.c
index c888644..ac31b8b 100644
--- a/jit/emit.c
+++ b/jit/emit.c
@@ -183,7 +183,7 @@ int emit_machine_code(struct compilation_unit *cu)
 struct jit_trampoline *alloc_jit_trampoline(void)
 {
        struct jit_trampoline *trampoline;
-       
+
        trampoline = malloc(sizeof(*trampoline));
        if (!trampoline)
                return NULL;
@@ -204,8 +204,35 @@ struct jit_trampoline *alloc_jit_trampoline(void)
        return NULL;
 }
 
+struct jni_trampoline *alloc_jni_trampoline(void)
+{
+       struct jni_trampoline *trampoline;
+
+       trampoline = malloc(sizeof(*trampoline));
+       if (!trampoline)
+               return NULL;
+
+       memset(trampoline, 0, sizeof(*trampoline));
+
+       trampoline->objcode = __alloc_buffer(&exec_buf_ops);
+       if (!trampoline->objcode)
+               goto failed;
+
+       return trampoline;
+
+  failed:
+       free_jni_trampoline(trampoline);
+       return NULL;
+}
+
 void free_jit_trampoline(struct jit_trampoline *trampoline)
 {
        free_buffer(trampoline->objcode);
        free(trampoline);
 }
+
+void free_jni_trampoline(struct jni_trampoline *trampoline)
+{
+       free_buffer(trampoline->objcode);
+       free(trampoline);
+}
diff --git a/jit/trampoline.c b/jit/trampoline.c
index c320272..0de2db5 100644
--- a/jit/trampoline.c
+++ b/jit/trampoline.c
@@ -36,15 +36,15 @@
 #include "vm/natives.h"
 #include "lib/string.h"
 #include "vm/method.h"
-#include "lib/buffer.h"
 #include "vm/die.h"
 #include "vm/vm.h"
+#include "vm/jni.h"
 
 #include <stdio.h>
 
 static void *jit_native_trampoline(struct compilation_unit *cu)
 {
-       const char *method_name, *class_name;
+       const char *method_name, *class_name, *method_type;
        struct vm_method *method;
        struct string *msg;
        void *ret;
@@ -52,6 +52,7 @@ static void *jit_native_trampoline(struct compilation_unit 
*cu)
        method = cu->method;
        class_name  = method->class->name;
        method_name = method->name;
+       method_type = method->type;
 
        ret = vm_lookup_native(class_name, method_name);
        if (ret) {
@@ -59,6 +60,16 @@ static void *jit_native_trampoline(struct compilation_unit 
*cu)
                return ret;
        }
 
+       ret = vm_jni_lookup_method(class_name, method_name, method_type);
+       if (ret) {
+               add_cu_mapping((unsigned long)ret, cu);
+
+               if (!method->jni_trampoline)
+                       method->jni_trampoline = build_jni_trampoline(ret);
+
+               return buffer_ptr(method->jni_trampoline->objcode);
+       }
+
        msg = alloc_str();
        if (!msg)
                /* TODO: signal OutOfMemoryError */
@@ -133,9 +144,20 @@ void *jit_magic_trampoline(struct compilation_unit *cu)
 struct jit_trampoline *build_jit_trampoline(struct compilation_unit *cu)
 {
        struct jit_trampoline *trampoline;
-       
+
        trampoline = alloc_jit_trampoline();
        if (trampoline)
                emit_trampoline(cu, jit_magic_trampoline, trampoline);
        return trampoline;
 }
+
+struct jni_trampoline *build_jni_trampoline(void *target)
+{
+       struct jni_trampoline *trampoline;
+
+       trampoline = alloc_jni_trampoline();
+       if (trampoline)
+               emit_jni_trampoline(trampoline->objcode, vm_jni_get_jni_env(),
+                                   target);
+       return trampoline;
+}
diff --git a/vm/class.c b/vm/class.c
index 762d34a..784f5e5 100644
--- a/vm/class.c
+++ b/vm/class.c
@@ -797,3 +797,9 @@ enum vm_type vm_class_get_storage_vmtype(const struct 
vm_class *class)
 
        return class->primitive_vm_type;
 }
+
+struct vm_class *vm_class_get_class_from_class_object(struct vm_object *clazz)
+{
+       return (struct vm_class*)field_get_object(clazz,
+                                                 vm_java_lang_Class_vmdata);
+}
diff --git a/vm/jato.c b/vm/jato.c
index fb7ecb0..dfdd60b 100644
--- a/vm/jato.c
+++ b/vm/jato.c
@@ -53,6 +53,7 @@
 #include "vm/fault-inject.h"
 #include "vm/preload.h"
 #include "vm/itable.h"
+#include "vm/jni.h"
 #include "vm/method.h"
 #include "vm/natives.h"
 #include "vm/object.h"
@@ -280,8 +281,7 @@ native_vmclass_getname(struct vm_object *object)
 {
        struct vm_class *class;
 
-       class = (struct vm_class*)field_get_object(object,
-                                                  vm_java_lang_Class_vmdata);
+       class = vm_class_get_class_from_class_object(object);
        assert(class != NULL);
 
        return vm_object_alloc_string_from_c(class->name);
@@ -317,6 +317,7 @@ static struct vm_native natives[] = {
        DEFINE_NATIVE("java/lang/VMObject", "getClass", 
&native_vmobject_getclass),
        DEFINE_NATIVE("java/lang/VMRuntime", "exit", &native_vmruntime_exit),
        DEFINE_NATIVE("java/lang/VMRuntime", "mapLibraryName", 
&native_vmruntime_maplibraryname),
+       DEFINE_NATIVE("java/lang/VMRuntime", "nativeLoad", 
&native_vmruntime_native_load),
        DEFINE_NATIVE("java/lang/VMSystem", "arraycopy", 
&native_vmsystem_arraycopy),
        DEFINE_NATIVE("java/lang/VMSystem", "identityHashCode", 
&native_vmsystem_identityhashcode),
        DEFINE_NATIVE("java/lang/VMThrowable", "fillInStackTrace", 
&native_vmthrowable_fill_in_stack_trace),
@@ -433,6 +434,7 @@ main(int argc, char *argv[])
        jit_init_natives();
 
        static_fixup_init();
+       vm_jni_init();
 
        /* Search $CLASSPATH last. */
        char *classpath = getenv("CLASSPATH");
diff --git a/vm/jni-interface.c b/vm/jni-interface.c
new file mode 100644
index 0000000..fad8988
--- /dev/null
+++ b/vm/jni-interface.c
@@ -0,0 +1,447 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "jit/exception.h"
+
+#include "vm/class.h"
+#include "vm/classloader.h"
+#include "vm/die.h"
+#include "vm/guard-page.h"
+#include "vm/jni.h"
+#include "vm/method.h"
+#include "vm/object.h"
+#include "vm/preload.h"
+
+#define check_null(x)                                                  \
+       if (x == NULL) {                                                \
+               signal_new_exception(vm_java_lang_NullPointerException, \
+                                    NULL);                             \
+               return NULL;                                            \
+       }
+
+jclass vm_jni_find_class(struct vm_jni_env *env, const char *name)
+{
+       struct vm_class *class;
+
+       class = classloader_load(name);
+       if (!class) {
+               signal_new_exception(vm_java_lang_NoClassDefFoundError,
+                                    name);
+               return NULL;
+       }
+
+       vm_class_ensure_init(class);
+       if (exception_occurred())
+               return NULL;
+
+       return class->object;
+}
+
+jmethodID vm_jni_get_method_id(struct vm_jni_env *env, jclass clazz,
+                              const char *name, const char *sig)
+{
+       struct vm_method *mb;
+       struct vm_class *class;
+
+       check_null(clazz);
+
+       class = vm_class_get_class_from_class_object(clazz);
+       check_null(class);
+
+       vm_class_ensure_init(class);
+       if (exception_occurred())
+               return NULL;
+
+       mb = vm_class_get_method(class, name, sig);
+       if (!mb) {
+               signal_new_exception(vm_java_lang_NoSuchMethodError, NULL);
+               return NULL;
+       }
+
+       return mb;
+}
+
+jfieldID vm_jni_get_field_id(struct vm_jni_env *env, jclass clazz,
+                            const char *name, const char *sig)
+{
+       struct vm_field *fb;
+       struct vm_class *class;
+
+       check_null(clazz);
+
+       class = vm_class_get_class_from_class_object(clazz);
+       check_null(class);
+
+       vm_class_ensure_init(class);
+       if (exception_occurred())
+               return NULL;
+
+       fb = vm_class_get_field(class, name, sig);
+       if (!fb) {
+               signal_new_exception(vm_java_lang_NoSuchFieldError, NULL);
+               return NULL;
+       }
+
+       return fb;
+}
+
+/*
+ * The JNI native interface table.
+ * See: http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/functions.html
+ */
+void *vm_jni_native_interface[] = {
+       /* 0 */
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL, /* GetVersion */
+
+       /* 5 */
+       NULL, /* DefineClass */
+       vm_jni_find_class,
+       NULL,
+       NULL,
+       NULL,
+
+       /* 10 */
+       NULL, /* GetSuperclass */
+       NULL, /* IsAssignableFrom */
+       NULL,
+       NULL, /* Throw */
+       NULL, /* ThrowNew */
+
+       /* 15 */
+       NULL, /* ExceptionOccurred */
+       NULL, /* ExceptionDescribe */
+       NULL, /* ExceptionClear */
+       NULL, /* FatalError */
+       NULL,
+
+       /* 20 */
+       NULL,
+       NULL, /* NewGlobalRef */
+       NULL, /* DeleteGlobalRef */
+       NULL, /* DeleteLocalRef */
+       NULL, /* IsSameObject */
+
+       /* 25 */
+       NULL,
+       NULL,
+       NULL, /* AllocObject */
+       NULL, /* NewObject */
+       NULL, /* NewObjectV */
+
+       /* 30 */
+       NULL, /* NewObjectA */
+       NULL, /* GetObjectClass */
+       NULL, /* IsInstanceOf */
+       vm_jni_get_method_id,
+       NULL, /* CallObjectMethod */
+
+       /* 35 */
+       NULL, /* CallObjectMethodV */
+       NULL, /* CallObjectMethodA */
+       NULL, /* CallBooleanMethod */
+       NULL, /* CallBooleanMethodV */
+       NULL, /* CallBooleanMethodA */
+
+       /* 40 */
+       NULL, /* CallByteMethod */
+       NULL, /* CallByteMethodV */
+       NULL, /* CallByteMethodA */
+       NULL, /* CallCharMethod */
+       NULL, /* CallCharMethodV */
+
+       /* 45 */
+       NULL, /* CallCharMethodA */
+       NULL, /* CallShortMethod */
+       NULL, /* CallShortMethodV */
+       NULL, /* CallShortMethodA */
+       NULL, /* CallIntMethod */
+
+       /* 50 */
+       NULL, /* CallIntMethodV */
+       NULL, /* CallIntMethodA */
+       NULL, /* CallLongMethod */
+       NULL, /* CallLongMethodV */
+       NULL, /* CallLongMethodA */
+
+       /* 55 */
+       NULL, /* CallFloatMethod */
+       NULL, /* CallFloatMethodV */
+       NULL, /* CallFloatMethodA */
+       NULL, /* CallDoubleMethod */
+       NULL, /* CallDoubleMethodV */
+
+       /* 60 */
+       NULL, /* CallDoubleMethodA */
+       NULL, /* CallVoidMethod */
+       NULL, /* CallVoidMethodV */
+       NULL, /* CallVoidMethodA */
+       NULL, /* CallNonvirtualObjectMethod */
+
+       /* 65 */
+       NULL, /* CallNonvirtualObjectMethodV */
+       NULL, /* CallNonvirtualObjectMethodA */
+       NULL, /* CallNonvirtualBooleanMethod */
+       NULL, /* CallNonvirtualBooleanMethodV */
+       NULL, /* CallNonvirtualBooleanMethodA */
+
+       /* 70 */
+       NULL, /* CallNonvirtualByteMethod */
+       NULL, /* CallNonvirtualByteMethodV */
+       NULL, /* CallNonvirtualByteMethodA */
+       NULL, /* CallNonvirtualCharMethod */
+       NULL, /* CallNonvirtualCharMethodV */
+
+       /* 75 */
+       NULL, /* CallNonvirtualCharMethodA */
+       NULL, /* CallNonvirtualShortMethod */
+       NULL, /* CallNonvirtualShortMethodV */
+       NULL, /* CallNonvirtualShortMethodA */
+       NULL, /* CallNonvirtualIntMethod */
+
+       /* 80 */
+       NULL, /* CallNonvirtualIntMethodV */
+       NULL, /* CallNonvirtualIntMethodA */
+       NULL, /* CallNonvirtualLongMethod */
+       NULL, /* CallNonvirtualLongMethodV */
+       NULL, /* CallNonvirtualLongMethodA */
+
+       /* 85 */
+       NULL, /* CallNonvirtualFloatMethod */
+       NULL, /* CallNonvirtualFloatMethodV */
+       NULL, /* CallNonvirtualFloatMethodA */
+       NULL, /* CallNonvirtualDoubleMethod */
+       NULL, /* CallNonvirtualDoubleMethodV */
+
+       /* 90 */
+       NULL, /* CallNonvirtualDoubleMethodA */
+       NULL, /* CallNonvirtualVoidMethod */
+       NULL, /* CallNonvirtualVoidMethodV */
+       NULL, /* CallNonvirtualVoidMethodA */
+       vm_jni_get_field_id,
+
+       /* 95 */
+       NULL, /* GetObjectField */
+       NULL, /* GetBooleanField */
+       NULL, /* GetByteField */
+       NULL, /* GetCharField */
+       NULL, /* GetShortField */
+
+       /* 100 */
+       NULL, /* GetIntField */
+       NULL, /* GetLongField */
+       NULL, /* GetFloatField */
+       NULL, /* GetDoubleField */
+       NULL, /* SetObjectField */
+
+       /* 105 */
+       NULL, /* SetBooleanField */
+       NULL, /* SetByteField */
+       NULL, /* SetCharField */
+       NULL, /* SetShortField */
+       NULL, /* SetIntField */
+
+       /* 110 */
+       NULL, /* SetLongField */
+       NULL, /* SetFloatField */
+       NULL, /* SetDoubleField */
+       NULL, /* GetStaticMethodID */
+       NULL, /* CallStaticObjectMethod */
+
+       /* 115 */
+       NULL, /* CallStaticObjectMethodV */
+       NULL, /* CallStaticObjectMethodA */
+       NULL, /* CallStaticBooleanMethod */
+       NULL, /* CallStaticBooleanMethodV */
+       NULL, /* CallStaticBooleanMethodA */
+
+       /* 120 */
+       NULL, /* CallStaticByteMethod */
+       NULL, /* CallStaticByteMethodV */
+       NULL, /* CallStaticByteMethodA */
+       NULL, /* CallStaticCharMethod */
+       NULL, /* CallStaticCharMethodV */
+
+       /* 125 */
+       NULL, /* CallStaticCharMethodA */
+       NULL, /* CallStaticShortMethod */
+       NULL, /* CallStaticShortMethodV */
+       NULL, /* CallStaticShortMethodA */
+       NULL, /* CallStaticIntMethod */
+
+       /* 130 */
+       NULL, /* CallStaticIntMethodV */
+       NULL, /* CallStaticIntMethodA */
+       NULL, /* CallStaticLongMethod */
+       NULL, /* CallStaticLongMethodV */
+       NULL, /* CallStaticLongMethodA */
+
+       /* 135 */
+       NULL, /* CallStaticFloatMethod */
+       NULL, /* CallStaticFloatMethodV */
+       NULL, /* CallStaticFloatMethodA */
+       NULL, /* CallStaticDoubleMethod */
+       NULL, /* CallStaticDoubleMethodV */
+
+       /* 140 */
+       NULL, /* CallStaticDoubleMethodA */
+       NULL, /* CallStaticVoidMethod */
+       NULL, /* CallStaticVoidMethodV */
+       NULL, /* CallStaticVoidMethodA */
+       NULL, /* GetStaticFieldID */
+
+       /* 145 */
+       NULL, /* GetStaticObjectField */
+       NULL, /* GetStaticBooleanField */
+       NULL, /* GetStaticByteField */
+       NULL, /* GetStaticCharField */
+       NULL, /* GetStaticShortField */
+
+       /* 150 */
+       NULL, /* GetStaticIntField */
+       NULL, /* GetStaticLongField */
+       NULL, /* GetStaticFloatField */
+       NULL, /* GetStaticDoubleField */
+       NULL, /* SetStaticObjectField */
+
+       /* 155 */
+       NULL, /* SetStaticBooleanField */
+       NULL, /* SetStaticByteField */
+       NULL, /* SetStaticCharField */
+       NULL, /* SetStaticShortField */
+       NULL, /* SetStaticIntField */
+
+       /* 160 */
+       NULL, /* SetStaticLongField */
+       NULL, /* SetStaticFloatField */
+       NULL, /* SetStaticDoubleField */
+       NULL, /* NewString */
+       NULL, /* GetStringLength */
+
+       /* 165 */
+       NULL, /* GetStringChars */
+       NULL, /* ReleaseStringChars */
+       NULL, /* NewStringUTF */
+       NULL, /* GetStringUTFLength */
+       NULL, /* GetStringUTFChars */
+
+       /* 170 */
+       NULL, /* ReleaseStringUTFChars */
+       NULL, /* GetArrayLength */
+       NULL, /* NewObjectArray */
+       NULL, /* GetObjectArrayElement */
+       NULL, /* SetObjectArrayElement */
+
+       /* 175 */
+       NULL, /* NewBooleanArray */
+       NULL, /* NewByteArray */
+       NULL, /* NewCharArray */
+       NULL, /* NewShortArray */
+       NULL, /* NewIntArray */
+
+       /* 180 */
+       NULL, /* NewLongArray */
+       NULL, /* NewFloatArray */
+       NULL, /* NewDoubleArray */
+       NULL, /* GetBooleanArrayElements */
+       NULL, /* GetByteArrayElements */
+
+       /* 185 */
+       NULL, /* GetCharArrayElements */
+       NULL, /* GetShortArrayElements */
+       NULL, /* GetIntArrayElements */
+       NULL, /* GetLongArrayElements */
+       NULL, /* GetFloatArrayElements */
+
+       /* 190 */
+       NULL, /* GetDoubleArrayElements */
+       NULL, /* ReleaseBooleanArrayElements */
+       NULL, /* ReleaseByteArrayElements */
+       NULL, /* ReleaseCharArrayElements */
+       NULL, /* ReleaseShortArrayElements */
+
+       /* 195 */
+       NULL, /* ReleaseIntArrayElements */
+       NULL, /* ReleaseLongArrayElements */
+       NULL, /* ReleaseFloatArrayElements */
+       NULL, /* ReleaseDoubleArrayElements */
+       NULL, /* GetBooleanArrayRegion */
+
+       /* 200 */
+       NULL, /* GetByteArrayRegion */
+       NULL, /* GetCharArrayRegion */
+       NULL, /* GetShortArrayRegion */
+       NULL, /* GetIntArrayRegion */
+       NULL, /* GetLongArrayRegion */
+
+       /* 205 */
+       NULL, /* GetFloatArrayRegion */
+       NULL, /* GetDoubleArrayRegion */
+       NULL, /* SetBooleanArrayRegion */
+       NULL, /* SetByteArrayRegion */
+       NULL, /* SetCharArrayRegion */
+
+       /* 210 */
+       NULL, /* SetShortArrayRegion */
+       NULL, /* SetIntArrayRegion */
+       NULL, /* SetLongArrayRegion */
+       NULL, /* SetFloatArrayRegion */
+       NULL, /* SetDoubleArrayRegion */
+
+       /* 215 */
+       NULL, /* RegisterNatives */
+       NULL, /* UnregisterNatives */
+       NULL, /* MonitorEnter */
+       NULL, /* MonitorExit */
+       NULL, /* GetJavaVM */
+
+       /* 220 */
+       NULL, /* GetJavaVM */
+};
+
+struct vm_jni_env vm_jni_default_env = {
+       .jni_table = vm_jni_native_interface,
+};
+
+struct vm_jni_env *vm_jni_get_jni_env()
+{
+       return &vm_jni_default_env;
+}
+
+static void *jni_not_implemented_trap;
+
+void vm_jni_init(void)
+{
+       jni_not_implemented_trap = alloc_guard_page();
+       if (!jni_not_implemented_trap)
+               die("guard page alloc failed");
+
+       /* Initialize traps in the vm_jni_default_native_interface[] */
+       unsigned int table_size = ARRAY_SIZE(vm_jni_native_interface);
+       for (unsigned int i = 0; i < table_size; i++) {
+               if (vm_jni_native_interface[i])
+                       continue;
+
+               vm_jni_native_interface[i] =
+                       jni_not_implemented_trap + i;
+       }
+}
+
+bool vm_jni_check_trap(void *ptr)
+{
+       int table_size;
+       int index;
+
+       index = (int)(ptr - jni_not_implemented_trap);
+       table_size = ARRAY_SIZE(vm_jni_native_interface);
+
+       if (index < 0 || index >= table_size)
+               return false;
+
+       die("JNI handler for index %d not implemented.\n", index);
+       return true;
+}
diff --git a/vm/jni.c b/vm/jni.c
new file mode 100644
index 0000000..3b8ec15
--- /dev/null
+++ b/vm/jni.c
@@ -0,0 +1,162 @@
+#include <dlfcn.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jit/disassemble.h"
+
+#include "vm/die.h"
+#include "vm/jni.h"
+
+#include "lib/string.h"
+
+static char *vm_jni_get_mangled_name(const char *name)
+{
+       struct string *str;
+       char *result;
+       int err;
+       int i;
+
+       str = alloc_str();
+       if (!str) {
+               NOT_IMPLEMENTED;
+               return NULL;
+       }
+
+       result = NULL;
+
+       for (i = 0; name[i]; i++) {
+               if (name[i] == '_')
+                       err = str_append(str, "_1");
+               else if (name[i] == ';')
+                       err = str_append(str, "_2");
+               else if (name[i] == '[')
+                       err = str_append(str, "_3");
+               else if (name[i] == '/')
+                       err = str_append(str, "_");
+               else if (name[i] & 0x80) {
+                       /* Unicode characters should be transformed to
+                          "_0xxxx" */
+                       NOT_IMPLEMENTED;
+               } else
+                       err = str_append(str, "%c", (char)name[i]);
+
+               if (err)
+                       goto out;
+       }
+
+       result = strdup(str->value);
+
+ out:
+       free_str(str);
+
+       return result;
+}
+
+static int vm_jni_lookup_object_handle(void *handle)
+{
+       for (int i = 0; i < vm_jni_nr_loaded_objects; i++)
+               if (vm_jni_loaded_objects[i] == handle)
+                       return i;
+
+       return -1;
+}
+
+static int vm_jni_add_object_handle(void *handle)
+{
+       void **new_table;
+       int new_size;
+
+       if (vm_jni_lookup_object_handle(handle) >= 0)
+               return 0; /* handle already in table */
+
+       new_size = sizeof(void *) * (vm_jni_nr_loaded_objects + 1);
+       new_table = realloc(vm_jni_loaded_objects, new_size);
+       if (!new_table)
+               return -ENOMEM;
+
+       vm_jni_loaded_objects = new_table;
+       vm_jni_loaded_objects[vm_jni_nr_loaded_objects++] = handle;
+
+       return 0;
+}
+
+int vm_jni_load_object(const char *name)
+{
+       char *classpath_install_dir;
+       void *handle;
+
+       classpath_install_dir = getenv("CLASSPATH_INSTALL_DIR");
+       if (!classpath_install_dir) {
+               warn("environment variable CLASSPATH_INSTALL_DIR not set");
+               return -1;
+       }
+
+       char *so_name = NULL;
+       asprintf(&so_name, "%s/lib/classpath/%s", classpath_install_dir, name);
+
+       handle = dlopen(so_name, RTLD_NOW);
+       free(so_name);
+
+       if (!handle) {
+               fprintf(stderr, "%s: %s\n", __func__, dlerror());
+               return -1;
+       }
+
+       if (vm_jni_add_object_handle(handle)) {
+               dlclose(handle);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void *vm_jni_lookup_symbol(const char *symbol_name)
+{
+       for (int i = 0; i < vm_jni_nr_loaded_objects; i++) {
+               void *addr;
+
+               addr = dlsym(vm_jni_loaded_objects[i], symbol_name);
+               if (addr)
+                       return addr;
+       }
+
+       return NULL;
+}
+
+void *vm_jni_lookup_method(const char *class_name, const char *method_name,
+                          const char *method_type)
+{
+       char *mangled_class_name;
+       char *mangled_method_name;
+       char *mangled_method_type;
+       char *symbol_name;
+       void *sym_addr;
+
+       mangled_class_name = vm_jni_get_mangled_name(class_name);
+       mangled_method_name = vm_jni_get_mangled_name(method_name);
+       mangled_method_type = vm_jni_get_mangled_name(method_type);
+
+       symbol_name = NULL;
+       asprintf(&symbol_name, "Java_%s_%s__%s", mangled_class_name,
+                mangled_method_name, mangled_method_type);
+
+       sym_addr = vm_jni_lookup_symbol(symbol_name);
+       if (sym_addr)
+               goto out;
+
+       asprintf(&symbol_name, "Java_%s_%s", mangled_class_name,
+                mangled_method_name);
+
+       sym_addr = vm_jni_lookup_symbol(symbol_name);
+
+ out:
+       free(mangled_method_name);
+       free(mangled_class_name);
+       free(mangled_method_type);
+       free(symbol_name);
+
+       return sym_addr;
+}
diff --git a/vm/method.c b/vm/method.c
index 39d0bf3..c4a7eb2 100644
--- a/vm/method.c
+++ b/vm/method.c
@@ -129,6 +129,8 @@ int vm_method_prepare_jit(struct vm_method *vmm)
                return -1;
        }
 
+       vmm->jni_trampoline = NULL;
+
        vmm->trampoline = build_jit_trampoline(vmm->compilation_unit);
        if (!vmm->trampoline) {
                NOT_IMPLEMENTED;
diff --git a/vm/preload.c b/vm/preload.c
index 264d7ab..9faabf9 100644
--- a/vm/preload.c
+++ b/vm/preload.c
@@ -54,6 +54,8 @@ struct vm_class *vm_java_lang_ArrayIndexOutOfBoundsException;
 struct vm_class *vm_java_lang_ArrayStoreException;
 struct vm_class *vm_java_lang_RuntimeException;
 struct vm_class *vm_java_lang_ExceptionInInitializerError;
+struct vm_class *vm_java_lang_NoSuchFieldError;
+struct vm_class *vm_java_lang_NoSuchMethodError;
 struct vm_class *vm_boolean_class;
 struct vm_class *vm_char_class;
 struct vm_class *vm_float_class;
@@ -83,6 +85,8 @@ static const struct preload_entry preload_entries[] = {
        { "java/lang/NullPointerException", &vm_java_lang_NullPointerException 
},
        { "java/lang/RuntimeException", &vm_java_lang_RuntimeException },
        { "java/lang/UnsatisfiedLinkError", &vm_java_lang_UnsatisfiedLinkError 
},
+       { "java/lang/NoSuchFieldError", &vm_java_lang_NoSuchFieldError },
+       { "java/lang/NoSuchMethodError", &vm_java_lang_NoSuchMethodError },
 };
 
 static const struct preload_entry primitive_preload_entries[] = {
diff --git a/vm/signal.c b/vm/signal.c
index 430699d..da2b6d4 100644
--- a/vm/signal.c
+++ b/vm/signal.c
@@ -31,6 +31,7 @@
 #include "vm/signal.h"
 #include "vm/class.h"
 #include "vm/object.h"
+#include "vm/jni.h"
 
 #include "arch/signal.h"
 
@@ -137,6 +138,8 @@ static void sigsegv_handler(int sig, siginfo_t *si, void 
*ctx)
        }
 
  exit:
+       vm_jni_check_trap(si->si_addr);
+
        print_backtrace_and_die(sig, si, ctx);
 }
 
-- 
1.6.0.6


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

Reply via email to