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

Reply via email to