diff options
Diffstat (limited to 'lfunc.c')
-rw-r--r-- | lfunc.c | 37 |
1 files changed, 16 insertions, 21 deletions
@@ -155,32 +155,19 @@ 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 | ** Create a to-be-closed upvalue. If there is a memory allocation error, |
159 | ** (can raise a memory-allocation error) | 159 | ** 'ptbc' keeps the object so it can be closed as soon as possible. |
160 | */ | 160 | ** (Since memory errors have no handler, that will happen before any |
161 | static void trynewtbcupval (lua_State *L, void *ud) { | 161 | ** stack reallocation.) |
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 | */ | 162 | */ |
171 | void luaF_newtbcupval (lua_State *L, StkId level) { | 163 | void luaF_newtbcupval (lua_State *L, StkId level) { |
172 | TValue *obj = s2v(level); | 164 | TValue *obj = s2v(level); |
173 | lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); | 165 | lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); |
174 | if (!l_isfalse(obj)) { /* false doesn't need to be closed */ | 166 | if (!l_isfalse(obj)) { /* false doesn't need to be closed */ |
175 | int status; | ||
176 | checkclosemth(L, level, obj); | 167 | checkclosemth(L, level, obj); |
177 | status = luaD_rawrunprotected(L, trynewtbcupval, level); | 168 | L->ptbc = level; /* in case of allocation error */ |
178 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ | 169 | newupval(L, 1, level, &L->openupval); |
179 | lua_assert(status == LUA_ERRMEM); | 170 | L->ptbc = NULL; /* no errors */ |
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 | } | 171 | } |
185 | } | 172 | } |
186 | 173 | ||
@@ -196,11 +183,19 @@ void luaF_unlinkupval (UpVal *uv) { | |||
196 | /* | 183 | /* |
197 | ** Close all upvalues up to the given stack level. A 'status' equal | 184 | ** Close all upvalues up to the given stack level. A 'status' equal |
198 | ** to NOCLOSINGMETH closes upvalues without running any __close | 185 | ** to NOCLOSINGMETH closes upvalues without running any __close |
199 | ** metamethods. | 186 | ** metamethods. If there is a pending to-be-closed value, close |
187 | ** it before anything else. | ||
200 | */ | 188 | */ |
201 | void luaF_close (lua_State *L, StkId level, int status, int yy) { | 189 | void luaF_close (lua_State *L, StkId level, int status, int yy) { |
202 | UpVal *uv; | 190 | UpVal *uv; |
203 | StkId upl; /* stack index pointed by 'uv' */ | 191 | StkId upl; /* stack index pointed by 'uv' */ |
192 | if (unlikely(status == LUA_ERRMEM && L->ptbc != NULL)) { | ||
193 | upl = L->ptbc; | ||
194 | L->ptbc = NULL; /* remove from "list" before closing */ | ||
195 | prepcallclosemth(L, upl, status, yy); | ||
196 | } | ||
197 | else | ||
198 | lua_assert(L->ptbc == NULL); /* must be empty for other status */ | ||
204 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { | 199 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { |
205 | TValue *slot = &uv->u.value; /* new position for value */ | 200 | TValue *slot = &uv->u.value; /* new position for value */ |
206 | lua_assert(uplevel(uv) < L->top); | 201 | lua_assert(uplevel(uv) < L->top); |