aboutsummaryrefslogtreecommitdiff
path: root/lfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lfunc.c')
-rw-r--r--lfunc.c66
1 files changed, 34 insertions, 32 deletions
diff --git a/lfunc.c b/lfunc.c
index 105590fc..b4c04bd0 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -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*/
126static void checkclosemth (lua_State *L, StkId level, const TValue *obj) { 126static 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*/
163void luaF_newtbcupval (lua_State *L, StkId level) { 160void 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*/
189void luaF_close (lua_State *L, StkId level, int status, int yy) { 187void 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*/
208void 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 }