aboutsummaryrefslogtreecommitdiff
path: root/src/lua/lfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua/lfunc.c')
-rw-r--r--src/lua/lfunc.c69
1 files changed, 34 insertions, 35 deletions
diff --git a/src/lua/lfunc.c b/src/lua/lfunc.c
index 13e44d4..b4c04bd 100644
--- a/src/lua/lfunc.c
+++ b/src/lua/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,33 +155,21 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
155 155
156 156
157/* 157/*
158** Try to create a to-be-closed upvalue 158** Insert a variable in the list of to-be-closed variables.
159** (can raise a memory-allocation error)
160*/
161static void trynewtbcupval (lua_State *L, void *ud) {
162 newupval(L, 1, cast(StkId, ud), &L->openupval);
163}
164
165
166/*
167** Create a to-be-closed upvalue. If there is a memory error
168** when creating the upvalue, the closing method must be called here,
169** as there is no upvalue to call it later.
170*/ 159*/
171void luaF_newtbcupval (lua_State *L, StkId level) { 160void luaF_newtbcupval (lua_State *L, StkId level) {
172 TValue *obj = s2v(level); 161 lua_assert(level > L->tbclist);
173 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); 162 if (l_isfalse(s2v(level)))
174 if (!l_isfalse(obj)) { /* false doesn't need to be closed */ 163 return; /* false doesn't need to be closed */
175 int status; 164 checkclosemth(L, level); /* value must have a close method */
176 checkclosemth(L, level, obj); 165 while (level - L->tbclist > USHRT_MAX) { /* is delta too large? */
177 status = luaD_rawrunprotected(L, trynewtbcupval, level); 166 L->tbclist += USHRT_MAX; /* create a dummy node at maximum delta */
178 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ 167 L->tbclist->tbclist.delta = USHRT_MAX;
179 lua_assert(status == LUA_ERRMEM); 168 L->tbclist->tbclist.isdummy = 1;
180 luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */
181 callclosemethod(L, s2v(level), s2v(level + 1), 0);
182 luaD_throw(L, LUA_ERRMEM); /* throw memory error */
183 }
184 } 169 }
170 level->tbclist.delta = level - L->tbclist;
171 level->tbclist.isdummy = 0;
172 L->tbclist = level;
185} 173}
186 174
187 175
@@ -194,11 +182,9 @@ void luaF_unlinkupval (UpVal *uv) {
194 182
195 183
196/* 184/*
197** Close all upvalues up to the given stack level. A 'status' equal 185** Close all upvalues up to the given stack level.
198** to NOCLOSINGMETH closes upvalues without running any __close
199** metamethods.
200*/ 186*/
201void luaF_close (lua_State *L, StkId level, int status, int yy) { 187void luaF_closeupval (lua_State *L, StkId level) {
202 UpVal *uv; 188 UpVal *uv;
203 StkId upl; /* stack index pointed by 'uv' */ 189 StkId upl; /* stack index pointed by 'uv' */
204 while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { 190 while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
@@ -211,9 +197,22 @@ void luaF_close (lua_State *L, StkId level, int status, int yy) {
211 nw2black(uv); /* closed upvalues cannot be gray */ 197 nw2black(uv); /* closed upvalues cannot be gray */
212 luaC_barrier(L, uv, slot); 198 luaC_barrier(L, uv, slot);
213 } 199 }
214 if (uv->tbc && status != NOCLOSINGMETH) { 200 }
215 ptrdiff_t levelrel = savestack(L, level); 201}
216 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 */
217 level = restorestack(L, levelrel); 216 level = restorestack(L, levelrel);
218 } 217 }
219 } 218 }