]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Implement tail calls properly.
authorRhys Weatherley <rweather@southern-storm.com.au>
Thu, 18 Nov 2004 01:41:54 +0000 (01:41 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Thu, 18 Nov 2004 01:41:54 +0000 (01:41 +0000)
ChangeLog
include/jit/jit-opcode.h
jit/jit-dump.c
jit/jit-insn.c
jit/jit-interp.c
jit/jit-opcode.c
jit/jit-rules-interp.c
jit/jit-rules-x86.sel

index 40830cf53da1697992c31bd8f681e463349cb22c..9e68841fe975338e268a570534874680692d6a0f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,10 @@
 
+2004-11-18  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * include/jit/jit-opcode.h, jit/jit-dump.c, jit/jit-insn.c,
+       jit/jit-interp.c, jit/jit-opcode.c, jit/jit-rules-interp.c,
+       jit/jit-rules-x86.sel: implement tail calls properly.
+
 2004-11-05  Evin Robertson  <evin@users.sourceforge.net>
 
        * jit/jit-insn.c (jit_insn_store): use the destination type
index 8bc88d7b7dd699bac5d2525e5f38be7b256f4c3d..438c6cd607f3a806efead348099554023404e1c7 100644 (file)
@@ -386,141 +386,144 @@ extern  "C" {
 #define        JIT_OP_CALL                                                     0x013D
 #define        JIT_OP_CALL_TAIL                                        0x013E
 #define        JIT_OP_CALL_INDIRECT                            0x013F
-#define        JIT_OP_CALL_VTABLE_PTR                          0x0140
-#define        JIT_OP_CALL_EXTERNAL                            0x0141
-#define        JIT_OP_RETURN                                           0x0142
-#define        JIT_OP_RETURN_INT                                       0x0143
-#define        JIT_OP_RETURN_LONG                                      0x0144
-#define        JIT_OP_RETURN_FLOAT32                           0x0145
-#define        JIT_OP_RETURN_FLOAT64                           0x0146
-#define        JIT_OP_RETURN_NFLOAT                            0x0147
-#define        JIT_OP_RETURN_SMALL_STRUCT                      0x0148
-#define        JIT_OP_SETUP_FOR_NESTED                         0x0149
-#define        JIT_OP_SETUP_FOR_SIBLING                        0x014A
-#define        JIT_OP_IMPORT                                           0x014B
+#define        JIT_OP_CALL_INDIRECT_TAIL                       0x0140
+#define        JIT_OP_CALL_VTABLE_PTR                          0x0141
+#define        JIT_OP_CALL_VTABLE_PTR_TAIL                     0x0142
+#define        JIT_OP_CALL_EXTERNAL                            0x0143
+#define        JIT_OP_CALL_EXTERNAL_TAIL                       0x0144
+#define        JIT_OP_RETURN                                           0x0145
+#define        JIT_OP_RETURN_INT                                       0x0146
+#define        JIT_OP_RETURN_LONG                                      0x0147
+#define        JIT_OP_RETURN_FLOAT32                           0x0148
+#define        JIT_OP_RETURN_FLOAT64                           0x0149
+#define        JIT_OP_RETURN_NFLOAT                            0x014A
+#define        JIT_OP_RETURN_SMALL_STRUCT                      0x014B
+#define        JIT_OP_SETUP_FOR_NESTED                         0x014C
+#define        JIT_OP_SETUP_FOR_SIBLING                        0x014D
+#define        JIT_OP_IMPORT                                           0x014E
 
 /*
  * Exception handling.
  */
-#define        JIT_OP_THROW                                            0x014C
-#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
+#define        JIT_OP_THROW                                            0x014F
+#define        JIT_OP_RETHROW                                          0x0150
+#define        JIT_OP_LOAD_PC                                          0x0151
+#define        JIT_OP_LOAD_EXCEPTION_PC                        0x0152
+#define        JIT_OP_ENTER_FINALLY                            0x0153
+#define        JIT_OP_LEAVE_FINALLY                            0x0154
+#define        JIT_OP_CALL_FINALLY                                     0x0155
+#define        JIT_OP_ENTER_FILTER                                     0x0156
+#define        JIT_OP_LEAVE_FILTER                                     0x0157
+#define        JIT_OP_CALL_FILTER                                      0x0158
+#define        JIT_OP_CALL_FILTER_RETURN                       0x0159
+#define        JIT_OP_ADDRESS_OF_LABEL                         0x015A
 
 /*
  * Data manipulation.
  */
-#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
+#define        JIT_OP_COPY_LOAD_SBYTE                          0x015B
+#define        JIT_OP_COPY_LOAD_UBYTE                          0x015C
+#define        JIT_OP_COPY_LOAD_SHORT                          0x015D
+#define        JIT_OP_COPY_LOAD_USHORT                         0x015E
+#define        JIT_OP_COPY_INT                                         0x015F
+#define        JIT_OP_COPY_LONG                                        0x0160
+#define        JIT_OP_COPY_FLOAT32                                     0x0161
+#define        JIT_OP_COPY_FLOAT64                                     0x0162
+#define        JIT_OP_COPY_NFLOAT                                      0x0163
+#define        JIT_OP_COPY_STRUCT                                      0x0164
+#define        JIT_OP_COPY_STORE_BYTE                          0x0165
+#define        JIT_OP_COPY_STORE_SHORT                         0x0166
+#define        JIT_OP_ADDRESS_OF                                       0x0167
 
 /*
  * Incoming registers, outgoing registers, and stack pushes.
  */
-#define        JIT_OP_INCOMING_REG                                     0x0165
-#define        JIT_OP_INCOMING_FRAME_POSN                      0x0166
-#define        JIT_OP_OUTGOING_REG                                     0x0167
-#define        JIT_OP_OUTGOING_FRAME_POSN                      0x0168
-#define        JIT_OP_RETURN_REG                                       0x0169
-#define        JIT_OP_PUSH_INT                                         0x016A
-#define        JIT_OP_PUSH_LONG                                        0x016B
-#define        JIT_OP_PUSH_FLOAT32                                     0x016C
-#define        JIT_OP_PUSH_FLOAT64                                     0x016D
-#define        JIT_OP_PUSH_NFLOAT                                      0x016E
-#define        JIT_OP_PUSH_STRUCT                                      0x016F
-#define        JIT_OP_POP_STACK                                        0x0170
-#define        JIT_OP_FLUSH_SMALL_STRUCT                       0x0171
-#define        JIT_OP_SET_PARAM_INT                            0x0172
-#define        JIT_OP_SET_PARAM_LONG                           0x0173
-#define        JIT_OP_SET_PARAM_FLOAT32                        0x0174
-#define        JIT_OP_SET_PARAM_FLOAT64                        0x0175
-#define        JIT_OP_SET_PARAM_NFLOAT                         0x0176
-#define        JIT_OP_SET_PARAM_STRUCT                         0x0177
-#define        JIT_OP_PUSH_RETURN_AREA_PTR                     0x0178
+#define        JIT_OP_INCOMING_REG                                     0x0168
+#define        JIT_OP_INCOMING_FRAME_POSN                      0x0169
+#define        JIT_OP_OUTGOING_REG                                     0x016A
+#define        JIT_OP_OUTGOING_FRAME_POSN                      0x016B
+#define        JIT_OP_RETURN_REG                                       0x016C
+#define        JIT_OP_PUSH_INT                                         0x016D
+#define        JIT_OP_PUSH_LONG                                        0x016E
+#define        JIT_OP_PUSH_FLOAT32                                     0x016F
+#define        JIT_OP_PUSH_FLOAT64                                     0x0170
+#define        JIT_OP_PUSH_NFLOAT                                      0x0171
+#define        JIT_OP_PUSH_STRUCT                                      0x0172
+#define        JIT_OP_POP_STACK                                        0x0173
+#define        JIT_OP_FLUSH_SMALL_STRUCT                       0x0174
+#define        JIT_OP_SET_PARAM_INT                            0x0175
+#define        JIT_OP_SET_PARAM_LONG                           0x0176
+#define        JIT_OP_SET_PARAM_FLOAT32                        0x0177
+#define        JIT_OP_SET_PARAM_FLOAT64                        0x0178
+#define        JIT_OP_SET_PARAM_NFLOAT                         0x0179
+#define        JIT_OP_SET_PARAM_STRUCT                         0x017A
+#define        JIT_OP_PUSH_RETURN_AREA_PTR                     0x017B
 
 /*
  * Pointer-relative loads and stores.
  */
-#define        JIT_OP_LOAD_RELATIVE_SBYTE                      0x0179
-#define        JIT_OP_LOAD_RELATIVE_UBYTE                      0x017A
-#define        JIT_OP_LOAD_RELATIVE_SHORT                      0x017B
-#define        JIT_OP_LOAD_RELATIVE_USHORT                     0x017C
-#define        JIT_OP_LOAD_RELATIVE_INT                        0x017D
-#define        JIT_OP_LOAD_RELATIVE_LONG                       0x017E
-#define        JIT_OP_LOAD_RELATIVE_FLOAT32            0x017F
-#define        JIT_OP_LOAD_RELATIVE_FLOAT64            0x0180
-#define        JIT_OP_LOAD_RELATIVE_NFLOAT                     0x0181
-#define        JIT_OP_LOAD_RELATIVE_STRUCT                     0x0182
-#define        JIT_OP_STORE_RELATIVE_BYTE                      0x0183
-#define        JIT_OP_STORE_RELATIVE_SHORT                     0x0184
-#define        JIT_OP_STORE_RELATIVE_INT                       0x0185
-#define        JIT_OP_STORE_RELATIVE_LONG                      0x0186
-#define        JIT_OP_STORE_RELATIVE_FLOAT32           0x0187
-#define        JIT_OP_STORE_RELATIVE_FLOAT64           0x0188
-#define        JIT_OP_STORE_RELATIVE_NFLOAT            0x0189
-#define        JIT_OP_STORE_RELATIVE_STRUCT            0x018A
-#define        JIT_OP_ADD_RELATIVE                                     0x018B
+#define        JIT_OP_LOAD_RELATIVE_SBYTE                      0x017C
+#define        JIT_OP_LOAD_RELATIVE_UBYTE                      0x017D
+#define        JIT_OP_LOAD_RELATIVE_SHORT                      0x017E
+#define        JIT_OP_LOAD_RELATIVE_USHORT                     0x017F
+#define        JIT_OP_LOAD_RELATIVE_INT                        0x0180
+#define        JIT_OP_LOAD_RELATIVE_LONG                       0x0181
+#define        JIT_OP_LOAD_RELATIVE_FLOAT32            0x0182
+#define        JIT_OP_LOAD_RELATIVE_FLOAT64            0x0183
+#define        JIT_OP_LOAD_RELATIVE_NFLOAT                     0x0184
+#define        JIT_OP_LOAD_RELATIVE_STRUCT                     0x0185
+#define        JIT_OP_STORE_RELATIVE_BYTE                      0x0186
+#define        JIT_OP_STORE_RELATIVE_SHORT                     0x0187
+#define        JIT_OP_STORE_RELATIVE_INT                       0x0188
+#define        JIT_OP_STORE_RELATIVE_LONG                      0x0189
+#define        JIT_OP_STORE_RELATIVE_FLOAT32           0x018A
+#define        JIT_OP_STORE_RELATIVE_FLOAT64           0x018B
+#define        JIT_OP_STORE_RELATIVE_NFLOAT            0x018C
+#define        JIT_OP_STORE_RELATIVE_STRUCT            0x018D
+#define        JIT_OP_ADD_RELATIVE                                     0x018E
 
 /*
  * Array element loads and stores.
  */
-#define        JIT_OP_LOAD_ELEMENT_SBYTE                       0x018C
-#define        JIT_OP_LOAD_ELEMENT_UBYTE                       0x018D
-#define        JIT_OP_LOAD_ELEMENT_SHORT                       0x018E
-#define        JIT_OP_LOAD_ELEMENT_USHORT                      0x018F
-#define        JIT_OP_LOAD_ELEMENT_INT                         0x0190
-#define        JIT_OP_LOAD_ELEMENT_LONG                        0x0191
-#define        JIT_OP_LOAD_ELEMENT_FLOAT32                     0x0192
-#define        JIT_OP_LOAD_ELEMENT_FLOAT64                     0x0193
-#define        JIT_OP_LOAD_ELEMENT_NFLOAT                      0x0194
-#define        JIT_OP_STORE_ELEMENT_BYTE                       0x0195
-#define        JIT_OP_STORE_ELEMENT_SHORT                      0x0196
-#define        JIT_OP_STORE_ELEMENT_INT                        0x0197
-#define        JIT_OP_STORE_ELEMENT_LONG                       0x0198
-#define        JIT_OP_STORE_ELEMENT_FLOAT32            0x0199
-#define        JIT_OP_STORE_ELEMENT_FLOAT64            0x019A
-#define        JIT_OP_STORE_ELEMENT_NFLOAT                     0x019B
+#define        JIT_OP_LOAD_ELEMENT_SBYTE                       0x018F
+#define        JIT_OP_LOAD_ELEMENT_UBYTE                       0x0190
+#define        JIT_OP_LOAD_ELEMENT_SHORT                       0x0191
+#define        JIT_OP_LOAD_ELEMENT_USHORT                      0x0192
+#define        JIT_OP_LOAD_ELEMENT_INT                         0x0193
+#define        JIT_OP_LOAD_ELEMENT_LONG                        0x0194
+#define        JIT_OP_LOAD_ELEMENT_FLOAT32                     0x0195
+#define        JIT_OP_LOAD_ELEMENT_FLOAT64                     0x0196
+#define        JIT_OP_LOAD_ELEMENT_NFLOAT                      0x0197
+#define        JIT_OP_STORE_ELEMENT_BYTE                       0x0198
+#define        JIT_OP_STORE_ELEMENT_SHORT                      0x0199
+#define        JIT_OP_STORE_ELEMENT_INT                        0x019A
+#define        JIT_OP_STORE_ELEMENT_LONG                       0x019B
+#define        JIT_OP_STORE_ELEMENT_FLOAT32            0x019C
+#define        JIT_OP_STORE_ELEMENT_FLOAT64            0x019D
+#define        JIT_OP_STORE_ELEMENT_NFLOAT                     0x019E
 
 /*
  * Block operations.
  */
-#define        JIT_OP_MEMCPY                                           0x019C
-#define        JIT_OP_MEMMOVE                                          0x019D
-#define        JIT_OP_MEMSET                                           0x019E
+#define        JIT_OP_MEMCPY                                           0x019F
+#define        JIT_OP_MEMMOVE                                          0x01A0
+#define        JIT_OP_MEMSET                                           0x01A1
 
 /*
  * Allocate memory from the stack.
  */
-#define        JIT_OP_ALLOCA                                           0x019F
+#define        JIT_OP_ALLOCA                                           0x01A2
 
 /*
  * Debugging support.
  */
-#define        JIT_OP_MARK_OFFSET                                      0x01A0
-#define        JIT_OP_MARK_BREAKPOINT                          0x01A1
+#define        JIT_OP_MARK_OFFSET                                      0x01A3
+#define        JIT_OP_MARK_BREAKPOINT                          0x01A4
 
 /*
  * The number of opcodes in the above list.
  */
-#define        JIT_OP_NUM_OPCODES                                      0x01A2
+#define        JIT_OP_NUM_OPCODES                                      0x01A5
 
 /*
  * Opcode information.
index 570c8bc502451d903997e12635b8f6cb6c1d393d..c2af40c6db47b6947054cf256e3ae949afc3cf18 100644 (file)
@@ -386,19 +386,19 @@ void jit_dump_insn(FILE *stream, jit_function_t func, jit_insn_t insn)
        else if((flags & JIT_OPCODE_IS_CALL) != 0)
        {
                if(insn->value1)
-                       fprintf(stream, "call %s", (const char *)(insn->value1));
+                       fprintf(stream, "%s %s", name, (const char *)(insn->value1));
                else
-                       fprintf(stream, "call 0x08%lx", (long)(jit_nuint)(insn->dest));
+                       fprintf(stream, "%s 0x08%lx", name, (long)(jit_nuint)(insn->dest));
                return;
        }
        else if((flags & JIT_OPCODE_IS_CALL_EXTERNAL) != 0)
        {
                if(insn->value1)
-                       fprintf(stream, "call_external %s (0x%08lx)",
+                       fprintf(stream, "%s %s (0x%08lx)", name,
                                        (const char *)(insn->value1),
                                        (long)(jit_nuint)(insn->dest));
                else
-                       fprintf(stream, "call_external 0x08%lx",
+                       fprintf(stream, "%s 0x08%lx", name,
                                        (long)(jit_nuint)(insn->dest));
                return;
        }
index 6c52113235610d05ff47ae6621a774517b402200..969a905e7a31d9dfc60863fb780b8067a1833434 100644 (file)
@@ -5381,6 +5381,9 @@ jit_value_t jit_insn_call_indirect
        }
 
        /* Verify that tail calls are possible to the destination */
+#if defined(JIT_BACKEND_INTERP)
+       flags &= ~JIT_CALL_TAIL;
+#else
        if((flags & JIT_CALL_TAIL) != 0)
        {
                if(func->nested_parent)
@@ -5392,6 +5395,7 @@ jit_value_t jit_insn_call_indirect
                        flags &= ~JIT_CALL_TAIL;
                }
        }
+#endif
 
        /* We are making a native call */
        flags |= JIT_CALL_NATIVE;
@@ -5443,7 +5447,15 @@ jit_value_t jit_insn_call_indirect
                return 0;
        }
        jit_value_ref(func, value);
-       insn->opcode = JIT_OP_CALL_INDIRECT;
+       if((flags & JIT_CALL_TAIL) != 0)
+       {
+               func->builder->has_tail_call = 1;
+               insn->opcode = JIT_OP_CALL_INDIRECT_TAIL;
+       }
+       else
+       {
+               insn->opcode = JIT_OP_CALL_INDIRECT;
+       }
        insn->flags = JIT_INSN_VALUE2_IS_SIGNATURE;
        insn->value1 = value;
        insn->value2 = (jit_value_t)jit_type_copy(signature);
@@ -5573,7 +5585,15 @@ jit_value_t jit_insn_call_indirect_vtable
                return 0;
        }
        jit_value_ref(func, value);
-       insn->opcode = JIT_OP_CALL_VTABLE_PTR;
+       if((flags & JIT_CALL_TAIL) != 0)
+       {
+               func->builder->has_tail_call = 1;
+               insn->opcode = JIT_OP_CALL_VTABLE_PTR_TAIL;
+       }
+       else
+       {
+               insn->opcode = JIT_OP_CALL_VTABLE_PTR;
+       }
        insn->value1 = value;
 
        /* If the function does not return, then end the current block.
@@ -5639,6 +5659,9 @@ jit_value_t jit_insn_call_native
        }
 
        /* Verify that tail calls are possible to the destination */
+#if defined(JIT_BACKEND_INTERP)
+       flags &= ~JIT_CALL_TAIL;
+#else
        if((flags & JIT_CALL_TAIL) != 0)
        {
                if(func->nested_parent)
@@ -5650,6 +5673,7 @@ jit_value_t jit_insn_call_native
                        flags &= ~JIT_CALL_TAIL;
                }
        }
+#endif
 
        /* We are making a native call */
        flags |= JIT_CALL_NATIVE;
@@ -5694,7 +5718,15 @@ jit_value_t jit_insn_call_native
        {
                return 0;
        }
-       insn->opcode = JIT_OP_CALL_EXTERNAL;
+       if((flags & JIT_CALL_TAIL) != 0)
+       {
+               func->builder->has_tail_call = 1;
+               insn->opcode = JIT_OP_CALL_EXTERNAL_TAIL;
+       }
+       else
+       {
+               insn->opcode = JIT_OP_CALL_EXTERNAL;
+       }
        insn->flags = JIT_INSN_DEST_IS_NATIVE | JIT_INSN_VALUE1_IS_NAME;
        insn->dest = (jit_value_t)native_func;
        insn->value1 = (jit_value_t)name;
index b035d5040746f745849d80053cc6319331a88a2c..6583877f359056674b1e28125ad037f1ca0d6fc9 100644 (file)
@@ -154,6 +154,26 @@ straight vanilla ANSI C.
                                } \
                        } while (0)
 
+/*
+ * Perform a tail call to a new function.
+ */
+#define        VM_PERFORM_TAIL(newfunc)        \
+                       { \
+                               if(jbuf) \
+                               { \
+                                       _jit_unwind_pop_setjmp(); \
+                               } \
+                               func = (newfunc); \
+                               if(func->frame_size > current_frame_size) \
+                               { \
+                                       current_frame_size = func->frame_size; \
+                                       frame_base = (jit_item *)alloca(current_frame_size); \
+                               } \
+                               stacktop = frame_base + func->working_area; \
+                               frame = stacktop; \
+                               goto restart_tail; \
+                       }
+
 /*
  * Call "jit_apply" from the interpreter, to invoke a native function.
  */
@@ -230,6 +250,7 @@ static void apply_from_interpreter
 void _jit_run_function(jit_function_interp_t func, jit_item *args,
                                           jit_item *return_area)
 {
+       jit_item *frame_base;
        jit_item *frame;
        jit_item *stacktop;
        void **pc;
@@ -244,16 +265,19 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args,
        void *exception_pc = 0;
        void *handler;
        jit_jmp_buf *jbuf;
+       jit_nint current_frame_size;
 
        /* Define the label table for computed goto dispatch */
        #include "jit-interp-labels.h"
 
        /* Set up the stack frame for this function */
-       frame = (jit_item *)alloca(func->frame_size);
-       stacktop = frame + func->working_area;
+       current_frame_size = func->frame_size;
+       frame_base = (jit_item *)alloca(current_frame_size);
+       stacktop = frame_base + func->working_area;
        frame = stacktop;
 
        /* Get the initial program counter */
+restart_tail:
        pc = jit_function_interp_entry_pc(func);
 
        /* Create a "setjmp" point if this function has a "try" block.
@@ -3319,7 +3343,6 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args,
                 ******************************************************************/
 
                VMCASE(JIT_OP_CALL):
-               VMCASE(JIT_OP_CALL_TAIL):
                {
                        /* Call a function that is under the control of the JIT */
                        call_func = (jit_function_t)VM_NINT_ARG;
@@ -3336,7 +3359,21 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args,
                }
                VMBREAK;
 
+               VMCASE(JIT_OP_CALL_TAIL):
+               {
+                       /* Tail call a function that is under the control of the JIT */
+                       call_func = (jit_function_t)VM_NINT_ARG;
+                       entry = call_func->entry_point;
+                       if(!entry)
+                       {
+                               entry = _jit_function_compile_on_demand(call_func);
+                       }
+                       VM_PERFORM_TAIL((jit_function_interp_t)entry);
+               }
+               /* Not reached */
+
                VMCASE(JIT_OP_CALL_INDIRECT):
+               VMCASE(JIT_OP_CALL_INDIRECT_TAIL):      /* Indirect tail not possible */
                {
                        /* Call a native function via an indirect pointer */
                        tempptr = (void *)VM_NINT_ARG;
@@ -3373,7 +3410,25 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args,
                }
                VMBREAK;
 
+               VMCASE(JIT_OP_CALL_VTABLE_PTR_TAIL):
+               {
+                       /* Tail call a JIT-managed function via indirect vtable pointer */
+                       call_func = (jit_function_t)(VM_STK_PTR0);
+                       if(!call_func)
+                       {
+                               VM_BUILTIN(JIT_RESULT_NULL_FUNCTION);
+                       }
+                       entry = call_func->entry_point;
+                       if(!entry)
+                       {
+                               entry = _jit_function_compile_on_demand(call_func);
+                       }
+                       VM_PERFORM_TAIL((jit_function_interp_t)entry);
+               }
+               /* Not reached */
+
                VMCASE(JIT_OP_CALL_EXTERNAL):
+               VMCASE(JIT_OP_CALL_EXTERNAL_TAIL):      /* External tail not possible */
                {
                        /* Call an external native function */
                        tempptr = (void *)VM_NINT_ARG;
index b6c9806a865a43930b55920f9f0929cfaa7ad508..f0684be9f789bddfef642fd92000bb61152312ae 100644 (file)
@@ -402,8 +402,11 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = {
        {"call",                                                JIT_OPCODE_IS_CALL},
        {"call_tail",                                   JIT_OPCODE_IS_CALL},
        {"call_indirect",                               F_(EMPTY, PTR, EMPTY) | INDIRECT_ARGS},
+       {"call_indirect_tail",                  F_(EMPTY, PTR, EMPTY) | INDIRECT_ARGS},
        {"call_vtable_ptr",                             F_(EMPTY, PTR, EMPTY)},
+       {"call_vtable_ptr_tail",                F_(EMPTY, PTR, EMPTY)},
        {"call_external",                               JIT_OPCODE_IS_CALL_EXTERNAL},
+       {"call_external_tail",                  JIT_OPCODE_IS_CALL_EXTERNAL},
        {"return",                                              F_(EMPTY, EMPTY, EMPTY)},
        {"return_int",                                  F_(EMPTY, INT, EMPTY)},
        {"return_long",                                 F_(EMPTY, LONG, EMPTY)},
index 27b7914ac29a5a5cd10372a1ae208ebdd38d5651..8377d0ecd07ce8ba6f01894c208a6f4979661a7d 100644 (file)
@@ -1145,6 +1145,7 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
                break;
 
                case JIT_OP_CALL_INDIRECT:
+               case JIT_OP_CALL_INDIRECT_TAIL:
                {
                        /* Call a function, whose pointer is supplied on the stack */
                        jit_cache_opcode(&(gen->posn), insn->opcode);
@@ -1156,6 +1157,7 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
                break;
 
                case JIT_OP_CALL_VTABLE_PTR:
+               case JIT_OP_CALL_VTABLE_PTR_TAIL:
                {
                        /* Call a function, whose vtable pointer is supplied on the stack */
                        jit_cache_opcode(&(gen->posn), insn->opcode);
@@ -1164,6 +1166,7 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
                break;
 
                case JIT_OP_CALL_EXTERNAL:
+               case JIT_OP_CALL_EXTERNAL_TAIL:
                {
                        /* Call a native function, whose pointer is supplied explicitly */
                        jit_cache_opcode(&(gen->posn), insn->opcode);
index 304f435b320b155d9cecdff1b0d5ead7395a70d1..e629c235d77b9b1aaf386252a2e5d20a182b5e7d 100644 (file)
@@ -1647,16 +1647,37 @@ JIT_OP_CALL_INDIRECT:
                x86_call_reg(inst, X86_EAX);
        }
 
+JIT_OP_CALL_INDIRECT_TAIL:
+       [] -> {
+               x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
+               x86_pop_reg(inst, X86_EBP);
+               x86_jump_reg(inst, X86_EAX);
+       }
+
 JIT_OP_CALL_VTABLE_PTR:
        [] -> {
                x86_call_reg(inst, X86_EAX);
        }
 
+JIT_OP_CALL_VTABLE_PTR_TAIL:
+       [] -> {
+               x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
+               x86_pop_reg(inst, X86_EBP);
+               x86_jump_reg(inst, X86_EAX);
+       }
+
 JIT_OP_CALL_EXTERNAL:
        [] -> {
                x86_call_code(inst, (void *)(insn->dest));
        }
 
+JIT_OP_CALL_EXTERNAL_TAIL:
+       [] -> {
+               x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
+               x86_pop_reg(inst, X86_EBP);
+               x86_jump_code(inst, (void *)(insn->dest));
+       }
+
 JIT_OP_RETURN:
        [] -> {
                inst = jump_to_epilog(gen, inst, block);