Motivation: Exception manager will need to translate native
instruction pointers to bytecode offsets to select appropriate
exception handler from exception_table.

Signed-off-by: Tomek Grabiec <[email protected]>
---
 Makefile                            |    3 +-
 arch/x86/include/arch/instruction.h |    1 +
 arch/x86/insn-selector_32.brg       |  294 ++++++++++++++++++-----------------
 arch/x86/instruction.c              |    3 +
 include/jit/bc-offset-mapping.h     |   19 +++
 include/jit/expression.h            |    2 +
 include/jit/statement.h             |    1 +
 jit/args.c                          |    9 +-
 jit/bc-offset-mapping.c             |  112 +++++++++++++
 jit/bytecode-to-ir.c                |   29 ++++
 jit/compiler.c                      |    3 +
 jit/expression.c                    |    2 +
 jit/invoke-bc.c                     |   11 +-
 jit/spill-reload.c                  |    4 +
 jit/statement.c                     |    2 +
 test/arch-x86/Makefile              |    1 +
 test/include/arch/instruction.h     |    3 +
 test/jit/Makefile                   |    1 +
 18 files changed, 353 insertions(+), 147 deletions(-)
 create mode 100644 include/jit/bc-offset-mapping.h
 create mode 100644 jit/bc-offset-mapping.c

diff --git a/Makefile b/Makefile
index 9dd15c9..6b2a12d 100644
--- a/Makefile
+++ b/Makefile
@@ -79,7 +79,8 @@ JIT_OBJS = \
        jit/typeconv-bc.o       \
        jit/vtable.o            \
        jit/fixup-site.o        \
-       jit/exception.o
+       jit/exception.o         \
+       jit/bc-offset-mapping.o
 
 VM_OBJS = \
        vm/bitset.o             \
diff --git a/arch/x86/include/arch/instruction.h 
b/arch/x86/include/arch/instruction.h
index ec5f4cb..cbeaad9 100644
--- a/arch/x86/include/arch/instruction.h
+++ b/arch/x86/include/arch/instruction.h
@@ -120,6 +120,7 @@ struct insn {
        /* Position of this instruction in LIR.  */
        unsigned long lir_pos;
        bool escaped;
+       unsigned long bytecode_offset;
 };
 
 static inline unsigned long lir_position(struct use_position *reg)
diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg
index 9dcc26c..61430a0 100644
--- a/arch/x86/insn-selector_32.brg
+++ b/arch/x86/insn-selector_32.brg
@@ -13,6 +13,7 @@
 #include <jit/emulate.h>
 #include <jit/expression.h>
 #include <jit/statement.h>
+#include <jit/bc-offset-mapping.h>
 
 #include <arch/instruction.h>
 #include <arch/stack-frame.h>
@@ -40,6 +41,9 @@
 #define MONOBURG_LOG 1
 #define HAVE_ARRAY_ELEM_INIT 1
 
+static void select_insn(struct basic_block *bb, struct tree_node *tree,
+                       struct insn *instruction);
+
 static unsigned char type_to_scale(enum vm_type vm_type)
 {
        unsigned char scale;
@@ -63,7 +67,8 @@ static unsigned char type_to_scale(enum vm_type vm_type)
        return scale;
 }
 
-static void method_args_cleanup(struct basic_block *bb, unsigned long 
args_count)
+static void method_args_cleanup(struct basic_block *bb, struct tree_node *tree,
+                               unsigned long args_count)
 {
        struct var_info *stack_ptr;
        unsigned long args_size;
@@ -71,7 +76,7 @@ static void method_args_cleanup(struct basic_block *bb, 
unsigned long args_count
        stack_ptr = bb->b_parent->stack_ptr;
        args_size = args_count * sizeof(uint32_t);
 
-       bb_add_insn(bb, imm_reg_insn(INSN_ADD_IMM_REG, args_size, stack_ptr));
+       select_insn(bb, tree, imm_reg_insn(INSN_ADD_IMM_REG, args_size, 
stack_ptr));
 }
 
 struct _MBState;
@@ -128,12 +133,12 @@ reg:      EXPR_VALUE      0
        result = get_var(s->b_parent);
        state->reg1 = result;
 
-       bb_add_insn(s, imm_reg_insn(INSN_MOV_IMM_REG, expr->value & ~0UL, 
result));
+       select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG, expr->value & ~0UL, 
result));
 
        if (expr->vm_type == J_LONG) {
                result = get_var(s->b_parent);
                state->reg2 = result;
-               bb_add_insn(s, imm_reg_insn(INSN_MOV_IMM_REG, expr->value >> 
32, state->reg2));
+               select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG, expr->value 
>> 32, state->reg2));
        }
 }
 
@@ -150,7 +155,7 @@ reg:        EXPR_LOCAL      1
        result = get_var(s->b_parent);
        state->reg1 = result;
 
-       bb_add_insn(s, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, result));
+       select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, 
result));
 
        if (expr->vm_type == J_LONG) {
                slot = get_local_slot(cu->stack_frame, expr->local_index + 1);
@@ -158,7 +163,7 @@ reg:        EXPR_LOCAL      1
                result = get_var(s->b_parent);
                state->reg2 = result;
 
-               bb_add_insn(s, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, 
result));
+               select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, 
slot, result));
        }
 }
 
@@ -237,7 +242,7 @@ reg:        OP_MUL(reg, EXPR_LOCAL) 1
 
        state->reg1 = eax;
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state->left->reg1, eax));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state->left->reg1, 
eax));
        __binop_reg_local(state, s, tree, INSN_MUL_MEMBASE_EAX, eax, 0);
 }
 
@@ -252,16 +257,16 @@ reg:      OP_MUL_64(reg, reg) 1
        state->reg2 = get_var(s->b_parent);
 
        tmp1 = get_var(s->b_parent);
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state->right->reg2, 
tmp1));
-       bb_add_insn(s, reg_reg_insn(INSN_MUL_REG_REG, state->left->reg1, tmp1));
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state->left->reg2, 
state->reg2));
-       bb_add_insn(s, reg_reg_insn(INSN_MUL_REG_REG, state->right->reg1, 
state->reg2));
-       bb_add_insn(s, reg_reg_insn(INSN_ADD_REG_REG, tmp1, state->reg2));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state->right->reg2, 
tmp1));
+       select_insn(s, tree, reg_reg_insn(INSN_MUL_REG_REG, state->left->reg1, 
tmp1));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state->left->reg2, 
state->reg2));
+       select_insn(s, tree, reg_reg_insn(INSN_MUL_REG_REG, state->right->reg1, 
state->reg2));
+       select_insn(s, tree, reg_reg_insn(INSN_ADD_REG_REG, tmp1, state->reg2));
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state->right->reg1, eax));
-       bb_add_insn(s, reg_reg_insn(INSN_MUL_REG_EAX, state->left->reg1, eax));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state->right->reg1, 
eax));
+       select_insn(s, tree, reg_reg_insn(INSN_MUL_REG_EAX, state->left->reg1, 
eax));
 
-       bb_add_insn(s, reg_reg_insn(INSN_ADD_REG_REG, edx, state->reg2));
+       select_insn(s, tree, reg_reg_insn(INSN_ADD_REG_REG, edx, state->reg2));
 }
 
 reg:   OP_DIV(reg, EXPR_LOCAL) 1
@@ -271,7 +276,7 @@ reg:        OP_DIV(reg, EXPR_LOCAL) 1
 
 reg:   OP_DIV_64(reg, reg) 1
 {
-       emulate_op_64(state, s, emulate_ldiv, J_LONG);
+       emulate_op_64(state, s, tree, emulate_ldiv, J_LONG);
 }
 
 reg:   OP_REM(reg, EXPR_LOCAL) 1
@@ -283,12 +288,12 @@ reg:      OP_REM(reg, EXPR_LOCAL) 1
        result = get_fixed_var(s->b_parent, REG_EAX);
        remainder = get_fixed_var(s->b_parent, REG_EDX);
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, remainder, result));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, remainder, result));
 }
 
 reg:   OP_REM_64(reg, reg) 1
 {
-       emulate_op_64(state, s, emulate_lrem, J_LONG);
+       emulate_op_64(state, s, tree, emulate_lrem, J_LONG);
 }
 
 reg:   OP_NEG(reg) 1
@@ -301,14 +306,14 @@ reg:      OP_NEG(reg) 1
        result = state->left->reg1;
        state->reg1 = result;
 
-       bb_add_insn(s, reg_insn(INSN_NEG_REG, result));
+       select_insn(s, tree, reg_insn(INSN_NEG_REG, result));
 
        if (expr->vm_type == J_LONG) {
                result = state->left->reg2;
                state->reg2 = result;
 
-               bb_add_insn(s, imm_reg_insn(INSN_ADC_IMM_REG, 0, result));
-               bb_add_insn(s, reg_insn(INSN_NEG_REG, result));
+               select_insn(s, tree, imm_reg_insn(INSN_ADC_IMM_REG, 0, result));
+               select_insn(s, tree, reg_insn(INSN_NEG_REG, result));
        }
 }
 
@@ -320,8 +325,8 @@ reg:        OP_SHL(reg, reg) 1
 
        state->reg1 = state->left->reg1;
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state->right->reg1, ecx));
-       bb_add_insn(s, reg_reg_insn(INSN_SHL_REG_REG, ecx, state->left->reg1));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state->right->reg1, 
ecx));
+       select_insn(s, tree, reg_reg_insn(INSN_SHL_REG_REG, ecx, 
state->left->reg1));
 }
 
 reg:   OP_SHL(reg, EXPR_LOCAL) 1
@@ -426,7 +431,7 @@ reg:        EXPR_INVOKE(arg) 1
        }
 
        call_insn = rel_insn(INSN_CALL_REL, (unsigned long) target);
-       bb_add_insn(s, call_insn);
+       select_insn(s, tree, call_insn);
 
        if (!is_compiled) {
                struct fixup_site *fixup;
@@ -439,7 +444,7 @@ reg:        EXPR_INVOKE(arg) 1
        }
 
        if (method->args_count)
-               method_args_cleanup(s, method->args_count);
+               method_args_cleanup(s, tree, method->args_count);
 }
 
 reg:   EXPR_INVOKEVIRTUAL(arg) 1
@@ -461,28 +466,28 @@ reg:      EXPR_INVOKEVIRTUAL(arg) 1
        stack_ptr = get_fixed_var(s->b_parent, REG_ESP);
 
        /* object reference */
-       bb_add_insn(s, membase_reg_insn(INSN_MOV_MEMBASE_REG, stack_ptr, 0, 
call_target));
+       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG, stack_ptr, 
0, call_target));
 
        /* object class */
-       bb_add_insn(s, membase_reg_insn(INSN_MOV_MEMBASE_REG, call_target, 
offsetof(struct object, class), call_target));
+       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG, 
call_target, offsetof(struct object, class), call_target));
 
        /* vtable */
-       bb_add_insn(s, membase_reg_insn(INSN_MOV_MEMBASE_REG, call_target, 
sizeof(struct object), call_target));
+       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG, 
call_target, sizeof(struct object), call_target));
 
        /* native ptr */
-       bb_add_insn(s, imm_reg_insn(INSN_ADD_IMM_REG, method_offset, 
call_target));
+       select_insn(s, tree, imm_reg_insn(INSN_ADD_IMM_REG, method_offset, 
call_target));
 
        /* invoke method */
-       bb_add_insn(s, reg_insn(INSN_CALL_REG, call_target));
+       select_insn(s, tree, reg_insn(INSN_CALL_REG, call_target));
 
        args_count = nr_args(to_expr(expr->args_list));
        if (args_count)
-               method_args_cleanup(s, args_count);
+               method_args_cleanup(s, tree, args_count);
 }
 
 reg:   OP_CMP(reg, reg) 1
 {
-       emulate_op_64(state, s, emulate_lcmp, J_INT);
+       emulate_op_64(state, s, tree, emulate_lcmp, J_INT);
 }
 
 reg:   OP_CMP(reg, EXPR_VALUE) 1
@@ -500,16 +505,16 @@ reg:      OP_CMP(reg, EXPR_VALUE) 1
                assert(!"OP_CMP implemented for J_LONG only");
        }
 
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, (unsigned long) (right->value >> 
32)));
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, (unsigned long) (right->value & 
~0UL)));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned long) 
(right->value >> 32)));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned long) 
(right->value & ~0UL)));
 
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, state->left->reg2));
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, state->left->reg1));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, state->left->reg2));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, state->left->reg1));
 
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) emulate_lcmp));
-       method_args_cleanup(s, 4);
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
emulate_lcmp));
+       method_args_cleanup(s, tree, 4);
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
 }
 
 reg:   OP_EQ(reg, EXPR_LOCAL) 1
@@ -614,13 +619,13 @@ reg:      EXPR_CLASS_FIELD 1
        state->reg1 = get_var(s->b_parent);
        field = get_var(s->b_parent);
 
-       bb_add_insn(s, imm_reg_insn(INSN_MOV_IMM_REG, (unsigned long) 
expr->class_field, field));
-       bb_add_insn(s, membase_reg_insn(INSN_MOV_MEMBASE_REG, field, offset, 
state->reg1));
+       select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG, (unsigned long) 
expr->class_field, field));
+       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG, field, 
offset, state->reg1));
 
        if (expr->vm_type == J_LONG) {
                state->reg2 = get_var(s->b_parent);
 
-               bb_add_insn(s, membase_reg_insn(INSN_MOV_MEMBASE_REG, field, 
offset+4, state->reg2));
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG, 
field, offset+4, state->reg2));
        }
 }
 
@@ -635,15 +640,15 @@ reg:      EXPR_INSTANCE_FIELD(reg) 1
        index = get_var(s->b_parent);
        state->reg1 = get_var(s->b_parent);
 
-       bb_add_insn(s, imm_reg_insn(INSN_ADD_IMM_REG, sizeof(struct object), 
base));
-       bb_add_insn(s, imm_reg_insn(INSN_MOV_IMM_REG, 
expr->instance_field->offset, index));
-       bb_add_insn(s, memindex_reg_insn(INSN_MOV_MEMINDEX_REG, base, index, 2, 
state->reg1));
+       select_insn(s, tree, imm_reg_insn(INSN_ADD_IMM_REG, sizeof(struct 
object), base));
+       select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG, 
expr->instance_field->offset, index));
+       select_insn(s, tree, memindex_reg_insn(INSN_MOV_MEMINDEX_REG, base, 
index, 2, state->reg1));
 
        if (expr->vm_type == J_LONG) {
                state->reg2 = get_var(s->b_parent);
 
-               bb_add_insn(s, imm_reg_insn(INSN_ADD_IMM_REG, 1, index));
-               bb_add_insn(s, memindex_reg_insn(INSN_MOV_MEMINDEX_REG, base, 
index, 2, state->reg2));
+               select_insn(s, tree, imm_reg_insn(INSN_ADD_IMM_REG, 1, index));
+               select_insn(s, tree, memindex_reg_insn(INSN_MOV_MEMINDEX_REG, 
base, index, 2, state->reg2));
        }
 }
 
@@ -657,9 +662,9 @@ reg:        EXPR_NEW
        var = get_fixed_var(s->b_parent, REG_EAX);
        state->reg1 = var;
 
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, (unsigned long) expr->class));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) allocObject));
-       method_args_cleanup(s, 1);
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned long) 
expr->class));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
allocObject));
+       method_args_cleanup(s, tree, 1);
 }
 
 reg:   EXPR_NEWARRAY(reg)
@@ -674,11 +679,11 @@ reg:      EXPR_NEWARRAY(reg)
 
        size = state->left->reg1;
 
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, size));
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, expr->array_type));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) allocTypeArray));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, size));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, expr->array_type));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
allocTypeArray));
 
-       method_args_cleanup(s, 2);
+       method_args_cleanup(s, tree, 2);
 }
 
 reg:   EXPR_MULTIANEWARRAY(arg)
@@ -697,12 +702,12 @@ reg:      EXPR_MULTIANEWARRAY(arg)
 
        dimension = nr_args(to_expr(expr->multianewarray_dimensions));
 
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, stack_ptr));
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, dimension));
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, (unsigned long) 
expr->multianewarray_ref_type));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) 
allocMultiArray));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, stack_ptr));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, dimension));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned long) 
expr->multianewarray_ref_type));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
allocMultiArray));
 
-       method_args_cleanup(s, dimension + 3);
+       method_args_cleanup(s, tree, dimension + 3);
 }
 
 reg:    EXPR_ANEWARRAY(reg)
@@ -717,12 +722,12 @@ reg:    EXPR_ANEWARRAY(reg)
 
         size = state->left->reg1;
 
-        bb_add_insn(s, imm_insn(INSN_PUSH_IMM, sizeof(struct object *)));
-        bb_add_insn(s, reg_insn(INSN_PUSH_REG, size));
-        bb_add_insn(s, imm_insn(INSN_PUSH_IMM, (unsigned long) 
expr->anewarray_ref_type));
-        bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) allocArray));
+        select_insn(s, tree, imm_insn(INSN_PUSH_IMM, sizeof(struct object *)));
+        select_insn(s, tree, reg_insn(INSN_PUSH_REG, size));
+        select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned long) 
expr->anewarray_ref_type));
+        select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
allocArray));
 
-        method_args_cleanup(s, 3);
+        method_args_cleanup(s, tree, 3);
 }
 
 reg:    EXPR_ARRAYLENGTH(reg)
@@ -734,7 +739,7 @@ reg:    EXPR_ARRAYLENGTH(reg)
        arraylength = get_fixed_var(s->b_parent, REG_EAX);
        state->reg1 = arraylength;
 
-       bb_add_insn(s, membase_reg_insn(INSN_MOV_MEMBASE_REG, arrayref, 
sizeof(struct object), arraylength));
+       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG, arrayref, 
sizeof(struct object), arraylength));
 }
 
 reg:   EXPR_INSTANCEOF(reg)
@@ -749,11 +754,11 @@ reg:      EXPR_INSTANCEOF(reg)
        instanceof_result = get_fixed_var(s->b_parent, REG_EAX);
        state->reg1 = instanceof_result;
 
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, (unsigned long) 
expr->instanceof_class));
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, ref));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) 
is_object_instance_of));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned long) 
expr->instanceof_class));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, ref));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
is_object_instance_of));
 
-       method_args_cleanup(s, 2);
+       method_args_cleanup(s, tree, 2);
 }
 
 reg:   EXPR_CONVERSION(reg)
@@ -767,9 +772,9 @@ reg:        EXPR_CONVERSION(reg)
                state->reg1 = get_var(s->b_parent);
                state->reg2 = get_var(s->b_parent);
 
-               bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, 
state->left->reg1, state->reg1));
-               bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, 
state->left->reg1, state->reg2));
-               bb_add_insn(s, imm_reg_insn(INSN_SAR_IMM_REG, 0x1f, 
state->reg2));
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, 
state->left->reg1, state->reg1));
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, 
state->left->reg1, state->reg2));
+               select_insn(s, tree, imm_reg_insn(INSN_SAR_IMM_REG, 0x1f, 
state->reg2));
        } else if (src->vm_type == J_LONG && expr->vm_type == J_INT) {
                state->reg1 = state->left->reg1;
        } else {
@@ -791,10 +796,10 @@ arg:      EXPR_ARG(EXPR_VALUE)
        imm  = arg_expr->value;
 
        if (arg_expr->vm_type == J_LONG) {
-               bb_add_insn(s, imm_insn(INSN_PUSH_IMM, imm >> 32));
+               select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm >> 32));
        }
 
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, imm & ~0UL));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm & ~0UL));
 }
 
 arg:   EXPR_ARG(reg)
@@ -807,11 +812,11 @@ arg:      EXPR_ARG(reg)
 
        if (arg_expr->vm_type == J_LONG) {
                src = state->left->reg2;
-               bb_add_insn(s, reg_insn(INSN_PUSH_REG, src));
+               select_insn(s, tree, reg_insn(INSN_PUSH_REG, src));
        }
 
        src = state->left->reg1;
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, src));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, src));
 }
 
 arg:   EXPR_ARGS_LIST(arg, arg)
@@ -825,7 +830,7 @@ reg:        EXPR_EXCEPTION_REF
        result = get_var(s->b_parent);
        state->reg1 = result;
 
-       bb_add_insn(s, reg_insn(INSN_POP_REG, result));
+       select_insn(s, tree, reg_insn(INSN_POP_REG, result));
 }
 
 stmt:  STMT_RETURN(reg)
@@ -839,21 +844,21 @@ stmt:     STMT_RETURN(reg)
        eax = get_fixed_var(s->b_parent, REG_EAX);
        src = state->left->reg1;
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, src, eax));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, src, eax));
 
        if (expr->vm_type == J_LONG) {
                edx = get_fixed_var(s->b_parent, REG_EDX);
                src = state->left->reg2;
 
-               bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, src, edx));
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, src, edx));
        }
 
-       bb_add_insn(s, branch_insn(INSN_JMP_BRANCH, s->b_parent->exit_bb));
+       select_insn(s, tree, branch_insn(INSN_JMP_BRANCH, 
s->b_parent->exit_bb));
 }
 
 stmt:  STMT_VOID_RETURN
 {
-       bb_add_insn(s, branch_insn(INSN_JMP_BRANCH, s->b_parent->exit_bb));
+       select_insn(s, tree, branch_insn(INSN_JMP_BRANCH, 
s->b_parent->exit_bb));
 }
 
 stmt:  STMT_EXPRESSION(reg)
@@ -878,13 +883,13 @@ stmt:     STMT_STORE(EXPR_CLASS_FIELD, reg)
 
        offset = get_var(s->b_parent);
 
-       bb_add_insn(s, imm_reg_insn(INSN_MOV_IMM_REG, (unsigned long) 
store_dest->class_field, offset));
-       bb_add_insn(s, reg_membase_insn(INSN_MOV_REG_MEMBASE, src, offset, 
field_offset));
+       select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG, (unsigned long) 
store_dest->class_field, offset));
+       select_insn(s, tree, reg_membase_insn(INSN_MOV_REG_MEMBASE, src, 
offset, field_offset));
 
        if (store_src->vm_type == J_LONG) {
                src = state->right->reg2;
-               bb_add_insn(s, imm_reg_insn(INSN_ADD_IMM_REG, 4, offset));
-               bb_add_insn(s, reg_membase_insn(INSN_MOV_REG_MEMBASE, src, 
offset, field_offset));
+               select_insn(s, tree, imm_reg_insn(INSN_ADD_IMM_REG, 4, offset));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_REG_MEMBASE, 
src, offset, field_offset));
        }
 }
 
@@ -903,9 +908,9 @@ inst_field: EXPR_INSTANCE_FIELD(reg) 1
        index = get_var(s->b_parent);
        state->reg2 = index;
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, src, base));
-       bb_add_insn(s, imm_reg_insn(INSN_ADD_IMM_REG, sizeof(struct object), 
base));
-       bb_add_insn(s, imm_reg_insn(INSN_MOV_IMM_REG, 
expr->instance_field->offset, index));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, src, base));
+       select_insn(s, tree, imm_reg_insn(INSN_ADD_IMM_REG, sizeof(struct 
object), base));
+       select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG, 
expr->instance_field->offset, index));
 }
 
 stmt:  STMT_STORE(inst_field, reg)
@@ -921,12 +926,12 @@ stmt:     STMT_STORE(inst_field, reg)
        base = state->left->reg1;
        index = state->left->reg2;
 
-       bb_add_insn(s, reg_memindex_insn(INSN_MOV_REG_MEMINDEX, src, base, 
index, 2));
+       select_insn(s, tree, reg_memindex_insn(INSN_MOV_REG_MEMINDEX, src, 
base, index, 2));
 
        if (store_src->vm_type == J_LONG) {
                src = state->right->reg2;
-               bb_add_insn(s, imm_reg_insn(INSN_ADD_IMM_REG, 1, index));
-               bb_add_insn(s, reg_memindex_insn(INSN_MOV_REG_MEMINDEX, src, 
base, index, 2));
+               select_insn(s, tree, imm_reg_insn(INSN_ADD_IMM_REG, 1, index));
+               select_insn(s, tree, reg_memindex_insn(INSN_MOV_REG_MEMINDEX, 
src, base, index, 2));
        }
 }
 
@@ -944,14 +949,14 @@ stmt:     STMT_STORE(EXPR_LOCAL, reg)
        local = to_expr(stmt->store_dest);
        slot = get_local_slot(cu->stack_frame, local->local_index);
 
-       bb_add_insn(s, reg_memlocal_insn(INSN_MOV_REG_MEMLOCAL, src, slot));
+       select_insn(s, tree, reg_memlocal_insn(INSN_MOV_REG_MEMLOCAL, src, 
slot));
 
        if (local->vm_type == J_LONG) {
                src = state->right->reg2;
 
                slot = get_local_slot(cu->stack_frame, local->local_index+1);
 
-               bb_add_insn(s, reg_memlocal_insn(INSN_MOV_REG_MEMLOCAL, src, 
slot));
+               select_insn(s, tree, reg_memlocal_insn(INSN_MOV_REG_MEMLOCAL, 
src, slot));
        }
 }
 
@@ -967,12 +972,12 @@ stmt:  STMT_STORE(EXPR_TEMPORARY, reg)
 
        dest = temp->tmp_low;
        src = state->right->reg1;
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, src, dest));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, src, dest));
 
        if (temp->vm_type == J_LONG) {
                dest = temp->tmp_high;
                src = state->right->reg2;
-               bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, src, dest));
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, src, dest));
        }
 }
 
@@ -992,9 +997,9 @@ array_deref:        EXPR_ARRAY_DEREF(reg, reg) 2
        index = get_var(s->b_parent);
        state->reg2 = index;
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state_base, base));
-       bb_add_insn(s, imm_reg_insn(INSN_ADD_IMM_REG, sizeof(struct object) + 
sizeof(uint32_t), base));
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state_index, index));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state_base, base));
+       select_insn(s, tree, imm_reg_insn(INSN_ADD_IMM_REG, sizeof(struct 
object) + sizeof(uint32_t), base));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state_index, 
index));
 }
 
 stmt:  STMT_STORE(array_deref, reg)
@@ -1013,7 +1018,7 @@ stmt:     STMT_STORE(array_deref, reg)
        index = state->left->reg2;
        src = state->right->reg1;
 
-       bb_add_insn(s, reg_memindex_insn(INSN_MOV_REG_MEMINDEX, src, base, 
index, scale));
+       select_insn(s, tree, reg_memindex_insn(INSN_MOV_REG_MEMINDEX, src, 
base, index, scale));
 }
 
 stmt:  STMT_STORE(reg, array_deref)
@@ -1034,7 +1039,7 @@ stmt:     STMT_STORE(reg, array_deref)
 
        state->reg1 = dest;
 
-       bb_add_insn(s, memindex_reg_insn(INSN_MOV_MEMINDEX_REG, base, index, 
scale, dest));
+       select_insn(s, tree, memindex_reg_insn(INSN_MOV_MEMINDEX_REG, base, 
index, scale, dest));
 }
 
 stmt:  STMT_ATHROW(reg)
@@ -1048,10 +1053,10 @@ stmt:   STMT_NULL_CHECK(reg)
 
        ref = state->left->reg1;
 
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, ref));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) check_null));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, ref));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
check_null));
 
-       method_args_cleanup(s, 1);
+       method_args_cleanup(s, tree, 1);
 }
 
 array_check:   EXPR_ARRAY_DEREF(reg, reg) 2
@@ -1070,8 +1075,8 @@ array_check:      EXPR_ARRAY_DEREF(reg, reg) 2
        index = get_var(s->b_parent);
        state->reg2 = index;
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state_base, base));
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, state_index, index));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state_base, base));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state_index, 
index));
 }
 
 stmt:  STMT_ARRAY_CHECK(array_check)
@@ -1081,11 +1086,11 @@ stmt:   STMT_ARRAY_CHECK(array_check)
        ref = state->left->reg1;
        index = state->left->reg2;
 
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, index));
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, ref));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) check_array));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, index));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, ref));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
check_array));
 
-       method_args_cleanup(s, 2);
+       method_args_cleanup(s, tree, 2);
 }
 
 stmt:  STMT_IF(reg)
@@ -1098,7 +1103,7 @@ stmt:     STMT_IF(reg)
        if_conditional = to_expr(stmt->if_conditional);
        insn_type = br_binop_to_insn_type(expr_bin_op(if_conditional));
 
-       bb_add_insn(s, branch_insn(insn_type, stmt->if_true));
+       select_insn(s, tree, branch_insn(insn_type, stmt->if_true));
 }
 
 stmt:  STMT_GOTO
@@ -1107,7 +1112,7 @@ stmt:     STMT_GOTO
 
        stmt = to_stmt(tree);
 
-       bb_add_insn(s, branch_insn(INSN_JMP_BRANCH, stmt->goto_target));
+       select_insn(s, tree, branch_insn(INSN_JMP_BRANCH, stmt->goto_target));
 }
 
 stmt:  STMT_MONITOR_ENTER(reg)
@@ -1115,10 +1120,10 @@ stmt:   STMT_MONITOR_ENTER(reg)
        struct var_info *ref;
        ref = state->left->reg1;
 
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, ref));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) objectLock));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, ref));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
objectLock));
 
-       method_args_cleanup(s, 1);
+       method_args_cleanup(s, tree, 1);
 }
 
 stmt:  STMT_MONITOR_EXIT(reg)
@@ -1126,10 +1131,10 @@ stmt:   STMT_MONITOR_EXIT(reg)
        struct var_info *ref;
        ref = state->left->reg1;
 
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, ref));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) objectUnlock));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, ref));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
objectUnlock));
 
-       method_args_cleanup(s, 1);
+       method_args_cleanup(s, tree, 1);
 }
 
 stmt:  STMT_CHECKCAST(reg)
@@ -1141,15 +1146,22 @@ stmt:   STMT_CHECKCAST(reg)
 
        stmt = to_stmt(tree);
 
-       bb_add_insn(s, imm_insn(INSN_PUSH_IMM, (unsigned long) 
stmt->checkcast_class));
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, ref));
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long)check_cast));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned long) 
stmt->checkcast_class));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, ref));
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned 
long)check_cast));
 
-       method_args_cleanup(s, 2);
+       method_args_cleanup(s, tree, 2);
 }
 
 %%
 
+static void select_insn(struct basic_block *bb, struct tree_node *tree,
+                       struct insn *instruction)
+{
+       instruction->bytecode_offset = tree_bytecode_offset(tree);
+       bb_add_insn(bb, instruction);
+}
+
 static void __binop_reg_local(struct _MBState *state, struct basic_block *bb,
                              struct tree_node *tree, enum insn_type insn_type,
                              struct var_info *result, long disp_offset)
@@ -1164,7 +1176,7 @@ static void __binop_reg_local(struct _MBState *state, 
struct basic_block *bb,
 
        frame_ptr = bb->b_parent->frame_ptr;
 
-       bb_add_insn(bb, membase_reg_insn(insn_type, frame_ptr, disp, result));
+       select_insn(bb, tree, membase_reg_insn(insn_type, frame_ptr, disp, 
result));
 }
 
 static void binop_reg_local_low(struct _MBState *state, struct basic_block *bb,
@@ -1193,7 +1205,7 @@ static void binop_reg_value_low(struct _MBState *state, 
struct basic_block *bb,
        expr = to_expr(tree);
        right = to_expr(expr->binary_right);
 
-       bb_add_insn(bb, imm_reg_insn(insn_type, right->value & ~0UL, 
state->reg1));
+       select_insn(bb, tree, imm_reg_insn(insn_type, right->value & ~0UL, 
state->reg1));
 }
 
 static void binop_reg_value_high(struct _MBState *state, struct basic_block 
*bb,
@@ -1206,7 +1218,7 @@ static void binop_reg_value_high(struct _MBState *state, 
struct basic_block *bb,
        expr = to_expr(tree);
        right = to_expr(expr->binary_right);
 
-       bb_add_insn(bb, imm_reg_insn(insn_type, right->value >> 32, 
state->reg2));
+       select_insn(bb, tree, imm_reg_insn(insn_type, right->value >> 32, 
state->reg2));
 }
 
 static void binop_reg_reg_low(struct _MBState *state, struct basic_block *bb,
@@ -1217,7 +1229,7 @@ static void binop_reg_reg_low(struct _MBState *state, 
struct basic_block *bb,
        src = state->right->reg1;
        dst = state->left->reg1;
 
-       bb_add_insn(bb, reg_reg_insn(insn_type, src, dst));
+       select_insn(bb, tree, reg_reg_insn(insn_type, src, dst));
 }
 
 static void binop_reg_reg_high(struct _MBState *state, struct basic_block *bb,
@@ -1228,7 +1240,7 @@ static void binop_reg_reg_high(struct _MBState *state, 
struct basic_block *bb,
        src = state->right->reg2;
        dst = state->left->reg2;
 
-       bb_add_insn(bb, reg_reg_insn(insn_type, src, dst));
+       select_insn(bb, tree, reg_reg_insn(insn_type, src, dst));
 }
 
 static void shift_reg_local(struct _MBState *state, struct basic_block *bb,
@@ -1247,8 +1259,8 @@ static void shift_reg_local(struct _MBState *state, 
struct basic_block *bb,
        frame_ptr = bb->b_parent->frame_ptr;
        shift_count = get_fixed_var(bb->b_parent, REG_ECX);
 
-       bb_add_insn(bb, membase_reg_insn(INSN_MOV_MEMBASE_REG, frame_ptr, disp, 
shift_count));
-       bb_add_insn(bb, reg_reg_insn(insn_type, shift_count, result));
+       select_insn(bb, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG, frame_ptr, 
disp, shift_count));
+       select_insn(bb, tree, reg_reg_insn(insn_type, shift_count, result));
 }
 
 static void div_reg_local(struct _MBState *state, struct basic_block *bb,
@@ -1267,15 +1279,15 @@ static void div_reg_local(struct _MBState *state, 
struct basic_block *bb,
 
        frame_ptr = bb->b_parent->frame_ptr;
 
-       bb_add_insn(bb, reg_reg_insn(INSN_MOV_REG_REG, state->left->reg1, 
result));
-       bb_add_insn(bb, reg_reg_insn(INSN_CLTD_REG_REG, result, edx));
-       bb_add_insn(bb, membase_reg_insn(INSN_DIV_MEMBASE_REG, frame_ptr, disp, 
result));
+       select_insn(bb, tree, reg_reg_insn(INSN_MOV_REG_REG, state->left->reg1, 
result));
+       select_insn(bb, tree, reg_reg_insn(INSN_CLTD_REG_REG, result, edx));
+       select_insn(bb, tree, membase_reg_insn(INSN_DIV_MEMBASE_REG, frame_ptr, 
disp, result));
 
 }
 
 static void
-emulate_op_64(struct _MBState *state, struct basic_block *s, void *func,
-             enum vm_type return_type)
+emulate_op_64(struct _MBState *state, struct basic_block *s,
+             struct tree_node *tree, void *func, enum vm_type return_type)
 {
        struct var_info *eax, *edx = NULL;
 
@@ -1286,17 +1298,17 @@ emulate_op_64(struct _MBState *state, struct 
basic_block *s, void *func,
                edx = get_fixed_var(s->b_parent, REG_EDX);
                state->reg2 = get_var(s->b_parent);
        }
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, state->right->reg2));
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, state->right->reg1));
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, state->left->reg2));
-       bb_add_insn(s, reg_insn(INSN_PUSH_REG, state->left->reg1));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, state->right->reg2));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, state->right->reg1));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, state->left->reg2));
+       select_insn(s, tree, reg_insn(INSN_PUSH_REG, state->left->reg1));
 
-       bb_add_insn(s, rel_insn(INSN_CALL_REL, (unsigned long) func));
-       method_args_cleanup(s, 4); 
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) func));
+       method_args_cleanup(s, tree, 4);
 
-       bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
        if (edx)
-               bb_add_insn(s, reg_reg_insn(INSN_MOV_REG_REG, edx, 
state->reg2));
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, edx, 
state->reg2));
 }
 
 static void emit_code(struct basic_block *bb, MBState *state, int goal)
diff --git a/arch/x86/instruction.c b/arch/x86/instruction.c
index 624651a..467bb74 100644
--- a/arch/x86/instruction.c
+++ b/arch/x86/instruction.c
@@ -24,6 +24,8 @@
  * Please refer to the file LICENSE for details.
  */
 
+#include <jit/bc-offset-mapping.h>
+
 #include <arch/instruction.h>
 
 #include <stdlib.h>
@@ -37,6 +39,7 @@ struct insn *alloc_insn(enum insn_type type)
                INIT_LIST_HEAD(&insn->insn_list_node);
                INIT_LIST_HEAD(&insn->branch_list_node);
                insn->type = type;
+               insn->bytecode_offset = BC_OFFSET_UNKNOWN;
        }
        return insn;
 }
diff --git a/include/jit/bc-offset-mapping.h b/include/jit/bc-offset-mapping.h
new file mode 100644
index 0000000..21ec6df
--- /dev/null
+++ b/include/jit/bc-offset-mapping.h
@@ -0,0 +1,19 @@
+#ifndef _BC_OFFSET_MAPPING
+#define _BC_OFFSET_MAPPING
+
+#include <jit/compilation-unit.h>
+#include <jit/tree-node.h>
+#include <vm/string.h>
+#include <limits.h>
+
+#define BC_OFFSET_UNKNOWN ULONG_MAX
+
+unsigned long native_ptr_to_bytecode_offset(struct compilation_unit *cu,
+                                           unsigned char *native_ptr);
+void print_bytecode_offset(unsigned long bc_offset, struct string *str);
+
+unsigned long tree_bytecode_offset(struct tree_node *node);
+void tree_patch_bc_offset(struct tree_node *node, unsigned long bc_offset);
+bool all_insn_have_bytecode_offset(struct compilation_unit *cu);
+
+#endif
diff --git a/include/jit/expression.h b/include/jit/expression.h
index cba8209..f57bb38 100644
--- a/include/jit/expression.h
+++ b/include/jit/expression.h
@@ -76,6 +76,8 @@ enum unary_operator {
 struct expression {
        unsigned long refcount;
        enum vm_type vm_type;
+       unsigned long bytecode_offset;
+
        union {
                struct tree_node node;
 
diff --git a/include/jit/statement.h b/include/jit/statement.h
index f87abc0..793e62d 100644
--- a/include/jit/statement.h
+++ b/include/jit/statement.h
@@ -50,6 +50,7 @@ struct statement {
                struct tree_node *expression;
        };
        struct list_head stmt_list_node;
+       unsigned long bytecode_offset;
 };
 
 static inline struct statement *to_stmt(struct tree_node *node)
diff --git a/jit/args.c b/jit/args.c
index c8b6c33..9ccac87 100644
--- a/jit/args.c
+++ b/jit/args.c
@@ -31,10 +31,15 @@
 struct expression *
 insert_arg(struct expression *root, struct expression *expr)
 {
+       struct expression *_expr;
+
+       _expr = arg_expr(expr);
+       _expr->bytecode_offset = expr->bytecode_offset;
+
        if (!root)
-               return arg_expr(expr);
+               return _expr;
 
-       return args_list_expr(root, arg_expr(expr));
+       return args_list_expr(root, _expr);
 }
 
 struct expression *
diff --git a/jit/bc-offset-mapping.c b/jit/bc-offset-mapping.c
new file mode 100644
index 0000000..707394e
--- /dev/null
+++ b/jit/bc-offset-mapping.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2009 Tomasz Grabiec
+ *
+ * This file is released under the GPL version 2 with the following
+ * clarification and special exception:
+ *
+ *     Linking this library statically or dynamically with other modules is
+ *     making a combined work based on this library. Thus, the terms and
+ *     conditions of the GNU General Public License cover the whole
+ *     combination.
+ *
+ *     As a special exception, the copyright holders of this library give you
+ *     permission to link this library with independent modules to produce an
+ *     executable, regardless of the license terms of these independent
+ *     modules, and to copy and distribute the resulting executable under terms
+ *     of your choice, provided that you also meet, for each linked independent
+ *     module, the terms and conditions of the license of that module. An
+ *     independent module is a module which is not derived from or based on
+ *     this library. If you modify this library, you may extend this exception
+ *     to your version of the library, but you are not obligated to do so. If
+ *     you do not wish to do so, delete this exception statement from your
+ *     version.
+ *
+ * Please refer to the file LICENSE for details.
+ */
+
+#include <jit/bc-offset-mapping.h>
+#include <jit/statement.h>
+#include <jit/expression.h>
+
+#include <arch/instruction.h>
+
+#include <vm/buffer.h>
+
+/**
+ * tree_patch_bc_offset - sets bytecode_offset field of a tree node container
+ *                        unless it is already set.
+ * @node: a tree node
+ * @offset: bytecode offset to set.
+ */
+void tree_patch_bc_offset(struct tree_node *node, unsigned long bc_offset)
+{
+       if (node_is_stmt(node)) {
+               struct statement *stmt = to_stmt(node);
+
+               if (stmt->bytecode_offset == BC_OFFSET_UNKNOWN)
+                       stmt->bytecode_offset = bc_offset;
+       } else {
+               struct expression *expr = to_expr(node);
+
+               if (expr->bytecode_offset == BC_OFFSET_UNKNOWN)
+                       expr->bytecode_offset = bc_offset;
+       }
+}
+
+/**
+ * native_ptr_to_bytecode_offset - translates native instruction pointer
+ *                                 to bytecode offset from which given
+ *                                 instruction originates.
+ * @cu: compilation unit of method containing @native_ptr.
+ * @native_ptr: native instruction pointer to be translated.
+ */
+unsigned long native_ptr_to_bytecode_offset(struct compilation_unit *cu,
+                                           unsigned char *native_ptr)
+{
+       unsigned char *method_ptr = buffer_ptr(cu->objcode);
+       struct basic_block *bb;
+       struct insn *insn;
+
+       for_each_basic_block(bb, &cu->bb_list) {
+               for_each_insn(insn, &bb->insn_list) {
+                       if (method_ptr + insn->mach_offset == native_ptr)
+                               return insn->bytecode_offset;
+               }
+       }
+
+       return BC_OFFSET_UNKNOWN;
+}
+
+void print_bytecode_offset(unsigned long bytecode_offset, struct string *str)
+{
+       if (bytecode_offset == BC_OFFSET_UNKNOWN)
+               str_append(str, "?");
+       else {
+               static char buf[32];
+               sprintf(buf, "%ld", bytecode_offset);
+               str_append(str, buf);
+       }
+}
+
+unsigned long tree_bytecode_offset(struct tree_node *node)
+{
+       if (node_is_stmt(node))
+               return to_stmt(node)->bytecode_offset;
+
+       return to_expr(node)->bytecode_offset;
+}
+
+bool all_insn_have_bytecode_offset(struct compilation_unit *cu)
+{
+       struct basic_block *bb;
+       struct insn *insn;
+
+       for_each_basic_block(bb, &cu->bb_list) {
+               for_each_insn(insn, &bb->insn_list) {
+                       if (insn->bytecode_offset == BC_OFFSET_UNKNOWN)
+                               return false;
+               }
+       }
+
+       return true;
+}
diff --git a/jit/bytecode-to-ir.c b/jit/bytecode-to-ir.c
index 07714f7..e6e0640 100644
--- a/jit/bytecode-to-ir.c
+++ b/jit/bytecode-to-ir.c
@@ -11,6 +11,8 @@
 #include <jit/compiler.h>
 #include <jit/statement.h>
 #include <jit/expression.h>
+#include <jit/bc-offset-mapping.h>
+#include <jit/tree-node.h>
 
 #include <vm/bytecode.h>
 #include <vm/bytecodes.h>
@@ -227,11 +229,38 @@ static convert_fn_t converters[] = {
 
 void convert_expression(struct parse_context *ctx, struct expression *expr)
 {
+       expr->bytecode_offset = ctx->offset;
        stack_push(ctx->bb->mimic_stack, expr);
 }
 
 void convert_statement(struct parse_context *ctx, struct statement *stmt)
 {
+       unsigned long bc_offset = ctx->offset;
+
+       /*
+        * Some expressions do not go through convert_expression()
+        * so we need to set their bytecode_offset here if it is not set.
+        */
+       switch (stmt_type(stmt)) {
+       case STMT_STORE:
+               tree_patch_bc_offset(stmt->store_dest, bc_offset);
+               tree_patch_bc_offset(stmt->store_src, bc_offset);
+               break;
+       case STMT_IF:
+               tree_patch_bc_offset(stmt->if_conditional, bc_offset);
+               break;
+       case STMT_RETURN:
+               tree_patch_bc_offset(stmt->return_value, bc_offset);
+               break;
+       case STMT_EXPRESSION:
+       case STMT_NULL_CHECK:
+       case STMT_ARRAY_CHECK:
+               tree_patch_bc_offset(stmt->expression, bc_offset);
+               break;
+       default: ;
+       }
+
+       stmt->bytecode_offset = bc_offset;
        bb_add_stmt(ctx->bb, stmt);
 }
 
diff --git a/jit/compiler.c b/jit/compiler.c
index d39ac00..4d7a71e 100644
--- a/jit/compiler.c
+++ b/jit/compiler.c
@@ -10,6 +10,7 @@
 #include <jit/compilation-unit.h>
 #include <jit/compiler.h>
 #include <jit/statement.h>
+#include <jit/bc-offset-mapping.h>
 
 #include <errno.h>
 #include <stdlib.h>
@@ -76,6 +77,8 @@ int compile(struct compilation_unit *cu)
        if (err)
                goto out;
 
+       assert(all_insn_have_bytecode_offset(cu));
+
        err = emit_machine_code(cu);
        if (err)
                goto out;
diff --git a/jit/expression.c b/jit/expression.c
index 8a37502..6b776f6 100644
--- a/jit/expression.c
+++ b/jit/expression.c
@@ -6,6 +6,7 @@
  */
 
 #include <jit/expression.h>
+#include <jit/bc-offset-mapping.h>
 #include <vm/vm.h>
 #include <vm/method.h>
 #include <stdlib.h>
@@ -21,6 +22,7 @@ struct expression *alloc_expression(enum expression_type type,
                expr->node.op = type << EXPR_TYPE_SHIFT;
                expr->vm_type = vm_type;
                expr->refcount = 1;
+               expr->bytecode_offset = BC_OFFSET_UNKNOWN;
        }
        return expr;
 }
diff --git a/jit/invoke-bc.c b/jit/invoke-bc.c
index 9162832..406d380 100644
--- a/jit/invoke-bc.c
+++ b/jit/invoke-bc.c
@@ -58,10 +58,15 @@ static unsigned int method_real_argument_count(struct 
methodblock *invoke_target
 static struct expression *insert_arg(struct expression *root,
                                     struct expression *expr)
 {
+       struct expression *_expr;
+
+       _expr = arg_expr(expr);
+       _expr->bytecode_offset = expr->bytecode_offset;
+
        if (!root)
-               return arg_expr(expr);
+               return _expr;
 
-       return args_list_expr(root, arg_expr(expr));
+       return args_list_expr(root, _expr);
 }
 
 static struct expression *convert_args(struct stack *mimic_stack,
@@ -119,7 +124,7 @@ static int insert_invoke_expr(struct parse_context *ctx,
 
 static struct methodblock *resolve_invoke_target(struct parse_context *ctx)
 {
-       unsigned long idx; 
+       unsigned long idx;
 
        idx = bytecode_read_u16(ctx->buffer);
 
diff --git a/jit/spill-reload.c b/jit/spill-reload.c
index 14e1758..f8d3230 100644
--- a/jit/spill-reload.c
+++ b/jit/spill-reload.c
@@ -63,6 +63,8 @@ static int insert_spill_insn(struct live_interval *interval, 
struct compilation_
 
        interval->spill_slot = slot;
 
+       spill->bytecode_offset = last->bytecode_offset;
+
        list_add(&spill->insn_list_node, &last->insn_list_node);
 
        return 0;
@@ -89,6 +91,8 @@ static int insert_reload_insn(struct live_interval *interval, 
struct compilation
        if (!reload)
                return -ENOMEM;
 
+       reload->bytecode_offset = first->bytecode_offset;
+
        list_add_tail(&reload->insn_list_node, &first->insn_list_node);
 
        return 0;
diff --git a/jit/statement.c b/jit/statement.c
index 0c8ecf4..60805e1 100644
--- a/jit/statement.c
+++ b/jit/statement.c
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <jit/expression.h>
 #include <jit/statement.h>
+#include <jit/bc-offset-mapping.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -19,6 +20,7 @@ struct statement *alloc_statement(enum statement_type type)
                memset(stmt, 0, sizeof *stmt);
                INIT_LIST_HEAD(&stmt->stmt_list_node);
                stmt->node.op = type << STMT_TYPE_SHIFT;
+               stmt->bytecode_offset = BC_OFFSET_UNKNOWN;
        }
 
        return stmt;
diff --git a/test/arch-x86/Makefile b/test/arch-x86/Makefile
index 5014de5..8ab76d4 100644
--- a/test/arch-x86/Makefile
+++ b/test/arch-x86/Makefile
@@ -43,6 +43,7 @@ OBJS = \
        ../../jit/statement.o \
        ../../jit/tree-printer.o \
        ../../jit/fixup-site.o \
+       ../../jit/bc-offset-mapping.o \
        ../../arch/x86/emit-code$(ARCH_POSTFIX).o \
        ../../arch/x86/instruction.o \
        ../../arch/x86/insn-selector$(ARCH_POSTFIX).o \
diff --git a/test/include/arch/instruction.h b/test/include/arch/instruction.h
index d9776ca..2821986 100644
--- a/test/include/arch/instruction.h
+++ b/test/include/arch/instruction.h
@@ -54,6 +54,9 @@ struct insn {
         struct list_head insn_list_node;
        /* Position of this instruction in LIR.  */
        unsigned long           lir_pos;
+       /* Offset in machine code.  */
+       unsigned long mach_offset;
+       unsigned long bytecode_offset;
 };
 
 static inline unsigned long lir_position(struct use_position *reg)
diff --git a/test/jit/Makefile b/test/jit/Makefile
index 1fb21d9..89d1489 100644
--- a/test/jit/Makefile
+++ b/test/jit/Makefile
@@ -34,6 +34,7 @@ OBJS = \
        ../../jit/tree-printer.o \
        ../../jit/args.o \
        ../../jit/exception.o \
+       ../../jit/bc-offset-mapping.o \
        ../libharness/libharness.o \
        ../jamvm/alloc-stub.o \
        ../jamvm/resolve-stub.o \
-- 
1.6.0.6


------------------------------------------------------------------------------
Register Now & Save for Velocity, the Web Performance & Operations 
Conference from O'Reilly Media. Velocity features a full day of 
expert-led, hands-on workshops and two days of sessions from industry 
leaders in dedicated Performance & Operations tracks. Use code vel09scf 
and Save an extra 15% before 5/3. http://p.sf.net/sfu/velocityconf
_______________________________________________
Jatovm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to