Add support for tailcalls from internal C functions.

PPC: Fix __call metamethod for tailcalls.
This commit is contained in:
Mike Pall 2011-04-12 19:12:29 +02:00
parent 23f847f4ed
commit fa5cd010e8
12 changed files with 4180 additions and 4103 deletions

View File

@ -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

View File

@ -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]

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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 ------------------------------------------------------- */

View File

@ -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)

View File

@ -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 : \