The following code made jato crash: public class Test() { public static void main(String []args) { throw new RuntimeException("test"); } }
That's because code selected for STMT_ATHROW didn't handle the case where the jump target was NULL which means a jump to exit block should be made and no exception object should be pushed (unwind function handles this correctly). Because of a need to perform a branch inside selected code a new pseudo instruction INSN_THROW_REG_CU was added to handle the whole throwing code. Signed-off-by: Tomek Grabiec <tgrab...@gmail.com> --- arch/x86/emit-code_32.c | 54 +++++++++++++++++++++++++++++++++++ arch/x86/include/arch/instruction.h | 9 ++++++ arch/x86/insn-selector_32.brg | 11 +------ arch/x86/instruction.c | 21 +++++++++++++ arch/x86/use-def.c | 1 + 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/arch/x86/emit-code_32.c b/arch/x86/emit-code_32.c index 2a9d29d..47ca3cd 100644 --- a/arch/x86/emit-code_32.c +++ b/arch/x86/emit-code_32.c @@ -770,6 +770,11 @@ static void emit_jne_branch(struct buffer *buf, struct insn *insn) __emit_branch(buf, 0x0f, 0x85, insn); } +static void emit_jne_branch_rel32(struct buffer *buf, unsigned long rel) +{ + emit_branch_rel(buf, 0x0f, 0x85, rel); +} + static void emit_jge_branch(struct buffer *buf, struct insn *insn) { __emit_branch(buf, 0x0f, 0x8d, insn); @@ -818,6 +823,54 @@ static void emit_xor_imm_reg(struct buffer *buf, struct operand * src, __emit_xor_imm_reg(buf, src->imm, mach_reg(&dest->reg)); } +static void __emit_test_reg_reg(struct buffer *buf, enum machine_reg reg1, + enum machine_reg reg2) +{ + __emit_reg_reg(buf, 0x85, reg1, reg2); +} + +static void backpatch_branch_rel32_target(unsigned char *site_addr, + struct buffer *buf) +{ + unsigned long new_target; + unsigned long target = (unsigned long) buffer_current(buf); + + new_target = target - ((uint32_t)site_addr + BRANCH_INSN_SIZE + + PREFIX_SIZE); + cpu_write_u32(site_addr + 1 + PREFIX_SIZE, new_target); +} + +static void emit_throw_reg_cu(struct buffer *buf, struct operand *exception, + struct operand *cu) +{ + unsigned char *branch_ptr; + + /* exception */ + __emit_push_reg(buf, mach_reg(&exception->reg)); + /* native_ptr */ + __emit_push_imm(buf, (unsigned long)buffer_current(buf)); + /* frame */ + __emit_push_reg(buf, REG_EBP); + /* compilation unit */ + __emit_push_imm(buf, (unsigned long)cu->cu); + __emit_call(buf, throw_exception_from); + __emit_add_imm_reg(buf, 12, REG_ESP); + + __emit_test_reg_reg(buf, REG_EAX, REG_EAX); + branch_ptr = buffer_current(buf); + emit_jne_branch_rel32(buf, 0); + + /* Jump to exit block. Do not push exception object */ + __emit_add_imm_reg(buf, 4, REG_ESP); + __emit_push_imm(buf, (unsigned long)cu->cu); + __emit_call(buf, cu_exit_bb_native_ptr); + __emit_add_imm_reg(buf, 4, REG_ESP); + + backpatch_branch_rel32_target(branch_ptr, buf); + __emit_push_reg(buf, REG_EAX); + emit_ret(buf); +} + enum emitter_type { NO_OPERANDS = 1, SINGLE_OPERAND, @@ -885,6 +938,7 @@ static struct emitter emitters[] = { DECL_EMITTER(INSN_SUB_IMM_REG, emit_sub_imm_reg, TWO_OPERANDS), DECL_EMITTER(INSN_SUB_MEMBASE_REG, emit_sub_membase_reg, TWO_OPERANDS), DECL_EMITTER(INSN_SUB_REG_REG, emit_sub_reg_reg, TWO_OPERANDS), + DECL_EMITTER(INSN_THROW_REG_CU, emit_throw_reg_cu, TWO_OPERANDS), DECL_EMITTER(INSN_XOR_MEMBASE_REG, emit_xor_membase_reg, TWO_OPERANDS), DECL_EMITTER(INSN_XOR_IMM_REG, emit_xor_imm_reg, TWO_OPERANDS), }; diff --git a/arch/x86/include/arch/instruction.h b/arch/x86/include/arch/instruction.h index 6dd0a75..689bfa8 100644 --- a/arch/x86/include/arch/instruction.h +++ b/arch/x86/include/arch/instruction.h @@ -20,6 +20,7 @@ enum operand_type { OPERAND_MEMLOCAL, OPERAND_REG, OPERAND_REL, + OPERAND_CU, LAST_OPERAND }; @@ -46,6 +47,7 @@ struct operand { unsigned long rel; struct basic_block *branch_target; + struct compilation_unit *cu; }; }; @@ -105,6 +107,7 @@ enum insn_type { INSN_SUB_IMM_REG, INSN_SUB_MEMBASE_REG, INSN_SUB_REG_REG, + INSN_THROW_REG_CU, /* composite pseudo instruction */ INSN_XOR_MEMBASE_REG, INSN_XOR_IMM_REG, }; @@ -118,6 +121,10 @@ struct insn { struct operand dest; }; struct operand operand; + struct { + struct operand exception; + struct compilation_unit *cu; + }; }; struct list_head insn_list_node; struct list_head branch_list_node; @@ -149,6 +156,8 @@ struct insn *imm_insn(enum insn_type, unsigned long); struct insn *rel_insn(enum insn_type, unsigned long); struct insn *branch_insn(enum insn_type, struct basic_block *); struct insn *memlocal_insn(enum insn_type, struct stack_slot *); +struct insn *reg_cu_insn(enum insn_type, struct var_info *, + struct compilation_unit *); /* * These functions are used by generic code to insert spill/reload diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg index af95758..20168d8 100644 --- a/arch/x86/insn-selector_32.brg +++ b/arch/x86/insn-selector_32.brg @@ -1103,16 +1103,7 @@ stmt: STMT_STORE(reg, array_deref) stmt: STMT_ATHROW(reg) { - struct var_info *reg_eax = get_fixed_var(s->b_parent, REG_EAX); - - select_insn(s, tree, reg_insn(INSN_PUSH_REG, state->left->reg1)); - select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned long)s->b_parent)); - select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long)throw_exception)); - method_args_cleanup(s, tree, 1); - - /* Jump where throw_exception() told us to jump */ - select_insn(s, tree, reg_insn(INSN_PUSH_REG, reg_eax)); - select_insn(s, tree, insn(INSN_RET)); + select_insn(s, tree, reg_cu_insn(INSN_THROW_REG_CU, state->left->reg1, s->b_parent)); } stmt: STMT_NULL_CHECK(reg) diff --git a/arch/x86/instruction.c b/arch/x86/instruction.c index d3ce609..bba249a 100644 --- a/arch/x86/instruction.c +++ b/arch/x86/instruction.c @@ -98,6 +98,15 @@ static void init_imm_operand(struct insn *insn, unsigned long idx, operand->imm = imm; } +static void init_cu_operand(struct insn *insn, unsigned long idx, + struct compilation_unit *cu) +{ + struct operand *operand = &insn->operands[idx]; + + operand->type = OPERAND_CU; + operand->cu = cu; +} + static void init_membase_operand(struct insn *insn, unsigned long idx, struct var_info *base_reg, unsigned long disp) { @@ -316,3 +325,15 @@ struct insn *memlocal_insn(enum insn_type insn_type, struct stack_slot *slot) return insn; } + +struct insn *reg_cu_insn(enum insn_type insn_type, struct var_info *src, + struct compilation_unit *cu) +{ + struct insn *insn = alloc_insn(insn_type); + if (insn) { + init_reg_operand(insn, 0, src); + init_cu_operand(insn, 1, cu); + } + + return insn; +} diff --git a/arch/x86/use-def.c b/arch/x86/use-def.c index 37524e3..8463128 100644 --- a/arch/x86/use-def.c +++ b/arch/x86/use-def.c @@ -77,6 +77,7 @@ static struct insn_info insn_infos[] = { DECLARE_INFO(INSN_SUB_IMM_REG, USE_NONE | DEF_DST), DECLARE_INFO(INSN_SUB_MEMBASE_REG, USE_SRC | DEF_DST), DECLARE_INFO(INSN_SUB_REG_REG, USE_SRC | DEF_DST), + DECLARE_INFO(INSN_THROW_REG_CU, USE_SRC | USE_FP | DEF_NONE), DECLARE_INFO(INSN_XOR_MEMBASE_REG, USE_SRC | DEF_DST), DECLARE_INFO(INSN_XOR_IMM_REG, USE_SRC | DEF_DST), }; -- 1.6.0.6 ------------------------------------------------------------------------------ Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT is a gathering of tech-side developers & brand creativity professionals. Meet the minds behind Google Creative Lab, Visual Complexity, Processing, & iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian Group, R/GA, & Big Spaceship. http://www.creativitycat.com _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel