-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | include/jit/jit-opcode.h | 135 | ||||
-rw-r--r-- | jit/jit-except.c | 14 | ||||
-rw-r--r-- | jit/jit-function.c | 2 | ||||
-rw-r--r-- | jit/jit-insn.c | 345 | ||||
-rw-r--r-- | jit/jit-internal.h | 7 | ||||
-rw-r--r-- | jit/jit-interp.c | 11 | ||||
-rw-r--r-- | jit/jit-opcode.c | 1 | ||||
-rw-r--r-- | jit/jit-setjmp.h | 8 |
@@ -10,6 +10,11 @@ to "jit_insn_move_blocks_to_end" and add a new function "jit_insn_move_blocks_to_start" for creating initialization code. + * include/jit/jit-opcode.h, jit/jit-except.c, jit/jit-function.c, + jit/jit-insn.c, jit/jit-internal.h, jit/jit-interp.c, jit/jit-opcode.c, + jit/jit-setjmp.h: modify the function call logic to use "setjmp" + with native back ends. + 2004年05月21日 Rhys Weatherley <rweather@southern-storm.com.au> * jit/jit-gen-arm.c, jit/jit-gen-arm.h: modify the ARM codegen diff --git a/include/jit/jit-opcode.h b/include/jit/jit-opcode.h index 52eb1be..9116c0f 100644 --- a/include/jit/jit-opcode.h +++ b/include/jit/jit-opcode.h @@ -413,101 +413,102 @@ extern "C" { #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 /* * Data manipulation. */ -#define JIT_OP_COPY_LOAD_SBYTE 0x0157 -#define JIT_OP_COPY_LOAD_UBYTE 0x0158 -#define JIT_OP_COPY_LOAD_SHORT 0x0159 -#define JIT_OP_COPY_LOAD_USHORT 0x015A -#define JIT_OP_COPY_INT 0x015B -#define JIT_OP_COPY_LONG 0x015C -#define JIT_OP_COPY_FLOAT32 0x015D -#define JIT_OP_COPY_FLOAT64 0x015E -#define JIT_OP_COPY_NFLOAT 0x015F -#define JIT_OP_COPY_STRUCT 0x0160 -#define JIT_OP_COPY_STORE_BYTE 0x0161 -#define JIT_OP_COPY_STORE_SHORT 0x0162 -#define JIT_OP_ADDRESS_OF 0x0163 +#define JIT_OP_COPY_LOAD_SBYTE 0x0158 +#define JIT_OP_COPY_LOAD_UBYTE 0x0159 +#define JIT_OP_COPY_LOAD_SHORT 0x015A +#define JIT_OP_COPY_LOAD_USHORT 0x015B +#define JIT_OP_COPY_INT 0x015C +#define JIT_OP_COPY_LONG 0x015D +#define JIT_OP_COPY_FLOAT32 0x015E +#define JIT_OP_COPY_FLOAT64 0x015F +#define JIT_OP_COPY_NFLOAT 0x0160 +#define JIT_OP_COPY_STRUCT 0x0161 +#define JIT_OP_COPY_STORE_BYTE 0x0162 +#define JIT_OP_COPY_STORE_SHORT 0x0163 +#define JIT_OP_ADDRESS_OF 0x0164 /* * Incoming registers, outgoing registers, and stack pushes. */ -#define JIT_OP_INCOMING_REG 0x0164 -#define JIT_OP_INCOMING_FRAME_POSN 0x0165 -#define JIT_OP_OUTGOING_REG 0x0166 -#define JIT_OP_RETURN_REG 0x0167 -#define JIT_OP_PUSH_INT 0x0168 -#define JIT_OP_PUSH_LONG 0x0169 -#define JIT_OP_PUSH_FLOAT32 0x016A -#define JIT_OP_PUSH_FLOAT64 0x016B -#define JIT_OP_PUSH_NFLOAT 0x016C -#define JIT_OP_PUSH_STRUCT 0x016D -#define JIT_OP_POP_STACK 0x016E -#define JIT_OP_FLUSH_SMALL_STRUCT 0x016F +#define JIT_OP_INCOMING_REG 0x0165 +#define JIT_OP_INCOMING_FRAME_POSN 0x0166 +#define JIT_OP_OUTGOING_REG 0x0167 +#define JIT_OP_RETURN_REG 0x0168 +#define JIT_OP_PUSH_INT 0x0169 +#define JIT_OP_PUSH_LONG 0x016A +#define JIT_OP_PUSH_FLOAT32 0x016B +#define JIT_OP_PUSH_FLOAT64 0x016C +#define JIT_OP_PUSH_NFLOAT 0x016D +#define JIT_OP_PUSH_STRUCT 0x016E +#define JIT_OP_POP_STACK 0x016F +#define JIT_OP_FLUSH_SMALL_STRUCT 0x0170 /* * Pointer-relative loads and stores. */ -#define JIT_OP_LOAD_RELATIVE_SBYTE 0x0170 -#define JIT_OP_LOAD_RELATIVE_UBYTE 0x0171 -#define JIT_OP_LOAD_RELATIVE_SHORT 0x0172 -#define JIT_OP_LOAD_RELATIVE_USHORT 0x0173 -#define JIT_OP_LOAD_RELATIVE_INT 0x0174 -#define JIT_OP_LOAD_RELATIVE_LONG 0x0175 -#define JIT_OP_LOAD_RELATIVE_FLOAT32 0x0176 -#define JIT_OP_LOAD_RELATIVE_FLOAT64 0x0177 -#define JIT_OP_LOAD_RELATIVE_NFLOAT 0x0178 -#define JIT_OP_LOAD_RELATIVE_STRUCT 0x0179 -#define JIT_OP_STORE_RELATIVE_BYTE 0x017A -#define JIT_OP_STORE_RELATIVE_SHORT 0x017B -#define JIT_OP_STORE_RELATIVE_INT 0x017C -#define JIT_OP_STORE_RELATIVE_LONG 0x017D -#define JIT_OP_STORE_RELATIVE_FLOAT32 0x017E -#define JIT_OP_STORE_RELATIVE_FLOAT64 0x017F -#define JIT_OP_STORE_RELATIVE_NFLOAT 0x0180 -#define JIT_OP_STORE_RELATIVE_STRUCT 0x0181 -#define JIT_OP_ADD_RELATIVE 0x0182 +#define JIT_OP_LOAD_RELATIVE_SBYTE 0x0171 +#define JIT_OP_LOAD_RELATIVE_UBYTE 0x0172 +#define JIT_OP_LOAD_RELATIVE_SHORT 0x0173 +#define JIT_OP_LOAD_RELATIVE_USHORT 0x0174 +#define JIT_OP_LOAD_RELATIVE_INT 0x0175 +#define JIT_OP_LOAD_RELATIVE_LONG 0x0176 +#define JIT_OP_LOAD_RELATIVE_FLOAT32 0x0177 +#define JIT_OP_LOAD_RELATIVE_FLOAT64 0x0178 +#define JIT_OP_LOAD_RELATIVE_NFLOAT 0x0179 +#define JIT_OP_LOAD_RELATIVE_STRUCT 0x017A +#define JIT_OP_STORE_RELATIVE_BYTE 0x017B +#define JIT_OP_STORE_RELATIVE_SHORT 0x017C +#define JIT_OP_STORE_RELATIVE_INT 0x017D +#define JIT_OP_STORE_RELATIVE_LONG 0x017E +#define JIT_OP_STORE_RELATIVE_FLOAT32 0x017F +#define JIT_OP_STORE_RELATIVE_FLOAT64 0x0180 +#define JIT_OP_STORE_RELATIVE_NFLOAT 0x0181 +#define JIT_OP_STORE_RELATIVE_STRUCT 0x0182 +#define JIT_OP_ADD_RELATIVE 0x0183 /* * Array element loads and stores. */ -#define JIT_OP_LOAD_ELEMENT_SBYTE 0x0183 -#define JIT_OP_LOAD_ELEMENT_UBYTE 0x0184 -#define JIT_OP_LOAD_ELEMENT_SHORT 0x0185 -#define JIT_OP_LOAD_ELEMENT_USHORT 0x0186 -#define JIT_OP_LOAD_ELEMENT_INT 0x0187 -#define JIT_OP_LOAD_ELEMENT_UINT 0x0188 -#define JIT_OP_LOAD_ELEMENT_LONG 0x0189 -#define JIT_OP_LOAD_ELEMENT_ULONG 0x018A -#define JIT_OP_LOAD_ELEMENT_FLOAT32 0x018B -#define JIT_OP_LOAD_ELEMENT_FLOAT64 0x018C -#define JIT_OP_LOAD_ELEMENT_NFLOAT 0x018D -#define JIT_OP_STORE_ELEMENT_BYTE 0x018E -#define JIT_OP_STORE_ELEMENT_SHORT 0x018F -#define JIT_OP_STORE_ELEMENT_INT 0x0190 -#define JIT_OP_STORE_ELEMENT_LONG 0x0191 -#define JIT_OP_STORE_ELEMENT_FLOAT32 0x0192 -#define JIT_OP_STORE_ELEMENT_FLOAT64 0x0193 -#define JIT_OP_STORE_ELEMENT_NFLOAT 0x0194 +#define JIT_OP_LOAD_ELEMENT_SBYTE 0x0184 +#define JIT_OP_LOAD_ELEMENT_UBYTE 0x0185 +#define JIT_OP_LOAD_ELEMENT_SHORT 0x0186 +#define JIT_OP_LOAD_ELEMENT_USHORT 0x0187 +#define JIT_OP_LOAD_ELEMENT_INT 0x0188 +#define JIT_OP_LOAD_ELEMENT_UINT 0x0189 +#define JIT_OP_LOAD_ELEMENT_LONG 0x018A +#define JIT_OP_LOAD_ELEMENT_ULONG 0x018B +#define JIT_OP_LOAD_ELEMENT_FLOAT32 0x018C +#define JIT_OP_LOAD_ELEMENT_FLOAT64 0x018D +#define JIT_OP_LOAD_ELEMENT_NFLOAT 0x018E +#define JIT_OP_STORE_ELEMENT_BYTE 0x018F +#define JIT_OP_STORE_ELEMENT_SHORT 0x0190 +#define JIT_OP_STORE_ELEMENT_INT 0x0191 +#define JIT_OP_STORE_ELEMENT_LONG 0x0192 +#define JIT_OP_STORE_ELEMENT_FLOAT32 0x0193 +#define JIT_OP_STORE_ELEMENT_FLOAT64 0x0194 +#define JIT_OP_STORE_ELEMENT_NFLOAT 0x0195 /* * Block operations. */ -#define JIT_OP_MEMCPY 0x0195 -#define JIT_OP_MEMMOVE 0x0196 -#define JIT_OP_MEMSET 0x0197 +#define JIT_OP_MEMCPY 0x0196 +#define JIT_OP_MEMMOVE 0x0197 +#define JIT_OP_MEMSET 0x0198 /* * Allocate memory from the stack. */ -#define JIT_OP_ALLOCA 0x0198 +#define JIT_OP_ALLOCA 0x0199 /* * The number of opcodes in the above list. */ -#define JIT_OP_NUM_OPCODES 0x0199 +#define JIT_OP_NUM_OPCODES 0x019A /* * Opcode information. diff --git a/jit/jit-except.c b/jit/jit-except.c index e8c20b1..7a63942 100644 --- a/jit/jit-except.c +++ b/jit/jit-except.c @@ -432,16 +432,13 @@ void jit_stack_trace_free(jit_stack_trace_t trace) } } -void _jit_backtrace_push - (jit_backtrace_t trace, void *pc, void *catch_pc, void *sp) +void _jit_backtrace_push(jit_backtrace_t trace, void *pc) { jit_thread_control_t control = _jit_thread_get_control(); if(control) { trace->parent = control->backtrace_head; trace->pc = pc; - trace->catch_pc = catch_pc; - trace->sp = sp; trace->security_object = 0; trace->free_security_object = 0; control->backtrace_head = trace; @@ -450,8 +447,6 @@ void _jit_backtrace_push { trace->parent = 0; trace->pc = pc; - trace->catch_pc = catch_pc; - trace->sp = sp; trace->security_object = 0; trace->free_security_object = 0; } @@ -490,6 +485,7 @@ void _jit_unwind_push_setjmp(jit_jmp_buf *jbuf) if(control) { jbuf->trace = control->backtrace_head; + jbuf->catcher = 0; jbuf->parent = control->setjmp_head; control->setjmp_head = jbuf; } @@ -504,3 +500,9 @@ void _jit_unwind_pop_setjmp(void) control->setjmp_head = control->setjmp_head->parent; } } + +void _jit_unwind_pop_and_rethrow(void) +{ + _jit_unwind_pop_setjmp(); + jit_exception_throw(jit_exception_get_last()); +} diff --git a/jit/jit-function.c b/jit/jit-function.c index 5ca0505..ac22229 100644 --- a/jit/jit-function.c +++ b/jit/jit-function.c @@ -1284,7 +1284,7 @@ int jit_function_apply_vararg /* Create a backtrace entry that blocks exceptions from flowing further than this up the stack */ - _jit_backtrace_push(&call_trace, 0, 0, 0); + _jit_backtrace_push(&call_trace, 0); /* Get the function's entry point */ if(!func) diff --git a/jit/jit-insn.c b/jit/jit-insn.c index 8781aaa..c65d5b9 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -20,6 +20,7 @@ #include "jit-internal.h" #include "jit-rules.h" +#include "jit-setjmp.h" #include <config.h> #if HAVE_ALLOCA_H #include <alloca.h> @@ -4624,8 +4625,22 @@ static int setup_eh_frame_for_call(jit_function_t func, int flags) jit_type_t params[2]; jit_value_t struct_return; - /* If the "nothrow" or "tail" flags are set, then we don't - need to worry about this */ + /* If "tail" is set, then we need to pop the "setjmp" context */ + if((flags & JIT_CALL_TAIL) != 0 && func->has_try) + { + 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); + } + + /* If "nothrow" or "tail" is set, then there is no more to do */ if((flags & (JIT_CALL_NOTHROW | JIT_CALL_TAIL)) != 0) { return 1; @@ -4634,6 +4649,7 @@ static int setup_eh_frame_for_call(jit_function_t func, int flags) /* This function may throw an exception */ func->builder->may_throw = 1; +#if JIT_APPLY_BROKEN_FRAME_BUILTINS != 0 /* Get the value that holds the exception frame information */ if((eh_frame_info = func->builder->eh_frame_info) == 0) { @@ -4685,43 +4701,44 @@ static int setup_eh_frame_for_call(jit_function_t func, int flags) return 0; } - /* Set up to call the "_jit_backtrace_push" intrinsic */ - if(!_jit_create_call_setup_insns - (func, type, args, 2, 0, 0, &struct_return)) - { - jit_type_free(type); - return 0; - } - - /* Terminate the current block and then call "_jit_backtrace_push" */ - block = _jit_block_create(func, 0); - if(!block) - { - jit_type_free(type); - return 0; - } - block->entered_via_top = 1; - func->builder->current_block = block; - insn = _jit_block_add_insn(block); - if(!insn) - { - jit_type_free(type); - return 0; - } - insn->opcode = JIT_OP_CALL_EXTERNAL; - insn->flags = JIT_INSN_DEST_IS_NATIVE | JIT_INSN_VALUE1_IS_NAME; - insn->dest = (jit_value_t)(void *)_jit_backtrace_push; - insn->value1 = (jit_value_t)"_jit_backtrace_push"; + /* Call the "_jit_backtrace_push" function */ + jit_insn_call_native + (func, "_jit_backtrace_push", + (void *)_jit_backtrace_push, type, args, 2, JIT_CALL_NOTHROW); + jit_type_free(type); +#endif - /* Clean up after the function call */ - if(!_jit_create_call_return_insns(func, type, args, 2, 0, 0)) + /* 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) { - jit_type_free(type); - return 0; + /* Set the "catcher" field within "setjmp_value" to the catcher */ + args[0] = jit_value_create(func, jit_type_void_ptr); + if(!(args[0])) + { + return 0; + } + insn = _jit_block_add_insn(func->builder->current_block); + if(!insn) + { + return 0; + } + jit_value_ref(func, args[1]); + insn->opcode = JIT_OP_LOAD_CATCHER_PC; + insn->flags |= JIT_INSN_VALUE1_IS_LABEL; + 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])) + { + return 0; + } } /* We are now ready to make the actual function call */ - jit_type_free(type); return 1; #else /* JIT_BACKEND_INTERP */ /* The interpreter handles exception frames for us */ @@ -4751,6 +4768,7 @@ static int restore_eh_frame_after_call(jit_function_t func, int flags) return 1; } +#if JIT_APPLY_BROKEN_FRAME_BUILTINS != 0 /* Create the signature prototype "void (void)" */ type = jit_type_create_signature (jit_abi_cdecl, jit_type_void, 0, 0, 0); @@ -4759,43 +4777,34 @@ static int restore_eh_frame_after_call(jit_function_t func, int flags) return 0; } - /* Set up to call the "_jit_backtrace_pop" intrinsic */ - if(!_jit_create_call_setup_insns - (func, type, 0, 0, 0, 0, &struct_return)) - { - jit_type_free(type); - return 0; - } - - /* Terminate the current block and then call "_jit_backtrace_pop" */ - block = _jit_block_create(func, 0); - if(!block) - { - jit_type_free(type); - return 0; - } - block->entered_via_top = 1; - func->builder->current_block = block; - insn = _jit_block_add_insn(block); - if(!insn) - { - jit_type_free(type); - return 0; - } - insn->opcode = JIT_OP_CALL_EXTERNAL; - insn->flags = JIT_INSN_DEST_IS_NATIVE | JIT_INSN_VALUE1_IS_NAME; - insn->dest = (jit_value_t)(void *)_jit_backtrace_pop; - insn->value1 = (jit_value_t)"_jit_backtrace_pop"; + /* Call the "_jit_backtrace_pop" function */ + jit_insn_call_native + (func, "_jit_backtrace_pop", + (void *)_jit_backtrace_pop, type, 0, 0, JIT_CALL_NOTHROW); + jit_type_free(type); +#endif - /* Clean up after the function call */ - if(!_jit_create_call_return_insns(func, type, 0, 0, 0, 0)) + /* 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) { - jit_type_free(type); - return 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])) + { + return 0; + } + if(!jit_insn_store_relative + (func, jit_insn_address_of(func->builder->setjmp_value), + jit_jmp_catcher_offset, args[0])) + { + return 0; + } } /* Everything is back to where it should be */ - jit_type_free(type); return 1; #else /* JIT_BACKEND_INTERP */ /* The interpreter handles exception frames for us */ @@ -4961,12 +4970,11 @@ jit_value_t jit_insn_call it will be eliminated during later code generation */ if((flags & JIT_CALL_NORETURN) != 0) { - block = _jit_block_create(func, 0); - if(!block) + func->builder->current_block->ends_in_dead = 1; + if(!jit_insn_label(func, 0)) { return 0; } - func->builder->current_block = block; } /* Create space for the return value, if we don't already have one */ @@ -5076,12 +5084,11 @@ jit_value_t jit_insn_call_indirect it will be eliminated during later code generation */ if((flags & JIT_CALL_NORETURN) != 0) { - block = _jit_block_create(func, 0); - if(!block) + func->builder->current_block->ends_in_dead = 1; + if(!jit_insn_label(func, 0)) { return 0; } - func->builder->current_block = block; } /* Create space for the return value, if we don't already have one */ @@ -5193,12 +5200,11 @@ jit_value_t jit_insn_call_indirect_vtable it will be eliminated during later code generation */ if((flags & JIT_CALL_NORETURN) != 0) { - block = _jit_block_create(func, 0); - if(!block) + func->builder->current_block->ends_in_dead = 1; + if(!jit_insn_label(func, 0)) { return 0; } - func->builder->current_block = block; } /* Create space for the return value, if we don't already have one */ @@ -5306,12 +5312,11 @@ jit_value_t jit_insn_call_native it will be eliminated during later code generation */ if((flags & JIT_CALL_NORETURN) != 0) { - block = _jit_block_create(func, 0); - if(!block) + func->builder->current_block->ends_in_dead = 1; + if(!jit_insn_label(func, 0)) { return 0; } - func->builder->current_block = block; } /* Create space for the return value, if we don't already have one */ @@ -6218,6 +6223,184 @@ jit_value_t jit_insn_get_call_stack(jit_function_t func) return value; } +/* + * Initialize the "setjmp" setup block that is needed to catch exceptions + * thrown back to this level of execution. The block looks like this: + * + * jit_jmp_buf jbuf; + * void *catcher; + * + * _jit_unwind_push_setjmp(&jbuf); + * if(setjmp(&jbuf.buf)) + * { + * catcher = jbuf.catcher; + * if(catcher) + * { + * jbuf.catcher = 0; + * goto *catcher; + * } + * else + * { + * _jit_unwind_pop_and_rethrow(); + * } + * } + * + * The field "jbuf.catcher" 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. + * + * Native back ends are responsible for outputting a call to the function + * "_jit_unwind_pop_setjmp()" just before "return" instructions if the + * "has_try" flag is set on the function. + */ +static int initialize_setjmp_block(jit_function_t func) +{ +#if !defined(JIT_BACKEND_INTERP) + jit_label_t start_label = jit_label_undefined; + jit_label_t end_label = jit_label_undefined; + jit_label_t rethrow_label = jit_label_undefined; + jit_type_t type; + jit_value_t args[1]; + jit_value_t value; + + /* Bail out if we have already done this before */ + if(func->builder->setjmp_value) + { + return 1; + } + func->builder->longjmp_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)) + { + return 0; + } + + /* Create a value to hold an item of type "jit_jmp_buf" */ + type = jit_type_create_struct(0, 0, 1); + if(!type) + { + return 0; + } + jit_type_set_size_and_alignment + (type, sizeof(jit_jmp_buf), JIT_BEST_ALIGNMENT); + if((func->builder->setjmp_value = jit_value_create(func, type)) == 0) + { + jit_type_free(type); + return 0; + } + jit_type_free(type); + + /* Call "_jit_unwind_push_setjmp" with "&setjmp_value" as its argument */ + type = jit_type_void_ptr; + type = jit_type_create_signature + (jit_abi_cdecl, jit_type_void, &type, 1, 1); + if(!type) + { + return 0; + } + args[0] = jit_insn_address_of(func, func->builder->setjmp_value); + jit_insn_call_native + (func, "_jit_unwind_push_setjmp", + (void *)_jit_unwind_push_setjmp, type, args, 1, JIT_CALL_NOTHROW); + jit_type_free(type); + + /* Call "setjmp" with "&setjmp_value" as its argument */ + type = jit_type_void_ptr; + type = jit_type_create_signature + (jit_abi_cdecl, jit_type_int, &type, 1, 1); + if(!type) + { + return 0; + } + args[0] = jit_insn_address_of(func, func->builder->setjmp_value); + value = jit_insn_call_native + (func, "setjmp", (void *)setjmp, type, args, 1, JIT_CALL_NOTHROW); + jit_type_free(type); + if(!value) + { + return 0; + } + + /* Branch to the end of the init code if "setjmp" returned zero */ + if(!jit_insn_branch_if_not(func, value, &end_label)) + { + return 0; + } + + /* The current point in the code is where "longjmp" will resume from */ + if(!jit_insn_label(func, &(func->builder->longjmp_label))) + { + 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 */ + value = jit_insn_load_relative + (func, jit_insn_address_of(func, func->builder->setjmp_value), + jit_jmp_catcher_offset, jit_type_void_ptr); + if(!value) + { + return 0; + } + if(!jit_insn_branch_if_not(func, value, &rethrow_label)) + { + return 0; + } + + /* Clear the original "catcher" 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 + (func, jit_type_void_ptr, 0))) + { + return 0; + } + + /* Jump to the address indicated by the catcher */ + if(!create_unary_note(func, JIT_OP_JUMP_TO_CATCHER, value)) + { + return 0; + } + func->builder->current_block->ends_in_dead = 1; + + /* Mark the position of the rethrow label */ + if(!jit_insn_label(func, &rethrow_label)) + { + return 0; + } + + /* Call "_jit_unwind_pop_and_rethrow" to pop the current + "setjmp" context and then rethrow the current exception */ + 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_and_rethrow", + (void *)_jit_unwind_pop_and_rethrow, type, 0, 0, + JIT_CALL_NOTHROW | JIT_CALL_NORETURN); + jit_type_free(type); + + /* Force the start of a new block to mark the end of the init code */ + if(!jit_insn_label(func, &end_label)) + { + return 0; + } + + /* Move the initialization code to the head of the function so that + it is performed once upon entry to the function */ + return jit_insn_move_blocks_to_start(func, start_label, end_label); +#else + /* The interpreter doesn't need the "setjmp" setup block */ + 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 @@ -6280,6 +6463,12 @@ int jit_insn_start_try register allocation */ func->has_try = 1; + /* Make sure that the "setjmp" setup block is present in this function */ + if(!initialize_setjmp_block(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) diff --git a/jit/jit-internal.h b/jit/jit-internal.h index 1dec549..1993d83 100644 --- a/jit/jit-internal.h +++ b/jit/jit-internal.h @@ -298,6 +298,8 @@ struct _jit_builder /* Exception handlers for the function */ jit_block_eh_t exception_handlers; jit_block_eh_t current_handler; + jit_value_t setjmp_value; + jit_label_t longjmp_label; /* Flag that is set to indicate that this function is not a leaf */ int non_leaf : 1; @@ -458,8 +460,6 @@ struct jit_backtrace { jit_backtrace_t parent; void *pc; - void *catch_pc; - void *sp; void *security_object; jit_meta_free_func free_security_object; }; @@ -467,8 +467,7 @@ struct jit_backtrace /* * Push a new backtrace onto the stack. The fields in "trace" are filled in. */ -void _jit_backtrace_push - (jit_backtrace_t trace, void *pc, void *catch_pc, void *sp); +void _jit_backtrace_push(jit_backtrace_t trace, void *pc); /* * Pop the top-most backtrace item. diff --git a/jit/jit-interp.c b/jit/jit-interp.c index 34bd53c..f4937c3 100644 --- a/jit/jit-interp.c +++ b/jit/jit-interp.c @@ -3324,7 +3324,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, call_func = (jit_function_t)VM_NINT_ARG; VM_MODIFY_PC_AND_STACK(2, 0); entry = call_func->entry_point; - _jit_backtrace_push(&call_trace, pc, 0, 0); + _jit_backtrace_push(&call_trace, pc); if(!entry) { entry = _jit_function_compile_on_demand(call_func); @@ -3341,7 +3341,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, tempptr = (void *)VM_NINT_ARG; temparg = VM_NINT_ARG2; VM_MODIFY_PC_AND_STACK(3, 2); - _jit_backtrace_push(&call_trace, pc, 0, 0); + _jit_backtrace_push(&call_trace, pc); apply_from_interpreter((jit_type_t)tempptr, (void *)VM_STK_PTRP2, stacktop, @@ -3361,7 +3361,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, } VM_MODIFY_PC_AND_STACK(1, 1); entry = call_func->entry_point; - _jit_backtrace_push(&call_trace, pc, 0, 0); + _jit_backtrace_push(&call_trace, pc); if(!entry) { entry = _jit_function_compile_on_demand(call_func); @@ -3379,7 +3379,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, tempptr2 = (void *)VM_NINT_ARG2; temparg = VM_NINT_ARG3; VM_MODIFY_PC_AND_STACK(4, 1); - _jit_backtrace_push(&call_trace, pc, 0, 0); + _jit_backtrace_push(&call_trace, pc); apply_from_interpreter((jit_type_t)tempptr, (void *)tempptr2, stacktop, @@ -4478,6 +4478,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, 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); @@ -4533,7 +4534,7 @@ int jit_function_apply_vararg } /* Initialize the backtrace information */ - _jit_backtrace_push(&call_trace, 0, 0, 0); + _jit_backtrace_push(&call_trace, 0); /* Clear the exception context */ jit_exception_clear_last(); diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c index cb5ff33..65d297d 100644 --- a/jit/jit-opcode.c +++ b/jit/jit-opcode.c @@ -429,6 +429,7 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = { {"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)}, /* * Data manipulation. diff --git a/jit/jit-setjmp.h b/jit/jit-setjmp.h index df6b596..b2baa65 100644 --- a/jit/jit-setjmp.h +++ b/jit/jit-setjmp.h @@ -34,9 +34,12 @@ typedef struct jit_jmp_buf { jmp_buf buf; jit_backtrace_t trace; + void *catcher; struct jit_jmp_buf *parent; } jit_jmp_buf; +#define jit_jmp_catcher_offset \ + ((jit_nint)&(((jit_jmp_buf *)0)->catcher)) /* * Push a "setjmp" buffer onto the current thread's unwind stck. @@ -48,6 +51,11 @@ void _jit_unwind_push_setjmp(jit_jmp_buf *jbuf); */ void _jit_unwind_pop_setjmp(void); +/* + * Pop the top-most "setjmp" buffer and rethrow the current exception. + */ +void _jit_unwind_pop_and_rethrow(void); + #ifdef __cplusplus }; #endif |