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.c117
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
103static 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*/
113static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { 108static 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*/
130static void varerror (lua_State *L, StkId level, const char *msg) { 126static 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*/
150static int callclosemth (lua_State *L, StkId level, int status) { 144static 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
223int 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*/
201void 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