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 | |
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.)
-rw-r--r-- | lfunc.c | 40 | ||||
-rw-r--r-- | lobject.h | 5 |
2 files changed, 32 insertions, 13 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 | ||
@@ -139,13 +139,14 @@ typedef struct TValue { | |||
139 | ** Entries in a Lua stack. Field 'tbclist' forms a list of all | 139 | ** Entries in a Lua stack. Field 'tbclist' forms a list of all |
140 | ** to-be-closed variables active in this stack. Dummy entries are | 140 | ** to-be-closed variables active in this stack. Dummy entries are |
141 | ** used when the distance between two tbc variables does not fit | 141 | ** used when the distance between two tbc variables does not fit |
142 | ** in an unsigned short. | 142 | ** in an unsigned short. They are represented by delta==0, and |
143 | ** their real delta is always the maximum value that fits in | ||
144 | ** that field. | ||
143 | */ | 145 | */ |
144 | typedef union StackValue { | 146 | typedef union StackValue { |
145 | TValue val; | 147 | TValue val; |
146 | struct { | 148 | struct { |
147 | TValuefields; | 149 | TValuefields; |
148 | lu_byte isdummy; | ||
149 | unsigned short delta; | 150 | unsigned short delta; |
150 | } tbclist; | 151 | } tbclist; |
151 | } StackValue; | 152 | } StackValue; |