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_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_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_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
|
||||
|
@ -411,7 +411,7 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
|
|
||||
|->vm_call_dispatch_f:
|
||||
| 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.
|
||||
| // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
|
||||
@ -445,18 +445,26 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
|->cont_dispatch:
|
||||
| // BASE = meta base, RA = resultptr, RC = (nresults+1)*8
|
||||
| ldr LFUNC:CARG3, [RB, FRAME_FUNC]
|
||||
| ldr CARG1, [BASE, #-16] // Get continuation.
|
||||
| mov CARG4, BASE
|
||||
| mov BASE, RB // Restore caller BASE.
|
||||
| cmp CARG1, #0
|
||||
| ldr PC, [CARG4, #-12] // Restore PC from [cont|PC].
|
||||
| beq >1
|
||||
| ldr CARG3, LFUNC:CARG3->field_pc
|
||||
| mvn INS, #~LJ_TNIL
|
||||
| add CARG2, RA, RC
|
||||
| ldr CARG1, [CARG4, #-16] // Get continuation.
|
||||
| str INS, [CARG2, #-4] // Ensure one valid arg.
|
||||
| ldr KBASE, [CARG3, #PC2PROTO(k)]
|
||||
| // BASE = base, RA = resultptr, CARG4 = meta base
|
||||
| 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
|
||||
| ldr INS, [PC, #-4]
|
||||
| sub CARG2, CARG4, #16
|
||||
@ -714,7 +722,7 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| str PC, SAVE_PC
|
||||
| add CARG3, RA, NARGS8:RC
|
||||
| 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]
|
||||
| add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now.
|
||||
| b ->BC_CALLT2_Z
|
||||
@ -1514,10 +1522,11 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| ldr CARG1, L->top
|
||||
| ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
|
||||
| sub NARGS8:RC, CARG1, BASE
|
||||
| bne >2 // Returned -1?
|
||||
| bne ->vm_call_tail // Returned -1?
|
||||
| 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
|
||||
| bic CARG2, PC, #FRAME_TYPEP
|
||||
| ldreq INS, [PC, #-4]
|
||||
|
@ -540,7 +540,7 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
|
|
||||
|->vm_call_dispatch_f:
|
||||
| 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.
|
||||
| // (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 BASE, TMP2 // Restore caller BASE.
|
||||
| lwz LFUNC:TMP1, FRAME_FUNC(TMP2)
|
||||
| cmplwi TMP0, 0
|
||||
| lwz PC, -16(RB) // Restore PC from [cont|PC].
|
||||
| beq >1
|
||||
| subi TMP2, RD, 8
|
||||
| lwz PC, -16(RB) // Restore PC from [cont|PC].
|
||||
| lwz TMP1, LFUNC:TMP1->pc
|
||||
| evstddx TISNIL, RA, TMP2 // Ensure one valid arg.
|
||||
| lwz KBASE, PC2PROTO(k)(TMP1)
|
||||
@ -590,6 +592,11 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| mtctr TMP0
|
||||
| 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
|
||||
| lwz INS, -4(PC)
|
||||
| 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)
|
||||
| lwz TMP1, FRAME_PC(BASE)
|
||||
| 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
|
||||
|
|
||||
|//-- Argument coercion for 'for' statement ------------------------------
|
||||
@ -1797,10 +1804,11 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| lwz TMP0, L->top
|
||||
| lwz LFUNC:RB, FRAME_FUNC(BASE)
|
||||
| sub NARGS8:RC, TMP0, BASE
|
||||
| bne >2 // Returned -1?
|
||||
| bne ->vm_call_tail // Returned -1?
|
||||
| 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
|
||||
| rlwinm TMP1, PC, 0, 0, 28
|
||||
| bne >3
|
||||
|
1486
src/buildvm_ppcspe.h
1486
src/buildvm_ppcspe.h
File diff suppressed because it is too large
Load Diff
2144
src/buildvm_x64.h
2144
src/buildvm_x64.h
File diff suppressed because it is too large
Load Diff
2140
src/buildvm_x64win.h
2140
src/buildvm_x64win.h
File diff suppressed because it is too large
Load Diff
@ -691,12 +691,12 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
|
||||
|->vm_call_dispatch:
|
||||
| mov LFUNC:RB, [RA-8]
|
||||
| cmp dword [RA-4], LJ_TFUNC
|
||||
| jne ->vmeta_call // Ensure KBASE defined and != BASE.
|
||||
| jne ->vmeta_call // Ensure KBASE defined and != BASE.
|
||||
|
|
||||
|->vm_call_dispatch_f:
|
||||
| mov BASE, RA
|
||||
| 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.
|
||||
| // (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].
|
||||
|.if X64
|
||||
| movsxd RAa, dword [RB-16] // May be negative on WIN64 with debug.
|
||||
| test RA, RA
|
||||
| jz >1
|
||||
| lea KBASEa, qword [=>0]
|
||||
| add RAa, KBASEa
|
||||
|.else
|
||||
| mov RA, dword [RB-16]
|
||||
| test RA, RA
|
||||
| jz >1
|
||||
|.endif
|
||||
| mov LFUNC:KBASE, [BASE-8]
|
||||
| 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
|
||||
| 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
|
||||
| movzx RA, PC_RB
|
||||
| sub RB, 16
|
||||
@ -2735,10 +2745,11 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
|
||||
| test RD, RD
|
||||
| lea NARGS:RD, [RA+1]
|
||||
| mov LFUNC:RB, [BASE-8]
|
||||
| jne >2 // Returned -1?
|
||||
| jne ->vm_call_tail // Returned -1?
|
||||
| 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
|
||||
| test PC, FRAME_TYPE
|
||||
| jnz >3
|
||||
|
2426
src/buildvm_x86.h
2426
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);
|
||||
setframe_pc(top+1, cframe_pc(cf)-1);
|
||||
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;
|
||||
}
|
||||
#if LJ_TARGET_X64
|
||||
|
@ -51,6 +51,7 @@ enum {
|
||||
/* Note: this macro does not skip over FRAME_VARG. */
|
||||
|
||||
#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)))
|
||||
|
||||
/* -- C stack frame ------------------------------------------------------- */
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "lj_str.h"
|
||||
#include "lj_tab.h"
|
||||
#include "lj_meta.h"
|
||||
#include "lj_frame.h"
|
||||
#include "lj_bc.h"
|
||||
#include "lj_vm.h"
|
||||
|
||||
@ -68,6 +69,29 @@ cTValue *lj_meta_lookup(lua_State *L, cTValue *o, MMS mm)
|
||||
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. */
|
||||
static TValue *mmcall(lua_State *L, ASMFunction cont, cTValue *mo,
|
||||
cTValue *a, cTValue *b)
|
||||
|
@ -12,6 +12,7 @@
|
||||
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_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) \
|
||||
((mt) == NULL ? NULL : ((mt)->nomm & (1u<<(mm))) ? NULL : \
|
||||
|
Loading…
Reference in New Issue
Block a user