diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-01-13 13:54:10 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-01-13 13:54:10 -0300 |
| commit | b07fc10e91a5954254b47280aba287220c734a4b (patch) | |
| tree | e50d4e5ef9aab68487caf0944e72a7de04bb8bb5 /lfunc.c | |
| parent | cc1692515e2a6aabc6d07159e7926656e38eda53 (diff) | |
| download | lua-b07fc10e91a5954254b47280aba287220c734a4b.tar.gz lua-b07fc10e91a5954254b47280aba287220c734a4b.tar.bz2 lua-b07fc10e91a5954254b47280aba287220c734a4b.zip | |
Allow yields inside '__close' metamethods
Initial implementation to allow yields inside '__close' metamethods.
This current version still does not allow a '__close' metamethod
to yield when called due to an error. '__close' metamethods from
C functions also are not allowed to yield.
Diffstat (limited to 'lfunc.c')
| -rw-r--r-- | lfunc.c | 20 |
1 files changed, 12 insertions, 8 deletions
| @@ -101,17 +101,21 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
| 101 | 101 | ||
| 102 | 102 | ||
| 103 | /* | 103 | /* |
| 104 | ** Call closing method for object 'obj' with error message 'err'. | 104 | ** Call closing method for object 'obj' with error message 'err'. The |
| 105 | ** boolean 'yy' controls whether the call is yieldable. | ||
| 105 | ** (This function assumes EXTRA_STACK.) | 106 | ** (This function assumes EXTRA_STACK.) |
| 106 | */ | 107 | */ |
| 107 | static void callclosemethod (lua_State *L, TValue *obj, TValue *err) { | 108 | static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { |
| 108 | StkId top = L->top; | 109 | StkId top = L->top; |
| 109 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); | 110 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); |
| 110 | setobj2s(L, top, tm); /* will call metamethod... */ | 111 | setobj2s(L, top, tm); /* will call metamethod... */ |
| 111 | setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ | 112 | setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ |
| 112 | setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ | 113 | setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ |
| 113 | L->top = top + 3; /* add function and arguments */ | 114 | L->top = top + 3; /* add function and arguments */ |
| 114 | luaD_callnoyield(L, top, 0); /* call method */ | 115 | if (yy) |
| 116 | luaD_call(L, top, 0); | ||
| 117 | else | ||
| 118 | luaD_callnoyield(L, top, 0); | ||
| 115 | } | 119 | } |
| 116 | 120 | ||
| 117 | 121 | ||
| @@ -137,7 +141,7 @@ static void checkclosemth (lua_State *L, StkId level, const TValue *obj) { | |||
| 137 | ** the 'level' of the upvalue being closed, as everything after that | 141 | ** the 'level' of the upvalue being closed, as everything after that |
| 138 | ** won't be used again. | 142 | ** won't be used again. |
| 139 | */ | 143 | */ |
| 140 | static void prepcallclosemth (lua_State *L, StkId level, int status) { | 144 | static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) { |
| 141 | TValue *uv = s2v(level); /* value being closed */ | 145 | TValue *uv = s2v(level); /* value being closed */ |
| 142 | TValue *errobj; | 146 | TValue *errobj; |
| 143 | if (status == CLOSEKTOP) | 147 | if (status == CLOSEKTOP) |
| @@ -146,7 +150,7 @@ static void prepcallclosemth (lua_State *L, StkId level, int status) { | |||
| 146 | errobj = s2v(level + 1); /* error object goes after 'uv' */ | 150 | errobj = s2v(level + 1); /* error object goes after 'uv' */ |
| 147 | luaD_seterrorobj(L, status, level + 1); /* set error object */ | 151 | luaD_seterrorobj(L, status, level + 1); /* set error object */ |
| 148 | } | 152 | } |
| 149 | callclosemethod(L, uv, errobj); | 153 | callclosemethod(L, uv, errobj, yy); |
| 150 | } | 154 | } |
| 151 | 155 | ||
| 152 | 156 | ||
| @@ -174,7 +178,7 @@ void luaF_newtbcupval (lua_State *L, StkId level) { | |||
| 174 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ | 178 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ |
| 175 | lua_assert(status == LUA_ERRMEM); | 179 | lua_assert(status == LUA_ERRMEM); |
| 176 | luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ | 180 | luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ |
| 177 | callclosemethod(L, s2v(level), s2v(level + 1)); | 181 | callclosemethod(L, s2v(level), s2v(level + 1), 0); |
| 178 | luaD_throw(L, LUA_ERRMEM); /* throw memory error */ | 182 | luaD_throw(L, LUA_ERRMEM); /* throw memory error */ |
| 179 | } | 183 | } |
| 180 | } | 184 | } |
| @@ -194,7 +198,7 @@ void luaF_unlinkupval (UpVal *uv) { | |||
| 194 | ** to NOCLOSINGMETH closes upvalues without running any __close | 198 | ** to NOCLOSINGMETH closes upvalues without running any __close |
| 195 | ** metamethods. | 199 | ** metamethods. |
| 196 | */ | 200 | */ |
| 197 | void luaF_close (lua_State *L, StkId level, int status) { | 201 | void luaF_close (lua_State *L, StkId level, int status, int yy) { |
| 198 | UpVal *uv; | 202 | UpVal *uv; |
| 199 | StkId upl; /* stack index pointed by 'uv' */ | 203 | StkId upl; /* stack index pointed by 'uv' */ |
| 200 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { | 204 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { |
| @@ -209,7 +213,7 @@ void luaF_close (lua_State *L, StkId level, int status) { | |||
| 209 | } | 213 | } |
| 210 | if (uv->tbc && status != NOCLOSINGMETH) { | 214 | if (uv->tbc && status != NOCLOSINGMETH) { |
| 211 | ptrdiff_t levelrel = savestack(L, level); | 215 | ptrdiff_t levelrel = savestack(L, level); |
| 212 | prepcallclosemth(L, upl, status); /* may change the stack */ | 216 | prepcallclosemth(L, upl, status, yy); /* may change the stack */ |
| 213 | level = restorestack(L, levelrel); | 217 | level = restorestack(L, levelrel); |
| 214 | } | 218 | } |
| 215 | } | 219 | } |
