New implementation for 'tbclist'
- Fixes a bug, by removing dummy nodes together with the node itself. (The previous implementation could leave dummy nodes in frames which otherwise had no tbc variables, and therefore would not close variables; that could leave 'tbclist' pointing higher than 'top', which could dangle if the stack shrank.) - Computes MAXDELTA based on the type of delta, to ease changing its type if needed. - Instead of 'isdummy', uses 'delta==0' to signal dummy nodes. (Dummy nodes always have MAXDELTA for their real delta.)
This commit is contained in:
40
lfunc.c
40
lfunc.c
@@ -154,6 +154,15 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Maximum value for deltas in 'tbclist', dependent on the type
|
||||||
|
** of delta. (This macro assumes that an 'L' is in scope where it
|
||||||
|
** is used.)
|
||||||
|
*/
|
||||||
|
#define MAXDELTA \
|
||||||
|
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Insert a variable in the list of to-be-closed variables.
|
** Insert a variable in the list of to-be-closed variables.
|
||||||
*/
|
*/
|
||||||
@@ -162,13 +171,11 @@ void luaF_newtbcupval (lua_State *L, StkId level) {
|
|||||||
if (l_isfalse(s2v(level)))
|
if (l_isfalse(s2v(level)))
|
||||||
return; /* false doesn't need to be closed */
|
return; /* false doesn't need to be closed */
|
||||||
checkclosemth(L, level); /* value must have a close method */
|
checkclosemth(L, level); /* value must have a close method */
|
||||||
while (level - L->tbclist > USHRT_MAX) { /* is delta too large? */
|
while (cast_uint(level - L->tbclist) > MAXDELTA) {
|
||||||
L->tbclist += USHRT_MAX; /* create a dummy node at maximum delta */
|
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
|
||||||
L->tbclist->tbclist.delta = USHRT_MAX;
|
L->tbclist->tbclist.delta = 0;
|
||||||
L->tbclist->tbclist.isdummy = 1;
|
|
||||||
}
|
}
|
||||||
level->tbclist.delta = level - L->tbclist;
|
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
|
||||||
level->tbclist.isdummy = 0;
|
|
||||||
L->tbclist = level;
|
L->tbclist = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +208,19 @@ void luaF_closeupval (lua_State *L, StkId level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Remove firt element from the tbclist plus its dummy nodes.
|
||||||
|
*/
|
||||||
|
static void poptbclist (lua_State *L) {
|
||||||
|
StkId tbc = L->tbclist;
|
||||||
|
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
|
||||||
|
tbc -= tbc->tbclist.delta;
|
||||||
|
while (tbc > L->stack && tbc->tbclist.delta == 0)
|
||||||
|
tbc -= MAXDELTA; /* remove dummy nodes */
|
||||||
|
L->tbclist = tbc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Close all upvalues and to-be-closed variables up to the given stack
|
** Close all upvalues and to-be-closed variables up to the given stack
|
||||||
** level.
|
** level.
|
||||||
@@ -210,11 +230,9 @@ void luaF_close (lua_State *L, StkId level, int status, int yy) {
|
|||||||
luaF_closeupval(L, level); /* first, close the upvalues */
|
luaF_closeupval(L, level); /* first, close the upvalues */
|
||||||
while (L->tbclist >= level) { /* traverse tbc's down to that level */
|
while (L->tbclist >= level) { /* traverse tbc's down to that level */
|
||||||
StkId tbc = L->tbclist; /* get variable index */
|
StkId tbc = L->tbclist; /* get variable index */
|
||||||
L->tbclist -= tbc->tbclist.delta; /* remove it from list */
|
poptbclist(L); /* remove it from list */
|
||||||
if (!tbc->tbclist.isdummy) { /* not a dummy entry? */
|
prepcallclosemth(L, tbc, status, yy); /* close variable */
|
||||||
prepcallclosemth(L, tbc, status, yy); /* close variable */
|
level = restorestack(L, levelrel);
|
||||||
level = restorestack(L, levelrel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,13 +139,14 @@ typedef struct TValue {
|
|||||||
** Entries in a Lua stack. Field 'tbclist' forms a list of all
|
** Entries in a Lua stack. Field 'tbclist' forms a list of all
|
||||||
** to-be-closed variables active in this stack. Dummy entries are
|
** to-be-closed variables active in this stack. Dummy entries are
|
||||||
** used when the distance between two tbc variables does not fit
|
** used when the distance between two tbc variables does not fit
|
||||||
** in an unsigned short.
|
** in an unsigned short. They are represented by delta==0, and
|
||||||
|
** their real delta is always the maximum value that fits in
|
||||||
|
** that field.
|
||||||
*/
|
*/
|
||||||
typedef union StackValue {
|
typedef union StackValue {
|
||||||
TValue val;
|
TValue val;
|
||||||
struct {
|
struct {
|
||||||
TValuefields;
|
TValuefields;
|
||||||
lu_byte isdummy;
|
|
||||||
unsigned short delta;
|
unsigned short delta;
|
||||||
} tbclist;
|
} tbclist;
|
||||||
} StackValue;
|
} StackValue;
|
||||||
|
|||||||
Reference in New Issue
Block a user