From: Rhys Weatherley Date: Thu, 18 Nov 2004 01:41:54 +0000 (+0000) Subject: Implement tail calls properly. X-Git-Tag: r.0.0.6~25 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=6334c1d701eeed5d2e903c39b2c8e168ba37dde9;p=francis%2Flibjit.git Implement tail calls properly. --- diff --git a/ChangeLog b/ChangeLog index 40830cf..9e68841 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ +2004-11-18 Rhys Weatherley + + * 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 * jit/jit-insn.c (jit_insn_store): use the destination type diff --git a/include/jit/jit-opcode.h b/include/jit/jit-opcode.h index 8bc88d7..438c6cd 100644 --- a/include/jit/jit-opcode.h +++ b/include/jit/jit-opcode.h @@ -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. diff --git a/jit/jit-dump.c b/jit/jit-dump.c index 570c8bc..c2af40c 100644 --- a/jit/jit-dump.c +++ b/jit/jit-dump.c @@ -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; } diff --git a/jit/jit-insn.c b/jit/jit-insn.c index 6c52113..969a905 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -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; diff --git a/jit/jit-interp.c b/jit/jit-interp.c index b035d50..6583877 100644 --- a/jit/jit-interp.c +++ b/jit/jit-interp.c @@ -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; diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c index b6c9806..f0684be 100644 --- a/jit/jit-opcode.c +++ b/jit/jit-opcode.c @@ -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)}, diff --git a/jit/jit-rules-interp.c b/jit/jit-rules-interp.c index 27b7914..8377d0e 100644 --- a/jit/jit-rules-interp.c +++ b/jit/jit-rules-interp.c @@ -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); diff --git a/jit/jit-rules-x86.sel b/jit/jit-rules-x86.sel index 304f435..e629c23 100644 --- a/jit/jit-rules-x86.sel +++ b/jit/jit-rules-x86.sel @@ -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);