Replace upvalue-based shell dispatch with OP_LUSH opcode
Add a dedicated OP_LUSH A B instruction that loads shell C functions directly from the registry, eliminating the need for upvalue allocation in mainfunc(), upvalue population in lua_load(), and the fragile LUSH_NUM_UPVALS heuristic. Every chunk no longer carries 4 extra upvalues.
This commit is contained in:
22
lapi.c
22
lapi.c
@@ -29,7 +29,6 @@
|
||||
#include "ltm.h"
|
||||
#include "lundump.h"
|
||||
#include "lvm.h"
|
||||
#include "lcmd.h"
|
||||
|
||||
|
||||
|
||||
@@ -1136,27 +1135,6 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
|
||||
setobj(L, f->upvals[0]->v.p, >);
|
||||
luaC_barrier(L, f->upvals[0], >);
|
||||
}
|
||||
if (f->nupvalues >= LUSH_NUM_UPVALS) { /* has lush upvalues? */
|
||||
/* populate shell function upvalues from registry */
|
||||
Table *regt = hvalue(&G(L)->l_registry);
|
||||
TValue lushtv;
|
||||
lu_byte tag = luaH_getint(regt, LUA_RIDX_LUSH, &lushtv);
|
||||
if (novariant(tag) == LUA_TTABLE) {
|
||||
static const char *const fields[] = {
|
||||
"command", "interactive", "getenv", "setenv"
|
||||
};
|
||||
Table *lusht = hvalue(&lushtv);
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
TValue val;
|
||||
TString *key = luaS_new(L, fields[i]);
|
||||
if (luaH_getstr(lusht, key, &val) != LUA_TNIL) {
|
||||
setobj(L, f->upvals[i + 1]->v.p, &val);
|
||||
luaC_barrier(L, f->upvals[i + 1], &val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lua_unlock(L);
|
||||
return APIstatus(status);
|
||||
|
||||
13
lcmd.h
13
lcmd.h
@@ -9,13 +9,12 @@
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
/* Upvalue indices for shell functions on the main chunk.
|
||||
** Index 0 is _ENV (standard). Indices 1-4 are lush shell functions. */
|
||||
#define LUSH_UPVAL_COMMAND 1
|
||||
#define LUSH_UPVAL_INTERACTIVE 2
|
||||
#define LUSH_UPVAL_GETENV 3
|
||||
#define LUSH_UPVAL_SETENV 4
|
||||
#define LUSH_NUM_UPVALS 5 /* total: _ENV(0) + 4 shell functions */
|
||||
/* OP_LUSH sub-operation indices (B operand selects which function) */
|
||||
#define LUSH_OP_COMMAND 0
|
||||
#define LUSH_OP_INTERACTIVE 1
|
||||
#define LUSH_OP_GETENV 2
|
||||
#define LUSH_OP_SETENV 3
|
||||
#define LUSH_OP_COUNT 4
|
||||
|
||||
int lushCmd_command (lua_State *L);
|
||||
int lushCmd_interactive (lua_State *L);
|
||||
|
||||
13
linit.c
13
linit.c
@@ -45,18 +45,19 @@ static const luaL_Reg stdlibs[] = {
|
||||
|
||||
/*
|
||||
** Store shell functions in a registry table at LUA_RIDX_LUSH.
|
||||
** These are populated as upvalues on the main chunk by lua_load().
|
||||
** Integer keys 1..4 hold the C functions (accessed by OP_LUSH).
|
||||
** String key "builtins" holds the builtins table (set by luaopen_builtins).
|
||||
*/
|
||||
static void opencommand (lua_State *L) {
|
||||
lua_createtable(L, 0, 5);
|
||||
lua_createtable(L, LUSH_OP_COUNT, 1);
|
||||
lua_pushcfunction(L, lushCmd_command);
|
||||
lua_setfield(L, -2, "command");
|
||||
lua_rawseti(L, -2, LUSH_OP_COMMAND + 1);
|
||||
lua_pushcfunction(L, lushCmd_interactive);
|
||||
lua_setfield(L, -2, "interactive");
|
||||
lua_rawseti(L, -2, LUSH_OP_INTERACTIVE + 1);
|
||||
lua_pushcfunction(L, lushCmd_getenv);
|
||||
lua_setfield(L, -2, "getenv");
|
||||
lua_rawseti(L, -2, LUSH_OP_GETENV + 1);
|
||||
lua_pushcfunction(L, lushCmd_setenv);
|
||||
lua_setfield(L, -2, "setenv");
|
||||
lua_rawseti(L, -2, LUSH_OP_SETENV + 1);
|
||||
lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_LUSH);
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ static const void *const disptab[NUM_OPCODES] = {
|
||||
&&L_OP_SETLIST,
|
||||
&&L_OP_CLOSURE,
|
||||
&&L_OP_VARARG,
|
||||
&&L_OP_LUSH,
|
||||
&&L_OP_GETVARG,
|
||||
&&L_OP_ERRNNIL,
|
||||
&&L_OP_VARARGPREP,
|
||||
|
||||
@@ -102,6 +102,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
||||
,opmode(0, 0, 1, 0, 0, ivABC) /* OP_SETLIST */
|
||||
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
|
||||
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
|
||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LUSH */
|
||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETVARG */
|
||||
,opmode(0, 0, 0, 0, 0, iABx) /* OP_ERRNNIL */
|
||||
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
|
||||
|
||||
@@ -338,6 +338,8 @@ OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
||||
|
||||
OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
|
||||
|
||||
OP_LUSH,/* A B R[A] := lush_func[B] */
|
||||
|
||||
OP_GETVARG, /* A B C R[A] := R[B][R[C]], R[B] is vararg parameter */
|
||||
|
||||
OP_ERRNNIL,/* A Bx raise error if R[A] ~= nil (K[Bx] is global name)*/
|
||||
|
||||
@@ -94,6 +94,7 @@ static const char *const opnames[] = {
|
||||
"SETLIST",
|
||||
"CLOSURE",
|
||||
"VARARG",
|
||||
"LUSH",
|
||||
"GETVARG",
|
||||
"ERRNNIL",
|
||||
"VARARGPREP",
|
||||
|
||||
58
lparser.c
58
lparser.c
@@ -501,15 +501,14 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
||||
|
||||
|
||||
/*
|
||||
** Look up a lush shell function (e.g. __command) that is registered
|
||||
** as an upvalue on the main chunk. singlevaraux will find it directly
|
||||
** as VUPVAL, emitting OP_GETUPVAL instead of OP_GETTABUP.
|
||||
** Emit OP_LUSH to load a shell C function into a register.
|
||||
** 'lushop' selects which function (LUSH_OP_COMMAND, etc.).
|
||||
*/
|
||||
static void buildlushvar (LexState *ls, TString *varname, expdesc *var) {
|
||||
FuncState *fs = ls->fs;
|
||||
init_exp(var, VGLOBAL, -1);
|
||||
singlevaraux(fs, varname, var, 1);
|
||||
lua_assert(var->k == VUPVAL); /* must be found as upvalue */
|
||||
static void codelushfunc (FuncState *fs, int lushop, expdesc *var) {
|
||||
int reg = fs->freereg;
|
||||
luaK_reserveregs(fs, 1);
|
||||
init_exp(var, VNONRELOC, reg);
|
||||
luaK_codeABC(fs, OP_LUSH, reg, lushop, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -564,11 +563,8 @@ static void codecommand (LexState *ls, expdesc *v, expdesc *cmdstr) {
|
||||
FuncState *fs = ls->fs;
|
||||
int base, line;
|
||||
expdesc func;
|
||||
TString *cmdname = luaX_newstring(ls, "__command", 9);
|
||||
line = ls->linenumber;
|
||||
/* look up __command as upvalue */
|
||||
buildlushvar(ls, cmdname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
codelushfunc(fs, LUSH_OP_COMMAND, &func);
|
||||
base = func.u.info;
|
||||
/* push the command string argument */
|
||||
luaK_exp2nextreg(fs, cmdstr);
|
||||
@@ -1254,11 +1250,9 @@ static void commandexp (LexState *ls, expdesc *v) {
|
||||
expdesc func, cmdstr;
|
||||
int base, nconcat = 0;
|
||||
int line = ls->linenumber;
|
||||
TString *cmdname = luaX_newstring(ls, "__command", 9);
|
||||
TString *tsname = luaX_newstring(ls, "tostring", 8);
|
||||
/* load __command function first so it occupies the base register */
|
||||
buildlushvar(ls, cmdname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
codelushfunc(fs, LUSH_OP_COMMAND, &func);
|
||||
base = func.u.info;
|
||||
/* load the first fragment */
|
||||
codestring(&cmdstr, ls->t.seminfo.ts);
|
||||
@@ -1320,10 +1314,8 @@ static void codeenvget (LexState *ls, expdesc *v, TString *name) {
|
||||
FuncState *fs = ls->fs;
|
||||
int base, line;
|
||||
expdesc func, arg;
|
||||
TString *fname = luaX_newstring(ls, "__getenv", 8);
|
||||
line = ls->linenumber;
|
||||
buildlushvar(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
codelushfunc(fs, LUSH_OP_GETENV, &func);
|
||||
base = func.u.info;
|
||||
codestring(&arg, name);
|
||||
luaK_exp2nextreg(fs, &arg);
|
||||
@@ -2202,13 +2194,10 @@ static void envstat (LexState *ls) {
|
||||
TString *name = ls->t.seminfo.ts;
|
||||
int base, line;
|
||||
expdesc func, arg, val;
|
||||
TString *fname;
|
||||
line = ls->linenumber;
|
||||
luaX_next(ls); /* skip TK_ENVVAR */
|
||||
checknext(ls, '=');
|
||||
fname = luaX_newstring(ls, "__setenv", 8);
|
||||
buildlushvar(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
codelushfunc(fs, LUSH_OP_SETENV, &func);
|
||||
base = func.u.info;
|
||||
codestring(&arg, name);
|
||||
luaK_exp2nextreg(fs, &arg);
|
||||
@@ -2231,10 +2220,8 @@ static void interactivestat (LexState *ls) {
|
||||
/* simple interactive command, no interpolation */
|
||||
int base, line;
|
||||
expdesc func, cmdstr, v;
|
||||
TString *fname = luaX_newstring(ls, "__interactive", 13);
|
||||
line = ls->linenumber;
|
||||
buildlushvar(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
codelushfunc(fs, LUSH_OP_INTERACTIVE, &func);
|
||||
base = func.u.info;
|
||||
codestring(&cmdstr, ls->t.seminfo.ts);
|
||||
luaK_exp2nextreg(fs, &cmdstr);
|
||||
@@ -2248,10 +2235,8 @@ static void interactivestat (LexState *ls) {
|
||||
expdesc func, cmdstr, v;
|
||||
int base, nconcat = 0;
|
||||
int line = ls->linenumber;
|
||||
TString *fname = luaX_newstring(ls, "__interactive", 13);
|
||||
TString *tsname = luaX_newstring(ls, "tostring", 8);
|
||||
buildlushvar(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
codelushfunc(fs, LUSH_OP_INTERACTIVE, &func);
|
||||
base = func.u.info;
|
||||
/* load the first fragment */
|
||||
codestring(&cmdstr, ls->t.seminfo.ts);
|
||||
@@ -2410,12 +2395,8 @@ static void statement (LexState *ls) {
|
||||
** upvalue named LUA_ENV
|
||||
*/
|
||||
static void mainfunc (LexState *ls, FuncState *fs) {
|
||||
static const char *const lush_upval_names[] = {
|
||||
"__command", "__interactive", "__getenv", "__setenv"
|
||||
};
|
||||
BlockCnt bl;
|
||||
Upvaldesc *env;
|
||||
int i;
|
||||
open_func(ls, fs, &bl);
|
||||
setvararg(fs, PF_ISVARARG); /* main function is always vararg */
|
||||
env = allocupvalue(fs); /* ...set environment upvalue */
|
||||
@@ -2424,15 +2405,6 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
||||
env->kind = VDKREG;
|
||||
env->name = ls->envn;
|
||||
luaC_objbarrier(ls->L, fs->f, env->name);
|
||||
/* allocate upvalues for lush shell functions */
|
||||
for (i = 0; i < 4; i++) {
|
||||
Upvaldesc *uv = allocupvalue(fs);
|
||||
uv->instack = 1;
|
||||
uv->idx = 0;
|
||||
uv->kind = VDKREG;
|
||||
uv->name = luaS_new(ls->L, lush_upval_names[i]);
|
||||
luaC_objbarrier(ls->L, fs->f, uv->name);
|
||||
}
|
||||
luaX_next(ls); /* read first token */
|
||||
statlist(ls); /* parse main body */
|
||||
check(ls, TK_EOS);
|
||||
@@ -2444,7 +2416,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
Dyndata *dyd, const char *name, int firstchar) {
|
||||
LexState lexstate;
|
||||
FuncState funcstate;
|
||||
LClosure *cl = luaF_newLclosure(L, LUSH_NUM_UPVALS); /* create main closure */
|
||||
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
||||
setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
|
||||
luaD_inctop(L);
|
||||
lexstate.h = luaH_new(L); /* create table for scanner */
|
||||
@@ -2459,7 +2431,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
|
||||
luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);
|
||||
mainfunc(&lexstate, &funcstate);
|
||||
lua_assert(!funcstate.prev && funcstate.nups == LUSH_NUM_UPVALS && !lexstate.fs);
|
||||
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
|
||||
/* all scopes should be correctly finished */
|
||||
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
|
||||
L->top.p--; /* remove scanner's table */
|
||||
|
||||
13
lvm.c
13
lvm.c
@@ -1939,6 +1939,19 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
Protect(luaT_getvarargs(L, ci, ra, n));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LUSH) {
|
||||
StkId ra = RA(i);
|
||||
int idx = GETARG_B(i);
|
||||
Table *regt = hvalue(&G(L)->l_registry);
|
||||
TValue lushtv;
|
||||
lu_byte tag = luaH_getint(regt, LUA_RIDX_LUSH, &lushtv);
|
||||
if (novariant(tag) == LUA_TTABLE) {
|
||||
TValue func;
|
||||
luaH_getint(hvalue(&lushtv), idx + 1, &func); /* 1-based */
|
||||
setobj2s(L, ra, &func);
|
||||
}
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_GETVARG) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rc = vRC(i);
|
||||
|
||||
Reference in New Issue
Block a user