issue #163 First attempt to implement a Go like defer statement

defer
Dibyendu Majumdar 5 years ago
parent de42b8b0eb
commit 9a0ced9620

@ -54,6 +54,7 @@ LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
#endif

@ -35,7 +35,8 @@
*/
struct UpVal {
TValue *v; /* points to stack or to its own value */
lu_mem refcount; /* reference counter */
unsigned int refcount; /* reference counter */
unsigned int flags; /* Used to mark deferred values */
union {
struct { /* (when open) */
UpVal *next; /* linked list */
@ -53,7 +54,7 @@ LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
/* The additional type argument is a Ravi extension */
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

@ -27,7 +27,7 @@ enum RESERVED {
/* terminal symbols denoted by reserved words */
TK_AND = FIRST_RESERVED, TK_BREAK,
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_DEFER, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,

@ -281,10 +281,12 @@ OP_RAVI_SELF_SK, /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)], string key *
OP_RAVI_SETFIELD, /* A B C R(A)[RK(B)] := RK(C), string key */
OP_RAVI_GETTABUP_SK, /* A B C R(A) := UpValue[B][RK(C)], string key */
OP_RAVI_DEFER, /* A mark variable A "deferred" */
} OpCode;
#define NUM_OPCODES (cast(int, OP_RAVI_GETTABUP_SK) + 1)
#define NUM_OPCODES (cast(int, OP_RAVI_DEFER) + 1)
/*===========================================================================
Notes:

@ -90,7 +90,7 @@ struct lua_longjmp {
};
static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
switch (errcode) {
case LUA_ERRMEM: { /* memory error? */
setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
@ -123,7 +123,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
}
else { /* no handler at all; abort */
if (g->panic) { /* panic function? */
seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
luaD_seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
if (L->ci->top < L->top)
L->ci->top = L->top; /* pushing msg. can break this invariant */
lua_unlock(L);
@ -713,8 +713,8 @@ static int recover (lua_State *L, int status) {
if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */
oldtop = restorestack(L, ci->extra);
luaF_close(L, oldtop);
seterrorobj(L, status, oldtop);
luaF_close(L, oldtop, status);
luaD_seterrorobj(L, status, oldtop);
L->ci = ci;
L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
L->nny = 0; /* should be zero to be yieldable */
@ -800,7 +800,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
}
if (errorstatus(status)) { /* unrecoverable error? */
L->status = cast_byte(status); /* mark thread as 'dead' */
seterrorobj(L, status, L->top); /* push error message */
luaD_seterrorobj(L, status, L->top); /* push error message */
L->ci->top = L->top;
}
else lua_assert(status == L->status); /* normal end or yield */
@ -858,11 +858,12 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
status = luaD_rawrunprotected(L, func, u);
if (status != LUA_OK) { /* an error occurred? */
StkId oldtop = restorestack(L, old_top);
luaF_close(L, oldtop); /* close possible pending closures */
seterrorobj(L, status, oldtop);
L->ci = old_ci;
L->allowhook = old_allowhooks;
L->nny = old_nny;
status = luaF_close(L, oldtop, status); /* close possible pending closures */
oldtop = restorestack(L, old_top);
luaD_seterrorobj(L, status, oldtop);
luaD_shrinkstack(L);
}
L->errfunc = old_errfunc;

@ -19,6 +19,7 @@
#include "lua.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
@ -66,13 +67,15 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
lua_assert(isintwups(L) || L->openupval == NULL);
while (*pp != NULL && (p = *pp)->v >= level) {
lua_assert(upisopen(p));
if (p->v == level) /* found a corresponding upvalue? */
return p; /* return it */
if (p->v == level && !p->flags) /* found a corresponding upvalue that is not a deferred value? */ {
return p; /* return it */
}
pp = &p->u.open.next;
}
/* not found: create a new upvalue */
uv = luaM_new(L, UpVal);
uv->refcount = 0;
uv->flags = 0;
uv->u.open.next = *pp; /* link it to list of open upvalues */
uv->u.open.touched = 1;
*pp = uv;
@ -84,20 +87,49 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
return uv;
}
static void callclose (lua_State *L, void *ud) {
luaD_callnoyield(L, cast(StkId, ud), 0);
}
void luaF_close (lua_State *L, StkId level) {
static int calldeferredfunction (lua_State *L, UpVal *uv, StkId level, int status) {
StkId func = level + 1; /* save slot for old error message */
setobj2s(L, func, uv->v); /* will call it */
if (status != LUA_OK) /* was there an error? */
luaD_seterrorobj(L, status, level); /* save error message */
else
setnilvalue(level);
setobjs2s(L, func + 1, level); /* error msg. as argument */
L->top = func + 2; /* add function and argument */
if (status == LUA_OK) /* not in "error mode"? */
callclose(L, func); /* call closing method */
else { /* already inside error handler; cannot raise another error */
int newstatus = luaD_pcall(L, callclose, func, savestack(L, level), 0);
if (newstatus != LUA_OK) /* error when closing? */
status = newstatus; /* this will be the new error */
}
return status;
}
int luaF_close (lua_State *L, StkId level, int status) {
UpVal *uv;
while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
lua_assert(upisopen(uv));
L->openupval = uv->u.open.next; /* remove from 'open' list */
if (uv->refcount == 0) /* no references? */
luaM_free(L, uv); /* free upvalue */
if (uv->refcount == 0) { /* no references? */
if (uv->flags && ttisfunction(uv->v)) {
ptrdiff_t levelrel = savestack(L, level);
status = calldeferredfunction(L, uv, uv->v, status);
level = restorestack(L, levelrel);
}
luaM_free(L, uv); /* free upvalue */
}
else {
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
luaC_upvalbarrier(L, uv);
}
}
return status;
}

@ -40,7 +40,7 @@
static const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"in", "local", "defer", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"//", "..", "...", "==", ">=", "<=", "~=",
"<<", ">>", "::", "<eof>",

@ -163,6 +163,7 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"SELF_SK", /* _SK*/ /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
"SETFIELD", /*_SK */ /* A B C R(A)[RK(B)] := RK(C), string key */
"GETTABUP_SK",
"DEFER",
NULL
};
@ -304,6 +305,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_SELF_SK */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETFIELD */
,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_RAVI_GETTABUP_SK */
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_DEFER */
};

@ -2177,11 +2177,18 @@ static void ifstat (LexState *ls, int line) {
}
/* parse a local function statement - called from statement() */
static void localfunc (LexState *ls) {
static void localfunc (LexState *ls, int defer) {
expdesc b = {.ravi_type = RAVI_TANY, .pc = -1};
FuncState *fs = ls->fs;
/* RAVI change - add type */
new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION, NULL); /* new local variable */
if (defer) {
static const char funcname[] = "(deferred function)";
new_localvar(ls, luaX_newstring(ls, funcname, sizeof funcname-1), RAVI_TFUNCTION, NULL); /* new local variable */
luaK_codeABC(fs, OP_RAVI_DEFER, fs->nactvar, 0, 0);
markupval(fs, fs->nactvar);
} else {
/* RAVI change - add type */
new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION, NULL); /* new local variable */
}
adjustlocalvars(ls, 1); /* enter its scope */
body(ls, &b, 0, ls->linenumber); /* function created in next register */
/* debug information will only see the variable after this point! */
@ -2339,11 +2346,17 @@ static void statement (LexState *ls) {
case TK_LOCAL: { /* stat -> localstat */
luaX_next(ls); /* skip LOCAL */
if (testnext(ls, TK_FUNCTION)) /* local function? */
localfunc(ls);
localfunc(ls, 0);
else
localstat(ls);
break;
}
case TK_DEFER: { /* stat -> deferstat */
luaX_next(ls); /* skip LOCAL */
checknext(ls, TK_FUNCTION);
localfunc(ls, 1);
break;
}
case TK_DBCOLON: { /* stat -> label */
luaX_next(ls); /* skip double colon */
labelstat(ls, str_checkname(ls), line);

@ -270,7 +270,7 @@ void *ravi_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize)
static void close_state (lua_State *L) {
global_State *g = G(L);
luaF_close(L, L->stack); /* close all upvalues for this thread */
luaF_close(L, L->stack, -1); /* close all upvalues for this thread */
luaC_freeallobjects(L); /* collect all objects */
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
@ -317,7 +317,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
luaF_close(L1, L1->stack); /* close all upvalues for this thread */
luaF_close(L1, L1->stack, -1); /* close all upvalues for this thread */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);

@ -1027,7 +1027,7 @@ void luaV_finishOp (lua_State *L) {
*/
#define dojump(ci,i,e) \
{ int a = GETARG_A(i); \
if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \
if (a != 0) luaF_close(L, ci->u.l.base + a - 1, LUA_OK); \
pc += GETARG_sBx(i) + e; updatemask(L); }
/* for test instructions, execute the jump instruction that follows it */
@ -1269,7 +1269,8 @@ int luaV_execute (lua_State *L) {
&&vmlabel(OP_RAVI_GETFIELD),
&&vmlabel(OP_RAVI_SELF_SK),
&&vmlabel(OP_RAVI_SETFIELD),
&&vmlabel(OP_RAVI_GETTABUP_SK)
&&vmlabel(OP_RAVI_GETTABUP_SK),
&&vmlabel(OP_RAVI_DEFER),
};
#endif
@ -1720,7 +1721,7 @@ int luaV_execute (lua_State *L) {
StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
int aux;
/* close all upvalues from previous call */
if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base, LUA_OK);
/* move new frame into old one */
for (aux = 0; nfunc + aux < lim; aux++)
setobjs2s(L, ofunc + aux, nfunc + aux);
@ -1737,7 +1738,7 @@ int luaV_execute (lua_State *L) {
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
if (cl->p->sizep > 0) luaF_close(L, base);
if (cl->p->sizep > 0) luaF_close(L, base, LUA_OK);
savepc(L);
int nres = (b != 0 ? b - 1 : cast_int(L->top - ra));
b = luaD_poscall(L, ci, ra, nres);
@ -2462,6 +2463,12 @@ int luaV_execute (lua_State *L) {
}
vmbreak;
}
vmcase(OP_RAVI_DEFER) {
UpVal *up = luaF_findupval(L, ra); /* create new upvalue */
up->flags = 1; /* mark it as deferred */
setnilvalue(ra); /* initialize it with nil */
vmbreak;
}
}
}
}

@ -65,6 +65,7 @@ static const char Lua_header[] = ""
"#define LUA_TFUNCTION 6\n"
"#define LUA_TUSERDATA 7\n"
"#define LUA_TTHREAD 8\n"
"#define LUA_OK 0\n"
"typedef enum {TM_INDEX,TM_NEWINDEX,TM_GC,\n"
" TM_MODE,TM_LEN,TM_EQ,TM_ADD,TM_SUB,TM_MUL,\n"
" TM_MOD,TM_POW,TM_DIV,TM_IDIV,TM_BAND,TM_BOR,\n"
@ -515,7 +516,8 @@ static const char Lua_header[] = ""
"};\n"
"struct UpVal {\n"
" TValue *v;\n"
" lu_mem refcount;\n"
" unsigned int refcount;\n"
" unsigned int flags;\n"
" union {\n"
" struct {\n"
" UpVal *next;\n"
@ -544,7 +546,7 @@ static const char Lua_header[] = ""
" (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))\n"
"extern int luaV_tonumber_(const TValue *obj, lua_Number *n);\n"
"extern int luaV_tointeger(const TValue *obj, lua_Integer *p, int mode);\n"
"extern void luaF_close (lua_State *L, StkId level);\n"
"extern int luaF_close (lua_State *L, StkId level, int status);\n"
"extern int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres);\n"
"extern int luaV_equalobj(lua_State *L, const TValue *t1, const TValue *t2);\n"
"extern int luaV_lessthan(lua_State *L, const TValue *l, const TValue *r);\n"
@ -1010,7 +1012,7 @@ static void emit_comparison(struct function *fn, int A, int B, int C, int j, int
membuff_add_fstring(&fn->body, "if (result == %d) {\n", A);
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
membuff_add_string(&fn->body, " luaF_close(L, ra);\n");
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, "}\n");
@ -1043,7 +1045,7 @@ static void emit_op_loadk(struct function *fn, int A, int Bx, int pc) {
static void emit_op_return(struct function *fn, int A, int B, int pc) {
(void)pc;
emit_reg(fn, "ra", A);
membuff_add_string(&fn->body, "if (cl->p->sizep > 0) luaF_close(L, base);\n");
membuff_add_string(&fn->body, "if (cl->p->sizep > 0) luaF_close(L, base, LUA_OK);\n");
membuff_add_fstring(&fn->body, "result = (%d != 0 ? %d - 1 : cast_int(L->top - ra));\n", B, B);
membuff_add_string(&fn->body, "return luaD_poscall(L, ci, ra, result);\n");
}
@ -1066,7 +1068,7 @@ static void emit_op_jmp(struct function *fn, int A, int sBx, int pc) {
(void)pc;
if (A > 0) {
membuff_add_fstring(&fn->body, "ra = R(%d);\n", A - 1);
membuff_add_string(&fn->body, "luaF_close(L, ra);\n");
membuff_add_string(&fn->body, "luaF_close(L, ra, LUA_OK);\n");
}
membuff_add_fstring(&fn->body, "goto Lbc_%d;\n", sBx);
}
@ -1090,7 +1092,7 @@ static void emit_op_test(struct function *fn, int A, int B, int C, int j, int jA
membuff_add_fstring(&fn->body, "if (!result) {\n", A);
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
membuff_add_string(&fn->body, " luaF_close(L, ra);\n");
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, " }\n");
@ -1108,7 +1110,7 @@ static void emit_op_testset(struct function *fn, int A, int B, int C, int j, int
membuff_add_string(&fn->body, " setobjs2s(L, ra, rb);");
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
membuff_add_string(&fn->body, " luaF_close(L, ra);\n");
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, " }\n");

@ -52,7 +52,7 @@ void RaviCodeGenerator::emit_JMP(RaviFunctionDef *def, int A, int sBx, int pc) {
// base + a - 1
llvm::Value *val = emit_gep_register(def, A - 1);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, val);
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
}
// Do the actual jump

@ -133,7 +133,7 @@ void RaviCodeGenerator::emit_EQ(RaviFunctionDef *def, int A, int B, int C,
llvm::Value *val = emit_gep_register(def, jA - 1);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, val);
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
@ -239,7 +239,7 @@ void RaviCodeGenerator::emit_TEST(RaviFunctionDef *def, int A, int B, int C,
llvm::Value *val = emit_gep_register(def, jA - 1);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, val);
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
@ -311,7 +311,7 @@ void RaviCodeGenerator::emit_TESTSET(RaviFunctionDef *def, int A, int B, int C,
llvm::Value *val = emit_gep_register(def, jA - 1);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, val);
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);

@ -77,7 +77,7 @@ void RaviCodeGenerator::emit_RETURN(RaviFunctionDef *def, int A, int B,
def->builder->SetInsertPoint(then_block);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, def->base_ptr);
CreateCall3(def->builder, def->luaF_closeF, def->L, def->base_ptr, def->types->kInt[LUA_OK]);
def->builder->CreateBr(else_block);
def->f->getBasicBlockList().push_back(else_block);

@ -694,7 +694,8 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
// struct UpVal {
// struct TValue *v; /* points to stack or to its own value */
// unsigned long long refcount; /* reference counter */
// unsigned int refcount; /* reference counter */
// unsigned int flags; /* Used to mark deferred values */
// union {
// struct { /* (when open) */
// struct UpVal *next; /* linked list */
@ -705,7 +706,8 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
//};
elements.clear();
elements.push_back(pTValueT);
elements.push_back(C_size_t);
elements.push_back(C_intT);
elements.push_back(C_intT);
elements.push_back(TValueT);
UpValT->setBody(elements);
@ -745,12 +747,13 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(plua_StateT);
luaV_executeT = llvm::FunctionType::get(C_intT, elements, false);
// void luaF_close (lua_State *L, StkId level)
// int luaF_close (lua_State *L, StkId level, int status)
elements.clear();
elements.push_back(plua_StateT);
elements.push_back(StkIdT);
elements.push_back(C_intT);
luaF_closeT =
llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
llvm::FunctionType::get(C_intT, elements, false);
// int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2)
elements.clear();
@ -1256,10 +1259,12 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
nodes.clear();
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_pointerT, 0));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_longlongT, 8));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_intT, 4));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_intT, 4));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_TValueT, 16));
tbaa_UpValT = mdbuilder.createTBAAStructTypeNode("UpVal", nodes);
tbaa_UpVal_vT =
mdbuilder.createTBAAStructTagNode(tbaa_UpValT, tbaa_pointerT, 0);
// RaviArray

Loading…
Cancel
Save