Add support for tailcalls from internal C functions.
PPC: Fix __call metamethod for tailcalls.
This commit is contained in:
parent
23f847f4ed
commit
fa5cd010e8
@ -114,7 +114,8 @@ lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
|||||||
lj_gc.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h lj_dispatch.h lj_bc.h \
|
lj_gc.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h lj_dispatch.h lj_bc.h \
|
||||||
lj_traceerr.h lj_vm.h
|
lj_traceerr.h lj_vm.h
|
||||||
lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||||
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_bc.h lj_vm.h
|
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
|
||||||
|
lj_vm.h
|
||||||
lj_obj.o: lj_obj.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
|
lj_obj.o: lj_obj.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
|
||||||
lj_opt_dce.o: lj_opt_dce.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
lj_opt_dce.o: lj_opt_dce.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||||
lj_ir.h lj_jit.h lj_iropt.h
|
lj_ir.h lj_jit.h lj_iropt.h
|
||||||
|
@ -411,7 +411,7 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
|
|
|
|
||||||
|->vm_call_dispatch_f:
|
|->vm_call_dispatch_f:
|
||||||
| ins_call
|
| ins_call
|
||||||
| // BASE = new base, RC = nargs*8
|
| // BASE = new base, CARG3 = func, RC = nargs*8, PC = caller PC
|
||||||
|
|
|
|
||||||
|->vm_cpcall: // Setup protected C frame, call C.
|
|->vm_cpcall: // Setup protected C frame, call C.
|
||||||
| // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
|
| // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
|
||||||
@ -445,18 +445,26 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
|->cont_dispatch:
|
|->cont_dispatch:
|
||||||
| // BASE = meta base, RA = resultptr, RC = (nresults+1)*8
|
| // BASE = meta base, RA = resultptr, RC = (nresults+1)*8
|
||||||
| ldr LFUNC:CARG3, [RB, FRAME_FUNC]
|
| ldr LFUNC:CARG3, [RB, FRAME_FUNC]
|
||||||
|
| ldr CARG1, [BASE, #-16] // Get continuation.
|
||||||
| mov CARG4, BASE
|
| mov CARG4, BASE
|
||||||
| mov BASE, RB // Restore caller BASE.
|
| mov BASE, RB // Restore caller BASE.
|
||||||
|
| cmp CARG1, #0
|
||||||
| ldr PC, [CARG4, #-12] // Restore PC from [cont|PC].
|
| ldr PC, [CARG4, #-12] // Restore PC from [cont|PC].
|
||||||
|
| beq >1
|
||||||
| ldr CARG3, LFUNC:CARG3->field_pc
|
| ldr CARG3, LFUNC:CARG3->field_pc
|
||||||
| mvn INS, #~LJ_TNIL
|
| mvn INS, #~LJ_TNIL
|
||||||
| add CARG2, RA, RC
|
| add CARG2, RA, RC
|
||||||
| ldr CARG1, [CARG4, #-16] // Get continuation.
|
|
||||||
| str INS, [CARG2, #-4] // Ensure one valid arg.
|
| str INS, [CARG2, #-4] // Ensure one valid arg.
|
||||||
| ldr KBASE, [CARG3, #PC2PROTO(k)]
|
| ldr KBASE, [CARG3, #PC2PROTO(k)]
|
||||||
| // BASE = base, RA = resultptr, CARG4 = meta base
|
| // BASE = base, RA = resultptr, CARG4 = meta base
|
||||||
| bx CARG1
|
| bx CARG1
|
||||||
|
|
|
|
||||||
|
|1: // Tail call from C function.
|
||||||
|
| ldr CARG3, [BASE, FRAME_FUNC]
|
||||||
|
| sub CARG4, CARG4, #16
|
||||||
|
| sub RC, CARG4, BASE
|
||||||
|
| b ->vm_call_tail
|
||||||
|
|
|
||||||
|->cont_cat: // RA = resultptr, CARG4 = meta base
|
|->cont_cat: // RA = resultptr, CARG4 = meta base
|
||||||
| ldr INS, [PC, #-4]
|
| ldr INS, [PC, #-4]
|
||||||
| sub CARG2, CARG4, #16
|
| sub CARG2, CARG4, #16
|
||||||
@ -714,7 +722,7 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
| str PC, SAVE_PC
|
| str PC, SAVE_PC
|
||||||
| add CARG3, RA, NARGS8:RC
|
| add CARG3, RA, NARGS8:RC
|
||||||
| bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
|
| bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
|
||||||
| ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here.
|
| ldr LFUNC:CARG3, [RA, FRAME_FUNC] // Guaranteed to be a function here.
|
||||||
| ldr PC, [BASE, FRAME_PC]
|
| ldr PC, [BASE, FRAME_PC]
|
||||||
| add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now.
|
| add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now.
|
||||||
| b ->BC_CALLT2_Z
|
| b ->BC_CALLT2_Z
|
||||||
@ -1514,10 +1522,11 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
| ldr CARG1, L->top
|
| ldr CARG1, L->top
|
||||||
| ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
|
| ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
|
||||||
| sub NARGS8:RC, CARG1, BASE
|
| sub NARGS8:RC, CARG1, BASE
|
||||||
| bne >2 // Returned -1?
|
| bne ->vm_call_tail // Returned -1?
|
||||||
| ins_callt // Returned 0: retry fast path.
|
| ins_callt // Returned 0: retry fast path.
|
||||||
|
|
|
|
||||||
|2: // Reconstruct previous base for vmeta_call during tailcall.
|
|// Reconstruct previous base for vmeta_call during tailcall.
|
||||||
|
|->vm_call_tail:
|
||||||
| ands CARG1, PC, #FRAME_TYPE
|
| ands CARG1, PC, #FRAME_TYPE
|
||||||
| bic CARG2, PC, #FRAME_TYPEP
|
| bic CARG2, PC, #FRAME_TYPEP
|
||||||
| ldreq INS, [PC, #-4]
|
| ldreq INS, [PC, #-4]
|
||||||
|
@ -540,7 +540,7 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
|
|
|
|
||||||
|->vm_call_dispatch_f:
|
|->vm_call_dispatch_f:
|
||||||
| ins_call
|
| ins_call
|
||||||
| // BASE = new base, RC = nargs*8
|
| // BASE = new base, RB = func, RC = nargs*8, PC = caller PC
|
||||||
|
|
|
|
||||||
|->vm_cpcall: // Setup protected C frame, call C.
|
|->vm_cpcall: // Setup protected C frame, call C.
|
||||||
| // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
|
| // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
|
||||||
@ -581,8 +581,10 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
| mr RB, BASE
|
| mr RB, BASE
|
||||||
| mr BASE, TMP2 // Restore caller BASE.
|
| mr BASE, TMP2 // Restore caller BASE.
|
||||||
| lwz LFUNC:TMP1, FRAME_FUNC(TMP2)
|
| lwz LFUNC:TMP1, FRAME_FUNC(TMP2)
|
||||||
| subi TMP2, RD, 8
|
| cmplwi TMP0, 0
|
||||||
| lwz PC, -16(RB) // Restore PC from [cont|PC].
|
| lwz PC, -16(RB) // Restore PC from [cont|PC].
|
||||||
|
| beq >1
|
||||||
|
| subi TMP2, RD, 8
|
||||||
| lwz TMP1, LFUNC:TMP1->pc
|
| lwz TMP1, LFUNC:TMP1->pc
|
||||||
| evstddx TISNIL, RA, TMP2 // Ensure one valid arg.
|
| evstddx TISNIL, RA, TMP2 // Ensure one valid arg.
|
||||||
| lwz KBASE, PC2PROTO(k)(TMP1)
|
| lwz KBASE, PC2PROTO(k)(TMP1)
|
||||||
@ -590,6 +592,11 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
| mtctr TMP0
|
| mtctr TMP0
|
||||||
| bctr // Jump to continuation.
|
| bctr // Jump to continuation.
|
||||||
|
|
|
|
||||||
|
|1: // Tail call from C function.
|
||||||
|
| subi TMP1, RB, 16
|
||||||
|
| sub RC, TMP1, BASE
|
||||||
|
| b ->vm_call_tail
|
||||||
|
|
|
||||||
|->cont_cat: // RA = resultptr, RB = meta base
|
|->cont_cat: // RA = resultptr, RB = meta base
|
||||||
| lwz INS, -4(PC)
|
| lwz INS, -4(PC)
|
||||||
| subi CARG2, RB, 16
|
| subi CARG2, RB, 16
|
||||||
@ -845,7 +852,7 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
| bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
|
| bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
|
||||||
| lwz TMP1, FRAME_PC(BASE)
|
| lwz TMP1, FRAME_PC(BASE)
|
||||||
| addi NARGS8:RC, SAVE0, 8 // Got one more argument now.
|
| addi NARGS8:RC, SAVE0, 8 // Got one more argument now.
|
||||||
| lwz LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here.
|
| lwz LFUNC:RB, FRAME_FUNC(RA) // Guaranteed to be a function here.
|
||||||
| b ->BC_CALLT_Z
|
| b ->BC_CALLT_Z
|
||||||
|
|
|
|
||||||
|//-- Argument coercion for 'for' statement ------------------------------
|
|//-- Argument coercion for 'for' statement ------------------------------
|
||||||
@ -1797,10 +1804,11 @@ static void build_subroutines(BuildCtx *ctx)
|
|||||||
| lwz TMP0, L->top
|
| lwz TMP0, L->top
|
||||||
| lwz LFUNC:RB, FRAME_FUNC(BASE)
|
| lwz LFUNC:RB, FRAME_FUNC(BASE)
|
||||||
| sub NARGS8:RC, TMP0, BASE
|
| sub NARGS8:RC, TMP0, BASE
|
||||||
| bne >2 // Returned -1?
|
| bne ->vm_call_tail // Returned -1?
|
||||||
| ins_callt // Returned 0: retry fast path.
|
| ins_callt // Returned 0: retry fast path.
|
||||||
|
|
|
|
||||||
|2: // Reconstruct previous base for vmeta_call during tailcall.
|
|// Reconstruct previous base for vmeta_call during tailcall.
|
||||||
|
|->vm_call_tail:
|
||||||
| andi. TMP0, PC, FRAME_TYPE
|
| andi. TMP0, PC, FRAME_TYPE
|
||||||
| rlwinm TMP1, PC, 0, 0, 28
|
| rlwinm TMP1, PC, 0, 0, 28
|
||||||
| bne >3
|
| bne >3
|
||||||
|
1486
src/buildvm_ppcspe.h
1486
src/buildvm_ppcspe.h
File diff suppressed because it is too large
Load Diff
2158
src/buildvm_x64.h
2158
src/buildvm_x64.h
File diff suppressed because it is too large
Load Diff
2152
src/buildvm_x64win.h
2152
src/buildvm_x64win.h
File diff suppressed because it is too large
Load Diff
@ -696,7 +696,7 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
|
|||||||
|->vm_call_dispatch_f:
|
|->vm_call_dispatch_f:
|
||||||
| mov BASE, RA
|
| mov BASE, RA
|
||||||
| ins_call
|
| ins_call
|
||||||
| // BASE = new base, RD = nargs+1
|
| // BASE = new base, RB = func, RD = nargs+1, PC = caller PC
|
||||||
|
|
|
|
||||||
|->vm_cpcall: // Setup protected C frame, call C.
|
|->vm_cpcall: // Setup protected C frame, call C.
|
||||||
| // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
|
| // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
|
||||||
@ -760,10 +760,14 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
|
|||||||
| mov PC, [RB-12] // Restore PC from [cont|PC].
|
| mov PC, [RB-12] // Restore PC from [cont|PC].
|
||||||
|.if X64
|
|.if X64
|
||||||
| movsxd RAa, dword [RB-16] // May be negative on WIN64 with debug.
|
| movsxd RAa, dword [RB-16] // May be negative on WIN64 with debug.
|
||||||
|
| test RA, RA
|
||||||
|
| jz >1
|
||||||
| lea KBASEa, qword [=>0]
|
| lea KBASEa, qword [=>0]
|
||||||
| add RAa, KBASEa
|
| add RAa, KBASEa
|
||||||
|.else
|
|.else
|
||||||
| mov RA, dword [RB-16]
|
| mov RA, dword [RB-16]
|
||||||
|
| test RA, RA
|
||||||
|
| jz >1
|
||||||
|.endif
|
|.endif
|
||||||
| mov LFUNC:KBASE, [BASE-8]
|
| mov LFUNC:KBASE, [BASE-8]
|
||||||
| mov KBASE, LFUNC:KBASE->pc
|
| mov KBASE, LFUNC:KBASE->pc
|
||||||
@ -771,6 +775,12 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
|
|||||||
| // BASE = base, RC = result, RB = meta base
|
| // BASE = base, RC = result, RB = meta base
|
||||||
| jmp RAa // Jump to continuation.
|
| jmp RAa // Jump to continuation.
|
||||||
|
|
|
|
||||||
|
|1: // Tail call from C function.
|
||||||
|
| sub RB, BASE
|
||||||
|
| shr RB, 3
|
||||||
|
| lea RD, [RB-1]
|
||||||
|
| jmp ->vm_call_tail
|
||||||
|
|
|
||||||
|->cont_cat: // BASE = base, RC = result, RB = mbase
|
|->cont_cat: // BASE = base, RC = result, RB = mbase
|
||||||
| movzx RA, PC_RB
|
| movzx RA, PC_RB
|
||||||
| sub RB, 16
|
| sub RB, 16
|
||||||
@ -2735,10 +2745,11 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
|
|||||||
| test RD, RD
|
| test RD, RD
|
||||||
| lea NARGS:RD, [RA+1]
|
| lea NARGS:RD, [RA+1]
|
||||||
| mov LFUNC:RB, [BASE-8]
|
| mov LFUNC:RB, [BASE-8]
|
||||||
| jne >2 // Returned -1?
|
| jne ->vm_call_tail // Returned -1?
|
||||||
| ins_callt // Returned 0: retry fast path.
|
| ins_callt // Returned 0: retry fast path.
|
||||||
|
|
|
|
||||||
|2: // Reconstruct previous base for vmeta_call during tailcall.
|
|// Reconstruct previous base for vmeta_call during tailcall.
|
||||||
|
|->vm_call_tail:
|
||||||
| mov RA, BASE
|
| mov RA, BASE
|
||||||
| test PC, FRAME_TYPE
|
| test PC, FRAME_TYPE
|
||||||
| jnz >3
|
| jnz >3
|
||||||
|
2446
src/buildvm_x86.h
2446
src/buildvm_x86.h
File diff suppressed because it is too large
Load Diff
@ -1104,7 +1104,7 @@ LUA_API int lua_yield(lua_State *L, int nresults)
|
|||||||
setcont(top+1, lj_cont_hook);
|
setcont(top+1, lj_cont_hook);
|
||||||
setframe_pc(top+1, cframe_pc(cf)-1);
|
setframe_pc(top+1, cframe_pc(cf)-1);
|
||||||
setframe_gc(top+2, obj2gco(L));
|
setframe_gc(top+2, obj2gco(L));
|
||||||
top[2].fr.tp.ftsz = (int)((char *)(top+3)-(char *)L->base)+FRAME_CONT;
|
setframe_ftsz(top+2, (int)((char *)(top+3)-(char *)L->base)+FRAME_CONT);
|
||||||
L->top = L->base = top+3;
|
L->top = L->base = top+3;
|
||||||
}
|
}
|
||||||
#if LJ_TARGET_X64
|
#if LJ_TARGET_X64
|
||||||
|
@ -51,6 +51,7 @@ enum {
|
|||||||
/* Note: this macro does not skip over FRAME_VARG. */
|
/* Note: this macro does not skip over FRAME_VARG. */
|
||||||
|
|
||||||
#define setframe_pc(f, pc) (setmref((f)->fr.tp.pcr, (pc)))
|
#define setframe_pc(f, pc) (setmref((f)->fr.tp.pcr, (pc)))
|
||||||
|
#define setframe_ftsz(f, sz) ((f)->fr.tp.ftsz = (sz))
|
||||||
#define setframe_gc(f, p) (setgcref((f)->fr.func, (p)))
|
#define setframe_gc(f, p) (setgcref((f)->fr.func, (p)))
|
||||||
|
|
||||||
/* -- C stack frame ------------------------------------------------------- */
|
/* -- C stack frame ------------------------------------------------------- */
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "lj_str.h"
|
#include "lj_str.h"
|
||||||
#include "lj_tab.h"
|
#include "lj_tab.h"
|
||||||
#include "lj_meta.h"
|
#include "lj_meta.h"
|
||||||
|
#include "lj_frame.h"
|
||||||
#include "lj_bc.h"
|
#include "lj_bc.h"
|
||||||
#include "lj_vm.h"
|
#include "lj_vm.h"
|
||||||
|
|
||||||
@ -68,6 +69,29 @@ cTValue *lj_meta_lookup(lua_State *L, cTValue *o, MMS mm)
|
|||||||
return niltv(L);
|
return niltv(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tailcall from C function. */
|
||||||
|
int lj_meta_tailcall(lua_State *L, cTValue *tv)
|
||||||
|
{
|
||||||
|
TValue *base = L->base;
|
||||||
|
TValue *top = L->top;
|
||||||
|
const BCIns *pc = frame_pc(base-1); /* Preserve old PC from frame. */
|
||||||
|
copyTV(L, base-1, tv); /* Replace frame with new object. */
|
||||||
|
top->u64 = 0;
|
||||||
|
setframe_pc(top, pc);
|
||||||
|
setframe_gc(top+1, obj2gco(L)); /* Dummy frame object. */
|
||||||
|
setframe_ftsz(top+1, (int)((char *)(top+2) - (char *)base) + FRAME_CONT);
|
||||||
|
L->base = L->top = top+2;
|
||||||
|
/*
|
||||||
|
** before: [old_mo|PC] [... ...]
|
||||||
|
** ^base ^top
|
||||||
|
** after: [new_mo|itype] [... ...] [NULL|PC] [dummy|delta]
|
||||||
|
** ^base/top
|
||||||
|
** tailcall: [new_mo|PC] [... ...]
|
||||||
|
** ^base ^top
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup call to metamethod to be run by Assembler VM. */
|
/* Setup call to metamethod to be run by Assembler VM. */
|
||||||
static TValue *mmcall(lua_State *L, ASMFunction cont, cTValue *mo,
|
static TValue *mmcall(lua_State *L, ASMFunction cont, cTValue *mo,
|
||||||
cTValue *a, cTValue *b)
|
cTValue *a, cTValue *b)
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
LJ_FUNC void lj_meta_init(lua_State *L);
|
LJ_FUNC void lj_meta_init(lua_State *L);
|
||||||
LJ_FUNC cTValue *lj_meta_cache(GCtab *mt, MMS mm, GCstr *name);
|
LJ_FUNC cTValue *lj_meta_cache(GCtab *mt, MMS mm, GCstr *name);
|
||||||
LJ_FUNC cTValue *lj_meta_lookup(lua_State *L, cTValue *o, MMS mm);
|
LJ_FUNC cTValue *lj_meta_lookup(lua_State *L, cTValue *o, MMS mm);
|
||||||
|
LJ_FUNC int lj_meta_tailcall(lua_State *L, cTValue *tv);
|
||||||
|
|
||||||
#define lj_meta_fastg(g, mt, mm) \
|
#define lj_meta_fastg(g, mt, mm) \
|
||||||
((mt) == NULL ? NULL : ((mt)->nomm & (1u<<(mm))) ? NULL : \
|
((mt) == NULL ? NULL : ((mt)->nomm & (1u<<(mm))) ? NULL : \
|
||||||
|
Loading…
Reference in New Issue
Block a user