This introduces a better approach for calling JNI methods. The approach is based on assumption that if native method is not a VM native then it is a JNI method. This lets us to prepare JNI call arguments at compilation time.
When method is prepared in vm_method_prepare_jit() it is checked whether native method is one of VM native methods and the address of it is stored in the ->vm_native_ptr field. When converting method invokation it is checked whether method is a JNI native method. If this is the case then JNI environment pointer is appended to call arguments. When static JNI method is called the class->object pointer is also appended according to the JNI specification. Signed-off-by: Tomek Grabiec <tgrab...@gmail.com> --- arch/x86/emit-code.c | 23 ----------------------- include/jit/compiler.h | 8 -------- include/vm/method.h | 9 ++++++++- jit/emit.c | 27 --------------------------- jit/invoke-bc.c | 39 +++++++++++++++++++++++++++++++++++++++ jit/trace-jit.c | 3 +++ jit/trampoline.c | 30 ++++++------------------------ test/arch-x86/Makefile | 1 + test/jit/Makefile | 1 + test/jit/invoke-bc-test.c | 21 +++++++++++++++++++++ test/vm/jni-stub.c | 8 ++++++++ vm/method.c | 21 ++++++++++++++++++++- 12 files changed, 107 insertions(+), 84 deletions(-) create mode 100644 test/vm/jni-stub.c diff --git a/arch/x86/emit-code.c b/arch/x86/emit-code.c index 6020bac..0ed73d4 100644 --- a/arch/x86/emit-code.c +++ b/arch/x86/emit-code.c @@ -21,7 +21,6 @@ #include "lib/list.h" #include "lib/buffer.h" -#include "vm/jni.h" #include "vm/method.h" #include "vm/object.h" @@ -1388,28 +1387,6 @@ 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/include/jit/compiler.h b/include/jit/compiler.h index 8584954..11df1be 100644 --- a/include/jit/compiler.h +++ b/include/jit/compiler.h @@ -31,10 +31,6 @@ struct jit_trampoline { pthread_mutex_t mutex; }; -struct jni_trampoline { - struct buffer *objcode; -}; - struct parse_context { struct compilation_unit *cu; struct basic_block *bb; @@ -60,12 +56,8 @@ 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 *); void trampoline_add_fixup_site(struct jit_trampoline *, struct fixup_site *); diff --git a/include/vm/method.h b/include/vm/method.h index fd19c16..e86df11 100644 --- a/include/vm/method.h +++ b/include/vm/method.h @@ -35,7 +35,8 @@ struct vm_method { struct compilation_unit *compilation_unit; struct jit_trampoline *trampoline; - struct jni_trampoline *jni_trampoline; + + void *vm_native_ptr; }; int vm_method_init(struct vm_method *vmm, @@ -80,6 +81,12 @@ static inline bool method_is_virtual(struct vm_method *vmm) | CAFEBABE_METHOD_ACC_PRIVATE)) == 0; } +static inline bool vm_method_is_jni_method(struct vm_method *vmm) +{ + return vmm->method->access_flags & CAFEBABE_METHOD_ACC_NATIVE + && !vmm->vm_native_ptr; +} + static inline enum vm_type method_return_type(struct vm_method *method) { char *return_type = method->type + (strlen(method->type) - 1); diff --git a/jit/emit.c b/jit/emit.c index ec79c3e..9d5c46a 100644 --- a/jit/emit.c +++ b/jit/emit.c @@ -205,35 +205,8 @@ 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/invoke-bc.c b/jit/invoke-bc.c index e5e0ff4..3a4b2da 100644 --- a/jit/invoke-bc.c +++ b/jit/invoke-bc.c @@ -19,6 +19,7 @@ #include "vm/method.h" #include "vm/stack.h" #include "vm/die.h" +#include "vm/jni.h" #include <string.h> #include <errno.h> @@ -204,6 +205,14 @@ int convert_invokevirtual(struct parse_context *ctx) return err; } +static void append_arg(struct expression *expr, struct expression *arg) +{ + struct expression *args_list; + + args_list = insert_arg(to_expr(expr->args_list), arg); + expr->args_list = &args_list->node; +} + int convert_invokespecial(struct parse_context *ctx) { struct vm_method *invoke_target; @@ -228,6 +237,17 @@ int convert_invokespecial(struct parse_context *ctx) null_check_first_arg(to_expr(expr->args_list)); + if (vm_method_is_jni_method(invoke_target)) { + struct expression *jni_env_expr; + + jni_env_expr = value_expr(J_REFERENCE, + (unsigned long)vm_jni_get_jni_env()); + if (!jni_env_expr) + goto failed; + + append_arg(expr, jni_env_expr); + } + err = insert_invoke_expr(ctx, expr); if (err) goto failed; @@ -260,6 +280,25 @@ int convert_invokestatic(struct parse_context *ctx) if (err) goto failed; + if (vm_method_is_jni_method(invoke_target)) { + struct expression *jni_env_expr; + struct expression *class_expr; + + class_expr = value_expr(J_REFERENCE, + (unsigned long)invoke_target->class->object); + if (!class_expr) + goto failed; + + append_arg(expr, class_expr); + + jni_env_expr = value_expr(J_REFERENCE, + (unsigned long)vm_jni_get_jni_env()); + if (!jni_env_expr) + goto failed; + + append_arg(expr, jni_env_expr); + } + err = insert_invoke_expr(ctx, expr); if (err) goto failed; diff --git a/jit/trace-jit.c b/jit/trace-jit.c index 7f41006..a7b4d3a 100644 --- a/jit/trace-jit.c +++ b/jit/trace-jit.c @@ -324,6 +324,9 @@ static void trace_invoke_args(struct vm_method *vmm, const char *type_str; int arg_index; + if (vm_method_is_jni_method(vmm)) + arg_index += 2; + arg_index = 0; if (!vm_method_is_static(vmm)) { diff --git a/jit/trampoline.c b/jit/trampoline.c index 0de2db5..dd9658a 100644 --- a/jit/trampoline.c +++ b/jit/trampoline.c @@ -46,31 +46,24 @@ static void *jit_native_trampoline(struct compilation_unit *cu) { const char *method_name, *class_name, *method_type; struct vm_method *method; - struct string *msg; void *ret; method = cu->method; + + if (method->vm_native_ptr) + return method->vm_native_ptr; + class_name = method->class->name; method_name = method->name; method_type = method->type; - ret = vm_lookup_native(class_name, method_name); - if (ret) { - add_cu_mapping((unsigned long)ret, 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); + return ret; } - msg = alloc_str(); + struct string *msg = alloc_str(); if (!msg) /* TODO: signal OutOfMemoryError */ die("out of memory"); @@ -150,14 +143,3 @@ struct jit_trampoline *build_jit_trampoline(struct compilation_unit *cu) 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/test/arch-x86/Makefile b/test/arch-x86/Makefile index c2b4d6d..53257ef 100644 --- a/test/arch-x86/Makefile +++ b/test/arch-x86/Makefile @@ -76,6 +76,7 @@ OBJS = \ ../../vm/utf8.o \ ../../vm/zalloc.o \ ../../vm/fault-inject.o \ + ../../vm/natives.o \ ../jamvm/alloc-stub.o \ ../jamvm/cast-stub.o \ ../jamvm/lock.o \ diff --git a/test/jit/Makefile b/test/jit/Makefile index 4182b0a..9c68e59 100644 --- a/test/jit/Makefile +++ b/test/jit/Makefile @@ -65,6 +65,7 @@ OBJS = \ ../vm/classloader-stub.o \ ../vm/object-stub.o \ ../vm/preload-stub.o \ + ../vm/jni-stub.o \ ../jit/trace-stub.o \ args-test-utils.o \ arithmetic-bc-test.o \ diff --git a/test/jit/invoke-bc-test.c b/test/jit/invoke-bc-test.c index a2c7edd..5415e4c 100644 --- a/test/jit/invoke-bc-test.c +++ b/test/jit/invoke-bc-test.c @@ -94,7 +94,12 @@ build_invoke_bb(unsigned char invoke_opc, unsigned short method_table_idx, struct expression **args) { + const struct cafebabe_method_info target_method_info = { + .access_flags = CAFEBABE_METHOD_ACC_STATIC, + }; + struct vm_method target_method = { + .method = &target_method_info, .type = type, .args_count = nr_args, .method_index = method_table_idx, @@ -197,6 +202,10 @@ static void assert_invoke_return_type(unsigned char invoke_opc, enum vm_type exp static struct basic_block * invoke_discarded_return_value(unsigned char invoke_opc, struct vm_method *target_method) { + const struct cafebabe_method_info target_method_info = { + .access_flags = CAFEBABE_METHOD_ACC_STATIC, + }; + unsigned char code[] = { invoke_opc, 0x00, 0x00, OPC_POP @@ -209,6 +218,7 @@ invoke_discarded_return_value(unsigned char invoke_opc, struct vm_method *target target_method->type = "()I"; target_method->args_count = 0; + target_method->method = &target_method_info; bb = __alloc_simple_bb(&invoker_method); convert_ir_invoke(bb->b_parent, target_method, 0); @@ -234,7 +244,12 @@ static void assert_invoke_return_value_discarded(enum expression_type expected_t static void assert_converts_to_invoke_expr(enum vm_type expected_vm_type, unsigned char opc, char *return_type, int nr_args) { + const struct cafebabe_method_info target_method_info = { + .access_flags = CAFEBABE_METHOD_ACC_STATIC, + }; + struct vm_method target_method = { + .method = &target_method_info, .type = return_type, .args_count = nr_args, }; @@ -358,6 +373,11 @@ void test_convert_invokestatic_for_void_return_type(void) unsigned char code[] = { OPC_INVOKESTATIC, 0x00, 0x00, }; + + const struct cafebabe_method_info target_method_info = { + .access_flags = CAFEBABE_METHOD_ACC_STATIC, + }; + struct vm_method method = { .code_attribute.code = code, .code_attribute.code_length = ARRAY_SIZE(code), @@ -367,6 +387,7 @@ void test_convert_invokestatic_for_void_return_type(void) mb.type = "()V"; mb.args_count = 0; + mb.method = &target_method_info; bb = __alloc_simple_bb(&method); convert_ir_invoke(bb->b_parent, &mb, 0); diff --git a/test/vm/jni-stub.c b/test/vm/jni-stub.c new file mode 100644 index 0000000..8f8d369 --- /dev/null +++ b/test/vm/jni-stub.c @@ -0,0 +1,8 @@ +#include <stdlib.h> + +#include "vm/jni.h" + +struct vm_jni_env *vm_jni_get_jni_env() +{ + return NULL; +} diff --git a/vm/method.c b/vm/method.c index c4a7eb2..5a8b688 100644 --- a/vm/method.c +++ b/vm/method.c @@ -12,6 +12,9 @@ #include "vm/class.h" #include "vm/method.h" +#include "vm/natives.h" + +#include "jit/cu-mapping.h" int vm_method_init(struct vm_method *vmm, struct vm_class *vmc, unsigned int method_index) @@ -129,8 +132,24 @@ int vm_method_prepare_jit(struct vm_method *vmm) return -1; } - vmm->jni_trampoline = NULL; + if (!vm_method_is_native(vmm)) + goto link_later; + + vmm->vm_native_ptr = NULL; + + void *native_ptr = vm_lookup_native(vmm->class->name, vmm->name); + if (native_ptr) { + vmm->vm_native_ptr = native_ptr; + + if (add_cu_mapping((unsigned long)native_ptr, + vmm->compilation_unit)) + { + NOT_IMPLEMENTED; + return -1; + } + } +link_later: vmm->trampoline = build_jit_trampoline(vmm->compilation_unit); if (!vmm->trampoline) { NOT_IMPLEMENTED; -- 1.6.0.6 ------------------------------------------------------------------------------ _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel