Stack unwinding will need a way to get the compilation_unit of the caller. This will be also needed by printStackTrace to work.
Signed-off-by: Tomek Grabiec <[email protected]> --- arch/x86/emit-code_32.c | 12 ++++++++- arch/x86/include/arch/emit-code.h | 2 +- arch/x86/include/arch/stack-frame.h | 15 ++++++++++ arch/x86/stack-frame.c | 46 +++++++++++++++++++++++++++++--- jit/emit.c | 2 +- test/arch-mmix/stack-frame.c | 41 +++++++++++++++++++++++++++++ test/arch-x86/emit-code-test_32.c | 24 +++++++++++----- test/arch-x86/insn-selector-test_32.c | 17 ++++++----- test/arch-x86/stack-frame-test_32.c | 11 ++++--- test/arch-x86/stack-frame-utils.h | 7 +++++ test/include/arch/stack-frame.h | 9 ++++++ 11 files changed, 157 insertions(+), 29 deletions(-) create mode 100644 test/arch-mmix/stack-frame.c create mode 100644 test/arch-x86/stack-frame-utils.h diff --git a/arch/x86/emit-code_32.c b/arch/x86/emit-code_32.c index 3be09f1..62f2a1c 100644 --- a/arch/x86/emit-code_32.c +++ b/arch/x86/emit-code_32.c @@ -27,6 +27,9 @@ #include <stdbool.h> #include <string.h> +static void __emit_add_imm_reg(struct buffer *buf, long imm, enum machine_reg reg); +static void __emit_push_imm(struct buffer *buf, long imm); + /* * __encode_reg: Encode register to be used in IA-32 instruction. * @reg: Register to encode. @@ -394,8 +397,12 @@ static void emit_sbb_reg_reg(struct buffer *buf, struct operand *src, emit_reg_reg(buf, 0x1B, src, dest); } -void emit_prolog(struct buffer *buf, unsigned long nr_locals) +void emit_prolog(struct compilation_unit *cu, struct buffer *buf, + unsigned long nr_locals) { + /* push pointer to method's compilation unit */ + __emit_push_imm(buf, (long)cu); + /* Unconditionally push callee-saved registers */ __emit_push_reg(buf, REG_EDI); __emit_push_reg(buf, REG_ESI); @@ -474,6 +481,9 @@ void emit_epilog(struct buffer *buf, unsigned long nr_locals) __emit_pop_reg(buf, REG_ESI); __emit_pop_reg(buf, REG_EDI); + /* Discard compilation unit pointer */ + __emit_add_imm_reg(buf, 0x04, REG_ESP); + emit_ret(buf); } diff --git a/arch/x86/include/arch/emit-code.h b/arch/x86/include/arch/emit-code.h index 52d1ef4..1e8eb16 100644 --- a/arch/x86/include/arch/emit-code.h +++ b/arch/x86/include/arch/emit-code.h @@ -6,7 +6,7 @@ struct compilation_unit; struct basic_block; struct buffer; -void emit_prolog(struct buffer *, unsigned long); +void emit_prolog(struct compilation_unit *, struct buffer *, unsigned long); void emit_epilog(struct buffer *, unsigned long); void emit_body(struct basic_block *, struct buffer *); void emit_trampoline(struct compilation_unit *, void *, struct jit_trampoline*); diff --git a/arch/x86/include/arch/stack-frame.h b/arch/x86/include/arch/stack-frame.h index ec1338a..d048375 100644 --- a/arch/x86/include/arch/stack-frame.h +++ b/arch/x86/include/arch/stack-frame.h @@ -6,8 +6,23 @@ struct methodblock; struct expression; +struct compilation_unit; + +struct jit_stack_frame { + struct jit_stack_frame *prev; + unsigned long old_ebx; + unsigned long old_esi; + unsigned long old_edi; + struct compilation_unit *cu; + unsigned long return_address; + unsigned long args[0]; +} __attribute__((packed)); + unsigned long frame_local_offset(struct methodblock *, struct expression *); unsigned long slot_offset(struct stack_slot *slot); unsigned long frame_locals_size(struct stack_frame *frame); +unsigned long jit_frame_locals_offset(struct jit_stack_frame *frame); +struct compilation_unit *get_cu_from_stack_frame(struct jit_stack_frame *frame); +bool called_from_jitted(struct jit_stack_frame *frame); #endif diff --git a/arch/x86/stack-frame.c b/arch/x86/stack-frame.c index cf1a612..384ad43 100644 --- a/arch/x86/stack-frame.c +++ b/arch/x86/stack-frame.c @@ -25,15 +25,17 @@ */ #include <jit/expression.h> +#include <jit/compilation-unit.h> #include <vm/vm.h> #include <arch/stack-frame.h> #include <stdlib.h> /* - * The three callee-saved registers are unconditionally stored on the stack - * after EIP and EBP (see emit_prolog() for details). Therefore, there are five - * 32-bit stack slots before the first argument to a function as illustrated by - * the following diagram: + * The three callee-saved registers are unconditionally stored on the + * stack after EIP and pointer to struct compilation_unit (see + * emit_prolog() for details). Therefore, there are five 32-bit stack + * slots before the first argument to a function as illustrated by the + * following diagram: * * : : ^ * : : | Higher memory addresses @@ -42,6 +44,7 @@ * : ... : * | Arg 1 | <-- Start offset of arguments * | Old EIP | + * | cu | <-- pointer to struct compilation_unit * | EDI | * | ESI | * | EBX | @@ -51,7 +54,7 @@ * | Local m : * +--------------+ */ -#define ARGS_START_OFFSET (sizeof(unsigned long) * 5) +#define ARGS_START_OFFSET offsetof(struct jit_stack_frame,args) static unsigned long __index_to_offset(unsigned long index) { @@ -90,3 +93,36 @@ unsigned long frame_locals_size(struct stack_frame *frame) unsigned long nr_locals = frame->nr_local_slots - frame->nr_args; return __index_to_offset(nr_locals + frame->nr_spill_slots); } + +struct compilation_unit *get_cu_from_stack_frame(struct jit_stack_frame *frame) +{ + return frame->cu; +} + +/* Points to the first address past text segment */ +extern char etext; + +/* + * Checks whether return address belongs to jitted or JATO method. + * This is used in deciding when to stop the unwind process upon + * exception throwing. + * + * It utilises the fact, that jitted code is allocated on heap. So by + * comparing return address with text segment end we can tell whether + * the caller is on heap or in text. + */ +bool called_from_jitted(struct jit_stack_frame *frame) +{ + return frame->return_address >= (unsigned long)&etext; +} + +/* + * Returns total offset to subtract from ESP to reserve space for locals. + */ +unsigned long jit_frame_locals_offset(struct jit_stack_frame *frame) +{ + struct compilation_unit *cu = get_cu_from_stack_frame(frame); + unsigned long frame_size = frame_locals_size(cu->stack_frame); + + return sizeof(unsigned long) * frame_size; +} diff --git a/jit/emit.c b/jit/emit.c index 1c8af96..b36df07 100644 --- a/jit/emit.c +++ b/jit/emit.c @@ -37,7 +37,7 @@ int emit_machine_code(struct compilation_unit *cu) frame_size = frame_locals_size(cu->stack_frame); - emit_prolog(cu->objcode, frame_size); + emit_prolog(cu, cu->objcode, frame_size); for_each_basic_block(bb, &cu->bb_list) emit_body(bb, cu->objcode); diff --git a/test/arch-mmix/stack-frame.c b/test/arch-mmix/stack-frame.c new file mode 100644 index 0000000..c1da03b --- /dev/null +++ b/test/arch-mmix/stack-frame.c @@ -0,0 +1,41 @@ +/* + * 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 <arch/stack-frame.h> + +struct jit_stack_frame { + unsigned long dummy; +}; + +struct compilation_unit *get_cu_from_stack_frame(struct jit_stack_frame *frame) +{ + return NULL; +} + +bool called_from_jitted(struct jit_stack_frame *frame) +{ + return false; +} diff --git a/test/arch-x86/emit-code-test_32.c b/test/arch-x86/emit-code-test_32.c index a793713..4cd81a7 100644 --- a/test/arch-x86/emit-code-test_32.c +++ b/test/arch-x86/emit-code-test_32.c @@ -16,6 +16,7 @@ #include <test/vars.h> #include <libharness.h> +#include <stack-frame-utils.h> static struct methodblock method; @@ -133,29 +134,35 @@ static void assert_emit_insn_7(unsigned char opcode, unsigned char modrm, void test_emit_prolog_no_locals(void) { - unsigned char expected[] = { 0x57, 0x56, 0x53, 0x55, 0x89, 0xe5}; + struct compilation_unit *cu = (struct compilation_unit*)0xcafebabe; + unsigned char expected[] = { 0x68, 0xbe, 0xba, 0xfe, 0xca, 0x57, 0x56, + 0x53, 0x55, 0x89, 0xe5}; struct buffer *buf; buf = alloc_buffer(); - emit_prolog(buf, 0); + emit_prolog(cu, buf, 0); assert_mem_equals(expected, buffer_ptr(buf), ARRAY_SIZE(expected)); free_buffer(buf); } void test_emit_prolog_has_locals(void) { - unsigned char expected[] = { 0x57, 0x56, 0x53, 0x55, 0x89, 0xe5, 0x81, 0xec, 0x80, 0x00, 0x00, 0x00 }; + struct compilation_unit *cu = (struct compilation_unit*)0xcafebabe; + unsigned char expected[] = { 0x68, 0xbe, 0xba, 0xfe, 0xca, 0x57, 0x56, + 0x53, 0x55, 0x89, 0xe5, 0x81, 0xec, 0x80, + 0x00, 0x00, 0x00 }; struct buffer *buf; buf = alloc_buffer(); - emit_prolog(buf, 0x20); + emit_prolog(cu, buf, 0x20); assert_mem_equals(expected, buffer_ptr(buf), ARRAY_SIZE(expected)); free_buffer(buf); } void test_emit_epilog_no_locals(void) { - unsigned char expected[] = { 0x5d, 0x5b, 0x5e, 0x5f, 0xc3 }; + unsigned char expected[] = { 0x5d, 0x5b, 0x5e, 0x5f, 0x83, 0xc4, 0x04, + 0xc3 }; struct buffer *buf; buf = alloc_buffer(); @@ -166,7 +173,8 @@ void test_emit_epilog_no_locals(void) void test_emit_epilog_has_locals(void) { - unsigned char expected[] = { 0xc9, 0x5b, 0x5e, 0x5f, 0xc3 }; + unsigned char expected[] = { 0xc9, 0x5b, 0x5e, 0x5f, 0x83, 0xc4, 0x04, + 0xc3 }; struct buffer *buf; buf = alloc_buffer(); @@ -281,8 +289,8 @@ void test_emit_mov_reg_memlocal(void) slot = get_local_slot(frame, 0); wide_slot = get_local_slot(frame, 31); - assert_emit_insn_3(0x89, 0x45, 0x14, reg_memlocal_insn(INSN_MOV_REG_MEMLOCAL, &VAR_EAX, slot)); - assert_emit_insn_6(0x89, 0x9d, 0x90, 0x00, 0x00, 0x00, reg_memlocal_insn(INSN_MOV_REG_MEMLOCAL, &VAR_EBX, wide_slot)); + assert_emit_insn_3(0x89, 0x45, ARG_OFFSET(0), reg_memlocal_insn(INSN_MOV_REG_MEMLOCAL, &VAR_EAX, slot)); + assert_emit_insn_6(0x89, 0x9d, ARG_OFFSET(31), 0x00, 0x00, 0x00, reg_memlocal_insn(INSN_MOV_REG_MEMLOCAL, &VAR_EBX, wide_slot)); free_stack_frame(frame); } diff --git a/test/arch-x86/insn-selector-test_32.c b/test/arch-x86/insn-selector-test_32.c index b573ed4..eb33799 100644 --- a/test/arch-x86/insn-selector-test_32.c +++ b/test/arch-x86/insn-selector-test_32.c @@ -10,6 +10,7 @@ #include <vm/vm.h> #include <vm/class.h> #include <arch/instruction.h> +#include <stack-frame-utils.h> #include <test/vars.h> #include <test/vm.h> @@ -177,14 +178,14 @@ void test_should_select_insn_for_every_statement(void) assert_memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, 0, dreg, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_membase_reg_insn(INSN_ADD_MEMBASE_REG, REG_EBP, 24, dreg, insn); + assert_membase_reg_insn(INSN_ADD_MEMBASE_REG, REG_EBP, ARG_OFFSET(1), dreg, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); dreg = mach_reg(&insn->dest.reg); assert_memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, 2, dreg, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_membase_reg_insn(INSN_ADD_MEMBASE_REG, REG_EBP, 32, dreg, insn); + assert_membase_reg_insn(INSN_ADD_MEMBASE_REG, REG_EBP, ARG_OFFSET(3), dreg, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); assert_reg_reg_insn(INSN_MOV_REG_REG, dreg, REG_EAX, insn); @@ -235,7 +236,7 @@ static void assert_select_local_local_binop(enum binary_operator expr_op, enum i insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); dreg = mach_reg(&insn->dest.reg); - assert_membase_reg_insn(insn_type, REG_EBP, 24, dreg, insn); + assert_membase_reg_insn(insn_type, REG_EBP, ARG_OFFSET(1), dreg, insn); free_compilation_unit(bb->b_parent); } @@ -292,7 +293,7 @@ void test_select_local_local_mul(void) assert_reg_reg_insn(INSN_MOV_REG_REG, dreg, REG_EAX, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_membase_reg_insn(INSN_MUL_MEMBASE_EAX, REG_EBP, 24, REG_EAX, insn); + assert_membase_reg_insn(INSN_MUL_MEMBASE_EAX, REG_EBP, ARG_OFFSET(1), REG_EAX, insn); free_compilation_unit(bb->b_parent); } @@ -317,7 +318,7 @@ void test_select_local_local_div(void) assert_reg_reg_insn(INSN_CLTD_REG_REG, REG_EAX, REG_EDX, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_membase_reg_insn(INSN_DIV_MEMBASE_REG, REG_EBP, 24, REG_EAX, insn); + assert_membase_reg_insn(INSN_DIV_MEMBASE_REG, REG_EBP, ARG_OFFSET(1), REG_EAX, insn); free_compilation_unit(bb->b_parent); } @@ -342,7 +343,7 @@ void test_select_local_local_rem(void) assert_reg_reg_insn(INSN_CLTD_REG_REG, REG_EAX, REG_EDX, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_membase_reg_insn(INSN_DIV_MEMBASE_REG, REG_EBP, 24, REG_EAX, insn); + assert_membase_reg_insn(INSN_DIV_MEMBASE_REG, REG_EBP, ARG_OFFSET(1), REG_EAX, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); assert_reg_reg_insn(INSN_MOV_REG_REG, REG_EDX, REG_EAX, insn); @@ -409,7 +410,7 @@ static void assert_select_local_local_shift(enum binary_operator expr_op, enum i assert_memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, 0, dreg, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_membase_reg_insn(INSN_MOV_MEMBASE_REG, REG_EBP, 24, REG_ECX, insn); + assert_membase_reg_insn(INSN_MOV_MEMBASE_REG, REG_EBP, ARG_OFFSET(1), REG_ECX, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); assert_reg_reg_insn(insn_type, REG_ECX, dreg, insn); @@ -736,7 +737,7 @@ static void assert_select_if_statement_local_local(enum insn_type expected, assert_memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, 0, dreg, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_membase_reg_insn(INSN_CMP_MEMBASE_REG, REG_EBP, 24, dreg, insn); + assert_membase_reg_insn(INSN_CMP_MEMBASE_REG, REG_EBP, ARG_OFFSET(1), dreg, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); assert_branch_insn(expected, stmt->if_true, insn); diff --git a/test/arch-x86/stack-frame-test_32.c b/test/arch-x86/stack-frame-test_32.c index db53f06..0b03584 100644 --- a/test/arch-x86/stack-frame-test_32.c +++ b/test/arch-x86/stack-frame-test_32.c @@ -5,6 +5,7 @@ #include <jit/expression.h> #include <vm/vm.h> #include <arch/stack-frame.h> +#include <stack-frame-utils.h> #include <stdlib.h> #include <libharness.h> @@ -19,13 +20,13 @@ static void assert_local_offset(unsigned long expected, struct expression *local void test_should_map_local_index_to_frame_offset(void) { - assert_local_offset(20, local_expr(J_INT, 0), 2); - assert_local_offset(24, local_expr(J_INT, 1), 2); + assert_local_offset(ARG_OFFSET(0), local_expr(J_INT, 0), 2); + assert_local_offset(ARG_OFFSET(1), local_expr(J_INT, 1), 2); } void test_should_map_local_variables_after_last_arg_at_negative_offsets(void) { - assert_local_offset(20, local_expr(J_INT, 0), 1); + assert_local_offset(ARG_OFFSET(0), local_expr(J_INT, 0), 1); assert_local_offset(-4, local_expr(J_INT, 1), 1); assert_local_offset(-8, local_expr(J_INT, 2), 1); } @@ -43,8 +44,8 @@ void test_arguments_are_at_successive_positive_offsets(void) param1 = get_local_slot(frame, 0); param2 = get_local_slot(frame, 1); - assert_int_equals(0x14, slot_offset(param1)); - assert_int_equals(0x18, slot_offset(param2)); + assert_int_equals(ARG_OFFSET(0), slot_offset(param1)); + assert_int_equals(ARG_OFFSET(1), slot_offset(param2)); free_stack_frame(frame); } diff --git a/test/arch-x86/stack-frame-utils.h b/test/arch-x86/stack-frame-utils.h new file mode 100644 index 0000000..68836f3 --- /dev/null +++ b/test/arch-x86/stack-frame-utils.h @@ -0,0 +1,7 @@ +#ifndef _STACK_FRAME_UTILS_ +#define _STACK_FRAME_UTILS_ + +#define ARGS_START_OFFSET (sizeof(unsigned long) * 6) +#define ARG_OFFSET(x) (ARGS_START_OFFSET + (x) * sizeof(unsigned long)) + +#endif diff --git a/test/include/arch/stack-frame.h b/test/include/arch/stack-frame.h index 946ac33..d8e5188 100644 --- a/test/include/arch/stack-frame.h +++ b/test/include/arch/stack-frame.h @@ -1,4 +1,13 @@ #ifndef MMIX_STACK_FRAME_H #define MMIX_STACK_FRAME_H +#include <stdlib.h> +#include <stdbool.h> + +struct jit_stack_frame; +struct compilation_unit; + +struct compilation_unit *get_cu_from_stack_frame(struct jit_stack_frame *frame); +bool called_from_jitted(struct jit_stack_frame *frame); + #endif /* MMIX_STACK_FRAME_H */ -- 1.6.0.6 ------------------------------------------------------------------------------ The NEW KODAK i700 Series Scanners deliver under ANY circumstances! Your production scanning environment may not be a perfect world - but thanks to Kodak, there's a perfect scanner to get the job done! With the NEW KODAK i700 Series Scanner you'll get full speed at 300 dpi even with all image processing features enabled. http://p.sf.net/sfu/kodak-com _______________________________________________ Jatovm-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/jatovm-devel
