no more fenvs!

This commit is contained in:
Roberto Ierusalimschy 2010-03-26 17:58:11 -03:00
parent 5c87f61e6b
commit 064e406f67
16 changed files with 78 additions and 170 deletions

97
lapi.c
View File

@ -1,5 +1,5 @@
/*
** $Id: lapi.c,v 2.115 2010/03/22 18:28:03 roberto Exp roberto $
** $Id: lapi.c,v 2.116 2010/03/25 19:37:23 roberto Exp roberto $
** Lua API
** See Copyright Notice in lua.h
*/
@ -39,16 +39,6 @@ const char lua_ident[] =
"invalid index")
static Table *getcurrenv (lua_State *L) {
if (L->ci->previous == NULL) /* no enclosing function? */
return G(L)->l_gt; /* use global table as environment */
else {
Closure *func = curr_func(L);
return func->c.env;
}
}
static TValue *index2addr (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
@ -61,20 +51,15 @@ static TValue *index2addr (lua_State *L, int idx) {
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return L->top + idx;
}
else switch (idx) { /* pseudo-indices */
case LUA_REGISTRYINDEX: return &G(L)->l_registry;
case LUA_ENVIRONINDEX: {
sethvalue(L, &L->env, getcurrenv(L));
return &L->env;
}
default: {
Closure *func = curr_func(L);
idx = LUA_ENVIRONINDEX - idx;
api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large");
return (idx <= func->c.nupvalues)
? &func->c.upvalue[idx-1]
: cast(TValue *, luaO_nilobject);
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
Closure *func = curr_func(L);
idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large");
return (idx <= func->c.nupvalues)
? &func->c.upvalue[idx-1]
: cast(TValue *, luaO_nilobject);
}
}
@ -195,17 +180,9 @@ LUA_API void lua_insert (lua_State *L, int idx) {
static void moveto (lua_State *L, TValue *fr, int idx) {
TValue *to = index2addr(L, idx);
api_checkvalidindex(L, to);
if (idx == LUA_ENVIRONINDEX) {
Closure *func = curr_func(L);
api_check(L, ttistable(fr), "table expected");
func->c.env = hvalue(fr);
luaC_barrier(L, func, fr);
}
else {
setobj(L, to, fr);
if (idx < LUA_ENVIRONINDEX) /* function upvalue? */
luaC_barrier(L, curr_func(L), fr);
}
setobj(L, to, fr);
if (idx < LUA_REGISTRYINDEX) /* function upvalue? */
luaC_barrier(L, curr_func(L), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
}
@ -213,9 +190,6 @@ static void moveto (lua_State *L, TValue *fr, int idx) {
LUA_API void lua_replace (lua_State *L, int idx) {
lua_lock(L);
/* explicit test for incompatible code */
if (idx == LUA_ENVIRONINDEX && L->ci->previous == NULL)
luaG_runerror(L, "no calling environment");
api_checknelems(L, 1);
moveto(L, L->top - 1, idx);
L->top--;
@ -503,7 +477,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_checknelems(L, n);
api_check(L, n <= UCHAR_MAX, "upvalue index too large");
luaC_checkGC(L);
cl = luaF_newCclosure(L, n, getcurrenv(L));
cl = luaF_newCclosure(L, n);
cl->c.f = fn;
L->top -= n;
while (n--)
@ -631,22 +605,16 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
}
LUA_API void lua_getfenv (lua_State *L, int idx) {
LUA_API void lua_getenv (lua_State *L, int idx) {
StkId o;
lua_lock(L);
o = index2addr(L, idx);
api_checkvalidindex(L, o);
switch (ttype(o)) {
case LUA_TFUNCTION:
sethvalue(L, L->top, clvalue(o)->c.env);
break;
case LUA_TUSERDATA:
sethvalue(L, L->top, uvalue(o)->env);
break;
default:
setnilvalue(L->top);
break;
}
api_check(L, ttisuserdata(o), "userdata expected");
if (uvalue(o)->env) {
sethvalue(L, L->top, uvalue(o)->env);
} else
setnilvalue(L->top);
api_incr_top(L);
lua_unlock(L);
}
@ -747,29 +715,22 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
}
LUA_API int lua_setfenv (lua_State *L, int idx) {
LUA_API void lua_setenv (lua_State *L, int idx) {
StkId o;
int res = 1;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
api_checkvalidindex(L, o);
api_check(L, ttistable(L->top - 1), "table expected");
switch (ttype(o)) {
case LUA_TFUNCTION:
clvalue(o)->c.env = hvalue(L->top - 1);
break;
case LUA_TUSERDATA:
uvalue(o)->env = hvalue(L->top - 1);
break;
default:
res = 0;
break;
api_check(L, ttisuserdata(o), "userdata expected");
if (ttisnil(L->top - 1))
uvalue(o)->env = NULL;
else {
api_check(L, ttistable(L->top - 1), "table expected");
uvalue(o)->env = hvalue(L->top - 1);
luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
}
if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
L->top--;
lua_unlock(L);
return res;
}
@ -1072,7 +1033,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u;
lua_lock(L);
luaC_checkGC(L);
u = luaS_newudata(L, size, getcurrenv(L));
u = luaS_newudata(L, size, NULL);
setuvalue(L, L->top, u);
api_incr_top(L);
lua_unlock(L);

View File

@ -1,5 +1,5 @@
/*
** $Id: lbaselib.c,v 1.238 2010/03/19 15:52:48 roberto Exp roberto $
** $Id: lbaselib.c,v 1.239 2010/03/22 18:28:03 roberto Exp roberto $
** Basic library
** See Copyright Notice in lua.h
*/
@ -107,50 +107,12 @@ static int luaB_setmetatable (lua_State *L) {
}
#if defined(LUA_COMPAT_FENV)
static void getfunc (lua_State *L, int opt) {
if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
else {
lua_Debug ar;
int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1);
luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
if (lua_getstack(L, level, &ar) == 0)
luaL_argerror(L, 1, "invalid level");
lua_getinfo(L, "f", &ar);
}
}
static int luaB_getfenv (lua_State *L) {
getfunc(L, 1);
if (lua_iscfunction(L, -1)) /* is a C function? */
lua_pushglobaltable(L); /* return the global env. */
else
lua_getfenv(L, -1);
return 1;
}
static int luaB_setfenv (lua_State *L) {
luaL_checktype(L, 2, LUA_TTABLE);
getfunc(L, 0);
lua_pushvalue(L, 2);
if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
return luaL_error(L,
LUA_QL("setfenv") " cannot change environment of given object");
return 1;
}
#else
static int luaB_getfenv (lua_State *L) {
return luaL_error(L, "getfenv/setfenv deprecated");
}
#define luaB_setfenv luaB_getfenv
#endif
static int luaB_rawequal (lua_State *L) {
luaL_checkany(L, 1);

View File

@ -1,5 +1,5 @@
/*
** $Id: ldblib.c,v 1.119 2010/01/06 14:42:35 roberto Exp roberto $
** $Id: ldblib.c,v 1.120 2010/02/18 19:18:41 roberto Exp roberto $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@ -44,19 +44,19 @@ static int db_setmetatable (lua_State *L) {
}
static int db_getfenv (lua_State *L) {
luaL_checkany(L, 1);
lua_getfenv(L, 1);
static int db_getenv (lua_State *L) {
luaL_checktype(L, 1, LUA_TUSERDATA);
lua_getenv(L, 1);
return 1;
}
static int db_setfenv (lua_State *L) {
luaL_checktype(L, 2, LUA_TTABLE);
static int db_setenv (lua_State *L) {
luaL_checktype(L, 1, LUA_TUSERDATA);
if (!lua_isnoneornil(L, 2))
luaL_checktype(L, 2, LUA_TTABLE);
lua_settop(L, 2);
if (lua_setfenv(L, 1) == 0)
luaL_error(L, LUA_QL("setfenv")
" cannot change environment of given object");
lua_setenv(L, 1);
return 1;
}
@ -367,7 +367,7 @@ static int db_traceback (lua_State *L) {
static const luaL_Reg dblib[] = {
{"debug", db_debug},
{"getfenv", db_getfenv},
{"getenv", db_getenv},
{"gethook", db_gethook},
{"getinfo", db_getinfo},
{"getlocal", db_getlocal},
@ -376,7 +376,7 @@ static const luaL_Reg dblib[] = {
{"getupvalue", db_getupvalue},
{"upvaluejoin", db_upvaluejoin},
{"upvalueid", db_upvalueid},
{"setfenv", db_setfenv},
{"setenv", db_setenv},
{"sethook", db_sethook},
{"setlocal", db_setlocal},
{"setmetatable", db_setmetatable},

4
ldo.c
View File

@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 2.80 2010/01/13 16:17:32 roberto Exp roberto $
** $Id: ldo.c,v 2.81 2010/02/09 11:56:29 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@ -622,7 +622,7 @@ static void f_parser (lua_State *L, void *ud) {
: luaY_parser(L, p->z, &p->buff, &p->varl, p->name);
setptvalue2s(L, L->top, tf);
incr_top(L);
cl = luaF_newLclosure(L, tf->sizeupvalues, G(L)->l_gt);
cl = luaF_newLclosure(L, tf->sizeupvalues);
cl->l.p = tf;
setclvalue(L, L->top - 1, cl);
for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */

View File

@ -1,5 +1,5 @@
/*
** $Id: lfunc.c,v 2.19 2009/12/16 16:42:58 roberto Exp roberto $
** $Id: lfunc.c,v 2.20 2010/03/12 19:14:06 roberto Exp roberto $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@ -21,19 +21,17 @@
Closure *luaF_newCclosure (lua_State *L, int n, Table *e) {
Closure *luaF_newCclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl;
c->c.isC = 1;
c->c.env = e;
c->c.nupvalues = cast_byte(n);
return c;
}
Closure *luaF_newLclosure (lua_State *L, int n, Table *e) {
Closure *luaF_newLclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl;
c->l.isC = 0;
c->l.env = e;
c->l.nupvalues = cast_byte(n);
while (n--) c->l.upvals[n] = NULL;
return c;

View File

@ -1,5 +1,5 @@
/*
** $Id: lfunc.h,v 2.3 2005/02/18 12:40:02 roberto Exp roberto $
** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp roberto $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@ -19,8 +19,8 @@
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);

7
lgc.c
View File

@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 2.72 2010/03/25 13:06:36 roberto Exp roberto $
** $Id: lgc.c,v 2.73 2010/03/25 19:37:23 roberto Exp roberto $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@ -375,7 +375,6 @@ static void traverseproto (global_State *g, Proto *f) {
static void traverseclosure (global_State *g, Closure *cl) {
markobject(g, cl->c.env);
if (cl->c.isC) {
int i;
for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
@ -605,8 +604,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
static void checkSizes (lua_State *L) {
global_State *g = G(L);
if (g->gckind == KGC_EMERGENCY)
return; /* do not move buffers during emergency collection */
if (g->strt.nuse < cast(lu_int32, g->strt.size)) {
/* string-table size could be the smaller power of 2 larger than 'nuse' */
int size = 1 << luaO_ceillog2(g->strt.nuse);
@ -787,7 +784,6 @@ static l_mem singlestep (lua_State *L) {
sweeplist(L, cast(GCObject **, &g->mainthread), 1);
g->sweepgc = &g->udgc; /* prepare to sweep userdata */
g->gcstate = GCSsweepudata;
checkSizes(L);
}
return GCSWEEPCOST;
}
@ -809,6 +805,7 @@ static l_mem singlestep (lua_State *L) {
return GCFINALIZECOST;
}
else {
checkSizes(L);
g->gcstate = GCSpause; /* end collection */
return 0;
}

View File

@ -1,5 +1,5 @@
/*
** $Id: linit.c,v 1.22 2009/12/17 12:26:09 roberto Exp roberto $
** $Id: linit.c,v 1.23 2009/12/22 15:32:50 roberto Exp roberto $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
@ -52,9 +52,9 @@ LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib;
/* call open functions from 'loadedlibs' */
for (lib = loadedlibs; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_settop(L, 0);
lua_pushstring(L, lib->name);
lua_call(L, 1, 0);
(lib->func)(L);
}
/* add open functions from 'preloadedlibs' into 'package.preload' table */
lua_pushglobaltable(L);
@ -65,8 +65,7 @@ LUALIB_API void luaL_openlibs (lua_State *L) {
}
lua_pop(L, 1); /* remove package.preload table */
#if defined(LUA_COMPAT_DEBUGLIB)
lua_pushglobaltable(L);
lua_getfield(L, -1, "require");
lua_getglobal(L, "require");
lua_pushliteral(L, LUA_DBLIBNAME);
lua_call(L, 1, 0); /* call 'require"debug"' */
lua_pop(L, 1); /* remove global table */

View File

@ -1,5 +1,5 @@
/*
** $Id: liolib.c,v 2.86 2010/03/03 18:48:57 roberto Exp roberto $
** $Id: liolib.c,v 2.87 2010/03/17 21:37:37 roberto Exp roberto $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@ -120,7 +120,7 @@ static FILE **newprefile (lua_State *L) {
static FILE **newfile (lua_State *L) {
FILE **pf = newprefile(L);
lua_pushvalue(L, lua_upvalueindex(1)); /* set upvalue... */
lua_setfenv(L, -2); /* ... as environment for new file */
lua_setenv(L, -2); /* ... as environment for new file */
return pf;
}
@ -163,7 +163,7 @@ static int io_fclose (lua_State *L) {
static int aux_close (lua_State *L) {
lua_getfenv(L, 1);
lua_getenv(L, 1);
lua_getfield(L, -1, "__close");
return (lua_tocfunction(L, -1))(L);
}
@ -595,7 +595,7 @@ static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
lua_rawseti(L, 1, k); /* add it to common upvalue */
}
lua_pushvalue(L, 3); /* get environment for default files */
lua_setfenv(L, -2); /* set it as environment for file */
lua_setenv(L, -2); /* set it as environment for file */
lua_setfield(L, 2, fname); /* add file to module */
}

View File

@ -1,5 +1,5 @@
/*
** $Id: lobject.h,v 2.34 2010/01/08 20:00:20 roberto Exp roberto $
** $Id: lobject.h,v 2.35 2010/03/12 19:14:06 roberto Exp roberto $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@ -297,8 +297,7 @@ typedef struct UpVal {
*/
#define ClosureHeader \
CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \
struct Table *env
CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist
typedef struct CClosure {
ClosureHeader;

View File

@ -1,5 +1,5 @@
/*
** $Id: lstate.c,v 2.73 2010/03/25 13:06:36 roberto Exp roberto $
** $Id: lstate.c,v 2.74 2010/03/25 19:37:23 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@ -118,9 +118,6 @@ static void freestack (lua_State *L) {
static int ccall (lua_State *L) {
lua_CFunction f = *(lua_CFunction *)lua_touserdata(L, 1);
lua_remove(L, 1); /* remove f from stack */
/* restore original environment for 'ccall' */
lua_pushglobaltable(L);
lua_replace(L, LUA_ENVIRONINDEX);
return f(L);
}
@ -139,7 +136,7 @@ static void init_registry (lua_State *L, global_State *g) {
setthvalue(L, &mt, L);
setobj2t(L, luaH_setint(L, registry, LUA_RIDX_MAINTHREAD), &mt);
/* registry[LUA_RIDX_CCALL] = ccall */
cp = luaF_newCclosure(L, 0, g->l_gt);
cp = luaF_newCclosure(L, 0);
cp->c.f = ccall;
setclvalue(L, &mt, cp);
setobj2t(L, luaH_setint(L, registry, LUA_RIDX_CCALL), &mt);

View File

@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 2.56 2010/03/24 13:07:01 roberto Exp roberto $
** $Id: lstate.h,v 2.57 2010/03/25 19:37:23 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@ -168,7 +168,6 @@ struct lua_State {
int basehookcount;
int hookcount;
lua_Hook hook;
TValue env; /* temporary place for environments */
GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */

View File

@ -1,5 +1,5 @@
/*
** $Id: ltests.c,v 2.88 2010/03/24 13:07:01 roberto Exp roberto $
** $Id: ltests.c,v 2.89 2010/03/25 13:06:36 roberto Exp roberto $
** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
@ -275,7 +275,6 @@ static void checkproto (global_State *g, Proto *f) {
static void checkclosure (global_State *g, Closure *cl) {
GCObject *clgc = obj2gco(cl);
checkobjref(g, clgc, cl->l.env);
if (cl->c.isC) {
int i;
for (i=0; i<cl->c.nupvalues; i++)
@ -875,7 +874,6 @@ static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) {
switch (*(*pc)++) {
case 'R': return LUA_REGISTRYINDEX;
case 'G': return luaL_error(L, "deprecated index 'G'");
case 'E': return LUA_ENVIRONINDEX;
case 'U': return lua_upvalueindex(getnum_aux(L, L1, pc));
default: (*pc)--; return getnum_aux(L, L1, pc);
}
@ -1021,6 +1019,9 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
else if EQ("gettable") {
lua_gettable(L1, getindex);
}
else if EQ("getglobal") {
lua_getglobal(L1, getstring);
}
else if EQ("getfield") {
int t = getindex;
lua_getfield(L1, t, getstring);
@ -1036,6 +1037,9 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
else if EQ("settable") {
lua_settable(L1, getindex);
}
else if EQ("setglobal") {
lua_setglobal(L1, getstring);
}
else if EQ("next") {
lua_next(L1, -2);
}

9
lua.h
View File

@ -1,5 +1,5 @@
/*
** $Id: lua.h,v 1.263 2010/03/19 21:04:17 roberto Exp roberto $
** $Id: lua.h,v 1.264 2010/03/22 18:28:03 roberto Exp roberto $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@ -34,8 +34,7 @@
** pseudo-indices
*/
#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX
#define LUA_ENVIRONINDEX (LUA_REGISTRYINDEX - 1)
#define lua_upvalueindex(i) (LUA_ENVIRONINDEX - (i))
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
/* thread status */
@ -212,7 +211,7 @@ LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
LUA_API void (lua_getfenv) (lua_State *L, int idx);
LUA_API void (lua_getenv) (lua_State *L, int idx);
/*
@ -223,7 +222,7 @@ LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
LUA_API int (lua_setfenv) (lua_State *L, int idx);
LUA_API void (lua_setenv) (lua_State *L, int idx);
/*

View File

@ -1,5 +1,5 @@
/*
** $Id: luaconf.h,v 1.133 2010/02/18 19:18:41 roberto Exp roberto $
** $Id: luaconf.h,v 1.134 2010/03/03 18:53:02 roberto Exp roberto $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@ -233,13 +233,6 @@
#define lua_cpcall(L,f,u) \
(lua_pushlightuserdata(L,(u)), luaL_cpcall(L,(f),1,0))
/*
@@ LUA_COMPAT_FENV controls the presence of functions 'setfenv/getfenv'.
** You can replace them with lexical environments, 'loadin', or the
** debug library.
*/
#define LUA_COMPAT_FENV
/*
@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.

4
lvm.c
View File

@ -1,5 +1,5 @@
/*
** $Id: lvm.c,v 2.105 2010/02/27 21:16:24 roberto Exp roberto $
** $Id: lvm.c,v 2.106 2010/03/12 19:14:06 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@ -771,7 +771,7 @@ void luaV_execute (lua_State *L) {
case OP_CLOSURE: {
Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */
int nup = p->sizeupvalues;
Closure *ncl = luaF_newLclosure(L, nup, cl->env);
Closure *ncl = luaF_newLclosure(L, nup);
Upvaldesc *uv = p->upvalues;
int j;
ncl->l.p = p;