Re: [PATCH] x86: add OP_AND(reg, reg)
On Thu, 2009-06-25 at 01:02 +0200, Arthur HUILLET wrote: > It is necessary for System.out.println > > Signed-off-by: Arthur HUILLET Seems reasonable although I usually don't like merging something that has no users. Anyway, applied! -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
Re: [PATCH] regression: ObjectStackTest now enabled
On Wed, 2009-06-24 at 22:25 +0200, Arthur HUILLET wrote: > Signed-off-by: Arthur HUILLET > --- > regression/jvm/ObjectStackTest.java |3 +-- > 1 files changed, 1 insertions(+), 2 deletions(-) Nice work! Applied. -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
Re: [PATCH 3/3] bc2ir: mimic stack spilling/reloading
On Wed, 2009-06-24 at 22:21 +0200, Arthur HUILLET wrote: > @@ -276,6 +277,121 @@ out: > return err; > } > > +static void assign_temporary(struct basic_block *bb, int entry, int slotnb, > + struct var_info *tmp_high, struct var_info *tmp_low) > +{ Indentation gone crazy in this function. > + unsigned int i; > + struct expression *expr; > + > + for (i = 0; i < bb->nr_mimic_stack_expr; i++) { > + expr = bb->mimic_stack_expr[i]; > + > + if (expr_type(expr) != EXPR_MIMIC_STACK_SLOT) > + continue; > + > + if (expr->entry != entry || > + expr->slotnb != slotnb) > + continue; > + > + expr_set_type(expr, EXPR_TEMPORARY); > + expr->tmp_high = tmp_high; > + expr->tmp_low = tmp_low; > + } > +} > +static int __do_resolve_mimic_stack_slots(int nr_neighbors, struct > basic_block **neighbors, > + int entry) > +{ The "__do" prefix makes no sense. The "__" is inherited from the kernel and strictly speaking, we should not be using it in userspace. The "do" prefix is what most people seem to do in userspace. But the combination of the two is just... strange. Anyway, I fixed it (and other goofs) up and applied the patch. Thanks! -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
Re: [PATCH 1/3] jit: add EXPR_MIMIC_STACK_SLOT and expr_set_type
On Wed, 2009-06-24 at 22:21 +0200, Arthur HUILLET wrote: > This will be necessary for bc2ir to work. > > Signed-off-by: Arthur HUILLET > @@ -235,6 +236,13 @@ struct expression { > > /* EXPR_ARRAY_SIZE_CHECK and EXPR_MULTIARRAY_SIZE_CHECK */ > struct tree_node *size_expr; > + > + /* EXPR_MIMIC_STACK_SLOT */ > + struct { > + char entry; > + int slotnb; I did s/slotnb/slot_ndx/ for the whole patch. Patch applied. -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
Re: [PATCH 1/2] jit: add predecessors to basic block structure
On Wed, 2009-06-24 at 18:13 +0200, Arthur HUILLET wrote: > diff --git a/test/jit/basic-block-assert.h > b/test/jit/basic-block-assert.h > index 8f00672..abec84c 100644 > --- a/test/jit/basic-block-assert.h > +++ b/test/jit/basic-block-assert.h > @@ -12,16 +12,28 @@ static void inline assert_basic_block(struct > compilation_unit *parent, > assert_int_equals(end, bb->end); > } > > +static void inline __assert_bb_neighbors(struct basic_block **neigh, int > nneigh, struct basic_block **array, unsigned long sz) The more common way to write the above is static inline void Anyway, I went ahead and cleaned up the whole header file which had turned into a big mess. Patch applied. Pekka -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
Re: Monoburg arithmetic operations
On Thu, 2009-06-25 at 00:53 +0200, Arthur Huillet wrote: > I wasted several hours until I noticed that OP_AND was only implemented with > (reg, EXPR_LOCAL). > > The (reg, reg) variant is missing for several binops, and it's very difficult > with monoburg to notice it. Yup, I think it's worth some of our time to spend on either (a) improving monoburg error reporting, (b) switching to some other tool, or (c) writing our own replacement. That said, I think Mono no longer has a "instruction selection" phase as we know it but rather directly generates LIR at the bytecode (or whatever it's called in .NET) parsing phase. Pekka -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
[PATCH] x86: add OP_AND(reg, reg)
It is necessary for System.out.println Signed-off-by: Arthur HUILLET --- arch/x86/emit-code.c|7 +++ arch/x86/include/arch/instruction.h |1 + arch/x86/insn-selector_32.brg | 15 +++ arch/x86/lir-printer.c |7 +++ arch/x86/use-def.c |1 + 5 files changed, 31 insertions(+), 0 deletions(-) diff --git a/arch/x86/emit-code.c b/arch/x86/emit-code.c index d66d9f0..3033adb 100644 --- a/arch/x86/emit-code.c +++ b/arch/x86/emit-code.c @@ -759,6 +759,12 @@ static void emit_add_membase_reg(struct buffer *buf, emit_membase_reg(buf, 0x03, src, dest); } +static void emit_and_reg_reg(struct buffer *buf, +struct operand *src, struct operand *dest) +{ + emit_reg_reg(buf, 0x23, dest, src); +} + static void emit_and_membase_reg(struct buffer *buf, struct operand *src, struct operand *dest) { @@ -1003,6 +1009,7 @@ struct emitter emitters[] = { DECL_EMITTER(INSN_ADD_MEMBASE_REG, emit_add_membase_reg, TWO_OPERANDS), DECL_EMITTER(INSN_ADD_REG_REG, emit_add_reg_reg, TWO_OPERANDS), DECL_EMITTER(INSN_AND_MEMBASE_REG, emit_and_membase_reg, TWO_OPERANDS), + DECL_EMITTER(INSN_AND_REG_REG, emit_and_reg_reg, TWO_OPERANDS), DECL_EMITTER(INSN_CALL_REG, emit_indirect_call, SINGLE_OPERAND), DECL_EMITTER(INSN_CLTD_REG_REG, emit_cltd_reg_reg, TWO_OPERANDS), DECL_EMITTER(INSN_CMP_IMM_REG, emit_cmp_imm_reg, TWO_OPERANDS), diff --git a/arch/x86/include/arch/instruction.h b/arch/x86/include/arch/instruction.h index 5e38144..8355a63 100644 --- a/arch/x86/include/arch/instruction.h +++ b/arch/x86/include/arch/instruction.h @@ -61,6 +61,7 @@ enum insn_type { INSN_ADD_MEMBASE_REG, INSN_ADD_REG_REG, INSN_AND_MEMBASE_REG, + INSN_AND_REG_REG, INSN_CALL_REG, INSN_CALL_REL, INSN_CLTD_REG_REG, /* CDQ in Intel manuals*/ diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg index fce1f50..bbe0f9e 100644 --- a/arch/x86/insn-selector_32.brg +++ b/arch/x86/insn-selector_32.brg @@ -432,6 +432,21 @@ reg: OP_AND(reg, EXPR_LOCAL) 1 } } +reg: OP_AND(reg, reg) 1 +{ + struct expression *expr; + + expr = to_expr(tree); + + state->reg1 = state->left->reg1; + binop_reg_reg_low(state, s, tree, INSN_AND_REG_REG); + + if (expr->vm_type == J_LONG) { + state->reg2 = state->left->reg2; + binop_reg_reg_high(state, s, tree, INSN_AND_REG_REG); + } +} + reg: OP_XOR(reg, EXPR_LOCAL) 1 { struct expression *expr; diff --git a/arch/x86/lir-printer.c b/arch/x86/lir-printer.c index 195f80e..31c89f6 100644 --- a/arch/x86/lir-printer.c +++ b/arch/x86/lir-printer.c @@ -196,6 +196,12 @@ static int print_and_membase_reg(struct string *str, struct insn *insn) return print_membase_reg(str, insn); } +static int print_and_reg_reg(struct string *str, struct insn *insn) +{ + print_func_name(str); + return print_reg_reg(str, insn); +} + static int print_call_reg(struct string *str, struct insn *insn) { print_func_name(str); @@ -501,6 +507,7 @@ static print_insn_fn insn_printers[] = { [INSN_ADD_MEMBASE_REG] = print_add_membase_reg, [INSN_ADD_REG_REG] = print_add_reg_reg, [INSN_AND_MEMBASE_REG] = print_and_membase_reg, + [INSN_AND_REG_REG] = print_and_reg_reg, [INSN_CALL_REG] = print_call_reg, [INSN_CALL_REL] = print_call_rel, [INSN_CLTD_REG_REG] = print_cltd_reg_reg, /* CDQ in Intel manuals*/ diff --git a/arch/x86/use-def.c b/arch/x86/use-def.c index 95342ad..38a4ef4 100644 --- a/arch/x86/use-def.c +++ b/arch/x86/use-def.c @@ -37,6 +37,7 @@ static struct insn_info insn_infos[] = { DECLARE_INFO(INSN_ADD_MEMBASE_REG, USE_SRC | DEF_DST), DECLARE_INFO(INSN_ADD_REG_REG, USE_SRC | DEF_DST), DECLARE_INFO(INSN_AND_MEMBASE_REG, USE_SRC | DEF_DST), + DECLARE_INFO(INSN_AND_REG_REG, USE_SRC | DEF_DST), DECLARE_INFO(INSN_CALL_REG, USE_SRC | DEF_EAX | DEF_ECX | DEF_EDX), DECLARE_INFO(INSN_CALL_REL, USE_NONE | DEF_EAX | DEF_ECX | DEF_EDX), DECLARE_INFO(INSN_CLTD_REG_REG, USE_SRC | DEF_SRC | DEF_DST), -- 1.6.2.2 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
Monoburg arithmetic operations
Hi, I wasted several hours until I noticed that OP_AND was only implemented with (reg, EXPR_LOCAL). The (reg, reg) variant is missing for several binops, and it's very difficult with monoburg to notice it. Implementing the (reg, reg) variants for operations will be my work of tomorrow as it is necessary for System.out.println, as exposed by my tests. This explains the upcoming patches. By the way, System.out.println: jato: arch/x86/insn-selector_32.c:1762: mono_burg_emit: Assertion `!"conversion not implemented"' failed. So that's on my list too :) -- Greetings, A.H. -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
[PATCH] regression: ObjectStackTest now enabled
Signed-off-by: Arthur HUILLET --- regression/jvm/ObjectStackTest.java |3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/regression/jvm/ObjectStackTest.java b/regression/jvm/ObjectStackTest.java index d49cc62..04efeca 100644 --- a/regression/jvm/ObjectStackTest.java +++ b/regression/jvm/ObjectStackTest.java @@ -49,8 +49,7 @@ public class ObjectStackTest extends TestCase { public static void testObjectStackWhenBranching() { assertIsGreaterThanOne(2); -// TODO -// assertIsNotGreaterThanOne(1); +assertIsNotGreaterThanOne(1); } public static void main(String[] args) { -- 1.6.2.2 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
[PATCH 3/3] bc2ir: mimic stack spilling/reloading
Mimic stack is now correctly spilled and reloaded at basic block boundaries. Signed-off-by: Arthur HUILLET --- jit/bytecode-to-ir.c | 155 +- 1 files changed, 141 insertions(+), 14 deletions(-) diff --git a/jit/bytecode-to-ir.c b/jit/bytecode-to-ir.c index 862a335..52d872f 100644 --- a/jit/bytecode-to-ir.c +++ b/jit/bytecode-to-ir.c @@ -102,28 +102,24 @@ void convert_statement(struct parse_context *ctx, struct statement *stmt) static int spill_expression(struct basic_block *bb, struct stack *reload_stack, - struct expression *expr) + struct expression *expr, int slotnb) { - struct compilation_unit *cu = bb->b_parent; - struct var_info *tmp_low, *tmp_high; struct statement *store, *branch; - struct expression *tmp; + struct expression *exit_tmp, *entry_tmp; - tmp_low = get_var(cu); - if (expr->vm_type == J_LONG) - tmp_high = get_var(cu); - else - tmp_high = NULL; + exit_tmp = mimic_stack_expr(expr->vm_type, 0, slotnb); + entry_tmp = mimic_stack_expr(expr->vm_type, 1, slotnb); - tmp = temporary_expr(expr->vm_type, tmp_high, tmp_low); - if (!tmp) + if (!exit_tmp || !entry_tmp) return -ENOMEM; + bb_add_mimic_stack_expr(bb, exit_tmp); + store = alloc_statement(STMT_STORE); if (!store) return -ENOMEM; - store->store_dest = &tmp->node; + store->store_dest = &exit_tmp->node; store->store_src = &expr->node; if (bb->has_branch) @@ -143,7 +139,7 @@ static int spill_expression(struct basic_block *bb, * And add a reload expression that is put on the mimic stack of * successor basic blocks. */ - stack_push(reload_stack, expr_get(tmp)); + stack_push(reload_stack, expr_get(entry_tmp)); return 0; } @@ -160,15 +156,18 @@ static struct stack *spill_mimic_stack(struct basic_block *bb) * The reload stack contains elements in reverse order of the mimic * stack. */ + int spillcount = 0; while (!stack_is_empty(bb->mimic_stack)) { struct expression *expr; int err; expr = stack_pop(bb->mimic_stack); - err = spill_expression(bb, reload_stack, expr); + err = spill_expression(bb, reload_stack, expr, spillcount); if (err) goto error_oom; + + spillcount++; } return reload_stack; error_oom: @@ -259,6 +258,8 @@ static int convert_bb_to_ir(struct basic_block *bb) expr_get(expr); + bb_add_mimic_stack_expr(s, expr); + stack_push(s->mimic_stack, expr); } expr_put(expr); @@ -276,6 +277,121 @@ out: return err; } +static void assign_temporary(struct basic_block *bb, int entry, int slotnb, + struct var_info *tmp_high, struct var_info *tmp_low) +{ + unsigned int i; + struct expression *expr; + + for (i = 0; i < bb->nr_mimic_stack_expr; i++) { + expr = bb->mimic_stack_expr[i]; + + if (expr_type(expr) != EXPR_MIMIC_STACK_SLOT) + continue; + + if (expr->entry != entry || + expr->slotnb != slotnb) + continue; + + expr_set_type(expr, EXPR_TEMPORARY); + expr->tmp_high = tmp_high; + expr->tmp_low = tmp_low; + } +} + +static void pick_and_propagate_temporaries(struct basic_block *bb, int entry) +{ + struct expression *expr; + struct var_info *tmp_high, *tmp_low; + struct basic_block **neighbors; + int neighbors_nr; + unsigned int i; + int slotnb; + + if (entry) { + neighbors = bb->predecessors; + neighbors_nr = bb->nr_predecessors; + } else { + neighbors = bb->successors; + neighbors_nr = bb->nr_successors; + } + + for (i = 0; i < bb->nr_mimic_stack_expr; i++) { + expr = bb->mimic_stack_expr[i]; + + /* Skip expressions that already been transformed */ + if (expr_type(expr) != EXPR_MIMIC_STACK_SLOT) + continue; + + /* Skip slots related to the exit when treating entrance +* and vice versa */ + if (expr->entry != entry) + continue; + + tmp_low = get_var(bb->b_parent); + if (expr->vm_type == J_LONG) + tmp_high = get_var(bb->b_parent); + else tmp_high = NULL; + +
[PATCH 2/3] jit: add list of mimic stack exprs to struct basic_block
BC2IR needs it to properly replace them by temporaries. Signed-off-by: Arthur HUILLET --- include/jit/basic-block.h |3 +++ jit/basic-block.c | 26 -- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/include/jit/basic-block.h b/include/jit/basic-block.h index 4919c95..c953ebe 100644 --- a/include/jit/basic-block.h +++ b/include/jit/basic-block.h @@ -26,6 +26,8 @@ struct basic_block { struct basic_block **successors; unsigned long nr_predecessors; struct basic_block **predecessors; + unsigned long nr_mimic_stack_expr; + struct expression **mimic_stack_expr; unsigned long mach_offset; /* The mimic stack is used to simulate JVM operand stack at @@ -69,6 +71,7 @@ struct basic_block *bb_split(struct basic_block *, unsigned long); void bb_add_stmt(struct basic_block *, struct statement *); void bb_add_insn(struct basic_block *, struct insn *); int bb_add_successor(struct basic_block *, struct basic_block *); +int bb_add_mimic_stack_expr(struct basic_block *, struct expression *); struct statement *bb_remove_last_stmt(struct basic_block *bb); unsigned char *bb_native_ptr(struct basic_block *bb); diff --git a/jit/basic-block.c b/jit/basic-block.c index 5a4fa53..23709a0 100644 --- a/jit/basic-block.c +++ b/jit/basic-block.c @@ -77,6 +77,7 @@ void free_basic_block(struct basic_block *bb) free_insn_list(&bb->insn_list); free(bb->successors); free(bb->predecessors); + free(bb->mimic_stack_expr); free(bb->use_set); free(bb->def_set); free(bb->live_in_set); @@ -146,20 +147,20 @@ void bb_add_insn(struct basic_block *bb, struct insn *insn) list_add_tail(&insn->insn_list_node, &bb->insn_list); } -int __bb_add_neighbor(struct basic_block *new, struct basic_block ***array, unsigned long *nb) +int __bb_add_neighbor(void *new, void **array, unsigned long *nb) { unsigned long new_size; - struct basic_block **new_neighbors; + void *new_array; - new_size = sizeof(struct basic_block *) * (*nb + 1); + new_size = sizeof(void *) * (*nb + 1); - new_neighbors = realloc(*array, new_size); - if (new_neighbors == NULL) + new_array = realloc(*array, new_size); + if (new_array == NULL) return -ENOMEM; - *array = new_neighbors; + *array = new_array; - (*array)[*nb] = new; + ((void **)(*array))[*nb] = new; (*nb)++; return 0; @@ -167,13 +168,18 @@ int __bb_add_neighbor(struct basic_block *new, struct basic_block ***array, unsi int bb_add_successor(struct basic_block *bb, struct basic_block *successor) { - __bb_add_neighbor(bb, &successor->predecessors, &successor->nr_predecessors); - return __bb_add_neighbor(successor, &bb->successors, &bb->nr_successors); + __bb_add_neighbor(bb, (void **)&successor->predecessors, &successor->nr_predecessors); + return __bb_add_neighbor(successor, (void **)&bb->successors, &bb->nr_successors); } int bb_add_predecessor(struct basic_block *bb, struct basic_block *predecessor) { - return __bb_add_neighbor(predecessor, &bb->predecessors, &bb->nr_predecessors); + return __bb_add_neighbor(predecessor, (void **)&bb->predecessors, &bb->nr_predecessors); +} + +int bb_add_mimic_stack_expr(struct basic_block *bb, struct expression *expr) +{ + return __bb_add_neighbor(expr, (void **)&bb->mimic_stack_expr, &bb->nr_mimic_stack_expr); } unsigned char *bb_native_ptr(struct basic_block *bb) -- 1.6.2.2 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
[PATCH 1/3] jit: add EXPR_MIMIC_STACK_SLOT and expr_set_type
This will be necessary for bc2ir to work. Signed-off-by: Arthur HUILLET --- include/jit/expression.h | 16 jit/expression.c | 12 jit/tree-printer.c | 11 +-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/jit/expression.h b/include/jit/expression.h index 43b41c0..d771778 100644 --- a/include/jit/expression.h +++ b/include/jit/expression.h @@ -35,6 +35,7 @@ enum expression_type { EXPR_NULL_CHECK, EXPR_ARRAY_SIZE_CHECK, EXPR_MULTIARRAY_SIZE_CHECK, + EXPR_MIMIC_STACK_SLOT, EXPR_LAST, /* Not a real type. Keep this last. */ }; @@ -235,6 +236,13 @@ struct expression { /* EXPR_ARRAY_SIZE_CHECK and EXPR_MULTIARRAY_SIZE_CHECK */ struct tree_node *size_expr; + + /* EXPR_MIMIC_STACK_SLOT */ + struct { + char entry; + int slotnb; + }; + }; }; @@ -248,6 +256,13 @@ static inline enum expression_type expr_type(struct expression *expr) return (expr->node.op & EXPR_TYPE_MASK) >> EXPR_TYPE_SHIFT; } +static inline void expr_set_type(struct expression *expr, int type) +{ + unsigned long op = expr->node.op & ~EXPR_TYPE_MASK; + type <<= EXPR_TYPE_SHIFT; + expr->node.op = op | type; +} + static inline enum binary_operator expr_bin_op(struct expression *expr) { return (expr->node.op & OP_MASK) >> OP_SHIFT; @@ -268,6 +283,7 @@ struct expression *value_expr(enum vm_type, unsigned long long); struct expression *fvalue_expr(enum vm_type, double); struct expression *local_expr(enum vm_type, unsigned long); struct expression *temporary_expr(enum vm_type, struct var_info *, struct var_info *); +struct expression *mimic_stack_expr(enum vm_type, int, int); struct expression *array_deref_expr(enum vm_type, struct expression *, struct expression *); struct expression *binop_expr(enum vm_type, enum binary_operator, struct expression *, struct expression *); struct expression *unary_op_expr(enum vm_type, enum unary_operator, struct expression *); diff --git a/jit/expression.c b/jit/expression.c index 8e4d736..a73217c 100644 --- a/jit/expression.c +++ b/jit/expression.c @@ -44,6 +44,7 @@ int expr_nr_kids(struct expression *expr) case EXPR_NO_ARGS: case EXPR_NEW: case EXPR_EXCEPTION_REF: + case EXPR_MIMIC_STACK_SLOT: return 0; default: assert(!"Invalid expression type"); @@ -134,6 +135,17 @@ struct expression *temporary_expr(enum vm_type vm_type, struct var_info *tmp_hig return expr; } +struct expression *mimic_stack_expr(enum vm_type vm_type, int entry, int slotnb) +{ + struct expression *expr = alloc_expression(EXPR_MIMIC_STACK_SLOT, vm_type); + if (expr) { + expr->entry = entry; + expr->slotnb = slotnb; + } + + return expr; +} + struct expression *array_deref_expr(enum vm_type vm_type, struct expression *arrayref, struct expression *array_index) diff --git a/jit/tree-printer.c b/jit/tree-printer.c index c96c87b..7a8c32a 100644 --- a/jit/tree-printer.c +++ b/jit/tree-printer.c @@ -84,7 +84,7 @@ static int simple_expr(struct expression *expr) return type == EXPR_VALUE || type == EXPR_FVALUE || type == EXPR_LOCAL || type == EXPR_TEMPORARY || type == EXPR_CLASS_FIELD - || type == EXPR_NO_ARGS || type == EXPR_EXCEPTION_REF; + || type == EXPR_NO_ARGS || type == EXPR_EXCEPTION_REF || type == EXPR_MIMIC_STACK_SLOT; } static int __tree_print(int, struct tree_node *, struct string *); @@ -355,6 +355,12 @@ static int print_temporary_expr(int lvl, struct string *str, expr->tmp_high, expr->tmp_low); } +static int print_mimic_stack_slot_expr(int lvl, struct string *str, + struct expression *expr) +{ + return str_append(str, "[mimic stack slot %d at %s]", expr->slotnb, expr->entry ? "entry" : "exit"); +} + static int print_array_deref_expr(int lvl, struct string *str, struct expression *expr) { @@ -807,7 +813,8 @@ static print_expr_fn expr_printers[] = { [EXPR_EXCEPTION_REF] = print_exception_ref_expr, [EXPR_NULL_CHECK] = print_null_check_expr, [EXPR_ARRAY_SIZE_CHECK] = print_array_size_check_expr, - [EXPR_MULTIARRAY_SIZE_CHECK] = print_multiarray_size_check_expr + [EXPR_MULTIARRAY_SIZE_CHECK] = print_multiarray_size_check_expr, + [EXPR_MIMIC_STACK_SLOT] = print_mimic_stack_slot_expr, }; -- 1.6.2.2 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm
[PATCH 2/2] jit: set up bb predecessors in bb_add_successor
Signed-off-by: Arthur HUILLET --- jit/basic-block.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/jit/basic-block.c b/jit/basic-block.c index df984eb..5a4fa53 100644 --- a/jit/basic-block.c +++ b/jit/basic-block.c @@ -167,6 +167,7 @@ int __bb_add_neighbor(struct basic_block *new, struct basic_block ***array, unsi int bb_add_successor(struct basic_block *bb, struct basic_block *successor) { + __bb_add_neighbor(bb, &successor->predecessors, &successor->nr_predecessors); return __bb_add_neighbor(successor, &bb->successors, &bb->nr_successors); } -- 1.6.2.2 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
[PATCH 1/2] jit: add predecessors to basic block structure
The list of predecessors is not set yet, this is just the infrastructure. Signed-off-by: Arthur HUILLET --- include/jit/basic-block.h |2 ++ jit/basic-block.c | 32 +++- jit/trace-jit.c | 23 +++ test/jit/basic-block-assert.h | 22 +- 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/include/jit/basic-block.h b/include/jit/basic-block.h index b555d9e..4919c95 100644 --- a/include/jit/basic-block.h +++ b/include/jit/basic-block.h @@ -24,6 +24,8 @@ struct basic_block { unsigned long br_target_off;/* Branch target offset in bytecode insns. */ unsigned long nr_successors; struct basic_block **successors; + unsigned long nr_predecessors; + struct basic_block **predecessors; unsigned long mach_offset; /* The mimic stack is used to simulate JVM operand stack at diff --git a/jit/basic-block.c b/jit/basic-block.c index 22b102a..df984eb 100644 --- a/jit/basic-block.c +++ b/jit/basic-block.c @@ -76,6 +76,7 @@ void free_basic_block(struct basic_block *bb) free_stmt_list(&bb->stmt_list); free_insn_list(&bb->insn_list); free(bb->successors); + free(bb->predecessors); free(bb->use_set); free(bb->def_set); free(bb->live_in_set); @@ -112,6 +113,9 @@ struct basic_block *bb_split(struct basic_block *orig_bb, unsigned long offset) new_bb->nr_successors = orig_bb->nr_successors; orig_bb->nr_successors = 0; + new_bb->predecessors = NULL; + new_bb->nr_predecessors = 0; + if (orig_bb->has_branch) { orig_bb->has_branch = false; new_bb->has_branch = true; @@ -142,25 +146,35 @@ void bb_add_insn(struct basic_block *bb, struct insn *insn) list_add_tail(&insn->insn_list_node, &bb->insn_list); } -int bb_add_successor(struct basic_block *bb, struct basic_block *successor) +int __bb_add_neighbor(struct basic_block *new, struct basic_block ***array, unsigned long *nb) { - int new_size; - struct basic_block **new_successors; + unsigned long new_size; + struct basic_block **new_neighbors; - new_size = sizeof(struct basic_block *) * (bb->nr_successors + 1); + new_size = sizeof(struct basic_block *) * (*nb + 1); - new_successors = realloc(bb->successors, new_size); - if (new_successors == NULL) + new_neighbors = realloc(*array, new_size); + if (new_neighbors == NULL) return -ENOMEM; - bb->successors = new_successors; + *array = new_neighbors; - bb->successors[bb->nr_successors] = successor; - bb->nr_successors++; + (*array)[*nb] = new; + (*nb)++; return 0; } +int bb_add_successor(struct basic_block *bb, struct basic_block *successor) +{ + return __bb_add_neighbor(successor, &bb->successors, &bb->nr_successors); +} + +int bb_add_predecessor(struct basic_block *bb, struct basic_block *predecessor) +{ + return __bb_add_neighbor(predecessor, &bb->predecessors, &bb->nr_predecessors); +} + unsigned char *bb_native_ptr(struct basic_block *bb) { return buffer_ptr(bb->b_parent->objcode) + bb->mach_offset; diff --git a/jit/trace-jit.c b/jit/trace-jit.c index c11a896..feb23d8 100644 --- a/jit/trace-jit.c +++ b/jit/trace-jit.c @@ -54,7 +54,7 @@ void trace_cfg(struct compilation_unit *cu) struct basic_block *bb; printf("Control Flow Graph:\n\n"); - printf(" #:\t\tRange\t\tSuccessors\n"); + printf(" #:\t\tRange\t\tSuccessors\t\tPredecessors\n"); for_each_basic_block(bb, &cu->bb_list) { unsigned long i; @@ -63,15 +63,30 @@ void trace_cfg(struct compilation_unit *cu) if (bb->is_eh) printf(" (eh)"); + printf("\t"); + for (i = 0; i < bb->nr_successors; i++) { - if (i == 0) - printf("\t"); - else + if (i != 0) printf(", "); printf("%p", bb->successors[i]); } + if (i == 0) + printf("none"); + + printf("\t"); + + for (i = 0; i < bb->nr_predecessors; i++) { + if (i != 0) + printf(", "); + + printf("%p", bb->predecessors[i]); + } + + if (i == 0) + printf("none"); + printf("\n"); } diff --git a/test/jit/basic-block-assert.h b/test/jit/basic-block-assert.h index 8f00672..abec84c 100644 --- a/test/jit/basic-block-assert.h +++ b/test/jit/basic-block-assert.h @@ -12,16 +12,28 @@ static void inline assert_basic_block(struct compilation_unit *parent, assert_int_equals(end, bb->e
[PATCH] bc2ir: fix refcount bug in spill_expression
Signed-off-by: Arthur HUILLET --- jit/bytecode-to-ir.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/jit/bytecode-to-ir.c b/jit/bytecode-to-ir.c index 76fd5a4..862a335 100644 --- a/jit/bytecode-to-ir.c +++ b/jit/bytecode-to-ir.c @@ -143,7 +143,7 @@ static int spill_expression(struct basic_block *bb, * And add a reload expression that is put on the mimic stack of * successor basic blocks. */ - stack_push(reload_stack, tmp); + stack_push(reload_stack, expr_get(tmp)); return 0; } -- 1.6.2.2 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
[PATCH 2/7] vm: replace signal_from_jit_method() with signal_from_native()
The rationale for this is the same as for commit 3d406995e21bf1695f6abc743fb37d16cc387f9e ("jit: remove is_jit_method() and introduce is_native()") Signed-off-by: Tomek Grabiec --- arch/x86/include/arch/signal.h |2 +- arch/x86/signal.c |9 ++--- vm/signal.c|8 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/arch/signal.h b/arch/x86/include/arch/signal.h index 1940a34..69406cd 100644 --- a/arch/x86/include/arch/signal.h +++ b/arch/x86/include/arch/signal.h @@ -19,7 +19,7 @@ struct compilation_unit; -bool signal_from_jit_method(void *ctx); +bool signal_from_native(void *ctx); struct compilation_unit *get_signal_source_cu(void *ctx); #endif diff --git a/arch/x86/signal.c b/arch/x86/signal.c index 61d7eba..f36464c 100644 --- a/arch/x86/signal.c +++ b/arch/x86/signal.c @@ -32,18 +32,13 @@ #include -bool signal_from_jit_method(void *ctx) +bool signal_from_native(void *ctx) { ucontext_t *uc; - unsigned long ip; uc = ctx; - ip = uc->uc_mcontext.gregs[REG_IP]; - if (is_native(ip)) - return false; - - return true; + return is_native(uc->uc_mcontext.gregs[REG_IP]); } struct compilation_unit *get_signal_source_cu(void *ctx) diff --git a/vm/signal.c b/vm/signal.c index d52ea50..2453549 100644 --- a/vm/signal.c +++ b/vm/signal.c @@ -51,19 +51,23 @@ static void throw_null_pointer_exception(void) static void sigfpe_handler(int sig, siginfo_t *si, void *ctx) { - if (signal_from_jit_method(ctx) && si->si_code == FPE_INTDIV) { + if (signal_from_native(ctx)) + goto exit; + + if (si->si_code == FPE_INTDIV) { if (install_signal_bh(ctx, throw_arithmetic_exception) == 0) return; fprintf(stderr, "%s: install_signal_bh() failed.\n", __func__); } + exit: print_backtrace_and_die(sig, si, ctx); } static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) { - if (!signal_from_jit_method(ctx)) + if (signal_from_native(ctx)) goto exit; /* Assume that zero-page access is caused by dereferencing a -- 1.6.0.6 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
[PATCH 5/7] vm: the foundation for java stack trace collecting
A number of utility functions are introduced for backtrace traversal to assist java stack trace collecting. Only JIT methods and VM natives should appear in stack trace so all native functions and trampolines must be filtered out. A new per-thread variable bottom_stack_frame is introduced to detect when to stop tracig back. It is set to a native frame pointer of the function that calls the main() method. Signed-off-by: Tomek Grabiec --- Makefile|3 +- arch/x86/include/arch/stack-frame.h | 18 +++-- arch/x86/stack-frame.c | 17 include/vm/stack-trace.h| 39 + test/arch-x86/stack-frame-test_32.c |6 ++ vm/jato.c |4 + vm/stack-trace.c| 160 +++ 7 files changed, 240 insertions(+), 7 deletions(-) create mode 100644 include/vm/stack-trace.h create mode 100644 vm/stack-trace.c diff --git a/Makefile b/Makefile index 76fc6b9..1d39741 100644 --- a/Makefile +++ b/Makefile @@ -104,7 +104,8 @@ VM_OBJS = \ vm/class.o \ vm/list.o \ vm/radix-tree.o \ - vm/guard-page.o + vm/guard-page.o \ + vm/stack-trace.o JAMVM_OBJS = \ vm/jato.o \ diff --git a/arch/x86/include/arch/stack-frame.h b/arch/x86/include/arch/stack-frame.h index 3813668..e9b2ad9 100644 --- a/arch/x86/include/arch/stack-frame.h +++ b/arch/x86/include/arch/stack-frame.h @@ -8,13 +8,19 @@ struct methodblock; struct expression; struct compilation_unit; +struct native_stack_frame { + void *prev; /* previous stack frame link */ + unsigned long return_address; + unsigned long args[0]; +} __attribute__((packed)); + struct jit_stack_frame { - struct jit_stack_frame *prev; - unsigned long old_ebx; - unsigned long old_esi; - unsigned long old_edi; - unsigned long return_address; - unsigned long args[0]; + void *prev; /* previous stack frame link */ + unsigned long old_ebx; + unsigned long old_esi; + unsigned long old_edi; + unsigned long return_address; + unsigned long args[0]; } __attribute__((packed)); unsigned long frame_local_offset(struct methodblock *, struct expression *); diff --git a/arch/x86/stack-frame.c b/arch/x86/stack-frame.c index 1754592..dc8ff82 100644 --- a/arch/x86/stack-frame.c +++ b/arch/x86/stack-frame.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -100,3 +101,19 @@ unsigned long cu_frame_locals_offset(struct compilation_unit *cu) unsigned long frame_size = frame_locals_size(cu->stack_frame); return frame_size * sizeof(unsigned long); } + +/* + * Checks whether given native function was called from jit trampoline + * code. It checks whether return address points after a relative call + * to jit_magic_trampoline, which is typical for trampolines. + */ +bool called_from_jit_trampoline(struct native_stack_frame *frame) +{ + void **call_rel_target_p; + void *call_target; + + call_rel_target_p = (void **)(frame->return_address - sizeof(void*)); + call_target = *call_rel_target_p + frame->return_address; + + return call_target == &jit_magic_trampoline; +} diff --git a/include/vm/stack-trace.h b/include/vm/stack-trace.h new file mode 100644 index 000..5064ecf --- /dev/null +++ b/include/vm/stack-trace.h @@ -0,0 +1,39 @@ +#ifndef JATO_VM_STACK_TRACE_H +#define JATO_VM_STACK_TRACE_H + +#include +#include + +#include + +/* + * Points to a native stack frame that is considered as bottom-most + * for given thread. + */ +extern __thread struct native_stack_frame *bottom_stack_frame; + +struct stack_trace_elem { + /* Holds instruction address of this stack trace element. */ + unsigned long addr; + + /* +* If true then @frame has format of struct native_stack_frame +* and struct jit_stack_frame otherwise. +*/ + bool is_native; + + /* If true then frame belongs to a trampoline */ + bool is_trampoline; + + /* Points to a stack frame of this stack trace element. */ + void *frame; +}; + +int init_stack_trace_elem(struct stack_trace_elem *elem); +int get_prev_stack_trace_elem(struct stack_trace_elem *elem); +int skip_frames_from_class(struct stack_trace_elem *elem, struct object *class); +int get_stack_trace_depth(struct stack_trace_elem *elem); + +bool called_from_jit_trampoline(struct native_stack_frame *frame); + +#endif /* JATO_VM_STACK_TRACE_H */ diff --git a/test/arch-x86/stack-frame-test_32.c b/test/arch-x86/stack-frame-test_32.c index db53f06..1fd5b6a 100644 --- a/test/arch-x86/stack-frame-test_32.c +++ b/test/arch-x86/stack-frame-test_32.c @@ -8,6 +8,12 @@ #include #include +/* Stub required by called_from_jit_trampoline() in arch/x86/stack-frame.c */ +void *jit_magic_trampoline(struct compilation_unit *cu) +{
[PATCH 4/7] vm: put all functions implementing virtual machine native methods in a separate section
All VM natives should be placed in a .vm_native section to allow stack traversal functions to distinguish between regular native functions and native functions which implement native java methods. The former ones do not appear in stack trace but the latter do. Signed-off-by: Tomek Grabiec --- Makefile |3 +- arch/x86/jato_32.ld | 199 ++ include/vm/natives.h | 17 vm/jato.c|4 +- 4 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 arch/x86/jato_32.ld diff --git a/Makefile b/Makefile index 1161405..76fc6b9 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ endif export ARCH_CFLAGS ARCH_CONFIG=arch/$(ARCH)/include/arch/config$(ARCH_POSTFIX).h +LINKER_SCRIPT=arch/$(ARCH)/jato$(ARCH_POSTFIX).ld # Make the build silent by default V = @@ -193,7 +194,7 @@ arch/$(ARCH)/insn-selector$(ARCH_POSTFIX).c: FORCE $(PROGRAM): lib monoburg $(JAMVM_ARCH_H) compile $(E) " CC " $@ - $(Q) $(CC) $(DEFAULT_CFLAGS) $(CFLAGS) $(OBJS) -o $(PROGRAM) $(LIBS) $(DEFAULT_LIBS) + $(Q) $(CC) -T $(LINKER_SCRIPT) $(DEFAULT_CFLAGS) $(CFLAGS) $(OBJS) -o $(PROGRAM) $(LIBS) $(DEFAULT_LIBS) compile: $(OBJS) diff --git a/arch/x86/jato_32.ld b/arch/x86/jato_32.ld new file mode 100644 index 000..083ea62 --- /dev/null +++ b/arch/x86/jato_32.ld @@ -0,0 +1,199 @@ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version: { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn: +{ + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) +} + .rela.dyn : +{ + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) +} + .rel.plt: { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { +KEEP (*(.init)) + } =0x90909090 + .plt: { *(.plt) } + .text : + { +*(.text .stub .text.* .gnu.linkonce.t.*) +KEEP (*(.text.*personality*)) +/* .gnu.warning sections are handled specially by elf32.em. */ +*(.gnu.warning) + } =0x90909090 + .fini : + { +KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1: { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { +PROVIDE_HIDDEN (__preinit_array_start = .); +KEEP (*(.preinit_array)) +PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { +PROVIDE_HIDDEN (__fini_array_start = .); +KEEP (*(.fini_array)) +KEEP (*(SORT(.fini_array.*))) +PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { +/* gcc uses crtbegin.o to find the start of +
[PATCH 6/7] vm: support for stack trace printing
The natives VMThrowable.fillInStackTrace and VMThrowable.getStackTrace are implemented. The stack trace can not be printed yet by invoking printStackTrace() on java.lang.Throwable instance because jato cannot execute PrintStream.print() yet. The stack trace can be however printed when printStackTrace() is executed by JamVM which happens when exception is thrown out of main() method. Signed-off-by: Tomek Grabiec --- include/jit/bc-offset-mapping.h |1 + include/vm/stack-trace.h| 11 ++ jit/bc-offset-mapping.c | 14 +++ vm/jato.c | 17 +-- vm/stack-trace.c| 238 +++ 5 files changed, 270 insertions(+), 11 deletions(-) diff --git a/include/jit/bc-offset-mapping.h b/include/jit/bc-offset-mapping.h index c47ea51..b6d76a6 100644 --- a/include/jit/bc-offset-mapping.h +++ b/include/jit/bc-offset-mapping.h @@ -13,5 +13,6 @@ unsigned long native_ptr_to_bytecode_offset(struct compilation_unit *cu, void print_bytecode_offset(unsigned long bc_offset, struct string *str); void tree_patch_bc_offset(struct tree_node *node, unsigned long bc_offset); bool all_insn_have_bytecode_offset(struct compilation_unit *cu); +int bytecode_offset_to_line_no(struct methodblock *mb, unsigned long bc_offset); #endif diff --git a/include/vm/stack-trace.h b/include/vm/stack-trace.h index 5064ecf..72d192a 100644 --- a/include/vm/stack-trace.h +++ b/include/vm/stack-trace.h @@ -2,6 +2,9 @@ #define JATO_VM_STACK_TRACE_H #include + +#include +#include #include #include @@ -29,10 +32,18 @@ struct stack_trace_elem { void *frame; }; +void init_stack_trace_printing(void); int init_stack_trace_elem(struct stack_trace_elem *elem); int get_prev_stack_trace_elem(struct stack_trace_elem *elem); int skip_frames_from_class(struct stack_trace_elem *elem, struct object *class); int get_stack_trace_depth(struct stack_trace_elem *elem); +struct object *get_stack_trace(struct stack_trace_elem *); +struct object *get_stack_trace_from_ctx(void *ctx); +struct object *convert_stack_trace(struct object *vmthrowable); +struct object *new_stack_trace_element(struct methodblock *, unsigned long); +struct object * __vm_native vm_throwable_fill_in_stack_trace(struct object *); +struct object * __vm_native vm_throwable_get_stack_trace(struct object *, struct object *); +void set_throwable_vmstate(struct object *throwable, struct object *vmstate); bool called_from_jit_trampoline(struct native_stack_frame *frame); diff --git a/jit/bc-offset-mapping.c b/jit/bc-offset-mapping.c index be3756d..f7b097e 100644 --- a/jit/bc-offset-mapping.c +++ b/jit/bc-offset-mapping.c @@ -116,3 +116,17 @@ bool all_insn_have_bytecode_offset(struct compilation_unit *cu) return true; } + +int bytecode_offset_to_line_no(struct methodblock *mb, unsigned long bc_offset) +{ + int i; + + if(mb->line_no_table_size == 0 || bc_offset == BC_OFFSET_UNKNOWN) + return -1; + + i = mb->line_no_table_size - 1; + while (i && bc_offset < mb->line_no_table[i].start_pc) + i--; + + return mb->line_no_table[i].line_no; +} diff --git a/vm/jato.c b/vm/jato.c index 10e3353..00e71c1 100644 --- a/vm/jato.c +++ b/vm/jato.c @@ -274,21 +274,14 @@ static void __vm_native vm_runtime_exit(int status) exitVM(status); } -/* - * This stub is needed by java.lang.VMThrowable constructor to work. It should - * return java.lang.VMState instance, or null in which case no stack trace will - * be printed by printStackTrace() method. - */ -static struct object * __vm_native vm_fill_in_stack_trace(struct object *object) -{ - return NULL; -} - static void jit_init_natives(void) { vm_register_native("java/lang/VMRuntime", "exit", vm_runtime_exit); vm_register_native("jato/internal/VM", "exit", vm_runtime_exit); - vm_register_native("java/lang/VMThrowable", "fillInStackTrace", vm_fill_in_stack_trace); + vm_register_native("java/lang/VMThrowable", "fillInStackTrace", + vm_throwable_fill_in_stack_trace); + vm_register_native("java/lang/VMThrowable", "getStackTrace", + vm_throwable_get_stack_trace); } int main(int argc, char *argv[]) { @@ -321,6 +314,8 @@ int main(int argc, char *argv[]) { exitVM(1); } +init_stack_trace_printing(); + mainThreadSetContextClassLoader(system_loader); for(cpntr = argv[class_arg]; *cpntr; cpntr++) diff --git a/vm/stack-trace.c b/vm/stack-trace.c index 773b501..a92e8f4 100644 --- a/vm/stack-trace.c +++ b/vm/stack-trace.c @@ -25,12 +25,66 @@ */ #include #include +#include +#include #include +#include #include +#include + __thread struct native_stack_frame *bottom_stack_frame; +static struct object *vmthrowable_class; +static struct object *throwable_class; +static struct object *ste_class; +static struct object *ste_array_class; +static int backtrace_offset; +static in
[PATCH 7/7] jit: fix condition on which fixup_direct_calls() is called from jit_magic_trampoline()
fixup_direct_calls() should be called whenever return address (ret) is not NULL, it should not depend on whether compilation unit is marked as compiled. That's because native methods are never marked as compiled and yet we can fixup the calls. Signed-off-by: Tomek Grabiec --- jit/trampoline.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/jit/trampoline.c b/jit/trampoline.c index 1fe6503..833a7d5 100644 --- a/jit/trampoline.c +++ b/jit/trampoline.c @@ -112,7 +112,7 @@ void *jit_magic_trampoline(struct compilation_unit *cu) * Therefore, do fixup for direct call sites unconditionally and fixup * vtables if method can be invoked via invokevirtual. */ - if (cu->is_compiled) + if (ret) fixup_direct_calls(method->trampoline, (unsigned long) ret); pthread_mutex_unlock(&cu->mutex); -- 1.6.0.6 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel
[PATCH 1/7] vm: move code creating exceptions out of signal handlers
It is not safe to execute jit code in signal handler context. One of the reasons is that throwing-by-signal mechanisms don't work in code executed from signal handler. That's becasue kernel will not execute user defined signal handler for SIGSEGV when second signal occures while executing the handler. This issue is addressed by introducing "bottom halfs". These are functions which are executed in normal context immediately after signal handler returns. They are installed by manipulating ucontext_t structure associated with signal handler. Signed-off-by: Tomek Grabiec --- arch/x86/signal.c | 28 include/vm/signal.h |3 +++ vm/signal.c | 45 + 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/arch/x86/signal.c b/arch/x86/signal.c index 6b59881..61d7eba 100644 --- a/arch/x86/signal.c +++ b/arch/x86/signal.c @@ -30,6 +30,8 @@ #include #include +#include + bool signal_from_jit_method(void *ctx) { ucontext_t *uc; @@ -51,3 +53,29 @@ struct compilation_unit *get_signal_source_cu(void *ctx) uc = ctx; return get_cu_from_native_addr(uc->uc_mcontext.gregs[REG_IP]); } + +/** + * install_signal_bh - installs signal's bottom half function by + * modifying user context so that control will be returned to @bh + * when signal handler returns. When @bh function returns, the + * control should be returned to the source of the signal. + * + * @ctx: pointer to struct ucontext_t + * @bh: bottom half function to install + */ +int install_signal_bh(void *ctx, signal_bh_fn bh) +{ + unsigned long *stack; + ucontext_t *uc; + + uc = ctx; + + /* push return address on stack */ + stack = (unsigned long*)uc->uc_mcontext.gregs[REG_SP] - 1; + *stack = uc->uc_mcontext.gregs[REG_IP]; + uc->uc_mcontext.gregs[REG_SP] -= sizeof(unsigned long); + + uc->uc_mcontext.gregs[REG_IP] = (unsigned long)bh; + + return 0; +} diff --git a/include/vm/signal.h b/include/vm/signal.h index 8aee067..dad9381 100644 --- a/include/vm/signal.h +++ b/include/vm/signal.h @@ -1,6 +1,9 @@ #ifndef VM_SIGNAL_H #define VM_SIGNAL_H +typedef void (*signal_bh_fn)(void); + void setup_signal_handlers(void); +int install_signal_bh(void *ctx, signal_bh_fn bh); #endif /* VM_SIGNAL_H */ diff --git a/vm/signal.c b/vm/signal.c index 747276a..d52ea50 100644 --- a/vm/signal.c +++ b/vm/signal.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -35,25 +36,28 @@ #include #include +static void throw_arithmetic_exception(void) +{ + signal_new_exception("java/lang/ArithmeticException", +"division by zero"); + throw_from_native(0); +} + +static void throw_null_pointer_exception(void) +{ + signal_new_exception("java/lang/NullPointerException", NULL); + throw_from_native(0); +} + static void sigfpe_handler(int sig, siginfo_t *si, void *ctx) { if (signal_from_jit_method(ctx) && si->si_code == FPE_INTDIV) { - struct object *exception; - - /* TODO: exception's stack trace should be filled using ctx */ - exception = new_exception( - "java/lang/ArithmeticException", "division by zero"); - if (exception == NULL) { - /* TODO: throw OutOfMemoryError */ - fprintf(stderr, "%s: Out of memory\n", __func__); - goto exit; - } + if (install_signal_bh(ctx, throw_arithmetic_exception) == 0) + return; - throw_exception_from_signal(ctx, exception); - return; + fprintf(stderr, "%s: install_signal_bh() failed.\n", __func__); } - exit: print_backtrace_and_die(sig, si, ctx); } @@ -65,23 +69,16 @@ static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) /* Assume that zero-page access is caused by dereferencing a null pointer */ if ((unsigned long)si->si_addr < (unsigned long)getpagesize()) { - struct object *exception; - /* We must be extra caucious here because IP might be invalid */ if (get_signal_source_cu(ctx) == NULL) goto exit; - /* TODO: exception's stack trace should be filled using ctx */ - exception = new_exception("java/lang/NullPointerException", NULL); - if (exception == NULL) { - /* TODO: throw OutOfMemoryError */ - fprintf(stderr, "%s: Out of memory\n", __func__); - goto exit; - } + if (install_signal_bh(ctx, throw_null_pointer_exception) == 0) + return; - throw_exception_from_signal(ctx, exception); - return; + fpr
[PATCH 3/7] vm: skip __cleanup_args if args_size is 0.
Signed-off-by: Tomek Grabiec --- arch/x86/include/arch/stack-frame.h |8 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/arch/stack-frame.h b/arch/x86/include/arch/stack-frame.h index 3f27fae..3813668 100644 --- a/arch/x86/include/arch/stack-frame.h +++ b/arch/x86/include/arch/stack-frame.h @@ -52,7 +52,7 @@ unsigned long cu_frame_locals_offset(struct compilation_unit *cu); */ #ifdef CONFIG_X86_32 #define __cleanup_args(args_size) \ - ({ \ + if (args_size) {\ __asm__ volatile ( \ "movl %%ebp, %%esi \n" \ "addl %1, %%esi \n"\ @@ -78,10 +78,10 @@ unsigned long cu_frame_locals_offset(struct compilation_unit *cu); : "b" (args_size), "n"(2*sizeof(unsigned long))\ : "%eax", "%edi", "%esi", "%ecx", "cc", "memory" \ ); \ - }) + } #else #define __cleanup_args(args_size) \ - ({ \ + if (args_size) {\ __asm__ volatile ( \ "movq %%rbp, %%rsi \n" \ "addq %1, %%rsi \n"\ @@ -107,7 +107,7 @@ unsigned long cu_frame_locals_offset(struct compilation_unit *cu); : "b" (args_size), "n"(2*sizeof(unsigned long))\ : "%rax", "%rdi", "%rsi", "%rcx", "cc", "memory" \ ); \ - }) + } #endif #endif -- 1.6.0.6 -- ___ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel