diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-03-10 10:27:19 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-03-10 10:27:19 -0300 |
commit | 81c6021fb40a254d9a586b0cb53453bba8973d80 (patch) | |
tree | 3abc818902b69ddbb89eaef0a3e52b0f218ceb6c /lfunc.c | |
parent | a7b8b27dd39f45b9464ffc4226b0616c3ffe5ad7 (diff) | |
download | lua-81c6021fb40a254d9a586b0cb53453bba8973d80.tar.gz lua-81c6021fb40a254d9a586b0cb53453bba8973d80.tar.bz2 lua-81c6021fb40a254d9a586b0cb53453bba8973d80.zip |
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.)
Diffstat (limited to 'lfunc.c')
-rw-r--r-- | lfunc.c | 40 |
1 files changed, 29 insertions, 11 deletions
@@ -155,6 +155,15 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) { | |||
155 | 155 | ||
156 | 156 | ||
157 | /* | 157 | /* |
158 | ** Maximum value for deltas in 'tbclist', dependent on the type | ||
159 | ** of delta. (This macro assumes that an 'L' is in scope where it | ||
160 | ** is used.) | ||
161 | */ | ||
162 | #define MAXDELTA \ | ||
163 | ((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1) | ||
164 | |||
165 | |||
166 | /* | ||
158 | ** Insert a variable in the list of to-be-closed variables. | 167 | ** Insert a variable in the list of to-be-closed variables. |
159 | */ | 168 | */ |
160 | void luaF_newtbcupval (lua_State *L, StkId level) { | 169 | void luaF_newtbcupval (lua_State *L, StkId level) { |
@@ -162,13 +171,11 @@ void luaF_newtbcupval (lua_State *L, StkId level) { | |||
162 | if (l_isfalse(s2v(level))) | 171 | if (l_isfalse(s2v(level))) |
163 | return; /* false doesn't need to be closed */ | 172 | return; /* false doesn't need to be closed */ |
164 | checkclosemth(L, level); /* value must have a close method */ | 173 | checkclosemth(L, level); /* value must have a close method */ |
165 | while (level - L->tbclist > USHRT_MAX) { /* is delta too large? */ | 174 | while (cast_uint(level - L->tbclist) > MAXDELTA) { |
166 | L->tbclist += USHRT_MAX; /* create a dummy node at maximum delta */ | 175 | L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */ |
167 | L->tbclist->tbclist.delta = USHRT_MAX; | 176 | L->tbclist->tbclist.delta = 0; |
168 | L->tbclist->tbclist.isdummy = 1; | ||
169 | } | 177 | } |
170 | level->tbclist.delta = level - L->tbclist; | 178 | level->tbclist.delta = cast(unsigned short, level - L->tbclist); |
171 | level->tbclist.isdummy = 0; | ||
172 | L->tbclist = level; | 179 | L->tbclist = level; |
173 | } | 180 | } |
174 | 181 | ||
@@ -202,6 +209,19 @@ void luaF_closeupval (lua_State *L, StkId level) { | |||
202 | 209 | ||
203 | 210 | ||
204 | /* | 211 | /* |
212 | ** Remove firt element from the tbclist plus its dummy nodes. | ||
213 | */ | ||
214 | static void poptbclist (lua_State *L) { | ||
215 | StkId tbc = L->tbclist; | ||
216 | lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */ | ||
217 | tbc -= tbc->tbclist.delta; | ||
218 | while (tbc > L->stack && tbc->tbclist.delta == 0) | ||
219 | tbc -= MAXDELTA; /* remove dummy nodes */ | ||
220 | L->tbclist = tbc; | ||
221 | } | ||
222 | |||
223 | |||
224 | /* | ||
205 | ** Close all upvalues and to-be-closed variables up to the given stack | 225 | ** Close all upvalues and to-be-closed variables up to the given stack |
206 | ** level. | 226 | ** level. |
207 | */ | 227 | */ |
@@ -210,11 +230,9 @@ void luaF_close (lua_State *L, StkId level, int status, int yy) { | |||
210 | luaF_closeupval(L, level); /* first, close the upvalues */ | 230 | luaF_closeupval(L, level); /* first, close the upvalues */ |
211 | while (L->tbclist >= level) { /* traverse tbc's down to that level */ | 231 | while (L->tbclist >= level) { /* traverse tbc's down to that level */ |
212 | StkId tbc = L->tbclist; /* get variable index */ | 232 | StkId tbc = L->tbclist; /* get variable index */ |
213 | L->tbclist -= tbc->tbclist.delta; /* remove it from list */ | 233 | poptbclist(L); /* remove it from list */ |
214 | if (!tbc->tbclist.isdummy) { /* not a dummy entry? */ | 234 | prepcallclosemth(L, tbc, status, yy); /* close variable */ |
215 | prepcallclosemth(L, tbc, status, yy); /* close variable */ | 235 | level = restorestack(L, levelrel); |
216 | level = restorestack(L, levelrel); | ||
217 | } | ||
218 | } | 236 | } |
219 | } | 237 | } |
220 | 238 | ||