Browse Source

Alternative compilation strategy without tail calls

Use a trampoline (another one...) to avoid tail calls. Apparently the
GCC version that Hisham was using doesn't optimize the tail call
correctly.
Hugo Musso Gualandi 4 years ago
parent
commit
cafd13ecfb
4 changed files with 77 additions and 3 deletions
  1. 4 0
      src/lobject.h
  2. 21 0
      src/luaot_gotos.c
  3. 21 0
      src/luaot_switches.c
  4. 31 3
      src/lvm.c

+ 4 - 0
src/lobject.h

@@ -537,7 +537,11 @@ typedef struct AbsLineInfo {
 /*
 /*
 ** AOT implementation
 ** AOT implementation
 */
 */
+#if AOT_USE_TAILCALL
 typedef void (*AotCompiledFunction) (lua_State *L, struct CallInfo *ci);
 typedef void (*AotCompiledFunction) (lua_State *L, struct CallInfo *ci);
+#else
+typedef struct CallInfo *(*AotCompiledFunction) (lua_State *L, struct CallInfo *ci);
+#endif
 
 
 /*
 /*
 ** Function Prototypes
 ** Function Prototypes

+ 21 - 0
src/luaot_gotos.c

@@ -19,12 +19,21 @@ void println_goto_ret()
 {
 {
     // This is the piece of code that is after the "ret" label.
     // This is the piece of code that is after the "ret" label.
     // It should be used in the places that do "goto ret;"
     // It should be used in the places that do "goto ret;"
+    #if AOT_USE_TAILCALL
     println("    if (ci->callstatus & CIST_FRESH)");
     println("    if (ci->callstatus & CIST_FRESH)");
     println("        return;  /* end this frame */");
     println("        return;  /* end this frame */");
     println("    else {");
     println("    else {");
     println("        ci = ci->previous;");
     println("        ci = ci->previous;");
     println("        return luaV_execute(L, ci); /* continue running caller in this frame */"); // (!)
     println("        return luaV_execute(L, ci); /* continue running caller in this frame */"); // (!)
     println("    }");
     println("    }");
+    #else
+    println("    if (ci->callstatus & CIST_FRESH)");
+    println("        return NULL;  /* end this frame */");
+    println("    else {");
+    println("        ci = ci->previous;");
+    println("        return ci;");
+    println("    }");
+    #endif
 }
 }
 
 
 static
 static
@@ -40,7 +49,11 @@ void create_function(Proto *f)
     }
     }
 
 
     println("static");
     println("static");
+#if AOT_USE_TAILCALL
     println("void magic_implementation_%02d(lua_State *L, CallInfo *ci)", func_id);
     println("void magic_implementation_%02d(lua_State *L, CallInfo *ci)", func_id);
+#else
+    println("CallInfo *magic_implementation_%02d(lua_State *L, CallInfo *ci)", func_id);
+#endif
     println("{");
     println("{");
     println("  LClosure *cl;");
     println("  LClosure *cl;");
     println("  TValue *k;");
     println("  TValue *k;");
@@ -574,7 +587,11 @@ void create_function(Proto *f)
                 println("    else {");
                 println("    else {");
                 println("        ci = newci;");
                 println("        ci = newci;");
                 println("        ci->callstatus = 0;  /* call re-uses 'luaV_execute' */");
                 println("        ci->callstatus = 0;  /* call re-uses 'luaV_execute' */");
+                #if AOT_USE_TAILCALL
                 println("        return luaV_execute(L, ci);"); // (!!!)
                 println("        return luaV_execute(L, ci);"); // (!!!)
+                #else
+                println("        return ci;");
+                #endif
                 println("    }");
                 println("    }");
                 break;
                 break;
             }
             }
@@ -609,7 +626,11 @@ void create_function(Proto *f)
                 println("    }");
                 println("    }");
                 println("    ci->func -= delta;  /* restore 'func' (if vararg) */");
                 println("    ci->func -= delta;  /* restore 'func' (if vararg) */");
                 println("    luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */");
                 println("    luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */");
+                #if AOT_USE_TAILCALL
                 println("    return luaV_execute(L, ci); /* execute the callee */"); // (!)
                 println("    return luaV_execute(L, ci); /* execute the callee */"); // (!)
+                #else
+                println("    return ci;");
+                #endif
                 break;
                 break;
             }
             }
             case OP_RETURN: {
             case OP_RETURN: {

+ 21 - 0
src/luaot_switches.c

@@ -11,12 +11,21 @@ void println_goto_ret()
 {
 {
     // This is the piece of code that is after the "ret" label.
     // This is the piece of code that is after the "ret" label.
     // It should be used in the places that do "goto ret;"
     // It should be used in the places that do "goto ret;"
+    #if AOT_USE_TAILCALL
     println("        if (ci->callstatus & CIST_FRESH)");
     println("        if (ci->callstatus & CIST_FRESH)");
     println("            return;  /* end this frame */");
     println("            return;  /* end this frame */");
     println("        else {");
     println("        else {");
     println("            ci = ci->previous;");
     println("            ci = ci->previous;");
     println("            return luaV_execute(L, ci); /* continue running caller in this frame */"); // (!)
     println("            return luaV_execute(L, ci); /* continue running caller in this frame */"); // (!)
     println("        }");
     println("        }");
+    #else
+    println("    if (ci->callstatus & CIST_FRESH)");
+    println("        return NULL;  /* end this frame */");
+    println("    else {");
+    println("        ci = ci->previous;");
+    println("        return ci;");
+    println("    }");
+    #endif
 }
 }
 
 
 static
 static
@@ -32,7 +41,11 @@ void create_function(Proto *f)
     }
     }
 
 
     println("static");
     println("static");
+#if AOT_USE_TAILCALL
     println("void magic_implementation_%02d(lua_State *L, CallInfo *ci)", func_id);
     println("void magic_implementation_%02d(lua_State *L, CallInfo *ci)", func_id);
+#else
+    println("CallInfo *magic_implementation_%02d(lua_State *L, CallInfo *ci)", func_id);
+#endif
     println("{");
     println("{");
     println("  LClosure *cl;");
     println("  LClosure *cl;");
     println("  TValue *k;");
     println("  TValue *k;");
@@ -643,7 +656,11 @@ void create_function(Proto *f)
                 println("        else {");
                 println("        else {");
                 println("            ci = newci;");
                 println("            ci = newci;");
                 println("            ci->callstatus = 0;  /* call re-uses 'luaV_execute' */");
                 println("            ci->callstatus = 0;  /* call re-uses 'luaV_execute' */");
+                #if AOT_USE_TAILCALL
                 println("            return luaV_execute(L, ci);"); // (!!!)
                 println("            return luaV_execute(L, ci);"); // (!!!)
+                #else
+                println("            return ci;");
+                #endif
                 println("        }");
                 println("        }");
                 // FALLTHROUGH
                 // FALLTHROUGH
                 break;
                 break;
@@ -679,7 +696,11 @@ void create_function(Proto *f)
                 println("        }");
                 println("        }");
                 println("        ci->func -= delta;  /* restore 'func' (if vararg) */");
                 println("        ci->func -= delta;  /* restore 'func' (if vararg) */");
                 println("        luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */");
                 println("        luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */");
+                #if AOT_USE_TAILCALL
                 println("        return luaV_execute(L, ci); /* execute the callee */"); // (!)
                 println("        return luaV_execute(L, ci); /* execute the callee */"); // (!)
+                #else
+                println("        return ci;");
+                #endif
                 // FALLTHROUGH
                 // FALLTHROUGH
                 break;
                 break;
             }
             }

+ 31 - 3
src/lvm.c

@@ -1162,8 +1162,12 @@ void luaV_finishOp (lua_State *L) {
 #define vmcase(l)	case l:
 #define vmcase(l)	case l:
 #define vmbreak		break
 #define vmbreak		break
 
 
-#ifndef LUAOT_IS_MODULE
-void luaV_execute (lua_State *L, CallInfo *ci) {
+#if AOT_USE_TAILCALL
+static void luaV_execute_(lua_State *L, CallInfo *ci)
+#else
+static CallInfo *luaV_execute_(lua_State *L, CallInfo *ci)
+#endif
+{
   LClosure *cl;
   LClosure *cl;
   TValue *k;
   TValue *k;
   StkId base;
   StkId base;
@@ -1178,7 +1182,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
   cl = clLvalue(s2v(ci->func));
   cl = clLvalue(s2v(ci->func));
 #if LUAOT
 #if LUAOT
   if (cl->p->aot_implementation) {
   if (cl->p->aot_implementation) {
-      return cl->p->aot_implementation(L, ci);
+      #if AOT_USE_TAILCALL
+          return cl->p->aot_implementation(L, ci);
+      #else
+          return ci;
+      #endif
   }
   }
 #endif
 #endif
   k = cl->p->k;
   k = cl->p->k;
@@ -1762,7 +1770,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         }
         }
        ret:  /* return from a Lua function */
        ret:  /* return from a Lua function */
         if (ci->callstatus & CIST_FRESH)
         if (ci->callstatus & CIST_FRESH)
+      #if AOT_USE_TAILCALL
           return;  /* end this frame */
           return;  /* end this frame */
+      #else
+          return NULL;  /* end this frame */
+      #endif
         else {
         else {
           ci = ci->previous;
           ci = ci->previous;
           goto returning;  /* continue running caller in this frame */
           goto returning;  /* continue running caller in this frame */
@@ -1874,6 +1886,22 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
     }
     }
   }
   }
 }
 }
+
+#ifndef LUAOT_IS_MODULE
+void luaV_execute (lua_State *L, CallInfo *ci) {
+#if AOT_USE_TAILCALL
+    return luaV_execute_(L, ci);
+#else
+    do {
+        LClosure *cl = clLvalue(s2v(ci->func));
+        if (cl->p->aot_implementation) {
+            ci = cl->p->aot_implementation(L, ci);
+        } else {
+            ci = luaV_execute_(L, ci);
+        }
+    } while (ci);
+#endif
+}
 #endif
 #endif
 
 
 /* }================================================================== */
 /* }================================================================== */