From 04320d4509faebf34b82bfab59155ad4f61b72ae Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Mon, 24 May 2004 04:19:42 +0000 Subject: [PATCH] Rewrite the exception region routines to make them easier to use from CLI and JVM style systems. --- ChangeLog | 10 + include/jit/jit-insn.h | 30 ++- include/jit/jit-opcode.h | 23 +- jit/jit-block.c | 19 -- jit/jit-dump.c | 9 +- jit/jit-except.c | 2 +- jit/jit-function.c | 131 ----------- jit/jit-insn.c | 460 ++++++++++++++++++++------------------- jit/jit-internal.h | 35 +-- jit/jit-interp.c | 30 ++- jit/jit-interp.h | 5 - jit/jit-opcode.c | 13 +- jit/jit-rules-arm.c | 11 - jit/jit-rules-interp.c | 79 +++---- jit/jit-rules-x86.c | 71 ------ jit/jit-rules.h | 3 - jit/jit-setjmp.h | 6 +- 17 files changed, 359 insertions(+), 578 deletions(-) diff --git a/ChangeLog b/ChangeLog index 35b9524..bb5dc29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,14 @@ +2004-05-24 Rhys Weatherley + + * include/jit/jit-insn.h, include/jit/jit-opcode.h, jit/jit-block.c, + jit/jit-dump.c, jit/jit-except.c, jit/jit-function.c, jit/jit-insn.c, + jit/jit-internal.h, jit/jit-interp.c, jit/jit-interp.h, + jit/jit-opcode.c, jit/jit-rules-arm.c, jit/jit-rules-interp.c, + jit/jit-rules-x86.c, jit/jit-rules.h, jit/jit-setjmp.h: + rewrite the exception region routines to make them easier + to use from CLI and JVM style systems. + 2004-05-22 Rhys Weatherley * jit/jit-block.c (_jit_block_peephole_branch): don't allow diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h index 43318bf..d19d169 100644 --- a/include/jit/jit-insn.h +++ b/include/jit/jit-insn.h @@ -210,6 +210,8 @@ int jit_insn_branch_if_not (jit_function_t func, jit_value_t value, jit_label_t *label) JIT_NOTHROW; jit_value_t jit_insn_address_of (jit_function_t func, jit_value_t value1) JIT_NOTHROW; +jit_value_t jit_insn_address_of_label + (jit_function_t func, jit_label_t *label) JIT_NOTHROW; jit_value_t jit_insn_convert (jit_function_t func, jit_value_t value, jit_type_t type, int overflow_check) JIT_NOTHROW; @@ -255,20 +257,26 @@ int jit_insn_return_ptr int jit_insn_default_return(jit_function_t func) JIT_NOTHROW; int jit_insn_throw(jit_function_t func, jit_value_t value) JIT_NOTHROW; jit_value_t jit_insn_get_call_stack(jit_function_t func) JIT_NOTHROW; -int jit_insn_start_try - (jit_function_t func, jit_label_t *catch_label, - jit_label_t *finally_label, int finally_on_fault); -jit_value_t jit_insn_start_catch - (jit_function_t func, jit_label_t *catch_label); -int jit_insn_end_try(jit_function_t func); -int jit_insn_start_finally(jit_function_t func, jit_label_t *finally_label); -int jit_insn_return_from_finally(jit_function_t func); + +jit_value_t jit_insn_thrown_exception(jit_function_t func) JIT_NOTHROW; +int jit_insn_uses_catcher(jit_function_t func) JIT_NOTHROW; +jit_value_t jit_insn_start_catcher(jit_function_t func) JIT_NOTHROW; +int jit_insn_branch_if_pc_not_in_range + (jit_function_t func, jit_label_t start_label, + jit_label_t end_label, jit_label_t *label) JIT_NOTHROW; +int jit_insn_rethrow_unhandled(jit_function_t func) JIT_NOTHROW; +int jit_insn_start_finally + (jit_function_t func, jit_label_t *finally_label) JIT_NOTHROW; +int jit_insn_return_from_finally(jit_function_t func) JIT_NOTHROW; +int jit_insn_call_finally + (jit_function_t func, jit_label_t *finally_label) JIT_NOTHROW; jit_value_t jit_insn_start_filter - (jit_function_t func, jit_label_t *label, jit_type_t type); -int jit_insn_return_from_filter(jit_function_t func, jit_value_t value); + (jit_function_t func, jit_label_t *label, jit_type_t type) JIT_NOTHROW; +int jit_insn_return_from_filter + (jit_function_t func, jit_value_t value) JIT_NOTHROW; jit_value_t jit_insn_call_filter (jit_function_t func, jit_label_t *label, - jit_value_t value, jit_type_t type); + jit_value_t value, jit_type_t type) JIT_NOTHROW; int jit_insn_memcpy (jit_function_t func, jit_value_t dest, diff --git a/include/jit/jit-opcode.h b/include/jit/jit-opcode.h index 9116c0f..8f51f7d 100644 --- a/include/jit/jit-opcode.h +++ b/include/jit/jit-opcode.h @@ -403,17 +403,17 @@ extern "C" { * Exception handling. */ #define JIT_OP_THROW 0x014C -#define JIT_OP_LOAD_PC 0x014D -#define JIT_OP_ENTER_CATCH 0x014E -#define JIT_OP_ENTER_FINALLY 0x014F -#define JIT_OP_LEAVE_FINALLY 0x0150 -#define JIT_OP_ENTER_FILTER 0x0151 -#define JIT_OP_LEAVE_FILTER 0x0152 -#define JIT_OP_CALL_FILTER 0x0153 -#define JIT_OP_CALL_FILTER_RETURN 0x0154 -#define JIT_OP_PREPARE_FOR_LEAVE 0x0155 -#define JIT_OP_PREPARE_FOR_RETURN 0x0156 -#define JIT_OP_JUMP_TO_CATCHER 0x0157 +#define JIT_OP_RETHROW 0x014D +#define JIT_OP_LOAD_PC 0x014E +#define JIT_OP_LOAD_EXCEPTION_PC 0x014F +#define JIT_OP_ENTER_FINALLY 0x0150 +#define JIT_OP_LEAVE_FINALLY 0x0151 +#define JIT_OP_CALL_FINALLY 0x0152 +#define JIT_OP_ENTER_FILTER 0x0153 +#define JIT_OP_LEAVE_FILTER 0x0154 +#define JIT_OP_CALL_FILTER 0x0155 +#define JIT_OP_CALL_FILTER_RETURN 0x0156 +#define JIT_OP_ADDRESS_OF_LABEL 0x0157 /* * Data manipulation. @@ -547,6 +547,7 @@ struct jit_opcode_info #define JIT_OPCODE_IS_CALL 0x00002000 #define JIT_OPCODE_IS_CALL_EXTERNAL 0x00004000 #define JIT_OPCODE_IS_REG 0x00008000 +#define JIT_OPCODE_IS_ADDROF_LABEL 0x00010000 #define JIT_OPCODE_OPER_MASK 0x01F00000 #define JIT_OPCODE_OPER_NONE 0x00000000 #define JIT_OPCODE_OPER_ADD 0x00100000 diff --git a/jit/jit-block.c b/jit/jit-block.c index 9517e0e..ae9cb90 100644 --- a/jit/jit-block.c +++ b/jit/jit-block.c @@ -43,8 +43,6 @@ void _jit_block_free(jit_function_t func) { jit_block_t current = func->builder->first_block; jit_block_t next; - jit_block_eh_t current_eh; - jit_block_eh_t next_eh; while(current != 0) { next = current->next; @@ -52,19 +50,10 @@ void _jit_block_free(jit_function_t func) jit_free(current); current = next; } - current_eh = func->builder->exception_handlers; - while(current_eh != 0) - { - next_eh = current_eh->next; - jit_free(current_eh); - current_eh = next_eh; - } func->builder->first_block = 0; func->builder->last_block = 0; func->builder->entry = 0; func->builder->current_block = 0; - func->builder->exception_handlers = 0; - func->builder->current_handler = 0; } jit_block_t _jit_block_create(jit_function_t func, jit_label_t *label) @@ -100,9 +89,6 @@ jit_block_t _jit_block_create(jit_function_t func, jit_label_t *label) block->label = jit_label_undefined; } - /* Set the exception handling context for this block */ - block->block_eh = func->builder->current_handler; - /* Add the block to the end of the function's list */ block->next = 0; block->prev = func->builder->last_block; @@ -481,11 +467,6 @@ void _jit_block_peephole_branch(jit_block_t block) { break; } - if(new_block->block_eh != block->block_eh && insn->opcode != JIT_OP_BR) - { - /* Conditional branches must never cross an exception context */ - break; - } if(new_block->first_insn < new_block->last_insn) { /* There is more than one instruction in this block, diff --git a/jit/jit-dump.c b/jit/jit-dump.c index 2a504e6..a48134c 100644 --- a/jit/jit-dump.c +++ b/jit/jit-dump.c @@ -406,6 +406,12 @@ void jit_dump_insn(FILE *stream, jit_function_t func, jit_insn_t insn) putc(')', stream); return; } + else if((flags & JIT_OPCODE_IS_ADDROF_LABEL) != 0) + { + fprintf(stream, "address_of_label .L%ld", + (long)(jit_insn_get_label(insn))); + return; + } /* Output the destination information */ if((flags & JIT_OPCODE_DEST_MASK) != JIT_OPCODE_DEST_EMPTY && @@ -598,7 +604,8 @@ static void dump_interp_code(FILE *stream, void **pc, void **end) default: { - if((info->flags & JIT_OPCODE_IS_BRANCH) != 0) + if((info->flags & (JIT_OPCODE_IS_BRANCH | + JIT_OPCODE_IS_ADDROF_LABEL)) != 0) { fprintf(stream, " %08lX", (long)(jit_nint)((pc - 1) + (jit_nint)(*pc))); diff --git a/jit/jit-except.c b/jit/jit-except.c index 7a63942..2f34bf7 100644 --- a/jit/jit-except.c +++ b/jit/jit-except.c @@ -485,7 +485,7 @@ void _jit_unwind_push_setjmp(jit_jmp_buf *jbuf) if(control) { jbuf->trace = control->backtrace_head; - jbuf->catcher = 0; + jbuf->catch_pc = 0; jbuf->parent = control->setjmp_head; control->setjmp_head = jbuf; } diff --git a/jit/jit-function.c b/jit/jit-function.c index ac22229..a831326 100644 --- a/jit/jit-function.c +++ b/jit/jit-function.c @@ -431,66 +431,6 @@ jit_function_t jit_function_get_nested_parent(jit_function_t func) } } -/* - * Call "finally" blocks that are relevant for a transition from - * "src" to "dest". "dest" should be NULL for a return instruction. - */ -static void call_finally_blocks(jit_gencode_t gen, jit_function_t func, - jit_block_eh_t src, jit_block_eh_t dest) -{ - jit_block_eh_t temp; - - /* Bail out if we are branching to an inner scope, because we - don't need to call "finally" clauses to go further in */ - temp = dest; - while(temp != 0) - { - if(temp == src) - { - return; - } - temp = temp->parent; - } - - /* Find the common ancestor of "src" and "dest" */ - while(dest != 0) - { - temp = src; - while(temp != 0 && temp != dest) - { - temp = temp->parent; - } - if(temp != 0) - { - break; - } - dest = dest->parent; - } - - /* Output all finally blocks between "src" and "dest" */ - while(src != dest) - { - if(src->catch_label != jit_label_undefined && - !(src->finally_on_fault)) - { - /* Call "finally" from the body of the "try" */ - if(src->finally_label != jit_label_undefined) - { - _jit_gen_call_finally(gen, func, src->finally_label); - } - } - else if(src->catch_label == jit_label_undefined) - { - /* Call "finally" from the body of the "catch" */ - if(src->finally_label != jit_label_undefined) - { - _jit_gen_call_finally(gen, func, src->finally_label); - } - } - src = src->parent; - } -} - /* * Compile a single basic block within a function. */ @@ -499,7 +439,6 @@ static void compile_block(jit_gencode_t gen, jit_function_t func, { jit_insn_iter_t iter; jit_insn_t insn; - jit_block_t branch_block; /* Iterate over all blocks in the function */ jit_insn_iter_init(&iter, block); @@ -519,28 +458,6 @@ static void compile_block(jit_gencode_t gen, jit_function_t func, } break; - case JIT_OP_PREPARE_FOR_LEAVE: - { - /* Call the finally clauses that are relevant to the - "JIT_OP_BR" instruction that follows */ - _jit_regs_spill_all(gen); - insn = jit_insn_iter_next(&iter); - branch_block = jit_block_from_label - (func, (jit_label_t)(insn->dest)); - call_finally_blocks - (gen, func, block->block_eh, branch_block->block_eh); - _jit_gen_insn(gen, func, block, insn); - } - break; - - case JIT_OP_PREPARE_FOR_RETURN: - { - /* Call all finally clauses on the way out of the function */ - _jit_regs_spill_all(gen); - call_finally_blocks(gen, func, block->block_eh, 0); - } - break; - case JIT_OP_INCOMING_REG: { /* Assign a register to an incoming value */ @@ -626,10 +543,6 @@ int jit_function_compile(jit_function_t func) void *recompilable_start = 0; void *end; jit_block_t block; - jit_block_eh_t eh; - jit_block_eh_t new_eh; - jit_cache_eh_t cache_eh; - jit_cache_eh_t cache_new_eh; int result; #ifdef JIT_PROLOG_SIZE int have_prolog; @@ -708,8 +621,6 @@ int jit_function_compile(jit_function_t func) /* Generate code for the blocks in the function */ block = 0; - eh = 0; - cache_eh = 0; while((block = jit_block_next(func, block)) != 0) { /* If this block is never entered, then discard it */ @@ -718,34 +629,6 @@ int jit_function_compile(jit_function_t func) continue; } - /* Start a new exception region in the cache if necessary */ - new_eh = block->block_eh; - if(new_eh && new_eh->catch_label == jit_label_undefined) - { - new_eh = 0; - } - if(new_eh != eh) - { - eh = new_eh; - cache_new_eh = _jit_cache_alloc - (&(gen.posn), sizeof(struct jit_cache_eh)); - if(cache_new_eh) - { - if(eh) - { - cache_new_eh->handler_label = eh->catch_label; - } - else - { - cache_new_eh->handler_label = jit_label_undefined; - } - cache_new_eh->handler = 0; - cache_new_eh->previous = cache_eh; - _jit_cache_new_region(&(gen.posn), cache_new_eh); - cache_eh = cache_new_eh; - } - } - /* Notify the back end that the block is starting */ _jit_gen_start_block(&gen, block); @@ -762,20 +645,6 @@ int jit_function_compile(jit_function_t func) _jit_regs_init_for_block(&gen); } - /* Fix up the labels for the exception regions */ - while(cache_eh != 0) - { - if(cache_eh->handler_label != jit_label_undefined) - { - block = jit_block_from_label(func, cache_eh->handler_label); - if(block) - { - cache_eh->handler = (unsigned char *)(block->address); - } - } - cache_eh = cache_eh->previous; - } - /* Output the function epilog. All return paths will jump to here */ _jit_gen_epilog(&gen, func); end = gen.posn.ptr; diff --git a/jit/jit-insn.c b/jit/jit-insn.c index c65d5b9..5ad7c0a 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -946,6 +946,11 @@ jit_label_t jit_insn_get_label(jit_insn_t insn) { return (jit_label_t)(insn->dest); } + else if(insn && (insn->flags & JIT_INSN_VALUE1_IS_LABEL) != 0) + { + /* "address_of_label" instruction */ + return (jit_label_t)(insn->value1); + } else { return 0; @@ -3439,33 +3444,6 @@ jit_value_t jit_insn_sign(jit_function_t func, jit_value_t value1) } } -/* - * Output instructions to handle "finally" clauses in the current context. - */ -static int handle_finally(jit_function_t func, int opcode) -{ - jit_block_eh_t eh = func->builder->current_handler; - while(eh != 0) - { - if(eh->finally_on_fault) - { - /* The "finally" clause only applies to the "catch" block */ - if(!(eh->in_try_body) && - eh->finally_label != jit_label_undefined) - { - return create_noarg_note(func, opcode); - } - } - else if(eh->finally_label != jit_label_undefined) - { - /* The "finally" clause applies to "try" body and the "catch" */ - return create_noarg_note(func, opcode); - } - eh = eh->parent; - } - return 1; -} - /*@ * @deftypefun int jit_insn_branch (jit_function_t func, {jit_label_t *} label) * Terminate the current block by branching unconditionally @@ -3484,10 +3462,6 @@ int jit_insn_branch(jit_function_t func, jit_label_t *label) { return 0; } - if(!handle_finally(func, JIT_OP_PREPARE_FOR_LEAVE)) - { - return 0; - } insn = _jit_block_add_insn(func->builder->current_block); if(!insn) { @@ -3936,6 +3910,42 @@ jit_value_t jit_insn_address_of(jit_function_t func, jit_value_t value1) return result; } +/*@ + * @deftypefun jit_value_t jit_insn_address_of_label (jit_function_t func, {jit_label_t *} label) + * Get the address of @code{label} into a new temporary. This is typically + * used for exception handling, to track where in a function an exception + * was actually thrown. + * @end deftypefun +@*/ +jit_value_t jit_insn_address_of_label(jit_function_t func, jit_label_t *label) +{ + jit_value_t dest; + jit_insn_t insn; + if(!_jit_function_ensure_builder(func) || !label) + { + return 0; + } + if(*label == jit_label_undefined) + { + *label = (func->builder->next_label)++; + } + insn = _jit_block_add_insn(func->builder->current_block); + if(!insn) + { + return 0; + } + dest = jit_value_create(func, jit_type_void_ptr); + if(!dest) + { + return 0; + } + insn->opcode = (short)JIT_OP_ADDRESS_OF_LABEL; + insn->flags = JIT_INSN_VALUE1_IS_LABEL; + insn->dest = dest; + insn->value1 = (jit_value_t)label; + return dest; +} + /* * Information about the opcodes for a particular conversion. */ @@ -4708,13 +4718,9 @@ static int setup_eh_frame_for_call(jit_function_t func, int flags) jit_type_free(type); #endif - /* Are we currently within a "try" context covered by a "catch"? */ - block = func->builder->current_block; - if(block->block_eh && - block->block_eh->catch_label != jit_label_undefined && - func->builder->setjmp_value != 0) + /* Update the "catch_pc" value to reflect the current context */ + if(func->builder->setjmp_value != 0) { - /* Set the "catcher" field within "setjmp_value" to the catcher */ args[0] = jit_value_create(func, jit_type_void_ptr); if(!(args[0])) { @@ -4725,14 +4731,12 @@ static int setup_eh_frame_for_call(jit_function_t func, int flags) { return 0; } - jit_value_ref(func, args[1]); - insn->opcode = JIT_OP_LOAD_CATCHER_PC; - insn->flags |= JIT_INSN_VALUE1_IS_LABEL; + jit_value_ref(func, args[0]); + insn->opcode = JIT_OP_LOAD_PC; insn->dest = args[0]; - insn->value1 = (jit_value_t)(block->block_eh->catch_label); if(!jit_insn_store_relative (func, jit_insn_address_of(func->builder->setjmp_value), - jit_jmp_catcher_offset, args[0])) + jit_jmp_catch_pc_offset, args[0])) { return 0; } @@ -4784,13 +4788,9 @@ static int restore_eh_frame_after_call(jit_function_t func, int flags) jit_type_free(type); #endif - /* Are we currently within a "try" context covered by a "catch"? */ - block = func->builder->current_block; - if(block->block_eh && - block->block_eh->catch_label != jit_label_undefined && - func->builder->setjmp_value != 0) + /* Clear the "catch_pc" value for the current context */ + if(func->builder->setjmp_value != 0) { - /* Set the "catcher" field within "setjmp_value" to NULL */ args[0] = jit_value_create_nint_constant(func, jit_type_void_ptr, 0); if(!(args[0])) { @@ -4798,7 +4798,7 @@ static int restore_eh_frame_after_call(jit_function_t func, int flags) } if(!jit_insn_store_relative (func, jit_insn_address_of(func->builder->setjmp_value), - jit_jmp_catcher_offset, args[0])) + jit_jmp_catch_pc_offset, args[0])) { return 0; } @@ -5873,12 +5873,6 @@ int jit_insn_return(jit_function_t func, jit_value_t value) type = jit_type_promote_int(type); if(!value || type == jit_type_void) { - /* Handle "finally" clauses if necessary */ - if(!handle_finally(func, JIT_OP_PREPARE_FOR_RETURN)) - { - return 0; - } - /* This function returns "void" */ if(!create_noarg_note(func, JIT_OP_RETURN)) { @@ -5894,12 +5888,6 @@ int jit_insn_return(jit_function_t func, jit_value_t value) return 0; } - /* Handle "finally" clauses if necessary */ - if(!handle_finally(func, JIT_OP_PREPARE_FOR_RETURN)) - { - return 0; - } - /* Create the "return" instruction */ switch(type->kind) { @@ -6050,12 +6038,6 @@ int jit_insn_return_ptr case JIT_TYPE_STRUCT: case JIT_TYPE_UNION: { - /* Handle "finally" clauses if necessary */ - if(!handle_finally(func, JIT_OP_PREPARE_FOR_RETURN)) - { - return 0; - } - /* Determine the kind of structure return to use */ return_ptr = jit_value_get_struct_pointer(func); if(return_ptr) @@ -6223,6 +6205,26 @@ jit_value_t jit_insn_get_call_stack(jit_function_t func) return value; } +/*@ + * @deftypefun jit_value_t jit_insn_thrown_exception (jit_function_t func) + * Get the value that holds the most recent thrown exception. This is + * typically used in @code{catch} clauses. + * @end deftypefun +@*/ +jit_value_t jit_insn_thrown_exception(jit_function_t func) +{ + if(!_jit_function_ensure_builder(func)) + { + return 0; + } + if(!(func->builder->thrown_exception)) + { + func->builder->thrown_exception = + jit_value_create(func, jit_type_void_ptr); + } + return func->builder->thrown_exception; +} + /* * Initialize the "setjmp" setup block that is needed to catch exceptions * thrown back to this level of execution. The block looks like this: @@ -6233,10 +6235,10 @@ jit_value_t jit_insn_get_call_stack(jit_function_t func) * _jit_unwind_push_setjmp(&jbuf); * if(setjmp(&jbuf.buf)) * { - * catcher = jbuf.catcher; - * if(catcher) + * catch_pc = jbuf.catch_pc; + * if(catch_pc) * { - * jbuf.catcher = 0; + * jbuf.catch_pc = 0; * goto *catcher; * } * else @@ -6245,7 +6247,7 @@ jit_value_t jit_insn_get_call_stack(jit_function_t func) * } * } * - * The field "jbuf.catcher" will be set to the address of the relevant + * The field "jbuf.catch_pc" will be set to the address of the relevant * "catch" block just before a subroutine call that may involve exceptions. * It will be reset to NULL after such subroutine calls. * @@ -6269,6 +6271,7 @@ static int initialize_setjmp_block(jit_function_t func) return 1; } func->builder->longjmp_label = jit_label_undefined; + func->builder->catcher_label = jit_label_undefined; /* Force the start of a new block to mark the start of the init code */ if(!jit_insn_label(func, &start_label)) @@ -6334,23 +6337,32 @@ static int initialize_setjmp_block(jit_function_t func) return 0; } - /* Get the value of "catcher" from within "setjmp_value". This indicates - which catcher we should use to handle the thrown exception. If the - catcher is NULL, then we need to rethrow the exception higher up - because it isn't covered by any of the catch blocks that we have */ + /* We need a value to hold the location of the thrown exception */ + if((func->builder->thrown_pc = + jit_value_create(func, jit_type_void_ptr)) == 0) + { + return 0; + } + + /* Get the value of "catch_pc" from within "setjmp_value" and store it + into the current frame. This indicates where the exception occurred */ value = jit_insn_load_relative (func, jit_insn_address_of(func, func->builder->setjmp_value), - jit_jmp_catcher_offset, jit_type_void_ptr); + jit_jmp_catch_pc_offset, jit_type_void_ptr); if(!value) { return 0; } + if(!jit_insn_store(func, func->builder->thrown_pc, value)) + { + return 0; + } if(!jit_insn_branch_if_not(func, value, &rethrow_label)) { return 0; } - /* Clear the original "catcher" value within "setjmp_value" */ + /* Clear the original "catch_pc" value within "setjmp_value" */ if(!jit_insn_store_relative (func, jit_insn_address_of(func, func->builder->setjmp_value), jit_jmp_catcher_offset, jit_value_create_nint_constant @@ -6359,12 +6371,11 @@ static int initialize_setjmp_block(jit_function_t func) return 0; } - /* Jump to the address indicated by the catcher */ - if(!create_unary_note(func, JIT_OP_JUMP_TO_CATCHER, value)) + /* Jump to this function's exception catcher */ + if(!jit_insn_branch(func, &(func->builder->catcher_label)) { return 0; } - func->builder->current_block->ends_in_dead = 1; /* Mark the position of the rethrow label */ if(!jit_insn_label(func, &rethrow_label)) @@ -6397,190 +6408,148 @@ static int initialize_setjmp_block(jit_function_t func) return jit_insn_move_blocks_to_start(func, start_label, end_label); #else /* The interpreter doesn't need the "setjmp" setup block */ + func->builder->catcher_label = jit_label_undefined; return 1; #endif } /*@ - * @deftypefun int jit_insn_start_try (jit_function_t func, {jit_label_t *} catch_label, {jit_label_t *} finally_label, int finally_on_fault) - * Start an exception-handling @code{try} block at the current position - * within @code{func}. - * - * Whenever an exception occurs in the block, execution will jump to - * @code{catch_label}. When execution exits the @code{try} block's scope, - * @code{finally_label} will be called. If @code{finally_on_fault} is - * non-zero, then @code{finally_label} will be called for exceptions, - * but not when control exits the @code{try} block normally. - * - * The @code{finally_label} parameter may be NULL if the @code{try} block - * does not have a @code{finally} clause associated with it. - * - * All of the blocks between @code{jit_insn_start_try} and - * @code{jit_insn_start_catch} are covered by the @code{catch} - * clause and the @code{finally} clause. Blocks between - * @code{jit_insn_start_catch} and @code{jit_insn_end_try} are - * covered by the @code{finally} clause. - * - * Calls to @code{jit_insn_branch}, @code{jit_insn_return}, - * @code{jit_insn_throw} and @code{jit_insn_rethrow} will cause - * additional code to be output to invoke the relevant @code{finally} - * clauses. - * - * The destinations for @code{jit_insn_branch_if} and - * @code{jit_insn_branch_if_not} must never be outside the current - * @code{finally} context. You should always use @code{jit_insn_branch} - * to branch out of @code{finally} contexts. - * - * Note: you don't need to output calls to @code{finally} clauses - * yourself as @code{libjit} can detect when it is necessary on its own. + * @deftypefun int jit_insn_uses_catcher (jit_function_t func) + * Notify the function building process that @code{func} contains + * some form of @code{catch} clause for catching exceptions. This must + * be called before any instruction that is covered by a @code{try}, + * ideally at the start of the function output process. * @end deftypefun @*/ -int jit_insn_start_try - (jit_function_t func, jit_label_t *catch_label, - jit_label_t *finally_label, int finally_on_fault) +int jit_insn_uses_catcher(jit_function_t func) { - jit_block_eh_t eh; - jit_block_t block; - - /* Ensure that we have a function builder */ - if(!_jit_function_ensure_builder(func) || !catch_label) + if(!_jit_function_ensure_builder(func)) { return 0; } - - /* Allocate the label numbers */ - if(*catch_label == jit_label_undefined) - { - *catch_label = (func->builder->next_label)++; - } - if(finally_label && *finally_label == jit_label_undefined) + if(func->has_try) { - *finally_label = (func->builder->next_label)++; + return 1; } - - /* This function has a "try" block. This flag helps native - back ends know when they must be careful about global - register allocation */ func->has_try = 1; + func->builder->may_throw = 1; + func->builder->non_leaf = 1; + return initialize_setjmp_block(func); +} - /* Make sure that the "setjmp" setup block is present in this function */ - if(!initialize_setjmp_block(func)) +/*@ + * @deftypefun jit_value_t jit_insn_start_catcher (jit_function_t func) + * Start the catcher block for @code{func}. There should be exactly one + * catcher block for any function that involves a @code{try}. All + * exceptions that are thrown within the function will cause control + * to jump to this point. Returns a value that holds the exception + * that was thrown. + * @end deftypefun +@*/ +jit_value_t jit_insn_start_catcher(jit_function_t func) +{ + jit_value_t value; + if(!_jit_function_ensure_builder(func)) { return 0; } - - /* Anything with a finally handler makes the function not a leaf, - because we may need to do a native "call" to invoke the handler */ - if(finally_label) + if(!jit_insn_label(func, &(func->builder->catcher_label))) { - func->builder->non_leaf = 1; + return 0; } - - /* Create a new exception handling context and populate it */ - eh = jit_cnew(struct jit_block_eh); - if(!eh) + value = jit_insn_thrown_exception(func); + if(!value) { return 0; } - eh->parent = func->builder->current_handler; - eh->next = func->builder->exception_handlers; - func->builder->exception_handlers = eh; - eh->catch_label = *catch_label; - eh->finally_label = (finally_label ? *finally_label : jit_label_undefined); - eh->finally_on_fault = finally_on_fault; - eh->in_try_body = 1; - func->builder->current_handler = eh; - - /* Start a new block, for the body of the "try" */ - block = _jit_block_create(func, 0); - if(!block) +#if defined(JIT_BACKEND_INTERP) + /* In the interpreter, the exception object will be on the top of + the operand stack when control reaches the catcher */ + if(!jit_insn_incoming_reg(func, value, 0)) { return 0; } - block->entered_via_top = 1; - return 1; +#endif + return value; } /*@ - * @deftypefun jit_value_t jit_insn_start_catch (jit_function_t func, {jit_label_t *} catch_label) - * Start the @code{catch} clause for the currently active @code{try} - * block. Returns a pointer @code{value} that indicates the exception - * that is thrown. - * - * There can be only one @code{catch} clause per @code{try} block. - * The front end is responsible for outputting instructions that - * inspect the exception object, determine if it is appropriate to - * the clause, and then either handle it or rethrow it. - * - * Every @code{try} block must have an associated @code{catch} clause, - * even if all it does is rethrow the exception immediately. Without a - * @code{catch} clause, the correct @code{finally} logic will not be - * performed for thrown exceptions. + * @deftypefun int jit_insn_branch_if_pc_not_in_range (jit_function_t func, jit_label_t start_label, jit_label_t end_label, {jit_label_t *} label) + * Branch to @code{label} if the program counter where an exception occurred + * does not fall between @code{start_label} and @code{end_label}. * @end deftypefun @*/ -jit_value_t jit_insn_start_catch - (jit_function_t func, jit_label_t *catch_label) +int jit_insn_branch_if_pc_not_in_range + (jit_function_t func, jit_label_t start_label, + jit_label_t end_label, jit_label_t *label) { - jit_block_eh_t eh; - jit_block_eh_t new_eh; + jit_value_t value1; + jit_value_t value2; - /* Ensure that we have a function builder */ + /* Ensure that we have a function builder and a try block */ if(!_jit_function_ensure_builder(func)) { return 0; } + if(!(func->has_try)) + { + return 0; + } - /* Create a new exception handler to indicate that we are in a "catch" */ - eh = func->builder->current_handler; - if(!eh) + /* Get the location where the exception occurred in this function */ +#if defined(JIT_BACKEND_INTERP) + value1 = create_dest_note + (func, JIT_OP_LOAD_EXCEPTION_PC, jit_type_void_ptr); +#else + value1 = func->builder->thrown_pc; +#endif + if(!value1) { return 0; } - new_eh = jit_cnew(struct jit_block_eh); - if(!new_eh) + + /* Compare the location against the start and end labels */ + value2 = jit_insn_address_of_label(func, &start_label); + if(!value2) { return 0; } - new_eh->parent = eh->parent; - new_eh->next = func->builder->exception_handlers; - func->builder->exception_handlers = new_eh; - if(eh->finally_label != jit_label_undefined) + if(!jit_insn_branch_if(func, jit_insn_lt(func, value1, value2), label)) { - /* We will need a mini "catch" block to call the "finally" - clause when an exception occurs within the "catch" */ - new_eh->catch_label = (func->builder->next_label)++; + return 0; } - else + value2 = jit_insn_address_of_label(func, &end_label); + if(!value2) { - new_eh->catch_label = jit_label_undefined; + return 0; } - new_eh->finally_label = eh->finally_label; - new_eh->finally_on_fault = eh->finally_on_fault; - new_eh->in_try_body = 0; - func->builder->current_handler = new_eh; - - /* Start a new block for the "catch" clause */ - if(!jit_insn_label(func, catch_label)) + if(!jit_insn_branch_if(func, jit_insn_ge(func, value1, value2), label)) { return 0; } - /* Output an instruction to notice the caught value */ - return create_dest_note(func, JIT_OP_ENTER_CATCH, jit_type_void_ptr); + /* If control gets here, then we have a location match */ + return 1; } /*@ - * @deftypefun int jit_insn_end_try (jit_function_t func) - * Mark the end of the @code{try} block and its associated @code{catch} - * clause. This is normally followed by a call to - * @code{jit_insn_start_finally} to define the @code{finally} clause. + * @deftypefun int jit_insn_rethrow_unhandled (jit_function_t func) + * Rethrow the current exception because it cannot be handled by + * any of the @code{catch} blocks in the current function. + * + * Note: this is intended for use within catcher blocks. It should not + * be used to rethrow exceptions in response to programmer requests + * (e.g. @code{throw;} in C#). The @code{jit_insn_throw} function + * should be used for that purpose. * @end deftypefun @*/ -int jit_insn_end_try(jit_function_t func) +int jit_insn_rethrow_unhandled(jit_function_t func) { - jit_block_eh_t eh; jit_block_t block; jit_value_t value; +#if !defined(JIT_BACKEND_INTERP) + jit_type_t type; +#endif /* Ensure that we have a function builder */ if(!_jit_function_ensure_builder(func)) @@ -6588,48 +6557,69 @@ int jit_insn_end_try(jit_function_t func) return 0; } - /* Get the current exception handling context */ - eh = func->builder->current_handler; - if(!eh) + /* Get the current exception value to be thrown */ + value = jit_insn_thrown_exception(func); + if(!value) { return 0; } - /* We may need another mini "catch" block to invoke the "finally" - clause for exceptions that happen during the "catch" */ - if(eh->catch_label != jit_label_undefined) +#if defined(JIT_BACKEND_INTERP) + + /* Rethrow the current exception (interpreter version) */ + if(!create_unary_note(func, JIT_OP_RETHROW, value)) { - /* TODO: not quite right */ - if(!jit_insn_label(func, &(eh->catch_label))) - { - return 0; - } - value = create_dest_note(func, JIT_OP_ENTER_CATCH, jit_type_void_ptr); - if(!value) - { - return 0; - } - if(!jit_insn_throw(func, value)) - { - return 0; - } + return 0; + } + +#else /* !JIT_BACKEND_INTERP */ + + /* Call "_jit_unwind_pop_setjmp" to remove the current exception catcher */ + if(!_jit_function_ensure_builder(func)) + { + return 0; + } + type = jit_type_create_signature + (jit_abi_cdecl, jit_type_void, 0, 0, 1); + if(!type) + { + return 0; + } + jit_insn_call_native + (func, "_jit_unwind_pop_setjmp", + (void *)_jit_unwind_pop_setjmp, type, 0, 0, JIT_CALL_NOTHROW); + jit_type_free(type); + + /* Call the "jit_exception_throw" function to effect the rethrow */ + type = jit_type_void_ptr; + type = jit_type_create_signature + (jit_abi_cdecl, jit_type_void, &type, 1, 1); + if(!type) + { + return 0; } + jit_insn_call_native + (func, "jit_exception_throw", + (void *)jit_exception_throw, type, &value, 1, + JIT_CALL_NOTHROW | JIT_CALL_NORETURN); + jit_type_free(type); - /* Pop the current exception context */ - func->builder->current_handler = eh->parent; +#endif /* !JIT_BACKEND_INTERP */ - /* Start a new block, covered by the next outer "try" context */ + /* The current block ends in dead and we need to start a new block */ + func->builder->current_block->ends_in_dead = 1; block = _jit_block_create(func, 0); if(!block) { return 0; } + func->builder->current_block = block; return 1; } /*@ * @deftypefun int jit_insn_start_finally (jit_function_t func, {jit_label_t *} finally_label) - * Start the @code{finally} clause for the preceding @code{try} block. + * Start a @code{finally} clause. * @end deftypefun @*/ int jit_insn_start_finally(jit_function_t func, jit_label_t *finally_label) @@ -6669,6 +6659,20 @@ int jit_insn_return_from_finally(jit_function_t func) return 1; } +/*@ + * @deftypefun int jit_insn_call_finally (jit_function_t func, {jit_label_t *} finally_label) + * Call a @code{finally} clause. + * @end deftypefun +@*/ +int jit_insn_call_finally(jit_function_t func, jit_label_t *finally_label) +{ + if(!jit_insn_label(func, finally_label)) + { + return 0; + } + return create_noarg_note(func, JIT_OP_CALL_FINALLY); +} + /*@ * @deftypefun jit_value_t jit_insn_start_filter (jit_function_t func, {jit_label_t *} label, jit_type_t type) * Define the start of a filter. Filters are embedded subroutines within diff --git a/jit/jit-internal.h b/jit/jit-internal.h index 1993d83..d044b46 100644 --- a/jit/jit-internal.h +++ b/jit/jit-internal.h @@ -169,20 +169,6 @@ struct _jit_meta jit_function_t pool_owner; }; -/* - * Exception handling information that is attached to blocks. - */ -typedef struct jit_block_eh *jit_block_eh_t; -struct jit_block_eh -{ - jit_block_eh_t parent; - jit_block_eh_t next; - jit_label_t catch_label; - jit_label_t finally_label; - int finally_on_fault : 1; - int in_try_body : 1; -}; - /* * Internal structure of a block. */ @@ -195,7 +181,6 @@ struct _jit_block jit_block_t next; jit_block_t prev; jit_meta_t meta; - jit_block_eh_t block_eh; int entered_via_top : 1; int entered_via_branch : 1; int ends_in_dead : 1; @@ -261,10 +246,11 @@ struct _jit_insn #define JIT_INSN_DEST_IS_NATIVE 0x0100 #define JIT_INSN_DEST_OTHER_FLAGS 0x01C0 #define JIT_INSN_VALUE1_IS_NAME 0x0200 -#define JIT_INSN_VALUE1_OTHER_FLAGS 0x0200 -#define JIT_INSN_VALUE2_IS_SIGNATURE 0x0400 -#define JIT_INSN_VALUE2_OTHER_FLAGS 0x0400 -#define JIT_INSN_DEST_IS_VALUE 0x0800 +#define JIT_INSN_VALUE1_IS_LABEL 0x0400 +#define JIT_INSN_VALUE1_OTHER_FLAGS 0x0600 +#define JIT_INSN_VALUE2_IS_SIGNATURE 0x0800 +#define JIT_INSN_VALUE2_OTHER_FLAGS 0x0800 +#define JIT_INSN_DEST_IS_VALUE 0x1000 /* * Information that is associated with a function for building @@ -295,11 +281,13 @@ struct _jit_builder jit_block_t init_block; int init_insn; - /* Exception handlers for the function */ - jit_block_eh_t exception_handlers; - jit_block_eh_t current_handler; + /* Exception handling definitions for the function */ jit_value_t setjmp_value; jit_label_t longjmp_label; + jit_value_t thrown_exception; + jit_value_t thrown_pc; + jit_label_t catcher_label; + jit_value_t eh_frame_info; /* Flag that is set to indicate that this function is not a leaf */ int non_leaf : 1; @@ -329,9 +317,6 @@ struct _jit_builder jit_value_t struct_return; jit_value_t parent_frame; - /* The value that holds the exception frame information for a callout */ - jit_value_t eh_frame_info; - /* Metadata that is stored only while the function is being built */ jit_meta_t meta; diff --git a/jit/jit-interp.c b/jit/jit-interp.c index f4937c3..1e24102 100644 --- a/jit/jit-interp.c +++ b/jit/jit-interp.c @@ -241,6 +241,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, struct jit_backtrace call_trace; void *entry; void *exception_object = 0; + void *exception_pc = 0; void *handler; jit_jmp_buf *jbuf; @@ -3553,6 +3554,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, /* Throw an exception, which may be handled in this function */ exception_object = VM_STK_PTR0; handle_exception: + exception_pc = pc; if(jit_function_from_pc(func->func->context, pc, &handler) == func->func && handler != 0) { @@ -3570,6 +3572,14 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, } VMBREAK; + VMCASE(JIT_OP_RETHROW): + { + /* Rethrow an exception to the caller */ + _jit_unwind_pop_setjmp(); + jit_exception_throw(VM_STK_PTR0); + } + VMBREAK; + VMCASE(JIT_OP_LOAD_PC): { /* Load the current program counter onto the stack */ @@ -3578,6 +3588,14 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, } VMBREAK; + VMCASE(JIT_OP_LOAD_EXCEPTION_PC): + { + /* Load the address where the exception occurred onto the stack */ + VM_STK_PTRP = (void *)exception_pc; + VM_MODIFY_PC_AND_STACK(1, -1); + } + VMBREAK; + VMCASE(JIT_OP_LEAVE_FINALLY): { /* Return from a "finally" handler */ @@ -3614,6 +3632,14 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, } VMBREAK; + VMCASE(JIT_OP_ADDRESS_OF_LABEL): + { + /* Load the address of a label onto the stack */ + VM_STK_PTRP = VM_BR_TARGET; + VM_MODIFY_PC_AND_STACK(2, -1); + } + VMBREAK; + /****************************************************************** * Pointer-relative loads and stores. ******************************************************************/ @@ -4472,13 +4498,9 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, VMCASE(JIT_OP_PUSH_FLOAT64): VMCASE(JIT_OP_PUSH_NFLOAT): VMCASE(JIT_OP_FLUSH_SMALL_STRUCT): - VMCASE(JIT_OP_ENTER_CATCH): VMCASE(JIT_OP_ENTER_FINALLY): VMCASE(JIT_OP_ENTER_FILTER): VMCASE(JIT_OP_CALL_FILTER_RETURN): - VMCASE(JIT_OP_PREPARE_FOR_LEAVE): - VMCASE(JIT_OP_PREPARE_FOR_RETURN): - VMCASE(JIT_OP_JUMP_TO_CATCHER): { /* Shouldn't happen, but skip the instruction anyway */ VM_MODIFY_PC_AND_STACK(1, 0); diff --git a/jit/jit-interp.h b/jit/jit-interp.h index fdffa24..2939aee 100644 --- a/jit/jit-interp.h +++ b/jit/jit-interp.h @@ -167,11 +167,6 @@ struct jit_function_interp #define JIT_OP_PUSH_CONST_FLOAT64 (JIT_OP_NUM_OPCODES + 0x0036) #define JIT_OP_PUSH_CONST_NFLOAT (JIT_OP_NUM_OPCODES + 0x0037) -/* - * Exception handling (interpreter-only). - */ -#define JIT_OP_CALL_FINALLY (JIT_OP_NUM_OPCODES + 0x0038) - /* * Marker opcode for the end of the interpreter-specific opcodes. */ diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c index 65d297d..a2621d4 100644 --- a/jit/jit-opcode.c +++ b/jit/jit-opcode.c @@ -419,17 +419,17 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = { * Exception handling. */ {"throw", F_(EMPTY, PTR, EMPTY)}, + {"rethrow", F_(EMPTY, PTR, EMPTY)}, {"load_pc", F_(PTR, EMPTY, EMPTY)}, - {"enter_catch", F_(PTR, EMPTY, EMPTY)}, + {"load_exception_pc", F_(PTR, EMPTY, EMPTY)}, {"enter_finally", F_(EMPTY, EMPTY, EMPTY)}, {"leave_finally", F_(EMPTY, EMPTY, EMPTY)}, + {"call_finally", B_(EMPTY, EMPTY)}, {"enter_filter", F_(ANY, EMPTY, EMPTY)}, {"leave_filter", F_(EMPTY, ANY, EMPTY)}, {"call_filter", B_(ANY, EMPTY)}, {"call_filter_return", F_(ANY, EMPTY, EMPTY)}, - {"prepare_for_leave", F_(EMPTY, EMPTY, EMPTY)}, - {"prepare_for_return", F_(EMPTY, EMPTY, EMPTY)}, - {"jump_to_catcher", F_(EMPTY, PTR, EMPTY)}, + {"address_of_label", JIT_OPCODE_IS_ADDROF_LABEL}, /* * Data manipulation. @@ -607,11 +607,6 @@ jit_opcode_info_t const _jit_interp_opcodes[JIT_OP_NUM_INTERP_OPCODES] = { {"push_const_float64", JIT_OPCODE_CONST_FLOAT64}, {"push_const_nfloat", JIT_OPCODE_CONST_NFLOAT}, - /* - * Exception handling (interpreter only). - */ - {"call_finally", B_(EMPTY, EMPTY)}, - /* * Marker opcode for the end of a function. */ diff --git a/jit/jit-rules-arm.c b/jit/jit-rules-arm.c index 28bb7eb..7f3a228 100644 --- a/jit/jit-rules-arm.c +++ b/jit/jit-rules-arm.c @@ -655,15 +655,4 @@ void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block) /* Nothing to do here for ARM */ } -void _jit_gen_call_finally - (jit_gencode_t gen, jit_function_t func, jit_label_t label) -{ - /* TODO */ -} - -void _jit_gen_unwind_stack(void *stacktop, void *catch_pc, void *object) -{ - /* TODO */ -} - #endif /* JIT_BACKEND_ARM */ diff --git a/jit/jit-rules-interp.c b/jit/jit-rules-interp.c index b092ade..2b0bebc 100644 --- a/jit/jit-rules-interp.c +++ b/jit/jit-rules-interp.c @@ -886,6 +886,7 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, switch(insn->opcode) { case JIT_OP_BR: + case JIT_OP_CALL_FINALLY: { /* Unconditional branch */ _jit_regs_spill_all(gen); @@ -1006,6 +1007,38 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, } /* Not reached */ + case JIT_OP_ADDRESS_OF_LABEL: + { + /* Get the address of a particular label */ + if(_jit_regs_num_used(gen, 0) >= JIT_NUM_REGS) + { + _jit_regs_spill_all(gen); + } + reg = _jit_regs_new_top(gen, insn->dest, 0); + adjust_working(gen, 1); + label = (jit_label_t)(insn->value1); + pc = (void **)(gen->posn.ptr); + jit_cache_opcode(&(gen->posn), insn->opcode); + block = jit_block_from_label(func, label); + if(!block) + { + break; + } + if(block->address) + { + /* We already know the address of the block */ + jit_cache_native + (&(gen->posn), ((void **)(block->address)) - pc); + } + else + { + /* Record this position on the block's fixup list */ + jit_cache_native(&(gen->posn), block->fixup_list); + block->fixup_list = (void *)pc; + } + } + break; + case JIT_OP_CALL: case JIT_OP_CALL_TAIL: { @@ -1160,6 +1193,7 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, break; case JIT_OP_LOAD_PC: + case JIT_OP_LOAD_EXCEPTION_PC: { /* Load the current program counter onto the stack */ if(_jit_regs_num_used(gen, 0) >= JIT_NUM_REGS) @@ -1172,7 +1206,6 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, } break; - case JIT_OP_ENTER_CATCH: case JIT_OP_CALL_FILTER_RETURN: { /* The top of stack currently contains "dest" */ @@ -1628,48 +1661,4 @@ void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block) gen->working_area = 0; } -/*@ - * @deftypefun void _jit_gen_call_finally (jit_gencode_t gen, jit_function_t func, jit_label_t label) - * Call a @code{finally} clause at @code{label}. - * @end deftypefun -@*/ -void _jit_gen_call_finally - (jit_gencode_t gen, jit_function_t func, jit_label_t label) -{ - jit_block_t block; - void **pc; - _jit_regs_spill_all(gen); - pc = (void **)(gen->posn.ptr); - jit_cache_opcode(&(gen->posn), JIT_OP_CALL_FINALLY); - block = jit_block_from_label(func, label); - if(!block) - { - return; - } - if(block->address) - { - /* We already know the address of the block */ - jit_cache_native - (&(gen->posn), ((void **)(block->address)) - pc); - } - else - { - /* Record this position on the block's fixup list */ - jit_cache_native(&(gen->posn), block->fixup_list); - block->fixup_list = (void *)pc; - } -} - -/*@ - * @deftypefun void _jit_gen_unwind_stack ({void *} stacktop, {void *} catch_pc, {void *} object) - * Unwind the stack back to @code{stacktop}, restore the frame, and - * jump to @code{catch_pc}. The registers are set up to arrange for - * @code{object} to be in the right place for a @code{catch} clause. - * @end deftypefun -@*/ -void _jit_gen_unwind_stack(void *stacktop, void *catch_pc, void *object) -{ - /* Not used by the interpreted back end */ -} - #endif /* JIT_BACKEND_INTERP */ diff --git a/jit/jit-rules-x86.c b/jit/jit-rules-x86.c index 4414635..ab3a56f 100644 --- a/jit/jit-rules-x86.c +++ b/jit/jit-rules-x86.c @@ -1544,75 +1544,4 @@ void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block) /* Nothing to do here for x86 */ } -void _jit_gen_call_finally - (jit_gencode_t gen, jit_function_t func, jit_label_t label) -{ - /* TODO */ -} - -void _jit_gen_unwind_stack(void *stacktop, void *catch_pc, void *object) -{ - void *frame; - - /* Fetch the proper EBP value from the stack, just before - where we need to unwind back to */ - frame = ((void **)stacktop)[-2]; - - /* Unwind the stack and jump to "catch_pc" */ -#if defined(__GNUC__) - __asm__ ( - "movl %0, %%edx\n\t" - "movl %1, %%eax\n\t" - "movl %2, %%ecx\n\t" - "movl %3, %%ebx\n\t" - "movl %%ebx, %%ebp\n\t" - "movl %%edx, %%esp\n\t" - "jmp *(%%eax)\n\t" - : : "m"(stacktop), "m"(catch_pc), "m"(object), "m"(frame) - : "eax", "ebx", "ecx", "edx" - ); -#elif defined(_MSC_VER) - __asm { - mov edx, dword ptr stacktop - mov eax, dword ptr catch_pc - mov ecx, dword ptr object - mov ebx, dword ptr frame - mov ebp, ebx - mov esp, edx - jmp [eax] - } -#else - #error "Don't know how to unwind the stack under x86" -#endif -} - -void _jit_unwind_stack(void *frame, void *pc, void *object) -{ -#if defined(__GNUC__) - __asm__ ( - "movl %0, %%edx\n\t" - "movl %1, %%eax\n\t" - "movl %2, %%ecx\n\t" - "movl %%edx, %%ebp\n\t" - "popl %%ebp\n\t" - "popl %%edx\n\t" - "jmp *%%eax\n\t" - : : "m"(frame), "m"(pc), "m"(object) - : "eax", "ecx", "edx" - ); -#elif defined(_MSC_VER) - __asm { - mov edx, dword ptr frame - mov eax, dword ptr pc - mov ecx, dword ptr object - mov ebp, edx - pop ebp - pop edx - jmp eax - } -#else - #error "Don't know how to unwind the stack on x86 platforms" -#endif -} - #endif /* JIT_BACKEND_X86 */ diff --git a/jit/jit-rules.h b/jit/jit-rules.h index 0337f71..7b48b58 100644 --- a/jit/jit-rules.h +++ b/jit/jit-rules.h @@ -181,9 +181,6 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, jit_block_t block, jit_insn_t insn); void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block); void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block); -void _jit_gen_call_finally - (jit_gencode_t gen, jit_function_t func, jit_label_t label); -void _jit_gen_unwind_stack(void *stacktop, void *catch_pc, void *object); /* * Determine the byte number within a "jit_int" where the low diff --git a/jit/jit-setjmp.h b/jit/jit-setjmp.h index b2baa65..1b0bafe 100644 --- a/jit/jit-setjmp.h +++ b/jit/jit-setjmp.h @@ -34,12 +34,12 @@ typedef struct jit_jmp_buf { jmp_buf buf; jit_backtrace_t trace; - void *catcher; + void *catch_pc; struct jit_jmp_buf *parent; } jit_jmp_buf; -#define jit_jmp_catcher_offset \ - ((jit_nint)&(((jit_jmp_buf *)0)->catcher)) +#define jit_jmp_catch_pc_offset \ + ((jit_nint)&(((jit_jmp_buf *)0)->catch_pc)) /* * Push a "setjmp" buffer onto the current thread's unwind stck. -- 2.47.3