diff options
Diffstat (limited to 'lfunc.c')
-rw-r--r-- | lfunc.c | 64 |
1 files changed, 33 insertions, 31 deletions
@@ -98,27 +98,29 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
98 | 98 | ||
99 | 99 | ||
100 | static void callclose (lua_State *L, void *ud) { | 100 | static void callclose (lua_State *L, void *ud) { |
101 | luaD_callnoyield(L, cast(StkId, ud), 0); | 101 | UNUSED(ud); |
102 | luaD_callnoyield(L, L->top - 2, 0); | ||
102 | } | 103 | } |
103 | 104 | ||
104 | 105 | ||
105 | /* | 106 | /* |
106 | ** Prepare closing method with its argument for object at | 107 | ** Prepare closing method plus its argument for object 'obj' with |
107 | ** index 'func' in the stack. Assume there is an error message | 108 | ** error message 'err'. (This function assumes EXTRA_STACK.) |
108 | ** (or nil) just below the object. | ||
109 | */ | 109 | */ |
110 | static int prepclosingmethod (lua_State *L, StkId func) { | 110 | static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { |
111 | if (ttisfunction(s2v(func))) { /* object to-be-closed is a function? */ | 111 | StkId top = L->top; |
112 | setobjs2s(L, func + 1, func - 1); /* push error msg. as argument */ | 112 | if (ttisfunction(obj)) { /* object to-be-closed is a function? */ |
113 | setobj2s(L, top, obj); /* push function */ | ||
114 | setobj2s(L, top + 1, err); /* push error msg. as argument */ | ||
113 | } | 115 | } |
114 | else { /* try '__close' metamethod */ | 116 | else { /* try '__close' metamethod */ |
115 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CLOSE); | 117 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); |
116 | if (ttisnil(tm)) /* no metamethod? */ | 118 | if (ttisnil(tm)) /* no metamethod? */ |
117 | return 0; /* nothing to call */ | 119 | return 0; /* nothing to call */ |
118 | setobjs2s(L, func + 1, func); /* 'self' is the argument */ | 120 | setobj2s(L, top, tm); /* will call metamethod... */ |
119 | setobj2s(L, func, tm); /* will call metamethod */ | 121 | setobj2s(L, top + 1, obj); /* with 'self' as the argument */ |
120 | } | 122 | } |
121 | L->top = func + 2; /* add function and argument */ | 123 | L->top = top + 2; /* add function and argument */ |
122 | return 1; | 124 | return 1; |
123 | } | 125 | } |
124 | 126 | ||
@@ -129,22 +131,24 @@ static int prepclosingmethod (lua_State *L, StkId func) { | |||
129 | ** will be handled there. Otherwise, a previous error already | 131 | ** will be handled there. Otherwise, a previous error already |
130 | ** activated original protected call, and so the call to the | 132 | ** activated original protected call, and so the call to the |
131 | ** closing method must be protected here. | 133 | ** closing method must be protected here. |
134 | ** If status is OK, the call to the closing method will be pushed | ||
135 | ** at the top of the stack. Otherwise, values are pushed after | ||
136 | ** the 'level' of the upvalue being closed, as everything after | ||
137 | ** that won't be used again. | ||
132 | */ | 138 | */ |
133 | static int closeupval (lua_State *L, TValue *uv, StkId level, int status) { | 139 | static int closeupval (lua_State *L, TValue *uv, StkId level, int status) { |
134 | StkId func = level + 1; /* save slot for old error message */ | 140 | if (likely(status == LUA_OK)) { |
135 | if (unlikely(status != LUA_OK)) /* was there an error? */ | 141 | if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ |
136 | luaD_seterrorobj(L, status, level); /* save error message */ | 142 | callclose(L, NULL); /* call closing method */ |
137 | else | 143 | } |
138 | setnilvalue(s2v(level)); /* no error message */ | 144 | else { /* there was an error */ |
139 | setobj2s(L, func, uv); /* put object on top of error message */ | 145 | /* save error message and set stack top to 'level + 1' */ |
140 | if (!prepclosingmethod(L, func)) | 146 | luaD_seterrorobj(L, status, level); |
141 | return status; /* nothing to call */ | 147 | if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */ |
142 | if (likely(status == LUA_OK)) /* not in "error mode"? */ | 148 | int newstatus = luaD_pcall(L, callclose, NULL, savestack(L, level), 0); |
143 | callclose(L, func); /* call closing method */ | 149 | if (newstatus != LUA_OK) /* another error when closing? */ |
144 | else { /* already inside error handler; cannot raise another error */ | 150 | status = newstatus; /* this will be the new error */ |
145 | int newstatus = luaD_pcall(L, callclose, func, savestack(L, level), 0); | 151 | } |
146 | if (newstatus != LUA_OK) /* error when closing? */ | ||
147 | status = newstatus; /* this will be the new error */ | ||
148 | } | 152 | } |
149 | return status; | 153 | return status; |
150 | } | 154 | } |
@@ -169,12 +173,10 @@ static void trynewtbcupval (lua_State *L, void *ud) { | |||
169 | void luaF_newtbcupval (lua_State *L, StkId level) { | 173 | void luaF_newtbcupval (lua_State *L, StkId level) { |
170 | int status = luaD_rawrunprotected(L, trynewtbcupval, level); | 174 | int status = luaD_rawrunprotected(L, trynewtbcupval, level); |
171 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ | 175 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ |
172 | StkId func = level + 1; | ||
173 | lua_assert(status == LUA_ERRMEM); | 176 | lua_assert(status == LUA_ERRMEM); |
174 | setobjs2s(L, func, level); /* open space for error message */ | 177 | luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ |
175 | luaD_seterrorobj(L, status, level); /* save error message */ | 178 | if (prepclosingmethod(L, s2v(level), s2v(level + 1))) |
176 | if (prepclosingmethod(L, func)) | 179 | callclose(L, NULL); /* call closing method */ |
177 | callclose(L, func); /* call closing method */ | ||
178 | luaD_throw(L, LUA_ERRMEM); /* throw memory error */ | 180 | luaD_throw(L, LUA_ERRMEM); /* throw memory error */ |
179 | } | 181 | } |
180 | } | 182 | } |
@@ -201,7 +203,7 @@ int luaF_close (lua_State *L, StkId level, int status) { | |||
201 | luaC_barrier(L, uv, slot); | 203 | luaC_barrier(L, uv, slot); |
202 | if (status >= 0 && uv->tt == LUA_TUPVALTBC) { /* must be closed? */ | 204 | if (status >= 0 && uv->tt == LUA_TUPVALTBC) { /* must be closed? */ |
203 | ptrdiff_t levelrel = savestack(L, level); | 205 | ptrdiff_t levelrel = savestack(L, level); |
204 | status = closeupval(L, uv->v, upl, status); /* may reallocate the stack */ | 206 | status = closeupval(L, uv->v, upl, status); /* may realloc. the stack */ |
205 | level = restorestack(L, levelrel); | 207 | level = restorestack(L, levelrel); |
206 | } | 208 | } |
207 | } | 209 | } |