]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Modify the function call logic to use "setjmp" with native back ends.
authorRhys Weatherley <rweather@southern-storm.com.au>
Sat, 22 May 2004 02:08:07 +0000 (02:08 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Sat, 22 May 2004 02:08:07 +0000 (02:08 +0000)
ChangeLog
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

index f84a9ba023c80eff445b0db804f358afb2d200e0..35b952466a1d14d3145092d3f24a57a5ebdd90e3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        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
index 52eb1befd123900a013c41ec31456e88a290a355..9116c0ff40e13e313bdad037f8683848b59ed363 100644 (file)
@@ -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.
index e8c20b180e4470d9960caa2c7c757d9d14e26da8..7a63942ae174893a5bee7f8227b18c362efd04fd 100644 (file)
@@ -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());
+}
index 5ca05050b2449fbc1aaa7f377bc140e38eb8a420..ac222291957ce4c97d71a079ad1e0622d0e52cf3 100644 (file)
@@ -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)
index 8781aaadb7a868211e7b56e6d48d51036205f5b7..c65d5b96b4a51a13c18cd5ac476d06b4e46ac618 100644 (file)
@@ -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)
index 1dec549c2b638b0e5242628a3e5b59a727e5d876..1993d832549f62e7665aaa937e775d70f5986c58 100644 (file)
@@ -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.
index 34bd53cf3786cdda3b25b47e685505513c874a9f..f4937c30ab14a81217c82f50a4740d9b9551add6 100644 (file)
@@ -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();
index cb5ff337a0c6715dbc5f1d35a3c2f2587a354080..65d297ddceeecafb9d8a4b5d5995cad221c5e4d8 100644 (file)
@@ -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.
index df6b596c74352fca565f67602d6af7e466535bb6..b2baa65b971ed9c231eed23ca89d117ab131daff 100644 (file)
@@ -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