From 745eb4199333f153a28c75837b6a1addf614f4a9 Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 29 Nov 2017 14:57:36 -0200
Subject: new opcodes OP_RETURN0/OP_RETURN1

---
 lcode.c    | 14 +++++++++++--
 lopcodes.c |  6 +++++-
 lopcodes.h |  5 ++++-
 lvm.c      | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++------------
 4 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/lcode.c b/lcode.c
index 97aa9dda..8f9fa408 100644
--- a/lcode.c
+++ b/lcode.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.137 2017/11/28 12:58:18 roberto Exp roberto $
+** $Id: lcode.c,v 2.138 2017/11/28 15:26:15 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -152,7 +152,17 @@ int luaK_jump (FuncState *fs) {
 ** Code a 'return' instruction
 */
 void luaK_ret (FuncState *fs, int first, int nret) {
-  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
+  switch (nret) {
+    case 0:
+      luaK_codeABC(fs, OP_RETURN0, 0, 0, 0);
+      break;
+    case 1:
+      luaK_codeABC(fs, OP_RETURN1, first, 0, 0);
+      break;
+    default:
+      luaK_codeABC(fs, OP_RETURN, first, nret + 1, 0);
+      break;
+  }
 }
 
 
diff --git a/lopcodes.c b/lopcodes.c
index 122157eb..1b081639 100644
--- a/lopcodes.c
+++ b/lopcodes.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.69 2017/11/22 18:41:20 roberto Exp roberto $
+** $Id: lopcodes.c,v 1.70 2017/11/27 17:44:31 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -75,6 +75,8 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
   "CALL",
   "TAILCALL",
   "RETURN",
+  "RETURN0",
+  "RETURN1",
   "FORLOOP",
   "FORPREP",
   "TFORCALL",
@@ -146,6 +148,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(0, 1, iABC)		/* OP_CALL */
  ,opmode(0, 1, iABC)		/* OP_TAILCALL */
  ,opmode(0, 0, iABC)		/* OP_RETURN */
+ ,opmode(0, 0, iABC)		/* OP_RETURN0 */
+ ,opmode(0, 0, iABC)		/* OP_RETURN1 */
  ,opmode(0, 1, iABx)		/* OP_FORLOOP */
  ,opmode(0, 1, iABx)		/* OP_FORPREP */
  ,opmode(0, 0, iABC)		/* OP_TFORCALL */
diff --git a/lopcodes.h b/lopcodes.h
index f2b67165..433d97a2 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.171 2017/11/27 17:44:31 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.172 2017/11/28 12:58:18 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -252,7 +252,10 @@ OP_TESTSET,/*	A B	if (not R(B) == k) then R(A) := R(B) else pc++	*/
 
 OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
 OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
+
 OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
+OP_RETURN0,/*	  	return 						*/
+OP_RETURN1,/*	A 	return R(A)					*/
 
 OP_FORLOOP,/*	A Bx	R(A)+=R(A+2);
 			if R(A) <?= R(A+1) then { pc-=Bx; R(A+3)=R(A) }*/
diff --git a/lvm.c b/lvm.c
index 05a4646e..16e4fde0 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.320 2017/11/28 14:51:00 roberto Exp roberto $
+** $Id: lvm.c,v 2.321 2017/11/29 13:02:17 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -798,6 +798,11 @@ void luaV_finishOp (lua_State *L) {
 */
 #define Protect(exp)  (savepc(L), (exp), updatetrap(ci))
 
+/*
+** Protect code that will return.
+*/
+#define halfProtect(exp)  (savepc(L), (exp))
+
 
 #define checkGC(L,c)  \
 	{ luaC_condGC(L, L->top = (c),  /* limit of live values */ \
@@ -824,11 +829,16 @@ void luaV_finishOp (lua_State *L) {
 
 
 void luaV_execute (lua_State *L, CallInfo *ci) {
-  LClosure *cl = clLvalue(s2v(ci->func));
-  TValue *k = cl->p->k;
-  StkId base = ci->func + 1;
+  LClosure *cl;
+  TValue *k;
+  StkId base;
+  const Instruction *pc;
   int trap = ci->u.l.trap;
-  const Instruction *pc = ci->u.l.savedpc;
+ tailcall:
+  cl = clLvalue(s2v(ci->func));
+  k = cl->p->k;
+  base = ci->func + 1;
+  pc = ci->u.l.savedpc;
   /* main loop of interpreter */
   for (;;) {
     int cond;  /* flag for conditional jumps */
@@ -1438,16 +1448,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
           vra = s2v(ra);
           b++;  /* there is now one extra argument */
         }
-        if (!ttisLclosure(vra))  /* C function? */
+        if (!ttisLclosure(vra)) {  /* C function? */
           Protect(luaD_call(L, ra, LUA_MULTRET));  /* call it */
+          /* next instruction will do the return */
+        }
         else {  /* tail call */
           if (cl->p->sizep > 0) /* close upvalues from previous call */
             luaF_close(L, ci->func + 1);
           luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */
-          cl = clLvalue(s2v(ci->func));
-          k = cl->p->k;
-          updatebase(ci);
-          pc = ci->u.l.savedpc;
+          goto tailcall;
         }
         vmbreak;
       }
@@ -1455,9 +1464,43 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         int b = GETARG_B(i);
         if (cl->p->sizep > 0)
           luaF_close(L, base);
-        savepc(L);
-        luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
-        return;  /* external invocation: return */
+        halfProtect(
+          luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)))
+        );
+        return;
+      }
+      vmcase(OP_RETURN0) {
+        if (cl->p->sizep > 0)
+          luaF_close(L, base);
+        if (L->hookmask)
+          halfProtect(luaD_poscall(L, ci, ra, 0));  /* no hurry... */
+        else {
+          int nres = ci->nresults;
+          L->ci = ci->previous;  /* back to caller */
+          L->top = base - 1;
+          while (nres-- > 0)
+            setnilvalue(s2v(L->top++));  /* all results are nil */
+        }
+        return;
+      }
+      vmcase(OP_RETURN1) {
+        if (cl->p->sizep > 0)
+          luaF_close(L, base);
+        if (L->hookmask)
+          halfProtect(luaD_poscall(L, ci, ra, 1));  /* no hurry... */
+        else {
+          int nres = ci->nresults;
+          L->ci = ci->previous;  /* back to caller */
+          if (nres == 0)
+            L->top = base - 1;  /* asked for no results */
+          else {
+            setobjs2s(L, base - 1, ra);  /* at least this result */
+            L->top = base;
+            while (--nres > 0)  /* complete missing results */
+              setnilvalue(s2v(L->top++));
+          }
+        }
+        return;
       }
       vmcase(OP_FORLOOP) {
         if (ttisinteger(vra)) {  /* integer loop? */
-- 
cgit v1.2.3-55-g6feb