commit 318a9a5859826d7af0294664e206236fc8814319
parent 73d797ce7ea4c547cb97e39633a71a242c7356c8
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 7 Feb 2018 13:17:37 -0200
new opcode 'PREPVARARG'
(avoids test for vararg function in all function calls)
Diffstat:
7 files changed, 50 insertions(+), 29 deletions(-)
diff --git a/ldo.c b/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 2.189 2018/01/29 16:21:35 roberto Exp roberto $
+** $Id: ldo.c,v 2.190 2018/02/06 19:16:56 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -297,15 +297,11 @@ void luaD_hook (lua_State *L, int event, int line) {
/*
** Executes a call hook for Lua functions. This function is called
** whenever 'hookmask' is not zero, so it checks whether call hooks are
-** active. Also, this function can be called when resuming a function,
-** so it checks whether the function is in its first instruction.
+** active.
*/
void luaD_hookcall (lua_State *L, CallInfo *ci) {
- Proto *p = clLvalue(s2v(ci->func))->p;
int hook = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL : LUA_HOOKCALL;
- ci->u.l.trap = 1; /* there may be other hooks */
- if (!(L->hookmask & LUA_MASKCALL) || /* some other hook? */
- ci->u.l.savedpc != p->code) /* not 1st instruction? */
+ if (!(L->hookmask & LUA_MASKCALL)) /* some other hook? */
return; /* don't call hook */
L->top = ci->top; /* prepare top */
ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
@@ -417,7 +413,7 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
int i;
for (i = 0; i < narg1; i++) /* move down function and arguments */
setobjs2s(L, ci->func + i, func + i);
- checkstackp(L, fsize, func);
+ luaD_checkstackaux(L, fsize, (void)0, luaC_checkGC(L));
func = ci->func; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
@@ -425,10 +421,7 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL;
- if (p->is_vararg) {
- L->top = func + narg1; /* set top */
- luaT_adjustvarargs(L, nfixparams, narg1 - 1);
- }
+ L->top = func + narg1; /* set top */
}
@@ -481,8 +474,6 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = 0;
- if (p->is_vararg)
- luaT_adjustvarargs(L, nfixparams, narg); /* may invoke GC */
luaV_execute(L, ci); /* run the function */
break;
}
diff --git a/lopcodes.c b/lopcodes.c
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.c,v 1.74 2017/12/18 17:49:31 roberto Exp $
+** $Id: lopcodes.c,v 1.75 2017/12/22 14:16:46 roberto Exp roberto $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -91,6 +91,7 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"SETLIST",
"CLOSURE",
"VARARG",
+ "PREPVARARG",
"EXTRAARG",
NULL
};
@@ -171,6 +172,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, 0, 0, iABC) /* OP_SETLIST */
,opmode(0, 0, 0, 1, iABx) /* OP_CLOSURE */
,opmode(1, 0, 0, 1, iABC) /* OP_VARARG */
+ ,opmode(0, 0, 0, 1, iABC) /* OP_PREPVARARG */
,opmode(0, 0, 0, 0, iAx) /* OP_EXTRAARG */
};
diff --git a/lopcodes.h b/lopcodes.h
@@ -288,6 +288,8 @@ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */
OP_VARARG,/* A B C R(A), R(A+1), ..., R(A+C-2) = vararg(B) */
+OP_PREPVARARG,/*A (adjust vararg parameters) */
+
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
} OpCode;
diff --git a/lparser.c b/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.174 2017/12/18 17:49:31 roberto Exp roberto $
+** $Id: lparser.c,v 2.175 2017/12/22 14:16:46 roberto Exp roberto $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -759,12 +759,18 @@ static void constructor (LexState *ls, expdesc *t) {
/* }====================================================================== */
+static void setvararg (FuncState *fs, int nparams) {
+ fs->f->is_vararg = 1;
+ luaK_codeABC(fs, OP_PREPVARARG, nparams, 0, 0);
+}
+
static void parlist (LexState *ls) {
/* parlist -> [ param { ',' param } ] */
FuncState *fs = ls->fs;
Proto *f = fs->f;
int nparams = 0;
+ int isvararg = 0;
if (ls->t.token != ')') { /* is 'parlist' not empty? */
do {
switch (ls->t.token) {
@@ -779,17 +785,21 @@ static void parlist (LexState *ls) {
new_localvar(ls, str_checkname(ls));
else
new_localvarliteral(ls, "_ARG");
- f->is_vararg = 1; /* declared vararg */
nparams++;
+ isvararg = 1;
break;
}
default: luaX_syntaxerror(ls, "<name> or '...' expected");
}
- } while (!f->is_vararg && testnext(ls, ','));
+ } while (!isvararg && testnext(ls, ','));
}
adjustlocalvars(ls, nparams);
- f->numparams = cast_byte(fs->nactvar) - f->is_vararg;
- luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
+ f->numparams = cast_byte(fs->nactvar);
+ if (isvararg) {
+ f->numparams--; /* exclude vararg parameter */
+ setvararg(fs, f->numparams); /* declared vararg */
+ }
+ luaK_reserveregs(fs, fs->nactvar); /* reserve registers for parameters */
}
@@ -1692,7 +1702,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
BlockCnt bl;
expdesc v;
open_func(ls, fs, &bl);
- fs->f->is_vararg = 1; /* main function is always declared vararg */
+ setvararg(fs, 0); /* main function is always declared vararg */
fs->f->numparams = 0;
new_localvarliteral(ls, "_ARG");
adjustlocalvars(ls, 1);
diff --git a/ltm.c b/ltm.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 2.57 2018/01/28 12:08:04 roberto Exp roberto $
+** $Id: ltm.c,v 2.58 2018/01/28 13:39:52 roberto Exp roberto $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -216,10 +216,11 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
}
-void luaT_adjustvarargs (lua_State *L, int nfixparams, int actual) {
+void luaT_adjustvarargs (lua_State *L, int nfixparams, StkId base) {
int i;
Table *vtab;
TValue nname;
+ int actual = cast_int(L->top - base); /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */
vtab = luaH_new(L); /* create vararg table */
sethvalue2s(L, L->top, vtab); /* anchor it for resizing */
diff --git a/ltm.h b/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 2.28 2017/12/13 18:32:09 roberto Exp roberto $
+** $Id: ltm.h,v 2.29 2018/01/28 13:39:52 roberto Exp roberto $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -77,7 +77,7 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, TMS event);
-LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, int actual);
+LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, StkId base);
LUAI_FUNC void luaT_getvarargs (lua_State *L, TValue *t, StkId where,
int wanted);
diff --git a/lvm.c b/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.336 2018/01/29 16:21:35 roberto Exp roberto $
+** $Id: lvm.c,v 2.337 2018/02/06 19:16:56 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -835,12 +835,17 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
int trap;
tailcall:
trap = L->hookmask;
- if (trap)
- luaD_hookcall(L, ci);
cl = clLvalue(s2v(ci->func));
k = cl->p->k;
- base = ci->func + 1;
pc = ci->u.l.savedpc;
+ if (trap) {
+ if (cl->p->is_vararg)
+ trap = 0; /* hooks will start with PREPVARARG instruction */
+ else if (pc == cl->p->code) /* first instruction (not resuming)? */
+ luaD_hookcall(L, ci);
+ ci->u.l.trap = 1; /* there may be other hooks */
+ }
+ base = ci->func + 1;
/* main loop of interpreter */
for (;;) {
int cond; /* flag for conditional jumps */
@@ -1701,6 +1706,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
Protect(luaT_getvarargs(L, vtab, ra, n));
vmbreak;
}
+ vmcase(OP_PREPVARARG) {
+ luaT_adjustvarargs(L, GETARG_A(i), base);
+ updatetrap(ci);
+ if (trap) {
+ luaD_hookcall(L, ci);
+ L->oldpc = pc + 1; /* next opcode will be seen as a new line */
+ }
+ updatebase(ci);
+ vmbreak;
+ }
vmcase(OP_EXTRAARG) {
lua_assert(0);
vmbreak;