Răsfoiți Sursa

Add support for tailcalls from internal C functions.

PPC: Fix __call metamethod for tailcalls.
Mike Pall 14 ani în urmă
părinte
comite
fa5cd010e8
12 a modificat fișierele cu 1957 adăugiri și 1885 ștergeri
  1. 2 1
      src/Makefile.dep
  2. 14 5
      src/buildvm_arm.dasc
  3. 13 5
      src/buildvm_ppc.dasc
  4. 206 198
      src/buildvm_ppcspe.h
  5. 638 634
      src/buildvm_x64.h
  6. 672 668
      src/buildvm_x64win.h
  7. 15 4
      src/buildvm_x86.dasc
  8. 370 369
      src/buildvm_x86.h
  9. 1 1
      src/lj_api.c
  10. 1 0
      src/lj_frame.h
  11. 24 0
      src/lj_meta.c
  12. 1 0
      src/lj_meta.h

+ 2 - 1
src/Makefile.dep

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

+ 14 - 5
src/buildvm_arm.dasc

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

+ 13 - 5
src/buildvm_ppc.dasc

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

Fișier diff suprimat deoarece este prea mare
+ 206 - 198
src/buildvm_ppcspe.h


Fișier diff suprimat deoarece este prea mare
+ 638 - 634
src/buildvm_x64.h


Fișier diff suprimat deoarece este prea mare
+ 672 - 668
src/buildvm_x64win.h


+ 15 - 4
src/buildvm_x86.dasc

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

Fișier diff suprimat deoarece este prea mare
+ 370 - 369
src/buildvm_x86.h


+ 1 - 1
src/lj_api.c

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

+ 1 - 0
src/lj_frame.h

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

+ 24 - 0
src/lj_meta.c

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

+ 1 - 0
src/lj_meta.h

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

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff