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 <[email protected]>
---
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/jatovm-devel