We can't decide at compile-time whether called method is JNI.
That's because methods declared as native in one class can
be overriden in subclass and be non-native.

Solution for this is to call potential JNI methods like any
other methods. Method pointers for actual JNI methods
point to a trampoline which takes care of pushing
pointer to JNI environment and class object reference
for static methods.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 arch/x86/emit-code.c               |   71 ++++++++++++++++----
 arch/x86/insn-selector.brg         |  128 +-----------------------------------
 include/jit/emit-code.h            |    2 +
 include/vm/stack-trace.h           |    8 +-
 jit/args.c                         |   60 ++---------------
 jit/trampoline.c                   |   23 ++++---
 regression/jvm/StackTraceTest.java |    8 +--
 test/vm/stack-trace-stub.c         |    7 +-
 vm/call.c                          |   56 ----------------
 vm/method.c                        |    7 --
 vm/stack-trace.c                   |   11 ++--
 11 files changed, 97 insertions(+), 284 deletions(-)

diff --git a/arch/x86/emit-code.c b/arch/x86/emit-code.c
index c4887a5..91fcf2b 100644
--- a/arch/x86/emit-code.c
+++ b/arch/x86/emit-code.c
@@ -1856,12 +1856,7 @@ void emit_trampoline(struct compilation_unit *cu,
        __emit_push_reg(buf, MACH_REG_EAX);
 
        if (method_is_virtual(cu->method)) {
-               /* For JNI calls 'this' pointer is in the second call
-                  argument. */
-               if (vm_method_is_jni(cu->method))
-                       __emit_push_membase(buf, MACH_REG_EBP, 0x0c);
-               else
-                       __emit_push_membase(buf, MACH_REG_EBP, 0x08);
+               __emit_push_membase(buf, MACH_REG_EBP, 0x08);
 
                __emit_push_imm(buf, (unsigned long)cu);
                __emit_call(buf, fixup_vtable);
@@ -1886,6 +1881,63 @@ static void fixup_branch_target(uint8_t *target_p, void 
*target)
        target_p[0] = cur;
 }
 
+void emit_jni_trampoline(struct buffer *buf, struct vm_method *vmm,
+                        void *target)
+{
+       uint8_t *jne_target;
+
+       jit_text_lock();
+
+       buf->buf = jit_text_ptr();
+
+       /* return address is passed implicitly as last argument */
+       __emit_push_imm(buf, (unsigned long) vmm);
+       __emit_push_reg(buf, MACH_REG_EBP);
+
+       /* If this returns non-zero then StackOverflowError occurred. */
+       __emit_call(buf, vm_enter_jni);
+
+       /* test %eax, %eax */
+       __emit_reg_reg(buf, 0x33, MACH_REG_EAX, MACH_REG_EAX);
+
+       /* jne */
+       emit(buf, 0x0f);
+       emit(buf, 0x85);
+       jne_target = buffer_current(buf);
+       emit_imm32(buf, 0);
+
+       /* Cleanup call arguments and return address. */
+       __emit_add_imm_reg(buf, 3 * sizeof(long), MACH_REG_ESP);
+
+       if (vm_method_is_static(vmm))
+               __emit_push_imm(buf, (unsigned long) vmm->class->object);
+
+       __emit_push_imm(buf, (unsigned long) vm_jni_get_jni_env());
+
+       __emit_call(buf, target);
+
+       /* Cleanup args. Leave one slot for return address. */
+       if (vm_method_is_static(vmm))
+               __emit_add_imm_reg(buf, sizeof(long), MACH_REG_ESP);
+
+       __emit_push_reg(buf, MACH_REG_EAX);
+       __emit_call(buf, vm_leave_jni);
+       __emit_mov_reg_membase(buf, MACH_REG_EAX, MACH_REG_ESP, sizeof(long));
+       __emit_pop_reg(buf, MACH_REG_EAX);
+
+       emit_ret(buf);
+
+       /* We will jump here if StackOverflowError occurred. */
+       fixup_branch_target(jne_target, buffer_current(buf));
+
+       /* cleanup vm_enter_jni() call arguments. */
+       __emit_add_imm_reg(buf, 2 * sizeof(long), MACH_REG_ESP);
+       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)
@@ -2786,12 +2838,7 @@ void emit_trampoline(struct compilation_unit *cu,
 
                __emit64_mov_imm_reg(buf, (unsigned long) cu, MACH_REG_RDI);
 
-               /* For JNI calls 'this' pointer is in the second call
-                  argument. */
-               if (vm_method_is_jni(cu->method))
-                       __emit64_mov_membase_reg(buf, MACH_REG_RBP, 0x18, 
MACH_REG_RSI);
-               else
-                       __emit64_mov_membase_reg(buf, MACH_REG_RBP, 0x10, 
MACH_REG_RSI);
+               __emit64_mov_membase_reg(buf, MACH_REG_RBP, 0x10, MACH_REG_RSI);
 
                __emit64_mov_reg_reg(buf, MACH_REG_RAX, MACH_REG_RDX);
                __emit_call(buf, fixup_vtable);
diff --git a/arch/x86/insn-selector.brg b/arch/x86/insn-selector.brg
index 42041cb..01b57d7 100644
--- a/arch/x86/insn-selector.brg
+++ b/arch/x86/insn-selector.brg
@@ -746,10 +746,7 @@ reg:       EXPR_INVOKEINTERFACE(arg) 1
        /* invoke method */
        call_insn = reg_insn(INSN_CALL_REG, call_target);
 
-       if (vm_method_is_jni(method))
-               select_jni_call(s, tree, call_insn, method);
-       else
-               select_insn(s, tree, call_insn);
+       select_insn(s, tree, call_insn);
 
        nr_stack_args = get_stack_args_count(method);
        if (nr_stack_args)
@@ -2748,120 +2745,6 @@ emulate_op_64(struct _MBState *state, struct 
basic_block *s,
 }
 
 #ifdef CONFIG_X86_32
-static void select_jni_set_call_site_addr(struct basic_block *s,
-                                         struct tree_node *tree,
-                                         struct var_info *offset_reg,
-                                         unsigned long field)
-{
-       select_insn(s, tree,
-                   membase_insn(INSN_MOV_IP_THREAD_LOCAL_MEMBASE,
-                                offset_reg, field));
-}
-
-static void select_jni_set_method(struct basic_block *s,
-                                 struct tree_node *tree,
-                                 struct vm_method *method,
-                                 struct var_info *offset_reg,
-                                 unsigned long field)
-{
-       select_insn(s, tree, imm_membase_insn(INSN_MOV_IMM_THREAD_LOCAL_MEMBASE,
-                               (unsigned long) method, offset_reg, field));
-}
-#else /* CONFIG_X86_32 */
-static void select_jni_set_call_site_addr(struct basic_block *s,
-                                         struct tree_node *tree,
-                                         struct var_info *offset_reg,
-                                         unsigned long field)
-{
-       struct var_info *ip_reg;
-
-       ip_reg = get_var(s->b_parent, J_LONG);
-
-       select_insn(s, tree, reg_insn(INSN_MOV_IP_REG, ip_reg));
-       select_insn(s, tree,
-                   reg_membase_insn(INSN_MOV_REG_THREAD_LOCAL_MEMBASE,
-                                    ip_reg, offset_reg, field));
-}
-
-static void select_jni_set_method(struct basic_block *s,
-                                 struct tree_node *tree,
-                                 struct vm_method *method,
-                                 struct var_info *offset_reg,
-                                 unsigned long field)
-{
-       struct var_info *method_reg;
-
-       method_reg = get_var(s->b_parent, J_LONG);
-
-       select_insn(s, tree,
-                   imm_reg_insn(INSN_MOV_IMM_REG,
-                                (unsigned long) method, method_reg));
-       select_insn(s, tree,
-                   reg_membase_insn(INSN_MOV_REG_THREAD_LOCAL_MEMBASE,
-                                    method_reg, offset_reg, field));
-}
-#endif /* CONFIG_X86_32 */
-
-static void select_jni_call(struct basic_block *s, struct tree_node *tree,
-                           struct insn *call_insn, struct vm_method *method)
-{
-       struct var_info *offset_reg;
-       struct var_info *frame_reg;
-       unsigned long offset_tls;
-       unsigned long tr_addr;
-       unsigned long guard;
-       unsigned long field;
-
-       frame_reg = get_fixed_var(s->b_parent, MACH_REG_xBP);
-       offset_reg = get_var(s->b_parent, J_REFERENCE);
-
-       offset_tls = get_thread_local_offset(&jni_stack_offset);
-       select_insn(s, tree,
-                   memdisp_reg_insn(INSN_MOV_THREAD_LOCAL_MEMDISP_REG,
-                                    offset_tls, offset_reg));
-
-       tr_addr = get_thread_local_offset(&jni_stack);
-
-       /* Check for stack overflow */
-       guard = (unsigned long) jni_stack_offset_guard;
-       select_insn(s, tree, membase_reg_insn(INSN_TEST_MEMBASE_REG,
-                                             offset_reg, guard, offset_reg));
-
-       /* Advance jni_stack_offset */
-       select_insn(s, tree,
-               imm_reg_insn(INSN_ADD_IMM_REG, sizeof(struct jni_stack_entry),
-                            offset_reg));
-       select_insn(s, tree,
-                   reg_memdisp_insn(INSN_MOV_REG_THREAD_LOCAL_MEMDISP,
-                                    offset_reg, offset_tls));
-
-       tr_addr -= sizeof(struct jni_stack_entry);
-
-       /* Set ->caller_frame */
-       field = tr_addr + offsetof(struct jni_stack_entry, caller_frame);
-       select_insn(s, tree, reg_membase_insn(INSN_MOV_REG_THREAD_LOCAL_MEMBASE,
-                                             frame_reg, offset_reg, field));
-
-       /* Set ->call_site_addr */
-       field = tr_addr + offsetof(struct jni_stack_entry, call_site_addr);
-       select_jni_set_call_site_addr(s, tree, offset_reg, field);
-
-       /* Set ->method */
-       field = tr_addr + offsetof(struct jni_stack_entry, method);
-       select_jni_set_method(s, tree, method, offset_reg, field);
-
-       select_insn(s, tree, call_insn);
-
-       /* Restore jni_stack_ffset (pop) */
-       select_insn(s, tree,
-               imm_reg_insn(INSN_SUB_IMM_REG, sizeof(struct jni_stack_entry),
-                            offset_reg));
-       select_insn(s, tree,
-                   reg_memdisp_insn(INSN_MOV_REG_THREAD_LOCAL_MEMDISP,
-                                    offset_reg, offset_tls));
-}
-
-#ifdef CONFIG_X86_32
 static void select_set_target(struct basic_block *s,
                              struct tree_node *tree,
                              void *target,
@@ -3006,9 +2889,7 @@ static void invoke(struct basic_block *s, struct 
tree_node *tree, struct compila
 
        call_insn = rel_insn(INSN_CALL_REL, (unsigned long) target);
 
-       if (vm_method_is_jni(method))
-               select_jni_call(s, tree, call_insn, method);
-       else if (vm_method_is_vm_native(method))
+       if (vm_method_is_vm_native(method))
                select_vm_native_call(s, tree, call_insn,
                                      vm_method_native_ptr(method));
        else
@@ -3065,10 +2946,7 @@ static void invokevirtual(struct _MBState *state, struct 
basic_block *s, struct
        /* invoke method */
        call_insn = reg_insn(INSN_CALL_REG, call_target);
 
-       if (vm_method_is_jni(method))
-               select_jni_call(s, tree, call_insn, method);
-       else
-               select_insn(s, tree, call_insn);
+       select_insn(s, tree, call_insn);
 
        nr_stack_args = get_stack_args_count(method);
        if (nr_stack_args)
diff --git a/include/jit/emit-code.h b/include/jit/emit-code.h
index d012c36..0b7c898 100644
--- a/include/jit/emit-code.h
+++ b/include/jit/emit-code.h
@@ -8,6 +8,7 @@ struct buffer;
 struct insn;
 struct vm_object;
 struct vm_jni_env;
+struct vm_method;
 
 enum emitter_type {
        NO_OPERANDS = 1,
@@ -40,5 +41,6 @@ extern void emit_insn(struct buffer *, struct basic_block *, 
struct insn *);
 extern void emit_nop(struct buffer *buf);
 extern void backpatch_branch_target(struct buffer *buf, struct insn *insn,
                                    unsigned long target_offset);
+extern void emit_jni_trampoline(struct buffer *, struct vm_method *, void *);
 
 #endif /* JATO_EMIT_CODE_H */
diff --git a/include/vm/stack-trace.h b/include/vm/stack-trace.h
index dcb68ac..de04ad5 100644
--- a/include/vm/stack-trace.h
+++ b/include/vm/stack-trace.h
@@ -16,7 +16,7 @@ struct vm_class;
 
 struct jni_stack_entry {
        void *caller_frame;
-       unsigned long call_site_addr;
+       unsigned long return_address;
 
        /* We don't know the address of JNI callee at compilation time
         * so code generated for JNI call site stores a pointer to
@@ -51,10 +51,10 @@ extern __thread unsigned long jni_stack_offset;
 extern __thread struct vm_native_stack_entry 
vm_native_stack[VM_NATIVE_STACK_SIZE];
 extern __thread unsigned long vm_native_stack_offset;
 
-int vm_enter_jni(void *caller_frame, unsigned long call_site_addr,
-                struct vm_method *method);
+int vm_enter_jni(void *caller_frame, struct vm_method *method,
+                unsigned long return_address);
 int vm_enter_vm_native(void *target, void *stack_ptr);
-void vm_leave_jni(void);
+unsigned long vm_leave_jni(void);
 void vm_leave_vm_native(void);
 
 static inline int jni_stack_index(void)
diff --git a/jit/args.c b/jit/args.c
index 3da92a8..46caee0 100644
--- a/jit/args.c
+++ b/jit/args.c
@@ -33,7 +33,6 @@
 
 #include "vm/method.h"
 #include "vm/stack.h"
-#include "vm/jni.h"
 
 #ifdef CONFIG_ARGS_MAP
 int get_stack_args_count(struct vm_method *method)
@@ -70,22 +69,11 @@ insert_arg(struct expression *root,
        struct expression *_expr;
 
        /* Check if we should put @expr in EXPR_ARG_THIS. */
-       if (!vm_method_is_static(method)) {
-               if (vm_method_is_jni(method)) {
-                       if (index == 1) {
-                               _expr = arg_this_expr(expr);
-                               goto from_expr_this;
-                       }
-               } else
-                       if (index == 0) {
-                               _expr = arg_this_expr(expr);
-                               goto from_expr_this;
-                       }
-       }
-
-       _expr = arg_expr(expr);
+       if (!vm_method_is_static(method) && index == 0)
+               _expr = arg_this_expr(expr);
+       else
+               _expr = arg_expr(expr);
 
- from_expr_this:
        _expr->bytecode_offset = expr->bytecode_offset;
        set_expr_arg_reg(_expr, method, index);
 
@@ -100,7 +88,6 @@ struct expression *convert_args(struct stack *mimic_stack,
                                struct vm_method *method)
 {
        struct expression *args_list = NULL;
-       unsigned long nr_args_total;
        unsigned long i;
 
        if (nr_args == 0) {
@@ -108,15 +95,6 @@ struct expression *convert_args(struct stack *mimic_stack,
                goto out;
        }
 
-       nr_args_total = nr_args;
-
-       if (vm_method_is_jni(method)) {
-               if (vm_method_is_static(method))
-                       --nr_args;
-
-               --nr_args;
-       }
-
        /*
         * We scan the args map in reverse order,
         * since the order of arguments is already reversed.
@@ -124,35 +102,7 @@ struct expression *convert_args(struct stack *mimic_stack,
        for (i = 0; i < nr_args; i++) {
                struct expression *expr = stack_pop(mimic_stack);
                args_list = insert_arg(args_list, expr,
-                                      method, nr_args_total - i - 1);
-       }
-
-       if (vm_method_is_jni(method)) {
-               struct expression *jni_env_expr;
-
-               if (vm_method_is_static(method)) {
-                       struct expression *class_expr;
-
-                       class_expr = value_expr(J_REFERENCE,
-                                       (unsigned long) method->class->object);
-
-                       if (!class_expr) {
-                               expr_put(args_list);
-                               return NULL;
-                       }
-
-                       args_list = insert_arg(args_list, class_expr,
-                                              method, 1);
-               }
-
-               jni_env_expr = value_expr(J_REFERENCE,
-                                         (unsigned long)vm_jni_get_jni_env());
-               if (!jni_env_expr) {
-                       expr_put(args_list);
-                       return NULL;
-               }
-
-               args_list = insert_arg(args_list, jni_env_expr, method, 0);
+                                      method, nr_args - i - 1);
        }
 
   out:
diff --git a/jit/trampoline.c b/jit/trampoline.c
index 1637a77..009d514 100644
--- a/jit/trampoline.c
+++ b/jit/trampoline.c
@@ -49,8 +49,6 @@ static void *jit_jni_trampoline(struct compilation_unit *cu)
        struct vm_method *method;
        void *ret;
 
-       enter_vm_from_jni();
-
        method = cu->method;
 
        class_name  = method->class->name;
@@ -59,12 +57,21 @@ static void *jit_jni_trampoline(struct compilation_unit *cu)
 
        ret = vm_jni_lookup_method(class_name, method_name, method_type);
        if (ret) {
-               add_cu_mapping((unsigned long)ret, cu);
+               struct buffer *buf;
+
+               if (add_cu_mapping((unsigned long)ret, cu))
+                       return NULL;
+
+               buf = alloc_exec_buffer();
+               if (!buf)
+                       return NULL;
+
+               emit_jni_trampoline(buf, method, ret);
 
-               cu->native_ptr = ret;
+               cu->native_ptr = buffer_ptr(buf);
                cu->is_compiled = true;
 
-               return ret;
+               return cu->native_ptr;
        }
 
        struct string *msg = alloc_str();
@@ -81,12 +88,6 @@ static void *jit_jni_trampoline(struct compilation_unit *cu)
        signal_new_exception(vm_java_lang_UnsatisfiedLinkError, msg->value);
        free_str(msg);
 
-       /* We must remove the jni_stack_entry from call stack here
-        * because we're not returning after call site - exception
-        * will be caught in trampoline code and delivered to handler.
-        */
-       vm_leave_jni();
-
        return NULL;
 }
 
diff --git a/regression/jvm/StackTraceTest.java 
b/regression/jvm/StackTraceTest.java
index f50957e..e680335 100644
--- a/regression/jvm/StackTraceTest.java
+++ b/regression/jvm/StackTraceTest.java
@@ -95,13 +95,9 @@ public class StackTraceTest extends TestCase {
         }
 
         assertNotNull(st);
-        assertEquals(3, st.length);
-
-        assertStackTraceElement(st[0], -1, null,
-                "jvm.StackTraceTest",
-                "nativeMethod", true);
+        assertEquals(2, st.length);
 
-        assertStackTraceElement(st[1], 92, "StackTraceTest.java",
+        assertStackTraceElement(st[0], 92, "StackTraceTest.java",
                 "jvm.StackTraceTest",
                 "testJNIUnsatisfiedLinkErrorStackTrace",
                 false);
diff --git a/test/vm/stack-trace-stub.c b/test/vm/stack-trace-stub.c
index f54172a..38e3df7 100644
--- a/test/vm/stack-trace-stub.c
+++ b/test/vm/stack-trace-stub.c
@@ -28,14 +28,15 @@ void vm_leave_vm_native(void)
 {
 }
 
-int vm_enter_jni(void *caller_frame, unsigned long call_site_addr,
-                struct vm_method *method)
+int vm_enter_jni(void *caller_frame, struct vm_method *method,
+                unsigned long return_address)
 {
        return 0;
 }
 
-void vm_leave_jni(void)
+unsigned long vm_leave_jni(void)
 {
+       return 0;
 }
 
 void init_stack_trace_elem(struct stack_trace_elem *elem, unsigned long addr,
diff --git a/vm/call.c b/vm/call.c
index 76fc83e..c286ac8 100644
--- a/vm/call.c
+++ b/vm/call.c
@@ -34,7 +34,6 @@
 
 #include "vm/call.h"
 #include "vm/class.h"
-#include "vm/jni.h"
 #include "vm/method.h"
 #include "vm/object.h"
 #include "vm/stack-trace.h"
@@ -63,16 +62,6 @@ vm_call_method_a(struct vm_method *method, unsigned long 
*args)
 
        target = vm_method_call_ptr(method);
 
-       if (vm_method_is_jni(method)) {
-               if (vm_enter_jni(__builtin_frame_address(0),
-                                (unsigned long) &&call_site, method))
-                       return -1;
-       call_site:
-               native_call(target, args, method->args_count, result);
-               vm_leave_jni();
-               goto out;
-       }
-
        native_call(target, args, method->args_count, result);
 
  out:
@@ -82,52 +71,10 @@ vm_call_method_a(struct vm_method *method, unsigned long 
*args)
        return result;
 }
 
-
-static unsigned long
-vm_call_jni_method_v(struct vm_method *method, va_list args)
-{
-       unsigned long args_array[method->args_count];
-       int i;
-
-       i = 0;
-       args_array[i++] = (unsigned long)vm_jni_get_jni_env();
-
-       if (vm_method_is_static(method))
-               args_array[i++] = (unsigned long)method->class->object;
-
-       while (i < method->args_count)
-               args_array[i++] = va_arg(args, long);
-
-       return vm_call_method_a(method, args_array);
-}
-
-static unsigned long
-vm_call_jni_method_this_v(struct vm_method *method, struct vm_object *this,
-                         va_list args)
-{
-       unsigned long args_array[method->args_count];
-       int i;
-
-       i = 0;
-       args_array[i++] = (unsigned long)vm_jni_get_jni_env();
-
-       assert(!vm_method_is_static(method));
-
-       args_array[i++] = (unsigned long) this;
-
-       while (i < method->args_count)
-               args_array[i++] = va_arg(args, long);
-
-       return vm_call_method_a(method, args_array);
-}
-
 unsigned long vm_call_method_v(struct vm_method *method, va_list args)
 {
        unsigned long args_array[method->args_count];
 
-       if (vm_method_is_jni(method))
-               return vm_call_jni_method_v(method, args);
-
        for (int i = 0; i < method->args_count; i++)
                args_array[i] = va_arg(args, unsigned long);
 
@@ -140,9 +87,6 @@ unsigned long vm_call_method_this_v(struct vm_method *method,
 {
        unsigned long args_array[method->args_count];
 
-       if (vm_method_is_jni(method))
-               return vm_call_jni_method_this_v(method, this, args);
-
        args_array[0] = (unsigned long) this;
 
        for (int i = 1; i < method->args_count; i++)
diff --git a/vm/method.c b/vm/method.c
index ffdc021..095c1de 100644
--- a/vm/method.c
+++ b/vm/method.c
@@ -76,13 +76,6 @@ int vm_method_init(struct vm_method *vmm,
        if (vm_method_is_native(vmm)) {
                vmm->is_vm_native =
                        vm_lookup_native(vmm->class->name, vmm->name);
-
-               if (vm_method_is_jni(vmm)) {
-                       if (vm_method_is_static(vmm))
-                               ++vmm->args_count;
-
-                       ++vmm->args_count;
-               }
        }
 
        if (args_map_init(vmm)) {
diff --git a/vm/stack-trace.c b/vm/stack-trace.c
index 5f4acea..9383333 100644
--- a/vm/stack-trace.c
+++ b/vm/stack-trace.c
@@ -104,8 +104,8 @@ static inline struct vm_native_stack_entry 
*new_vm_native_stack_entry(void)
        return tr;
 }
 
-int vm_enter_jni(void *caller_frame, unsigned long call_site_addr,
-                struct vm_method *method)
+int vm_enter_jni(void *caller_frame, struct vm_method *method,
+                unsigned long return_address)
 {
        if (jni_stack_is_full()) {
                struct vm_object *e = vm_alloc_stack_overflow_error();
@@ -119,7 +119,7 @@ int vm_enter_jni(void *caller_frame, unsigned long 
call_site_addr,
        struct jni_stack_entry *tr = new_jni_stack_entry();
 
        tr->caller_frame = caller_frame;
-       tr->call_site_addr = call_site_addr;
+       tr->return_address = return_address;
        tr->method = method;
        return 0;
 }
@@ -142,9 +142,10 @@ int vm_enter_vm_native(void *target, void *stack_ptr)
        return 0;
 }
 
-void vm_leave_jni()
+unsigned long vm_leave_jni()
 {
        jni_stack_offset -= sizeof(struct jni_stack_entry);
+       return jni_stack[jni_stack_index()].return_address;
 }
 
 void vm_leave_vm_native()
@@ -172,7 +173,7 @@ int stack_trace_elem_next(struct stack_trace_elem *elem)
                        &jni_stack[elem->jni_stack_index--];
 
                new_frame = tr->caller_frame;
-               new_addr = tr->call_site_addr;
+               new_addr = tr->return_address - 1;
                goto out;
        }
 
-- 
1.6.0.6


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to