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