Skip to content

Commit

Permalink
issue #163 First attempt to implement a Go like defer statement
Browse files Browse the repository at this point in the history
  • Loading branch information
dibyendumajumdar committed Dec 11, 2019
1 parent de42b8b commit 9a0ced9
Show file tree
Hide file tree
Showing 16 changed files with 112 additions and 44 deletions.
1 change: 1 addition & 0 deletions include/ldo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

5 changes: 3 additions & 2 deletions include/lfunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion include/llex.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion include/lopcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
15 changes: 8 additions & 7 deletions src/ldo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down
42 changes: 37 additions & 5 deletions src/lfunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "lua.h"

#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}


Expand Down
2 changes: 1 addition & 1 deletion src/llex.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>",
Expand Down
4 changes: 4 additions & 0 deletions src/lopcodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down Expand Up @@ -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 */

};


Expand Down
21 changes: 17 additions & 4 deletions src/lparser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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! */
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/lstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
15 changes: 11 additions & 4 deletions src/lvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
}
}
}
Expand Down
16 changes: 9 additions & 7 deletions src/ravi_jitshared.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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");
}
Expand All @@ -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);
}
Expand All @@ -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");
Expand All @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion src/ravi_llvmcall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 9a0ced9

Please sign in to comment.