diff options
Diffstat (limited to 'lfunc.c')
-rw-r--r-- | lfunc.c | 66 |
1 files changed, 34 insertions, 32 deletions
@@ -120,11 +120,11 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { | |||
120 | 120 | ||
121 | 121 | ||
122 | /* | 122 | /* |
123 | ** Check whether 'obj' has a close metamethod and raise an error | 123 | ** Check whether object at given level has a close metamethod and raise |
124 | ** if not. | 124 | ** an error if not. |
125 | */ | 125 | */ |
126 | static void checkclosemth (lua_State *L, StkId level, const TValue *obj) { | 126 | static void checkclosemth (lua_State *L, StkId level) { |
127 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); | 127 | const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE); |
128 | if (ttisnil(tm)) { /* no metamethod? */ | 128 | if (ttisnil(tm)) { /* no metamethod? */ |
129 | int idx = cast_int(level - L->ci->func); /* variable index */ | 129 | int idx = cast_int(level - L->ci->func); /* variable index */ |
130 | const char *vname = luaG_findlocal(L, L->ci, idx, NULL); | 130 | const char *vname = luaG_findlocal(L, L->ci, idx, NULL); |
@@ -155,20 +155,21 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) { | |||
155 | 155 | ||
156 | 156 | ||
157 | /* | 157 | /* |
158 | ** Create a to-be-closed upvalue. If there is a memory allocation error, | 158 | ** Insert a variable in the list of to-be-closed variables. |
159 | ** 'ptbc' keeps the object so it can be closed as soon as possible. | ||
160 | ** (Since memory errors have no handler, that will happen before any | ||
161 | ** stack reallocation.) | ||
162 | */ | 159 | */ |
163 | void luaF_newtbcupval (lua_State *L, StkId level) { | 160 | void luaF_newtbcupval (lua_State *L, StkId level) { |
164 | TValue *obj = s2v(level); | 161 | lua_assert(level > L->tbclist); |
165 | lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); | 162 | if (l_isfalse(s2v(level))) |
166 | if (!l_isfalse(obj)) { /* false doesn't need to be closed */ | 163 | return; /* false doesn't need to be closed */ |
167 | checkclosemth(L, level, obj); | 164 | checkclosemth(L, level); /* value must have a close method */ |
168 | L->ptbc = level; /* in case of allocation error */ | 165 | while (level - L->tbclist > USHRT_MAX) { /* is delta too large? */ |
169 | newupval(L, 1, level, &L->openupval); | 166 | L->tbclist += USHRT_MAX; /* create a dummy node at maximum delta */ |
170 | L->ptbc = NULL; /* no errors */ | 167 | L->tbclist->tbclist.delta = USHRT_MAX; |
168 | L->tbclist->tbclist.isdummy = 1; | ||
171 | } | 169 | } |
170 | level->tbclist.delta = level - L->tbclist; | ||
171 | level->tbclist.isdummy = 0; | ||
172 | L->tbclist = level; | ||
172 | } | 173 | } |
173 | 174 | ||
174 | 175 | ||
@@ -181,23 +182,11 @@ void luaF_unlinkupval (UpVal *uv) { | |||
181 | 182 | ||
182 | 183 | ||
183 | /* | 184 | /* |
184 | ** Close all upvalues up to the given stack level. A 'status' equal | 185 | ** Close all upvalues up to the given stack level. |
185 | ** to NOCLOSINGMETH closes upvalues without running any __close | ||
186 | ** metamethods. If there is a pending to-be-closed value, close | ||
187 | ** it before anything else. | ||
188 | */ | 186 | */ |
189 | void luaF_close (lua_State *L, StkId level, int status, int yy) { | 187 | void luaF_closeupval (lua_State *L, StkId level) { |
190 | UpVal *uv; | 188 | UpVal *uv; |
191 | StkId upl; /* stack index pointed by 'uv' */ | 189 | StkId upl; /* stack index pointed by 'uv' */ |
192 | if (unlikely(status == LUA_ERRMEM && L->ptbc != NULL)) { | ||
193 | ptrdiff_t levelrel = savestack(L, level); | ||
194 | upl = L->ptbc; | ||
195 | L->ptbc = NULL; /* remove from "list" before closing */ | ||
196 | prepcallclosemth(L, upl, status, yy); | ||
197 | level = restorestack(L, levelrel); | ||
198 | } | ||
199 | else | ||
200 | lua_assert(L->ptbc == NULL); /* must be empty for other status */ | ||
201 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { | 190 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { |
202 | TValue *slot = &uv->u.value; /* new position for value */ | 191 | TValue *slot = &uv->u.value; /* new position for value */ |
203 | lua_assert(uplevel(uv) < L->top); | 192 | lua_assert(uplevel(uv) < L->top); |
@@ -208,9 +197,22 @@ void luaF_close (lua_State *L, StkId level, int status, int yy) { | |||
208 | nw2black(uv); /* closed upvalues cannot be gray */ | 197 | nw2black(uv); /* closed upvalues cannot be gray */ |
209 | luaC_barrier(L, uv, slot); | 198 | luaC_barrier(L, uv, slot); |
210 | } | 199 | } |
211 | if (uv->tbc && status != NOCLOSINGMETH) { | 200 | } |
212 | ptrdiff_t levelrel = savestack(L, level); | 201 | } |
213 | prepcallclosemth(L, upl, status, yy); /* may change the stack */ | 202 | |
203 | |||
204 | /* | ||
205 | ** Close all upvalues and to-be-closed variables up to the given stack | ||
206 | ** level. | ||
207 | */ | ||
208 | void luaF_close (lua_State *L, StkId level, int status, int yy) { | ||
209 | ptrdiff_t levelrel = savestack(L, level); | ||
210 | luaF_closeupval(L, level); /* first, close the upvalues */ | ||
211 | while (L->tbclist >= level) { /* traverse tbc's down to that level */ | ||
212 | StkId tbc = L->tbclist; /* get variable index */ | ||
213 | L->tbclist -= tbc->tbclist.delta; /* remove it from list */ | ||
214 | if (!tbc->tbclist.isdummy) { /* not a dummy entry? */ | ||
215 | prepcallclosemth(L, tbc, status, yy); /* close variable */ | ||
214 | level = restorestack(L, levelrel); | 216 | level = restorestack(L, levelrel); |
215 | } | 217 | } |
216 | } | 218 | } |