diff options
Diffstat (limited to 'src/lua/lfunc.c')
-rw-r--r-- | src/lua/lfunc.c | 117 |
1 files changed, 47 insertions, 70 deletions
diff --git a/src/lua/lfunc.c b/src/lua/lfunc.c index c4360f0..13e44d4 100644 --- a/src/lua/lfunc.c +++ b/src/lua/lfunc.c | |||
@@ -100,80 +100,57 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
100 | } | 100 | } |
101 | 101 | ||
102 | 102 | ||
103 | static void callclose (lua_State *L, void *ud) { | ||
104 | UNUSED(ud); | ||
105 | luaD_callnoyield(L, L->top - 3, 0); | ||
106 | } | ||
107 | |||
108 | |||
109 | /* | 103 | /* |
110 | ** Prepare closing method plus its arguments for object 'obj' with | 104 | ** Call closing method for object 'obj' with error message 'err'. The |
111 | ** error message 'err'. (This function assumes EXTRA_STACK.) | 105 | ** boolean 'yy' controls whether the call is yieldable. |
106 | ** (This function assumes EXTRA_STACK.) | ||
112 | */ | 107 | */ |
113 | static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { | 108 | static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { |
114 | StkId top = L->top; | 109 | StkId top = L->top; |
115 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); | 110 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); |
116 | if (ttisnil(tm)) /* no metamethod? */ | ||
117 | return 0; /* nothing to call */ | ||
118 | setobj2s(L, top, tm); /* will call metamethod... */ | 111 | setobj2s(L, top, tm); /* will call metamethod... */ |
119 | setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ | 112 | setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ |
120 | setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ | 113 | setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ |
121 | L->top = top + 3; /* add function and arguments */ | 114 | L->top = top + 3; /* add function and arguments */ |
122 | return 1; | 115 | if (yy) |
116 | luaD_call(L, top, 0); | ||
117 | else | ||
118 | luaD_callnoyield(L, top, 0); | ||
123 | } | 119 | } |
124 | 120 | ||
125 | 121 | ||
126 | /* | 122 | /* |
127 | ** Raise an error with message 'msg', inserting the name of the | 123 | ** Check whether 'obj' has a close metamethod and raise an error |
128 | ** local variable at position 'level' in the stack. | 124 | ** if not. |
129 | */ | 125 | */ |
130 | static void varerror (lua_State *L, StkId level, const char *msg) { | 126 | static void checkclosemth (lua_State *L, StkId level, const TValue *obj) { |
131 | int idx = cast_int(level - L->ci->func); | 127 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); |
132 | const char *vname = luaG_findlocal(L, L->ci, idx, NULL); | 128 | if (ttisnil(tm)) { /* no metamethod? */ |
133 | if (vname == NULL) vname = "?"; | 129 | int idx = cast_int(level - L->ci->func); /* variable index */ |
134 | luaG_runerror(L, msg, vname); | 130 | const char *vname = luaG_findlocal(L, L->ci, idx, NULL); |
131 | if (vname == NULL) vname = "?"; | ||
132 | luaG_runerror(L, "variable '%s' got a non-closable value", vname); | ||
133 | } | ||
135 | } | 134 | } |
136 | 135 | ||
137 | 136 | ||
138 | /* | 137 | /* |
139 | ** Prepare and call a closing method. If status is OK, code is still | 138 | ** Prepare and call a closing method. |
140 | ** inside the original protected call, and so any error will be handled | 139 | ** If status is CLOSEKTOP, the call to the closing method will be pushed |
141 | ** there. Otherwise, a previous error already activated the original | 140 | ** at the top of the stack. Otherwise, values can be pushed right after |
142 | ** protected call, and so the call to the closing method must be | 141 | ** the 'level' of the upvalue being closed, as everything after that |
143 | ** protected here. (A status == CLOSEPROTECT behaves like a previous | 142 | ** won't be used again. |
144 | ** error, to also run the closing method in protected mode). | ||
145 | ** If status is OK, the call to the closing method will be pushed | ||
146 | ** at the top of the stack. Otherwise, values are pushed after | ||
147 | ** the 'level' of the upvalue being closed, as everything after | ||
148 | ** that won't be used again. | ||
149 | */ | 143 | */ |
150 | static int callclosemth (lua_State *L, StkId level, int status) { | 144 | static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) { |
151 | TValue *uv = s2v(level); /* value being closed */ | 145 | TValue *uv = s2v(level); /* value being closed */ |
152 | if (likely(status == LUA_OK)) { | 146 | TValue *errobj; |
153 | if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ | 147 | if (status == CLOSEKTOP) |
154 | callclose(L, NULL); /* call closing method */ | 148 | errobj = &G(L)->nilvalue; /* error object is nil */ |
155 | else if (!l_isfalse(uv)) /* non-closable non-false value? */ | 149 | else { /* 'luaD_seterrorobj' will set top to level + 2 */ |
156 | varerror(L, level, "attempt to close non-closable variable '%s'"); | 150 | errobj = s2v(level + 1); /* error object goes after 'uv' */ |
151 | luaD_seterrorobj(L, status, level + 1); /* set error object */ | ||
157 | } | 152 | } |
158 | else { /* must close the object in protected mode */ | 153 | callclosemethod(L, uv, errobj, yy); |
159 | ptrdiff_t oldtop; | ||
160 | level++; /* space for error message */ | ||
161 | oldtop = savestack(L, level + 1); /* top will be after that */ | ||
162 | luaD_seterrorobj(L, status, level); /* set error message */ | ||
163 | if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */ | ||
164 | int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0); | ||
165 | if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */ | ||
166 | status = newstatus; /* this will be the new error */ | ||
167 | else { | ||
168 | if (newstatus != LUA_OK) /* suppressed error? */ | ||
169 | luaE_warnerror(L, "__close metamethod"); | ||
170 | /* leave original error (or nil) on top */ | ||
171 | L->top = restorestack(L, oldtop); | ||
172 | } | ||
173 | } | ||
174 | /* else no metamethod; ignore this case and keep original error */ | ||
175 | } | ||
176 | return status; | ||
177 | } | 154 | } |
178 | 155 | ||
179 | 156 | ||
@@ -196,16 +173,12 @@ void luaF_newtbcupval (lua_State *L, StkId level) { | |||
196 | lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); | 173 | lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); |
197 | if (!l_isfalse(obj)) { /* false doesn't need to be closed */ | 174 | if (!l_isfalse(obj)) { /* false doesn't need to be closed */ |
198 | int status; | 175 | int status; |
199 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); | 176 | checkclosemth(L, level, obj); |
200 | if (ttisnil(tm)) /* no metamethod? */ | ||
201 | varerror(L, level, "variable '%s' got a non-closable value"); | ||
202 | status = luaD_rawrunprotected(L, trynewtbcupval, level); | 177 | status = luaD_rawrunprotected(L, trynewtbcupval, level); |
203 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ | 178 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ |
204 | lua_assert(status == LUA_ERRMEM); | 179 | lua_assert(status == LUA_ERRMEM); |
205 | luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ | 180 | luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ |
206 | /* next call must succeed, as object is closable */ | 181 | callclosemethod(L, s2v(level), s2v(level + 1), 0); |
207 | prepclosingmethod(L, s2v(level), s2v(level + 1)); | ||
208 | callclose(L, NULL); /* call closing method */ | ||
209 | luaD_throw(L, LUA_ERRMEM); /* throw memory error */ | 182 | luaD_throw(L, LUA_ERRMEM); /* throw memory error */ |
210 | } | 183 | } |
211 | } | 184 | } |
@@ -220,26 +193,30 @@ void luaF_unlinkupval (UpVal *uv) { | |||
220 | } | 193 | } |
221 | 194 | ||
222 | 195 | ||
223 | int luaF_close (lua_State *L, StkId level, int status) { | 196 | /* |
197 | ** Close all upvalues up to the given stack level. A 'status' equal | ||
198 | ** to NOCLOSINGMETH closes upvalues without running any __close | ||
199 | ** metamethods. | ||
200 | */ | ||
201 | void luaF_close (lua_State *L, StkId level, int status, int yy) { | ||
224 | UpVal *uv; | 202 | UpVal *uv; |
225 | while ((uv = L->openupval) != NULL && uplevel(uv) >= level) { | 203 | StkId upl; /* stack index pointed by 'uv' */ |
204 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { | ||
226 | TValue *slot = &uv->u.value; /* new position for value */ | 205 | TValue *slot = &uv->u.value; /* new position for value */ |
227 | lua_assert(uplevel(uv) < L->top); | 206 | lua_assert(uplevel(uv) < L->top); |
228 | if (uv->tbc && status != NOCLOSINGMETH) { | 207 | luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ |
229 | /* must run closing method, which may change the stack */ | ||
230 | ptrdiff_t levelrel = savestack(L, level); | ||
231 | status = callclosemth(L, uplevel(uv), status); | ||
232 | level = restorestack(L, levelrel); | ||
233 | } | ||
234 | luaF_unlinkupval(uv); | ||
235 | setobj(L, slot, uv->v); /* move value to upvalue slot */ | 208 | setobj(L, slot, uv->v); /* move value to upvalue slot */ |
236 | uv->v = slot; /* now current value lives here */ | 209 | uv->v = slot; /* now current value lives here */ |
237 | if (!iswhite(uv)) { /* neither white nor dead? */ | 210 | if (!iswhite(uv)) { /* neither white nor dead? */ |
238 | nw2black(uv); /* closed upvalues cannot be gray */ | 211 | nw2black(uv); /* closed upvalues cannot be gray */ |
239 | luaC_barrier(L, uv, slot); | 212 | luaC_barrier(L, uv, slot); |
240 | } | 213 | } |
214 | if (uv->tbc && status != NOCLOSINGMETH) { | ||
215 | ptrdiff_t levelrel = savestack(L, level); | ||
216 | prepcallclosemth(L, upl, status, yy); /* may change the stack */ | ||
217 | level = restorestack(L, levelrel); | ||
218 | } | ||
241 | } | 219 | } |
242 | return status; | ||
243 | } | 220 | } |
244 | 221 | ||
245 | 222 | ||