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

Reply via email to