diff options
author | Li Jin <dragon-fly@qq.com> | 2021-03-03 21:31:01 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2021-03-03 21:33:37 +0800 |
commit | 1df786307c1983b8ce693e3916081a8bcd4e95ae (patch) | |
tree | 6c7aeb2198d825877fd3d179c394b7a5c1f06a17 /src | |
parent | 66168b112b707172b9035edf8c1daed469781e06 (diff) | |
download | yuescript-1df786307c1983b8ce693e3916081a8bcd4e95ae.tar.gz yuescript-1df786307c1983b8ce693e3916081a8bcd4e95ae.tar.bz2 yuescript-1df786307c1983b8ce693e3916081a8bcd4e95ae.zip |
add new metatable syntax for issue #41, fix reusing local variable issue, update built-in Lua.
Diffstat (limited to 'src')
39 files changed, 974 insertions, 553 deletions
diff --git a/src/lua/lapi.c b/src/lua/lapi.c index 3583e9c..a9cf2fd 100644 --- a/src/lua/lapi.c +++ b/src/lua/lapi.c | |||
@@ -39,7 +39,7 @@ const char lua_ident[] = | |||
39 | 39 | ||
40 | 40 | ||
41 | /* | 41 | /* |
42 | ** Test for a valid index. | 42 | ** Test for a valid index (one that is not the 'nilvalue'). |
43 | ** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed. | 43 | ** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed. |
44 | ** However, it covers the most common cases in a faster way. | 44 | ** However, it covers the most common cases in a faster way. |
45 | */ | 45 | */ |
@@ -74,7 +74,8 @@ static TValue *index2value (lua_State *L, int idx) { | |||
74 | return &G(L)->nilvalue; /* it has no upvalues */ | 74 | return &G(L)->nilvalue; /* it has no upvalues */ |
75 | else { | 75 | else { |
76 | CClosure *func = clCvalue(s2v(ci->func)); | 76 | CClosure *func = clCvalue(s2v(ci->func)); |
77 | return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : &G(L)->nilvalue; | 77 | return (idx <= func->nupvalues) ? &func->upvalue[idx-1] |
78 | : &G(L)->nilvalue; | ||
78 | } | 79 | } |
79 | } | 80 | } |
80 | } | 81 | } |
@@ -191,9 +192,8 @@ LUA_API void lua_settop (lua_State *L, int idx) { | |||
191 | if (diff < 0 && hastocloseCfunc(ci->nresults)) | 192 | if (diff < 0 && hastocloseCfunc(ci->nresults)) |
192 | luaF_close(L, L->top + diff, CLOSEKTOP, 0); | 193 | luaF_close(L, L->top + diff, CLOSEKTOP, 0); |
193 | #endif | 194 | #endif |
195 | api_check(L, L->tbclist < L->top + diff, "cannot pop an unclosed slot"); | ||
194 | L->top += diff; | 196 | L->top += diff; |
195 | api_check(L, L->openupval == NULL || uplevel(L->openupval) < L->top, | ||
196 | "cannot pop an unclosed slot"); | ||
197 | lua_unlock(L); | 197 | lua_unlock(L); |
198 | } | 198 | } |
199 | 199 | ||
@@ -202,10 +202,10 @@ LUA_API void lua_closeslot (lua_State *L, int idx) { | |||
202 | StkId level; | 202 | StkId level; |
203 | lua_lock(L); | 203 | lua_lock(L); |
204 | level = index2stack(L, idx); | 204 | level = index2stack(L, idx); |
205 | api_check(L, hastocloseCfunc(L->ci->nresults) && L->openupval != NULL && | 205 | api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level, |
206 | uplevel(L->openupval) == level, | ||
207 | "no variable to close at given level"); | 206 | "no variable to close at given level"); |
208 | luaF_close(L, level, CLOSEKTOP, 0); | 207 | luaF_close(L, level, CLOSEKTOP, 0); |
208 | level = index2stack(L, idx); /* stack may be moved */ | ||
209 | setnilvalue(s2v(level)); | 209 | setnilvalue(s2v(level)); |
210 | lua_unlock(L); | 210 | lua_unlock(L); |
211 | } | 211 | } |
@@ -1264,8 +1264,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) { | |||
1264 | lua_lock(L); | 1264 | lua_lock(L); |
1265 | o = index2stack(L, idx); | 1265 | o = index2stack(L, idx); |
1266 | nresults = L->ci->nresults; | 1266 | nresults = L->ci->nresults; |
1267 | api_check(L, L->openupval == NULL || uplevel(L->openupval) <= o, | 1267 | api_check(L, L->tbclist < o, "given index below or equal a marked one"); |
1268 | "marked index below or equal new one"); | ||
1269 | luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ | 1268 | luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ |
1270 | if (!hastocloseCfunc(nresults)) /* function not marked yet? */ | 1269 | if (!hastocloseCfunc(nresults)) /* function not marked yet? */ |
1271 | L->ci->nresults = codeNresults(nresults); /* mark it */ | 1270 | L->ci->nresults = codeNresults(nresults); /* mark it */ |
diff --git a/src/lua/lapi.h b/src/lua/lapi.h index 41216b2..9e99cc4 100644 --- a/src/lua/lapi.h +++ b/src/lua/lapi.h | |||
@@ -42,6 +42,8 @@ | |||
42 | 42 | ||
43 | #define hastocloseCfunc(n) ((n) < LUA_MULTRET) | 43 | #define hastocloseCfunc(n) ((n) < LUA_MULTRET) |
44 | 44 | ||
45 | /* Map [-1, inf) (range of 'nresults') into (-inf, -2] */ | ||
45 | #define codeNresults(n) (-(n) - 3) | 46 | #define codeNresults(n) (-(n) - 3) |
47 | #define decodeNresults(n) (-(n) - 3) | ||
46 | 48 | ||
47 | #endif | 49 | #endif |
diff --git a/src/lua/lauxlib.c b/src/lua/lauxlib.c index e8fc486..94835ef 100644 --- a/src/lua/lauxlib.c +++ b/src/lua/lauxlib.c | |||
@@ -190,7 +190,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { | |||
190 | } | 190 | } |
191 | 191 | ||
192 | 192 | ||
193 | int luaL_typeerror (lua_State *L, int arg, const char *tname) { | 193 | LUALIB_API int luaL_typeerror (lua_State *L, int arg, const char *tname) { |
194 | const char *msg; | 194 | const char *msg; |
195 | const char *typearg; /* name for the type of the actual argument */ | 195 | const char *typearg; /* name for the type of the actual argument */ |
196 | if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) | 196 | if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) |
@@ -378,7 +378,7 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, | |||
378 | ** but without 'msg'.) | 378 | ** but without 'msg'.) |
379 | */ | 379 | */ |
380 | LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { | 380 | LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { |
381 | if (!lua_checkstack(L, space)) { | 381 | if (l_unlikely(!lua_checkstack(L, space))) { |
382 | if (msg) | 382 | if (msg) |
383 | luaL_error(L, "stack overflow (%s)", msg); | 383 | luaL_error(L, "stack overflow (%s)", msg); |
384 | else | 384 | else |
@@ -388,20 +388,20 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { | |||
388 | 388 | ||
389 | 389 | ||
390 | LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { | 390 | LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { |
391 | if (lua_type(L, arg) != t) | 391 | if (l_unlikely(lua_type(L, arg) != t)) |
392 | tag_error(L, arg, t); | 392 | tag_error(L, arg, t); |
393 | } | 393 | } |
394 | 394 | ||
395 | 395 | ||
396 | LUALIB_API void luaL_checkany (lua_State *L, int arg) { | 396 | LUALIB_API void luaL_checkany (lua_State *L, int arg) { |
397 | if (lua_type(L, arg) == LUA_TNONE) | 397 | if (l_unlikely(lua_type(L, arg) == LUA_TNONE)) |
398 | luaL_argerror(L, arg, "value expected"); | 398 | luaL_argerror(L, arg, "value expected"); |
399 | } | 399 | } |
400 | 400 | ||
401 | 401 | ||
402 | LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { | 402 | LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { |
403 | const char *s = lua_tolstring(L, arg, len); | 403 | const char *s = lua_tolstring(L, arg, len); |
404 | if (!s) tag_error(L, arg, LUA_TSTRING); | 404 | if (l_unlikely(!s)) tag_error(L, arg, LUA_TSTRING); |
405 | return s; | 405 | return s; |
406 | } | 406 | } |
407 | 407 | ||
@@ -420,7 +420,7 @@ LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, | |||
420 | LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { | 420 | LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { |
421 | int isnum; | 421 | int isnum; |
422 | lua_Number d = lua_tonumberx(L, arg, &isnum); | 422 | lua_Number d = lua_tonumberx(L, arg, &isnum); |
423 | if (!isnum) | 423 | if (l_unlikely(!isnum)) |
424 | tag_error(L, arg, LUA_TNUMBER); | 424 | tag_error(L, arg, LUA_TNUMBER); |
425 | return d; | 425 | return d; |
426 | } | 426 | } |
@@ -442,7 +442,7 @@ static void interror (lua_State *L, int arg) { | |||
442 | LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { | 442 | LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { |
443 | int isnum; | 443 | int isnum; |
444 | lua_Integer d = lua_tointegerx(L, arg, &isnum); | 444 | lua_Integer d = lua_tointegerx(L, arg, &isnum); |
445 | if (!isnum) { | 445 | if (l_unlikely(!isnum)) { |
446 | interror(L, arg); | 446 | interror(L, arg); |
447 | } | 447 | } |
448 | return d; | 448 | return d; |
@@ -475,7 +475,7 @@ static void *resizebox (lua_State *L, int idx, size_t newsize) { | |||
475 | lua_Alloc allocf = lua_getallocf(L, &ud); | 475 | lua_Alloc allocf = lua_getallocf(L, &ud); |
476 | UBox *box = (UBox *)lua_touserdata(L, idx); | 476 | UBox *box = (UBox *)lua_touserdata(L, idx); |
477 | void *temp = allocf(ud, box->box, box->bsize, newsize); | 477 | void *temp = allocf(ud, box->box, box->bsize, newsize); |
478 | if (temp == NULL && newsize > 0) { /* allocation error? */ | 478 | if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ |
479 | lua_pushliteral(L, "not enough memory"); | 479 | lua_pushliteral(L, "not enough memory"); |
480 | lua_error(L); /* raise a memory error */ | 480 | lua_error(L); /* raise a memory error */ |
481 | } | 481 | } |
@@ -516,12 +516,21 @@ static void newbox (lua_State *L) { | |||
516 | 516 | ||
517 | 517 | ||
518 | /* | 518 | /* |
519 | ** Whenever buffer is accessed, slot 'idx' must either be a box (which | ||
520 | ** cannot be NULL) or it is a placeholder for the buffer. | ||
521 | */ | ||
522 | #define checkbufferlevel(B,idx) \ | ||
523 | lua_assert(buffonstack(B) ? lua_touserdata(B->L, idx) != NULL \ | ||
524 | : lua_touserdata(B->L, idx) == (void*)B) | ||
525 | |||
526 | |||
527 | /* | ||
519 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' | 528 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' |
520 | ** bytes. | 529 | ** bytes. |
521 | */ | 530 | */ |
522 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { | 531 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { |
523 | size_t newsize = B->size * 2; /* double buffer size */ | 532 | size_t newsize = B->size * 2; /* double buffer size */ |
524 | if (MAX_SIZET - sz < B->n) /* overflow in (B->n + sz)? */ | 533 | if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ |
525 | return luaL_error(B->L, "buffer too large"); | 534 | return luaL_error(B->L, "buffer too large"); |
526 | if (newsize < B->n + sz) /* double is not big enough? */ | 535 | if (newsize < B->n + sz) /* double is not big enough? */ |
527 | newsize = B->n + sz; | 536 | newsize = B->n + sz; |
@@ -531,10 +540,11 @@ static size_t newbuffsize (luaL_Buffer *B, size_t sz) { | |||
531 | 540 | ||
532 | /* | 541 | /* |
533 | ** Returns a pointer to a free area with at least 'sz' bytes in buffer | 542 | ** Returns a pointer to a free area with at least 'sz' bytes in buffer |
534 | ** 'B'. 'boxidx' is the relative position in the stack where the | 543 | ** 'B'. 'boxidx' is the relative position in the stack where is the |
535 | ** buffer's box is or should be. | 544 | ** buffer's box or its placeholder. |
536 | */ | 545 | */ |
537 | static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { | 546 | static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { |
547 | checkbufferlevel(B, boxidx); | ||
538 | if (B->size - B->n >= sz) /* enough space? */ | 548 | if (B->size - B->n >= sz) /* enough space? */ |
539 | return B->b + B->n; | 549 | return B->b + B->n; |
540 | else { | 550 | else { |
@@ -545,6 +555,7 @@ static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { | |||
545 | if (buffonstack(B)) /* buffer already has a box? */ | 555 | if (buffonstack(B)) /* buffer already has a box? */ |
546 | newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ | 556 | newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ |
547 | else { /* no box yet */ | 557 | else { /* no box yet */ |
558 | lua_remove(L, boxidx); /* remove placeholder */ | ||
548 | newbox(L); /* create a new box */ | 559 | newbox(L); /* create a new box */ |
549 | lua_insert(L, boxidx); /* move box to its intended position */ | 560 | lua_insert(L, boxidx); /* move box to its intended position */ |
550 | lua_toclose(L, boxidx); | 561 | lua_toclose(L, boxidx); |
@@ -581,11 +592,11 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { | |||
581 | 592 | ||
582 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { | 593 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { |
583 | lua_State *L = B->L; | 594 | lua_State *L = B->L; |
595 | checkbufferlevel(B, -1); | ||
584 | lua_pushlstring(L, B->b, B->n); | 596 | lua_pushlstring(L, B->b, B->n); |
585 | if (buffonstack(B)) { | 597 | if (buffonstack(B)) |
586 | lua_closeslot(L, -2); /* close the box */ | 598 | lua_closeslot(L, -2); /* close the box */ |
587 | lua_remove(L, -2); /* remove box from the stack */ | 599 | lua_remove(L, -2); /* remove box or placeholder from the stack */ |
588 | } | ||
589 | } | 600 | } |
590 | 601 | ||
591 | 602 | ||
@@ -620,6 +631,7 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { | |||
620 | B->b = B->init.b; | 631 | B->b = B->init.b; |
621 | B->n = 0; | 632 | B->n = 0; |
622 | B->size = LUAL_BUFFERSIZE; | 633 | B->size = LUAL_BUFFERSIZE; |
634 | lua_pushlightuserdata(L, (void*)B); /* push placeholder */ | ||
623 | } | 635 | } |
624 | 636 | ||
625 | 637 | ||
@@ -861,7 +873,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { | |||
861 | int isnum; | 873 | int isnum; |
862 | lua_len(L, idx); | 874 | lua_len(L, idx); |
863 | l = lua_tointegerx(L, -1, &isnum); | 875 | l = lua_tointegerx(L, -1, &isnum); |
864 | if (!isnum) | 876 | if (l_unlikely(!isnum)) |
865 | luaL_error(L, "object length is not an integer"); | 877 | luaL_error(L, "object length is not an integer"); |
866 | lua_pop(L, 1); /* remove object */ | 878 | lua_pop(L, 1); /* remove object */ |
867 | return l; | 879 | return l; |
@@ -1074,7 +1086,7 @@ static void warnfon (void *ud, const char *message, int tocont) { | |||
1074 | 1086 | ||
1075 | LUALIB_API lua_State *luaL_newstate (void) { | 1087 | LUALIB_API lua_State *luaL_newstate (void) { |
1076 | lua_State *L = lua_newstate(l_alloc, NULL); | 1088 | lua_State *L = lua_newstate(l_alloc, NULL); |
1077 | if (L) { | 1089 | if (l_likely(L)) { |
1078 | lua_atpanic(L, &panic); | 1090 | lua_atpanic(L, &panic); |
1079 | lua_setwarnf(L, warnfoff, L); /* default is warnings off */ | 1091 | lua_setwarnf(L, warnfoff, L); /* default is warnings off */ |
1080 | } | 1092 | } |
diff --git a/src/lua/lauxlib.h b/src/lua/lauxlib.h index 6571491..9058e26 100644 --- a/src/lua/lauxlib.h +++ b/src/lua/lauxlib.h | |||
@@ -122,6 +122,10 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, | |||
122 | ** =============================================================== | 122 | ** =============================================================== |
123 | */ | 123 | */ |
124 | 124 | ||
125 | #if !defined(l_likely) | ||
126 | #define l_likely(x) x | ||
127 | #endif | ||
128 | |||
125 | 129 | ||
126 | #define luaL_newlibtable(L,l) \ | 130 | #define luaL_newlibtable(L,l) \ |
127 | lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) | 131 | lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) |
@@ -130,10 +134,10 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, | |||
130 | (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) | 134 | (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) |
131 | 135 | ||
132 | #define luaL_argcheck(L, cond,arg,extramsg) \ | 136 | #define luaL_argcheck(L, cond,arg,extramsg) \ |
133 | ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) | 137 | ((void)(l_likely(cond) || luaL_argerror(L, (arg), (extramsg)))) |
134 | 138 | ||
135 | #define luaL_argexpected(L,cond,arg,tname) \ | 139 | #define luaL_argexpected(L,cond,arg,tname) \ |
136 | ((void)((cond) || luaL_typeerror(L, (arg), (tname)))) | 140 | ((void)(l_likely(cond) || luaL_typeerror(L, (arg), (tname)))) |
137 | 141 | ||
138 | #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) | 142 | #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) |
139 | #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) | 143 | #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) |
diff --git a/src/lua/lbaselib.c b/src/lua/lbaselib.c index 747fd45..83ad306 100644 --- a/src/lua/lbaselib.c +++ b/src/lua/lbaselib.c | |||
@@ -138,7 +138,7 @@ static int luaB_setmetatable (lua_State *L) { | |||
138 | int t = lua_type(L, 2); | 138 | int t = lua_type(L, 2); |
139 | luaL_checktype(L, 1, LUA_TTABLE); | 139 | luaL_checktype(L, 1, LUA_TTABLE); |
140 | luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); | 140 | luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); |
141 | if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) | 141 | if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)) |
142 | return luaL_error(L, "cannot change a protected metatable"); | 142 | return luaL_error(L, "cannot change a protected metatable"); |
143 | lua_settop(L, 2); | 143 | lua_settop(L, 2); |
144 | lua_setmetatable(L, 1); | 144 | lua_setmetatable(L, 1); |
@@ -182,7 +182,8 @@ static int luaB_rawset (lua_State *L) { | |||
182 | 182 | ||
183 | 183 | ||
184 | static int pushmode (lua_State *L, int oldmode) { | 184 | static int pushmode (lua_State *L, int oldmode) { |
185 | lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" : "generational"); | 185 | lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" |
186 | : "generational"); | ||
186 | return 1; | 187 | return 1; |
187 | } | 188 | } |
188 | 189 | ||
@@ -299,7 +300,7 @@ static int luaB_ipairs (lua_State *L) { | |||
299 | 300 | ||
300 | 301 | ||
301 | static int load_aux (lua_State *L, int status, int envidx) { | 302 | static int load_aux (lua_State *L, int status, int envidx) { |
302 | if (status == LUA_OK) { | 303 | if (l_likely(status == LUA_OK)) { |
303 | if (envidx != 0) { /* 'env' parameter? */ | 304 | if (envidx != 0) { /* 'env' parameter? */ |
304 | lua_pushvalue(L, envidx); /* environment for loaded function */ | 305 | lua_pushvalue(L, envidx); /* environment for loaded function */ |
305 | if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ | 306 | if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ |
@@ -355,7 +356,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { | |||
355 | *size = 0; | 356 | *size = 0; |
356 | return NULL; | 357 | return NULL; |
357 | } | 358 | } |
358 | else if (!lua_isstring(L, -1)) | 359 | else if (l_unlikely(!lua_isstring(L, -1))) |
359 | luaL_error(L, "reader function must return a string"); | 360 | luaL_error(L, "reader function must return a string"); |
360 | lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ | 361 | lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ |
361 | return lua_tolstring(L, RESERVEDSLOT, size); | 362 | return lua_tolstring(L, RESERVEDSLOT, size); |
@@ -393,7 +394,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) { | |||
393 | static int luaB_dofile (lua_State *L) { | 394 | static int luaB_dofile (lua_State *L) { |
394 | const char *fname = luaL_optstring(L, 1, NULL); | 395 | const char *fname = luaL_optstring(L, 1, NULL); |
395 | lua_settop(L, 1); | 396 | lua_settop(L, 1); |
396 | if (luaL_loadfile(L, fname) != LUA_OK) | 397 | if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK)) |
397 | return lua_error(L); | 398 | return lua_error(L); |
398 | lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); | 399 | lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); |
399 | return dofilecont(L, 0, 0); | 400 | return dofilecont(L, 0, 0); |
@@ -401,7 +402,7 @@ static int luaB_dofile (lua_State *L) { | |||
401 | 402 | ||
402 | 403 | ||
403 | static int luaB_assert (lua_State *L) { | 404 | static int luaB_assert (lua_State *L) { |
404 | if (lua_toboolean(L, 1)) /* condition is true? */ | 405 | if (l_likely(lua_toboolean(L, 1))) /* condition is true? */ |
405 | return lua_gettop(L); /* return all arguments */ | 406 | return lua_gettop(L); /* return all arguments */ |
406 | else { /* error */ | 407 | else { /* error */ |
407 | luaL_checkany(L, 1); /* there must be a condition */ | 408 | luaL_checkany(L, 1); /* there must be a condition */ |
@@ -437,7 +438,7 @@ static int luaB_select (lua_State *L) { | |||
437 | ** ignored). | 438 | ** ignored). |
438 | */ | 439 | */ |
439 | static int finishpcall (lua_State *L, int status, lua_KContext extra) { | 440 | static int finishpcall (lua_State *L, int status, lua_KContext extra) { |
440 | if (status != LUA_OK && status != LUA_YIELD) { /* error? */ | 441 | if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */ |
441 | lua_pushboolean(L, 0); /* first result (false) */ | 442 | lua_pushboolean(L, 0); /* first result (false) */ |
442 | lua_pushvalue(L, -2); /* error message */ | 443 | lua_pushvalue(L, -2); /* error message */ |
443 | return 2; /* return false, msg */ | 444 | return 2; /* return false, msg */ |
diff --git a/src/lua/lcode.c b/src/lua/lcode.c index d8d353f..80d975c 100644 --- a/src/lua/lcode.c +++ b/src/lua/lcode.c | |||
@@ -314,15 +314,6 @@ void luaK_patchtohere (FuncState *fs, int list) { | |||
314 | } | 314 | } |
315 | 315 | ||
316 | 316 | ||
317 | /* | ||
318 | ** MAXimum number of successive Instructions WiTHout ABSolute line | ||
319 | ** information. | ||
320 | */ | ||
321 | #if !defined(MAXIWTHABS) | ||
322 | #define MAXIWTHABS 120 | ||
323 | #endif | ||
324 | |||
325 | |||
326 | /* limit for difference between lines in relative line info. */ | 317 | /* limit for difference between lines in relative line info. */ |
327 | #define LIMLINEDIFF 0x80 | 318 | #define LIMLINEDIFF 0x80 |
328 | 319 | ||
@@ -337,13 +328,13 @@ void luaK_patchtohere (FuncState *fs, int list) { | |||
337 | static void savelineinfo (FuncState *fs, Proto *f, int line) { | 328 | static void savelineinfo (FuncState *fs, Proto *f, int line) { |
338 | int linedif = line - fs->previousline; | 329 | int linedif = line - fs->previousline; |
339 | int pc = fs->pc - 1; /* last instruction coded */ | 330 | int pc = fs->pc - 1; /* last instruction coded */ |
340 | if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ > MAXIWTHABS) { | 331 | if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ >= MAXIWTHABS) { |
341 | luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo, | 332 | luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo, |
342 | f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines"); | 333 | f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines"); |
343 | f->abslineinfo[fs->nabslineinfo].pc = pc; | 334 | f->abslineinfo[fs->nabslineinfo].pc = pc; |
344 | f->abslineinfo[fs->nabslineinfo++].line = line; | 335 | f->abslineinfo[fs->nabslineinfo++].line = line; |
345 | linedif = ABSLINEINFO; /* signal that there is absolute information */ | 336 | linedif = ABSLINEINFO; /* signal that there is absolute information */ |
346 | fs->iwthabs = 0; /* restart counter */ | 337 | fs->iwthabs = 1; /* restart counter */ |
347 | } | 338 | } |
348 | luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte, | 339 | luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte, |
349 | MAX_INT, "opcodes"); | 340 | MAX_INT, "opcodes"); |
@@ -1307,7 +1298,8 @@ static int validop (int op, TValue *v1, TValue *v2) { | |||
1307 | case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: | 1298 | case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: |
1308 | case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ | 1299 | case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ |
1309 | lua_Integer i; | 1300 | lua_Integer i; |
1310 | return (tointegerns(v1, &i) && tointegerns(v2, &i)); | 1301 | return (luaV_tointegerns(v1, &i, LUA_FLOORN2I) && |
1302 | luaV_tointegerns(v2, &i, LUA_FLOORN2I)); | ||
1311 | } | 1303 | } |
1312 | case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ | 1304 | case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ |
1313 | return (nvalue(v2) != 0); | 1305 | return (nvalue(v2) != 0); |
diff --git a/src/lua/lcorolib.c b/src/lua/lcorolib.c index ed7c58b..fedbebe 100644 --- a/src/lua/lcorolib.c +++ b/src/lua/lcorolib.c | |||
@@ -31,14 +31,14 @@ static lua_State *getco (lua_State *L) { | |||
31 | */ | 31 | */ |
32 | static int auxresume (lua_State *L, lua_State *co, int narg) { | 32 | static int auxresume (lua_State *L, lua_State *co, int narg) { |
33 | int status, nres; | 33 | int status, nres; |
34 | if (!lua_checkstack(co, narg)) { | 34 | if (l_unlikely(!lua_checkstack(co, narg))) { |
35 | lua_pushliteral(L, "too many arguments to resume"); | 35 | lua_pushliteral(L, "too many arguments to resume"); |
36 | return -1; /* error flag */ | 36 | return -1; /* error flag */ |
37 | } | 37 | } |
38 | lua_xmove(L, co, narg); | 38 | lua_xmove(L, co, narg); |
39 | status = lua_resume(co, L, narg, &nres); | 39 | status = lua_resume(co, L, narg, &nres); |
40 | if (status == LUA_OK || status == LUA_YIELD) { | 40 | if (l_likely(status == LUA_OK || status == LUA_YIELD)) { |
41 | if (!lua_checkstack(L, nres + 1)) { | 41 | if (l_unlikely(!lua_checkstack(L, nres + 1))) { |
42 | lua_pop(co, nres); /* remove results anyway */ | 42 | lua_pop(co, nres); /* remove results anyway */ |
43 | lua_pushliteral(L, "too many results to resume"); | 43 | lua_pushliteral(L, "too many results to resume"); |
44 | return -1; /* error flag */ | 44 | return -1; /* error flag */ |
@@ -57,7 +57,7 @@ static int luaB_coresume (lua_State *L) { | |||
57 | lua_State *co = getco(L); | 57 | lua_State *co = getco(L); |
58 | int r; | 58 | int r; |
59 | r = auxresume(L, co, lua_gettop(L) - 1); | 59 | r = auxresume(L, co, lua_gettop(L) - 1); |
60 | if (r < 0) { | 60 | if (l_unlikely(r < 0)) { |
61 | lua_pushboolean(L, 0); | 61 | lua_pushboolean(L, 0); |
62 | lua_insert(L, -2); | 62 | lua_insert(L, -2); |
63 | return 2; /* return false + error message */ | 63 | return 2; /* return false + error message */ |
@@ -73,7 +73,7 @@ static int luaB_coresume (lua_State *L) { | |||
73 | static int luaB_auxwrap (lua_State *L) { | 73 | static int luaB_auxwrap (lua_State *L) { |
74 | lua_State *co = lua_tothread(L, lua_upvalueindex(1)); | 74 | lua_State *co = lua_tothread(L, lua_upvalueindex(1)); |
75 | int r = auxresume(L, co, lua_gettop(L)); | 75 | int r = auxresume(L, co, lua_gettop(L)); |
76 | if (r < 0) { /* error? */ | 76 | if (l_unlikely(r < 0)) { /* error? */ |
77 | int stat = lua_status(co); | 77 | int stat = lua_status(co); |
78 | if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ | 78 | if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ |
79 | stat = lua_resetthread(co); /* close its tbc variables */ | 79 | stat = lua_resetthread(co); /* close its tbc variables */ |
diff --git a/src/lua/ldblib.c b/src/lua/ldblib.c index 15593bf..6dcbaa9 100644 --- a/src/lua/ldblib.c +++ b/src/lua/ldblib.c | |||
@@ -33,7 +33,7 @@ static const char *const HOOKKEY = "_HOOKKEY"; | |||
33 | ** checked. | 33 | ** checked. |
34 | */ | 34 | */ |
35 | static void checkstack (lua_State *L, lua_State *L1, int n) { | 35 | static void checkstack (lua_State *L, lua_State *L1, int n) { |
36 | if (L != L1 && !lua_checkstack(L1, n)) | 36 | if (l_unlikely(L != L1 && !lua_checkstack(L1, n))) |
37 | luaL_error(L, "stack overflow"); | 37 | luaL_error(L, "stack overflow"); |
38 | } | 38 | } |
39 | 39 | ||
@@ -152,6 +152,7 @@ static int db_getinfo (lua_State *L) { | |||
152 | lua_State *L1 = getthread(L, &arg); | 152 | lua_State *L1 = getthread(L, &arg); |
153 | const char *options = luaL_optstring(L, arg+2, "flnSrtu"); | 153 | const char *options = luaL_optstring(L, arg+2, "flnSrtu"); |
154 | checkstack(L, L1, 3); | 154 | checkstack(L, L1, 3); |
155 | luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'"); | ||
155 | if (lua_isfunction(L, arg + 1)) { /* info about a function? */ | 156 | if (lua_isfunction(L, arg + 1)) { /* info about a function? */ |
156 | options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ | 157 | options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ |
157 | lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ | 158 | lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ |
@@ -212,7 +213,7 @@ static int db_getlocal (lua_State *L) { | |||
212 | lua_Debug ar; | 213 | lua_Debug ar; |
213 | const char *name; | 214 | const char *name; |
214 | int level = (int)luaL_checkinteger(L, arg + 1); | 215 | int level = (int)luaL_checkinteger(L, arg + 1); |
215 | if (!lua_getstack(L1, level, &ar)) /* out of range? */ | 216 | if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */ |
216 | return luaL_argerror(L, arg+1, "level out of range"); | 217 | return luaL_argerror(L, arg+1, "level out of range"); |
217 | checkstack(L, L1, 1); | 218 | checkstack(L, L1, 1); |
218 | name = lua_getlocal(L1, &ar, nvar); | 219 | name = lua_getlocal(L1, &ar, nvar); |
@@ -237,7 +238,7 @@ static int db_setlocal (lua_State *L) { | |||
237 | lua_Debug ar; | 238 | lua_Debug ar; |
238 | int level = (int)luaL_checkinteger(L, arg + 1); | 239 | int level = (int)luaL_checkinteger(L, arg + 1); |
239 | int nvar = (int)luaL_checkinteger(L, arg + 2); | 240 | int nvar = (int)luaL_checkinteger(L, arg + 2); |
240 | if (!lua_getstack(L1, level, &ar)) /* out of range? */ | 241 | if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */ |
241 | return luaL_argerror(L, arg+1, "level out of range"); | 242 | return luaL_argerror(L, arg+1, "level out of range"); |
242 | luaL_checkany(L, arg+3); | 243 | luaL_checkany(L, arg+3); |
243 | lua_settop(L, arg+3); | 244 | lua_settop(L, arg+3); |
diff --git a/src/lua/ldebug.c b/src/lua/ldebug.c index 819550d..8e3657a 100644 --- a/src/lua/ldebug.c +++ b/src/lua/ldebug.c | |||
@@ -33,8 +33,6 @@ | |||
33 | 33 | ||
34 | #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) | 34 | #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) |
35 | 35 | ||
36 | /* inverse of 'pcRel' */ | ||
37 | #define invpcRel(pc, p) ((p)->code + (pc) + 1) | ||
38 | 36 | ||
39 | static const char *funcnamefromcode (lua_State *L, CallInfo *ci, | 37 | static const char *funcnamefromcode (lua_State *L, CallInfo *ci, |
40 | const char **name); | 38 | const char **name); |
@@ -48,10 +46,14 @@ static int currentpc (CallInfo *ci) { | |||
48 | 46 | ||
49 | /* | 47 | /* |
50 | ** Get a "base line" to find the line corresponding to an instruction. | 48 | ** Get a "base line" to find the line corresponding to an instruction. |
51 | ** For that, search the array of absolute line info for the largest saved | 49 | ** Base lines are regularly placed at MAXIWTHABS intervals, so usually |
52 | ** instruction smaller or equal to the wanted instruction. A special | 50 | ** an integer division gets the right place. When the source file has |
53 | ** case is when there is no absolute info or the instruction is before | 51 | ** large sequences of empty/comment lines, it may need extra entries, |
54 | ** the first absolute one. | 52 | ** so the original estimate needs a correction. |
53 | ** The assertion that the estimate is a lower bound for the correct base | ||
54 | ** is valid as long as the debug info has been generated with the same | ||
55 | ** value for MAXIWTHABS or smaller. (Previous releases use a little | ||
56 | ** smaller value.) | ||
55 | */ | 57 | */ |
56 | static int getbaseline (const Proto *f, int pc, int *basepc) { | 58 | static int getbaseline (const Proto *f, int pc, int *basepc) { |
57 | if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) { | 59 | if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) { |
@@ -59,20 +61,11 @@ static int getbaseline (const Proto *f, int pc, int *basepc) { | |||
59 | return f->linedefined; | 61 | return f->linedefined; |
60 | } | 62 | } |
61 | else { | 63 | else { |
62 | unsigned int i; | 64 | int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */ |
63 | if (pc >= f->abslineinfo[f->sizeabslineinfo - 1].pc) | 65 | /* estimate must be a lower bond of the correct base */ |
64 | i = f->sizeabslineinfo - 1; /* instruction is after last saved one */ | 66 | lua_assert(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc); |
65 | else { /* binary search */ | 67 | while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc) |
66 | unsigned int j = f->sizeabslineinfo - 1; /* pc < anchorlines[j] */ | 68 | i++; /* low estimate; adjust it */ |
67 | i = 0; /* abslineinfo[i] <= pc */ | ||
68 | while (i < j - 1) { | ||
69 | unsigned int m = (j + i) / 2; | ||
70 | if (pc >= f->abslineinfo[m].pc) | ||
71 | i = m; | ||
72 | else | ||
73 | j = m; | ||
74 | } | ||
75 | } | ||
76 | *basepc = f->abslineinfo[i].pc; | 69 | *basepc = f->abslineinfo[i].pc; |
77 | return f->abslineinfo[i].line; | 70 | return f->abslineinfo[i].line; |
78 | } | 71 | } |
@@ -305,8 +298,8 @@ static void collectvalidlines (lua_State *L, Closure *f) { | |||
305 | sethvalue2s(L, L->top, t); /* push it on stack */ | 298 | sethvalue2s(L, L->top, t); /* push it on stack */ |
306 | api_incr_top(L); | 299 | api_incr_top(L); |
307 | setbtvalue(&v); /* boolean 'true' to be the value of all indices */ | 300 | setbtvalue(&v); /* boolean 'true' to be the value of all indices */ |
308 | for (i = 0; i < p->sizelineinfo; i++) { /* for all lines with code */ | 301 | for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */ |
309 | currentline = nextline(p, currentline, i); | 302 | currentline = nextline(p, currentline, i); /* get its line */ |
310 | luaH_setint(L, t, currentline, &v); /* table[line] = true */ | 303 | luaH_setint(L, t, currentline, &v); /* table[line] = true */ |
311 | } | 304 | } |
312 | } | 305 | } |
@@ -645,14 +638,18 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, | |||
645 | 638 | ||
646 | 639 | ||
647 | /* | 640 | /* |
648 | ** The subtraction of two potentially unrelated pointers is | 641 | ** Check whether pointer 'o' points to some value in the stack |
649 | ** not ISO C, but it should not crash a program; the subsequent | 642 | ** frame of the current function. Because 'o' may not point to a |
650 | ** checks are ISO C and ensure a correct result. | 643 | ** value in this stack, we cannot compare it with the region |
644 | ** boundaries (undefined behaviour in ISO C). | ||
651 | */ | 645 | */ |
652 | static int isinstack (CallInfo *ci, const TValue *o) { | 646 | static int isinstack (CallInfo *ci, const TValue *o) { |
653 | StkId base = ci->func + 1; | 647 | StkId pos; |
654 | ptrdiff_t i = cast(StkId, o) - base; | 648 | for (pos = ci->func + 1; pos < ci->top; pos++) { |
655 | return (0 <= i && i < (ci->top - base) && s2v(base + i) == o); | 649 | if (o == s2v(pos)) |
650 | return 1; | ||
651 | } | ||
652 | return 0; /* not found */ | ||
656 | } | 653 | } |
657 | 654 | ||
658 | 655 | ||
@@ -733,7 +730,7 @@ l_noret luaG_opinterror (lua_State *L, const TValue *p1, | |||
733 | */ | 730 | */ |
734 | l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { | 731 | l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { |
735 | lua_Integer temp; | 732 | lua_Integer temp; |
736 | if (!tointegerns(p1, &temp)) | 733 | if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I)) |
737 | p2 = p1; | 734 | p2 = p1; |
738 | luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); | 735 | luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); |
739 | } | 736 | } |
@@ -791,16 +788,30 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { | |||
791 | 788 | ||
792 | /* | 789 | /* |
793 | ** Check whether new instruction 'newpc' is in a different line from | 790 | ** Check whether new instruction 'newpc' is in a different line from |
794 | ** previous instruction 'oldpc'. | 791 | ** previous instruction 'oldpc'. More often than not, 'newpc' is only |
792 | ** one or a few instructions after 'oldpc' (it must be after, see | ||
793 | ** caller), so try to avoid calling 'luaG_getfuncline'. If they are | ||
794 | ** too far apart, there is a good chance of a ABSLINEINFO in the way, | ||
795 | ** so it goes directly to 'luaG_getfuncline'. | ||
795 | */ | 796 | */ |
796 | static int changedline (const Proto *p, int oldpc, int newpc) { | 797 | static int changedline (const Proto *p, int oldpc, int newpc) { |
797 | if (p->lineinfo == NULL) /* no debug information? */ | 798 | if (p->lineinfo == NULL) /* no debug information? */ |
798 | return 0; | 799 | return 0; |
799 | while (oldpc++ < newpc) { | 800 | if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ |
800 | if (p->lineinfo[oldpc] != 0) | 801 | int delta = 0; /* line diference */ |
801 | return (luaG_getfuncline(p, oldpc - 1) != luaG_getfuncline(p, newpc)); | 802 | int pc = oldpc; |
803 | for (;;) { | ||
804 | int lineinfo = p->lineinfo[++pc]; | ||
805 | if (lineinfo == ABSLINEINFO) | ||
806 | break; /* cannot compute delta; fall through */ | ||
807 | delta += lineinfo; | ||
808 | if (pc == newpc) | ||
809 | return (delta != 0); /* delta computed successfully */ | ||
810 | } | ||
802 | } | 811 | } |
803 | return 0; /* no line changes between positions */ | 812 | /* either instructions are too far apart or there is an absolute line |
813 | info in the way; compute line difference explicitly */ | ||
814 | return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc)); | ||
804 | } | 815 | } |
805 | 816 | ||
806 | 817 | ||
@@ -808,20 +819,19 @@ static int changedline (const Proto *p, int oldpc, int newpc) { | |||
808 | ** Traces the execution of a Lua function. Called before the execution | 819 | ** Traces the execution of a Lua function. Called before the execution |
809 | ** of each opcode, when debug is on. 'L->oldpc' stores the last | 820 | ** of each opcode, when debug is on. 'L->oldpc' stores the last |
810 | ** instruction traced, to detect line changes. When entering a new | 821 | ** instruction traced, to detect line changes. When entering a new |
811 | ** function, 'npci' will be zero and will test as a new line without | 822 | ** function, 'npci' will be zero and will test as a new line whatever |
812 | ** the need for 'oldpc'; so, 'oldpc' does not need to be initialized | 823 | ** the value of 'oldpc'. Some exceptional conditions may return to |
813 | ** before. Some exceptional conditions may return to a function without | 824 | ** a function without setting 'oldpc'. In that case, 'oldpc' may be |
814 | ** updating 'oldpc'. In that case, 'oldpc' may be invalid; if so, it is | 825 | ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' |
815 | ** reset to zero. (A wrong but valid 'oldpc' at most causes an extra | 826 | ** at most causes an extra call to a line hook.) |
816 | ** call to a line hook.) | 827 | ** This function is not "Protected" when called, so it should correct |
828 | ** 'L->top' before calling anything that can run the GC. | ||
817 | */ | 829 | */ |
818 | int luaG_traceexec (lua_State *L, const Instruction *pc) { | 830 | int luaG_traceexec (lua_State *L, const Instruction *pc) { |
819 | CallInfo *ci = L->ci; | 831 | CallInfo *ci = L->ci; |
820 | lu_byte mask = L->hookmask; | 832 | lu_byte mask = L->hookmask; |
821 | const Proto *p = ci_func(ci)->p; | 833 | const Proto *p = ci_func(ci)->p; |
822 | int counthook; | 834 | int counthook; |
823 | /* 'L->oldpc' may be invalid; reset it in this case */ | ||
824 | int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; | ||
825 | if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ | 835 | if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ |
826 | ci->u.l.trap = 0; /* don't need to stop again */ | 836 | ci->u.l.trap = 0; /* don't need to stop again */ |
827 | return 0; /* turn off 'trap' */ | 837 | return 0; /* turn off 'trap' */ |
@@ -837,15 +847,16 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { | |||
837 | ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ | 847 | ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ |
838 | return 1; /* do not call hook again (VM yielded, so it did not move) */ | 848 | return 1; /* do not call hook again (VM yielded, so it did not move) */ |
839 | } | 849 | } |
840 | if (!isIT(*(ci->u.l.savedpc - 1))) | 850 | if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ |
841 | L->top = ci->top; /* prepare top */ | 851 | L->top = ci->top; /* correct top */ |
842 | if (counthook) | 852 | if (counthook) |
843 | luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ | 853 | luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ |
844 | if (mask & LUA_MASKLINE) { | 854 | if (mask & LUA_MASKLINE) { |
855 | /* 'L->oldpc' may be invalid; use zero in this case */ | ||
856 | int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; | ||
845 | int npci = pcRel(pc, p); | 857 | int npci = pcRel(pc, p); |
846 | if (npci == 0 || /* call linehook when enter a new function, */ | 858 | if (npci <= oldpc || /* call hook when jump back (loop), */ |
847 | pc <= invpcRel(oldpc, p) || /* when jump back (loop), or when */ | 859 | changedline(p, oldpc, npci)) { /* or when enter new line */ |
848 | changedline(p, oldpc, npci)) { /* enter new line */ | ||
849 | int newline = luaG_getfuncline(p, npci); | 860 | int newline = luaG_getfuncline(p, npci); |
850 | luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ | 861 | luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ |
851 | } | 862 | } |
diff --git a/src/lua/ldebug.h b/src/lua/ldebug.h index 55b3ae0..974960e 100644 --- a/src/lua/ldebug.h +++ b/src/lua/ldebug.h | |||
@@ -26,6 +26,16 @@ | |||
26 | */ | 26 | */ |
27 | #define ABSLINEINFO (-0x80) | 27 | #define ABSLINEINFO (-0x80) |
28 | 28 | ||
29 | |||
30 | /* | ||
31 | ** MAXimum number of successive Instructions WiTHout ABSolute line | ||
32 | ** information. (A power of two allows fast divisions.) | ||
33 | */ | ||
34 | #if !defined(MAXIWTHABS) | ||
35 | #define MAXIWTHABS 128 | ||
36 | #endif | ||
37 | |||
38 | |||
29 | LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc); | 39 | LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc); |
30 | LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, | 40 | LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, |
31 | StkId *pos); | 41 | StkId *pos); |
diff --git a/src/lua/ldo.c b/src/lua/ldo.c index aa159cf..7135079 100644 --- a/src/lua/ldo.c +++ b/src/lua/ldo.c | |||
@@ -160,9 +160,8 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
160 | static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { | 160 | static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { |
161 | CallInfo *ci; | 161 | CallInfo *ci; |
162 | UpVal *up; | 162 | UpVal *up; |
163 | if (oldstack == newstack) | ||
164 | return; /* stack address did not change */ | ||
165 | L->top = (L->top - oldstack) + newstack; | 163 | L->top = (L->top - oldstack) + newstack; |
164 | L->tbclist = (L->tbclist - oldstack) + newstack; | ||
166 | for (up = L->openupval; up != NULL; up = up->u.open.next) | 165 | for (up = L->openupval; up != NULL; up = up->u.open.next) |
167 | up->v = s2v((uplevel(up) - oldstack) + newstack); | 166 | up->v = s2v((uplevel(up) - oldstack) + newstack); |
168 | for (ci = L->ci; ci != NULL; ci = ci->previous) { | 167 | for (ci = L->ci; ci != NULL; ci = ci->previous) { |
@@ -178,19 +177,35 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { | |||
178 | #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) | 177 | #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) |
179 | 178 | ||
180 | 179 | ||
180 | /* | ||
181 | ** Reallocate the stack to a new size, correcting all pointers into | ||
182 | ** it. (There are pointers to a stack from its upvalues, from its list | ||
183 | ** of call infos, plus a few individual pointers.) The reallocation is | ||
184 | ** done in two steps (allocation + free) because the correction must be | ||
185 | ** done while both addresses (the old stack and the new one) are valid. | ||
186 | ** (In ISO C, any pointer use after the pointer has been deallocated is | ||
187 | ** undefined behavior.) | ||
188 | ** In case of allocation error, raise an error or return false according | ||
189 | ** to 'raiseerror'. | ||
190 | */ | ||
181 | int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | 191 | int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { |
182 | int lim = stacksize(L); | 192 | int oldsize = stacksize(L); |
183 | StkId newstack = luaM_reallocvector(L, L->stack, | 193 | int i; |
184 | lim + EXTRA_STACK, newsize + EXTRA_STACK, StackValue); | 194 | StkId newstack = luaM_reallocvector(L, NULL, 0, |
195 | newsize + EXTRA_STACK, StackValue); | ||
185 | lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); | 196 | lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); |
186 | if (unlikely(newstack == NULL)) { /* reallocation failed? */ | 197 | if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ |
187 | if (raiseerror) | 198 | if (raiseerror) |
188 | luaM_error(L); | 199 | luaM_error(L); |
189 | else return 0; /* do not raise an error */ | 200 | else return 0; /* do not raise an error */ |
190 | } | 201 | } |
191 | for (; lim < newsize; lim++) | 202 | /* number of elements to be copied to the new stack */ |
192 | setnilvalue(s2v(newstack + lim + EXTRA_STACK)); /* erase new segment */ | 203 | i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK; |
204 | memcpy(newstack, L->stack, i * sizeof(StackValue)); | ||
205 | for (; i < newsize + EXTRA_STACK; i++) | ||
206 | setnilvalue(s2v(newstack + i)); /* erase new segment */ | ||
193 | correctstack(L, L->stack, newstack); | 207 | correctstack(L, L->stack, newstack); |
208 | luaM_freearray(L, L->stack, oldsize + EXTRA_STACK); | ||
194 | L->stack = newstack; | 209 | L->stack = newstack; |
195 | L->stack_last = L->stack + newsize; | 210 | L->stack_last = L->stack + newsize; |
196 | return 1; | 211 | return 1; |
@@ -203,7 +218,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | |||
203 | */ | 218 | */ |
204 | int luaD_growstack (lua_State *L, int n, int raiseerror) { | 219 | int luaD_growstack (lua_State *L, int n, int raiseerror) { |
205 | int size = stacksize(L); | 220 | int size = stacksize(L); |
206 | if (unlikely(size > LUAI_MAXSTACK)) { | 221 | if (l_unlikely(size > LUAI_MAXSTACK)) { |
207 | /* if stack is larger than maximum, thread is already using the | 222 | /* if stack is larger than maximum, thread is already using the |
208 | extra space reserved for errors, that is, thread is handling | 223 | extra space reserved for errors, that is, thread is handling |
209 | a stack error; cannot grow further than that. */ | 224 | a stack error; cannot grow further than that. */ |
@@ -219,7 +234,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) { | |||
219 | newsize = LUAI_MAXSTACK; | 234 | newsize = LUAI_MAXSTACK; |
220 | if (newsize < needed) /* but must respect what was asked for */ | 235 | if (newsize < needed) /* but must respect what was asked for */ |
221 | newsize = needed; | 236 | newsize = needed; |
222 | if (likely(newsize <= LUAI_MAXSTACK)) | 237 | if (l_likely(newsize <= LUAI_MAXSTACK)) |
223 | return luaD_reallocstack(L, newsize, raiseerror); | 238 | return luaD_reallocstack(L, newsize, raiseerror); |
224 | else { /* stack overflow */ | 239 | else { /* stack overflow */ |
225 | /* add extra size to be able to handle the error message */ | 240 | /* add extra size to be able to handle the error message */ |
@@ -294,8 +309,8 @@ void luaD_hook (lua_State *L, int event, int line, | |||
294 | if (hook && L->allowhook) { /* make sure there is a hook */ | 309 | if (hook && L->allowhook) { /* make sure there is a hook */ |
295 | int mask = CIST_HOOKED; | 310 | int mask = CIST_HOOKED; |
296 | CallInfo *ci = L->ci; | 311 | CallInfo *ci = L->ci; |
297 | ptrdiff_t top = savestack(L, L->top); | 312 | ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */ |
298 | ptrdiff_t ci_top = savestack(L, ci->top); | 313 | ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */ |
299 | lua_Debug ar; | 314 | lua_Debug ar; |
300 | ar.event = event; | 315 | ar.event = event; |
301 | ar.currentline = line; | 316 | ar.currentline = line; |
@@ -305,8 +320,10 @@ void luaD_hook (lua_State *L, int event, int line, | |||
305 | ci->u2.transferinfo.ftransfer = ftransfer; | 320 | ci->u2.transferinfo.ftransfer = ftransfer; |
306 | ci->u2.transferinfo.ntransfer = ntransfer; | 321 | ci->u2.transferinfo.ntransfer = ntransfer; |
307 | } | 322 | } |
323 | if (isLua(ci) && L->top < ci->top) | ||
324 | L->top = ci->top; /* protect entire activation register */ | ||
308 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | 325 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ |
309 | if (L->top + LUA_MINSTACK > ci->top) | 326 | if (ci->top < L->top + LUA_MINSTACK) |
310 | ci->top = L->top + LUA_MINSTACK; | 327 | ci->top = L->top + LUA_MINSTACK; |
311 | L->allowhook = 0; /* cannot call hooks inside a hook */ | 328 | L->allowhook = 0; /* cannot call hooks inside a hook */ |
312 | ci->callstatus |= mask; | 329 | ci->callstatus |= mask; |
@@ -328,38 +345,40 @@ void luaD_hook (lua_State *L, int event, int line, | |||
328 | ** active. | 345 | ** active. |
329 | */ | 346 | */ |
330 | void luaD_hookcall (lua_State *L, CallInfo *ci) { | 347 | void luaD_hookcall (lua_State *L, CallInfo *ci) { |
331 | int hook = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL : LUA_HOOKCALL; | 348 | L->oldpc = 0; /* set 'oldpc' for new function */ |
332 | Proto *p; | 349 | if (L->hookmask & LUA_MASKCALL) { /* is call hook on? */ |
333 | if (!(L->hookmask & LUA_MASKCALL)) /* some other hook? */ | 350 | int event = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL |
334 | return; /* don't call hook */ | 351 | : LUA_HOOKCALL; |
335 | p = clLvalue(s2v(ci->func))->p; | ||
336 | L->top = ci->top; /* prepare top */ | ||
337 | ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ | ||
338 | luaD_hook(L, hook, -1, 1, p->numparams); | ||
339 | ci->u.l.savedpc--; /* correct 'pc' */ | ||
340 | } | ||
341 | |||
342 | |||
343 | static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { | ||
344 | ptrdiff_t oldtop = savestack(L, L->top); /* hook may change top */ | ||
345 | int delta = 0; | ||
346 | if (isLuacode(ci)) { | ||
347 | Proto *p = ci_func(ci)->p; | 352 | Proto *p = ci_func(ci)->p; |
348 | if (p->is_vararg) | 353 | ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ |
349 | delta = ci->u.l.nextraargs + p->numparams + 1; | 354 | luaD_hook(L, event, -1, 1, p->numparams); |
350 | if (L->top < ci->top) | 355 | ci->u.l.savedpc--; /* correct 'pc' */ |
351 | L->top = ci->top; /* correct top to run hook */ | ||
352 | } | 356 | } |
357 | } | ||
358 | |||
359 | |||
360 | /* | ||
361 | ** Executes a return hook for Lua and C functions and sets/corrects | ||
362 | ** 'oldpc'. (Note that this correction is needed by the line hook, so it | ||
363 | ** is done even when return hooks are off.) | ||
364 | */ | ||
365 | static void rethook (lua_State *L, CallInfo *ci, int nres) { | ||
353 | if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ | 366 | if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ |
367 | StkId firstres = L->top - nres; /* index of first result */ | ||
368 | int delta = 0; /* correction for vararg functions */ | ||
354 | int ftransfer; | 369 | int ftransfer; |
370 | if (isLua(ci)) { | ||
371 | Proto *p = ci_func(ci)->p; | ||
372 | if (p->is_vararg) | ||
373 | delta = ci->u.l.nextraargs + p->numparams + 1; | ||
374 | } | ||
355 | ci->func += delta; /* if vararg, back to virtual 'func' */ | 375 | ci->func += delta; /* if vararg, back to virtual 'func' */ |
356 | ftransfer = cast(unsigned short, firstres - ci->func); | 376 | ftransfer = cast(unsigned short, firstres - ci->func); |
357 | luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ | 377 | luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ |
358 | ci->func -= delta; | 378 | ci->func -= delta; |
359 | } | 379 | } |
360 | if (isLua(ci = ci->previous)) | 380 | if (isLua(ci = ci->previous)) |
361 | L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* update 'oldpc' */ | 381 | L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ |
362 | return restorestack(L, oldtop); | ||
363 | } | 382 | } |
364 | 383 | ||
365 | 384 | ||
@@ -371,7 +390,7 @@ static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { | |||
371 | void luaD_tryfuncTM (lua_State *L, StkId func) { | 390 | void luaD_tryfuncTM (lua_State *L, StkId func) { |
372 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); | 391 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); |
373 | StkId p; | 392 | StkId p; |
374 | if (unlikely(ttisnil(tm))) | 393 | if (l_unlikely(ttisnil(tm))) |
375 | luaG_callerror(L, s2v(func)); /* nothing to call */ | 394 | luaG_callerror(L, s2v(func)); /* nothing to call */ |
376 | for (p = L->top; p > func; p--) /* open space for metamethod */ | 395 | for (p = L->top; p > func; p--) /* open space for metamethod */ |
377 | setobjs2s(L, p, p-1); | 396 | setobjs2s(L, p, p-1); |
@@ -396,27 +415,34 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) { | |||
396 | case 1: /* one value needed */ | 415 | case 1: /* one value needed */ |
397 | if (nres == 0) /* no results? */ | 416 | if (nres == 0) /* no results? */ |
398 | setnilvalue(s2v(res)); /* adjust with nil */ | 417 | setnilvalue(s2v(res)); /* adjust with nil */ |
399 | else | 418 | else /* at least one result */ |
400 | setobjs2s(L, res, L->top - nres); /* move it to proper place */ | 419 | setobjs2s(L, res, L->top - nres); /* move it to proper place */ |
401 | L->top = res + 1; | 420 | L->top = res + 1; |
402 | return; | 421 | return; |
403 | case LUA_MULTRET: | 422 | case LUA_MULTRET: |
404 | wanted = nres; /* we want all results */ | 423 | wanted = nres; /* we want all results */ |
405 | break; | 424 | break; |
406 | default: /* multiple results (or to-be-closed variables) */ | 425 | default: /* two/more results and/or to-be-closed variables */ |
407 | if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ | 426 | if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ |
408 | ptrdiff_t savedres = savestack(L, res); | 427 | ptrdiff_t savedres = savestack(L, res); |
409 | luaF_close(L, res, CLOSEKTOP, 0); /* may change the stack */ | 428 | L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ |
410 | res = restorestack(L, savedres); | 429 | L->ci->u2.nres = nres; |
411 | wanted = codeNresults(wanted); /* correct value */ | 430 | luaF_close(L, res, CLOSEKTOP, 1); |
431 | L->ci->callstatus &= ~CIST_CLSRET; | ||
432 | if (L->hookmask) /* if needed, call hook after '__close's */ | ||
433 | rethook(L, L->ci, nres); | ||
434 | res = restorestack(L, savedres); /* close and hook can move stack */ | ||
435 | wanted = decodeNresults(wanted); | ||
412 | if (wanted == LUA_MULTRET) | 436 | if (wanted == LUA_MULTRET) |
413 | wanted = nres; | 437 | wanted = nres; /* we want all results */ |
414 | } | 438 | } |
415 | break; | 439 | break; |
416 | } | 440 | } |
441 | /* generic case */ | ||
417 | firstresult = L->top - nres; /* index of first result */ | 442 | firstresult = L->top - nres; /* index of first result */ |
418 | /* move all results to correct place */ | 443 | if (nres > wanted) /* extra results? */ |
419 | for (i = 0; i < nres && i < wanted; i++) | 444 | nres = wanted; /* don't need them */ |
445 | for (i = 0; i < nres; i++) /* move all results to correct place */ | ||
420 | setobjs2s(L, res + i, firstresult + i); | 446 | setobjs2s(L, res + i, firstresult + i); |
421 | for (; i < wanted; i++) /* complete wanted number of results */ | 447 | for (; i < wanted; i++) /* complete wanted number of results */ |
422 | setnilvalue(s2v(res + i)); | 448 | setnilvalue(s2v(res + i)); |
@@ -425,15 +451,21 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) { | |||
425 | 451 | ||
426 | 452 | ||
427 | /* | 453 | /* |
428 | ** Finishes a function call: calls hook if necessary, removes CallInfo, | 454 | ** Finishes a function call: calls hook if necessary, moves current |
429 | ** moves current number of results to proper place. | 455 | ** number of results to proper place, and returns to previous call |
456 | ** info. If function has to close variables, hook must be called after | ||
457 | ** that. | ||
430 | */ | 458 | */ |
431 | void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { | 459 | void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { |
432 | if (L->hookmask) | 460 | int wanted = ci->nresults; |
433 | L->top = rethook(L, ci, L->top - nres, nres); | 461 | if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) |
434 | L->ci = ci->previous; /* back to caller */ | 462 | rethook(L, ci, nres); |
435 | /* move results to proper place */ | 463 | /* move results to proper place */ |
436 | moveresults(L, ci->func, nres, ci->nresults); | 464 | moveresults(L, ci->func, nres, wanted); |
465 | /* function cannot be in any of these cases when returning */ | ||
466 | lua_assert(!(ci->callstatus & | ||
467 | (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET))); | ||
468 | L->ci = ci->previous; /* back to caller (after closing variables) */ | ||
437 | } | 469 | } |
438 | 470 | ||
439 | 471 | ||
@@ -492,7 +524,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { | |||
492 | ci->top = L->top + LUA_MINSTACK; | 524 | ci->top = L->top + LUA_MINSTACK; |
493 | ci->func = func; | 525 | ci->func = func; |
494 | lua_assert(ci->top <= L->stack_last); | 526 | lua_assert(ci->top <= L->stack_last); |
495 | if (L->hookmask & LUA_MASKCALL) { | 527 | if (l_unlikely(L->hookmask & LUA_MASKCALL)) { |
496 | int narg = cast_int(L->top - func) - 1; | 528 | int narg = cast_int(L->top - func) - 1; |
497 | luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); | 529 | luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); |
498 | } | 530 | } |
@@ -538,7 +570,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { | |||
538 | static void ccall (lua_State *L, StkId func, int nResults, int inc) { | 570 | static void ccall (lua_State *L, StkId func, int nResults, int inc) { |
539 | CallInfo *ci; | 571 | CallInfo *ci; |
540 | L->nCcalls += inc; | 572 | L->nCcalls += inc; |
541 | if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) | 573 | if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) |
542 | luaE_checkcstack(L); | 574 | luaE_checkcstack(L); |
543 | if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ | 575 | if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ |
544 | ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ | 576 | ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ |
@@ -565,27 +597,74 @@ void luaD_callnoyield (lua_State *L, StkId func, int nResults) { | |||
565 | 597 | ||
566 | 598 | ||
567 | /* | 599 | /* |
568 | ** Completes the execution of an interrupted C function, calling its | 600 | ** Finish the job of 'lua_pcallk' after it was interrupted by an yield. |
569 | ** continuation function. | 601 | ** (The caller, 'finishCcall', does the final call to 'adjustresults'.) |
602 | ** The main job is to complete the 'luaD_pcall' called by 'lua_pcallk'. | ||
603 | ** If a '__close' method yields here, eventually control will be back | ||
604 | ** to 'finishCcall' (when that '__close' method finally returns) and | ||
605 | ** 'finishpcallk' will run again and close any still pending '__close' | ||
606 | ** methods. Similarly, if a '__close' method errs, 'precover' calls | ||
607 | ** 'unroll' which calls ''finishCcall' and we are back here again, to | ||
608 | ** close any pending '__close' methods. | ||
609 | ** Note that, up to the call to 'luaF_close', the corresponding | ||
610 | ** 'CallInfo' is not modified, so that this repeated run works like the | ||
611 | ** first one (except that it has at least one less '__close' to do). In | ||
612 | ** particular, field CIST_RECST preserves the error status across these | ||
613 | ** multiple runs, changing only if there is a new error. | ||
570 | */ | 614 | */ |
571 | static void finishCcall (lua_State *L, int status) { | 615 | static int finishpcallk (lua_State *L, CallInfo *ci) { |
572 | CallInfo *ci = L->ci; | 616 | int status = getcistrecst(ci); /* get original status */ |
573 | int n; | 617 | if (l_likely(status == LUA_OK)) /* no error? */ |
574 | /* must have a continuation and must be able to call it */ | 618 | status = LUA_YIELD; /* was interrupted by an yield */ |
575 | lua_assert(ci->u.c.k != NULL && yieldable(L)); | 619 | else { /* error */ |
576 | /* error status can only happen in a protected call */ | 620 | StkId func = restorestack(L, ci->u2.funcidx); |
577 | lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); | 621 | L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ |
578 | if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ | 622 | luaF_close(L, func, status, 1); /* can yield or raise an error */ |
579 | ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */ | 623 | func = restorestack(L, ci->u2.funcidx); /* stack may be moved */ |
580 | L->errfunc = ci->u.c.old_errfunc; /* with the same error function */ | 624 | luaD_seterrorobj(L, status, func); |
581 | } | 625 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ |
582 | /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already | 626 | setcistrecst(ci, LUA_OK); /* clear original status */ |
583 | handled */ | 627 | } |
584 | adjustresults(L, ci->nresults); | 628 | ci->callstatus &= ~CIST_YPCALL; |
585 | lua_unlock(L); | 629 | L->errfunc = ci->u.c.old_errfunc; |
586 | n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ | 630 | /* if it is here, there were errors or yields; unlike 'lua_pcallk', |
587 | lua_lock(L); | 631 | do not change status */ |
588 | api_checknelems(L, n); | 632 | return status; |
633 | } | ||
634 | |||
635 | |||
636 | /* | ||
637 | ** Completes the execution of a C function interrupted by an yield. | ||
638 | ** The interruption must have happened while the function was either | ||
639 | ** closing its tbc variables in 'moveresults' or executing | ||
640 | ** 'lua_callk'/'lua_pcallk'. In the first case, it just redoes | ||
641 | ** 'luaD_poscall'. In the second case, the call to 'finishpcallk' | ||
642 | ** finishes the interrupted execution of 'lua_pcallk'. After that, it | ||
643 | ** calls the continuation of the interrupted function and finally it | ||
644 | ** completes the job of the 'luaD_call' that called the function. In | ||
645 | ** the call to 'adjustresults', we do not know the number of results | ||
646 | ** of the function called by 'lua_callk'/'lua_pcallk', so we are | ||
647 | ** conservative and use LUA_MULTRET (always adjust). | ||
648 | */ | ||
649 | static void finishCcall (lua_State *L, CallInfo *ci) { | ||
650 | int n; /* actual number of results from C function */ | ||
651 | if (ci->callstatus & CIST_CLSRET) { /* was returning? */ | ||
652 | lua_assert(hastocloseCfunc(ci->nresults)); | ||
653 | n = ci->u2.nres; /* just redo 'luaD_poscall' */ | ||
654 | /* don't need to reset CIST_CLSRET, as it will be set again anyway */ | ||
655 | } | ||
656 | else { | ||
657 | int status = LUA_YIELD; /* default if there were no errors */ | ||
658 | /* must have a continuation and must be able to call it */ | ||
659 | lua_assert(ci->u.c.k != NULL && yieldable(L)); | ||
660 | if (ci->callstatus & CIST_YPCALL) /* was inside a 'lua_pcallk'? */ | ||
661 | status = finishpcallk(L, ci); /* finish it */ | ||
662 | adjustresults(L, LUA_MULTRET); /* finish 'lua_callk' */ | ||
663 | lua_unlock(L); | ||
664 | n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation */ | ||
665 | lua_lock(L); | ||
666 | api_checknelems(L, n); | ||
667 | } | ||
589 | luaD_poscall(L, ci, n); /* finish 'luaD_call' */ | 668 | luaD_poscall(L, ci, n); /* finish 'luaD_call' */ |
590 | } | 669 | } |
591 | 670 | ||
@@ -600,7 +679,7 @@ static void unroll (lua_State *L, void *ud) { | |||
600 | UNUSED(ud); | 679 | UNUSED(ud); |
601 | while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ | 680 | while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ |
602 | if (!isLua(ci)) /* C function? */ | 681 | if (!isLua(ci)) /* C function? */ |
603 | finishCcall(L, LUA_YIELD); /* complete its execution */ | 682 | finishCcall(L, ci); /* complete its execution */ |
604 | else { /* Lua function */ | 683 | else { /* Lua function */ |
605 | luaV_finishOp(L); /* finish interrupted instruction */ | 684 | luaV_finishOp(L); /* finish interrupted instruction */ |
606 | luaV_execute(L, ci); /* execute down to higher C 'boundary' */ | 685 | luaV_execute(L, ci); /* execute down to higher C 'boundary' */ |
@@ -624,40 +703,6 @@ static CallInfo *findpcall (lua_State *L) { | |||
624 | 703 | ||
625 | 704 | ||
626 | /* | 705 | /* |
627 | ** Auxiliary structure to call 'recover' in protected mode. | ||
628 | */ | ||
629 | struct RecoverS { | ||
630 | int status; | ||
631 | CallInfo *ci; | ||
632 | }; | ||
633 | |||
634 | |||
635 | /* | ||
636 | ** Recovers from an error in a coroutine: completes the execution of the | ||
637 | ** interrupted 'luaD_pcall', completes the interrupted C function which | ||
638 | ** called 'lua_pcallk', and continues running the coroutine. If there is | ||
639 | ** an error in 'luaF_close', this function will be called again and the | ||
640 | ** coroutine will continue from where it left. | ||
641 | */ | ||
642 | static void recover (lua_State *L, void *ud) { | ||
643 | struct RecoverS *r = cast(struct RecoverS *, ud); | ||
644 | int status = r->status; | ||
645 | CallInfo *ci = r->ci; /* recover point */ | ||
646 | StkId func = restorestack(L, ci->u2.funcidx); | ||
647 | /* "finish" luaD_pcall */ | ||
648 | L->ci = ci; | ||
649 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ | ||
650 | luaF_close(L, func, status, 0); /* may change the stack */ | ||
651 | func = restorestack(L, ci->u2.funcidx); | ||
652 | luaD_seterrorobj(L, status, func); | ||
653 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ | ||
654 | L->errfunc = ci->u.c.old_errfunc; | ||
655 | finishCcall(L, status); /* finish 'lua_pcallk' callee */ | ||
656 | unroll(L, NULL); /* continue running the coroutine */ | ||
657 | } | ||
658 | |||
659 | |||
660 | /* | ||
661 | ** Signal an error in the call to 'lua_resume', not in the execution | 706 | ** Signal an error in the call to 'lua_resume', not in the execution |
662 | ** of the coroutine itself. (Such errors should not be handled by any | 707 | ** of the coroutine itself. (Such errors should not be handled by any |
663 | ** coroutine error handler and should not kill the coroutine.) | 708 | ** coroutine error handler and should not kill the coroutine.) |
@@ -688,8 +733,10 @@ static void resume (lua_State *L, void *ud) { | |||
688 | lua_assert(L->status == LUA_YIELD); | 733 | lua_assert(L->status == LUA_YIELD); |
689 | L->status = LUA_OK; /* mark that it is running (again) */ | 734 | L->status = LUA_OK; /* mark that it is running (again) */ |
690 | luaE_incCstack(L); /* control the C stack */ | 735 | luaE_incCstack(L); /* control the C stack */ |
691 | if (isLua(ci)) /* yielded inside a hook? */ | 736 | if (isLua(ci)) { /* yielded inside a hook? */ |
737 | L->top = firstArg; /* discard arguments */ | ||
692 | luaV_execute(L, ci); /* just continue running Lua code */ | 738 | luaV_execute(L, ci); /* just continue running Lua code */ |
739 | } | ||
693 | else { /* 'common' yield */ | 740 | else { /* 'common' yield */ |
694 | if (ci->u.c.k != NULL) { /* does it have a continuation function? */ | 741 | if (ci->u.c.k != NULL) { /* does it have a continuation function? */ |
695 | lua_unlock(L); | 742 | lua_unlock(L); |
@@ -705,19 +752,21 @@ static void resume (lua_State *L, void *ud) { | |||
705 | 752 | ||
706 | 753 | ||
707 | /* | 754 | /* |
708 | ** Calls 'recover' in protected mode, repeating while there are | 755 | ** Unrolls a coroutine in protected mode while there are recoverable |
709 | ** recoverable errors, that is, errors inside a protected call. (Any | 756 | ** errors, that is, errors inside a protected call. (Any error |
710 | ** error interrupts 'recover', and this loop protects it again so it | 757 | ** interrupts 'unroll', and this loop protects it again so it can |
711 | ** can continue.) Stops with a normal end (status == LUA_OK), an yield | 758 | ** continue.) Stops with a normal end (status == LUA_OK), an yield |
712 | ** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't | 759 | ** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't |
713 | ** find a recover point). | 760 | ** find a recover point). |
714 | */ | 761 | */ |
715 | static int p_recover (lua_State *L, int status) { | 762 | static int precover (lua_State *L, int status) { |
716 | struct RecoverS r; | 763 | CallInfo *ci; |
717 | r.status = status; | 764 | while (errorstatus(status) && (ci = findpcall(L)) != NULL) { |
718 | while (errorstatus(status) && (r.ci = findpcall(L)) != NULL) | 765 | L->ci = ci; /* go down to recovery functions */ |
719 | r.status = luaD_rawrunprotected(L, recover, &r); | 766 | setcistrecst(ci, status); /* status to finish 'pcall' */ |
720 | return r.status; | 767 | status = luaD_rawrunprotected(L, unroll, NULL); |
768 | } | ||
769 | return status; | ||
721 | } | 770 | } |
722 | 771 | ||
723 | 772 | ||
@@ -738,8 +787,8 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
738 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 787 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
739 | status = luaD_rawrunprotected(L, resume, &nargs); | 788 | status = luaD_rawrunprotected(L, resume, &nargs); |
740 | /* continue running after recoverable errors */ | 789 | /* continue running after recoverable errors */ |
741 | status = p_recover(L, status); | 790 | status = precover(L, status); |
742 | if (likely(!errorstatus(status))) | 791 | if (l_likely(!errorstatus(status))) |
743 | lua_assert(status == L->status); /* normal end or yield */ | 792 | lua_assert(status == L->status); /* normal end or yield */ |
744 | else { /* unrecoverable error */ | 793 | else { /* unrecoverable error */ |
745 | L->status = cast_byte(status); /* mark thread as 'dead' */ | 794 | L->status = cast_byte(status); /* mark thread as 'dead' */ |
@@ -765,22 +814,22 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, | |||
765 | lua_lock(L); | 814 | lua_lock(L); |
766 | ci = L->ci; | 815 | ci = L->ci; |
767 | api_checknelems(L, nresults); | 816 | api_checknelems(L, nresults); |
768 | if (unlikely(!yieldable(L))) { | 817 | if (l_unlikely(!yieldable(L))) { |
769 | if (L != G(L)->mainthread) | 818 | if (L != G(L)->mainthread) |
770 | luaG_runerror(L, "attempt to yield across a C-call boundary"); | 819 | luaG_runerror(L, "attempt to yield across a C-call boundary"); |
771 | else | 820 | else |
772 | luaG_runerror(L, "attempt to yield from outside a coroutine"); | 821 | luaG_runerror(L, "attempt to yield from outside a coroutine"); |
773 | } | 822 | } |
774 | L->status = LUA_YIELD; | 823 | L->status = LUA_YIELD; |
824 | ci->u2.nyield = nresults; /* save number of results */ | ||
775 | if (isLua(ci)) { /* inside a hook? */ | 825 | if (isLua(ci)) { /* inside a hook? */ |
776 | lua_assert(!isLuacode(ci)); | 826 | lua_assert(!isLuacode(ci)); |
827 | api_check(L, nresults == 0, "hooks cannot yield values"); | ||
777 | api_check(L, k == NULL, "hooks cannot continue after yielding"); | 828 | api_check(L, k == NULL, "hooks cannot continue after yielding"); |
778 | ci->u2.nyield = 0; /* no results */ | ||
779 | } | 829 | } |
780 | else { | 830 | else { |
781 | if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ | 831 | if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ |
782 | ci->u.c.ctx = ctx; /* save context */ | 832 | ci->u.c.ctx = ctx; /* save context */ |
783 | ci->u2.nyield = nresults; /* save number of results */ | ||
784 | luaD_throw(L, LUA_YIELD); | 833 | luaD_throw(L, LUA_YIELD); |
785 | } | 834 | } |
786 | lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ | 835 | lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ |
@@ -818,7 +867,7 @@ int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) { | |||
818 | struct CloseP pcl; | 867 | struct CloseP pcl; |
819 | pcl.level = restorestack(L, level); pcl.status = status; | 868 | pcl.level = restorestack(L, level); pcl.status = status; |
820 | status = luaD_rawrunprotected(L, &closepaux, &pcl); | 869 | status = luaD_rawrunprotected(L, &closepaux, &pcl); |
821 | if (likely(status == LUA_OK)) /* no more errors? */ | 870 | if (l_likely(status == LUA_OK)) /* no more errors? */ |
822 | return pcl.status; | 871 | return pcl.status; |
823 | else { /* an error occurred; restore saved state and repeat */ | 872 | else { /* an error occurred; restore saved state and repeat */ |
824 | L->ci = old_ci; | 873 | L->ci = old_ci; |
@@ -841,7 +890,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, | |||
841 | ptrdiff_t old_errfunc = L->errfunc; | 890 | ptrdiff_t old_errfunc = L->errfunc; |
842 | L->errfunc = ef; | 891 | L->errfunc = ef; |
843 | status = luaD_rawrunprotected(L, func, u); | 892 | status = luaD_rawrunprotected(L, func, u); |
844 | if (unlikely(status != LUA_OK)) { /* an error occurred? */ | 893 | if (l_unlikely(status != LUA_OK)) { /* an error occurred? */ |
845 | L->ci = old_ci; | 894 | L->ci = old_ci; |
846 | L->allowhook = old_allowhooks; | 895 | L->allowhook = old_allowhooks; |
847 | status = luaD_closeprotected(L, old_top, status); | 896 | status = luaD_closeprotected(L, old_top, status); |
diff --git a/src/lua/ldo.h b/src/lua/ldo.h index c7721d6..6bf0ed8 100644 --- a/src/lua/ldo.h +++ b/src/lua/ldo.h | |||
@@ -23,7 +23,7 @@ | |||
23 | ** at every check. | 23 | ** at every check. |
24 | */ | 24 | */ |
25 | #define luaD_checkstackaux(L,n,pre,pos) \ | 25 | #define luaD_checkstackaux(L,n,pre,pos) \ |
26 | if (L->stack_last - L->top <= (n)) \ | 26 | if (l_unlikely(L->stack_last - L->top <= (n))) \ |
27 | { pre; luaD_growstack(L, n, 1); pos; } \ | 27 | { pre; luaD_growstack(L, n, 1); pos; } \ |
28 | else { condmovestack(L,pre,pos); } | 28 | else { condmovestack(L,pre,pos); } |
29 | 29 | ||
diff --git a/src/lua/lfunc.c b/src/lua/lfunc.c index 13e44d4..b4c04bd 100644 --- a/src/lua/lfunc.c +++ b/src/lua/lfunc.c | |||
@@ -120,11 +120,11 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { | |||
120 | 120 | ||
121 | 121 | ||
122 | /* | 122 | /* |
123 | ** Check whether 'obj' has a close metamethod and raise an error | 123 | ** Check whether object at given level has a close metamethod and raise |
124 | ** if not. | 124 | ** an error if not. |
125 | */ | 125 | */ |
126 | static void checkclosemth (lua_State *L, StkId level, const TValue *obj) { | 126 | static void checkclosemth (lua_State *L, StkId level) { |
127 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); | 127 | const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE); |
128 | if (ttisnil(tm)) { /* no metamethod? */ | 128 | if (ttisnil(tm)) { /* no metamethod? */ |
129 | int idx = cast_int(level - L->ci->func); /* variable index */ | 129 | int idx = cast_int(level - L->ci->func); /* variable index */ |
130 | const char *vname = luaG_findlocal(L, L->ci, idx, NULL); | 130 | const char *vname = luaG_findlocal(L, L->ci, idx, NULL); |
@@ -155,33 +155,21 @@ 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 | ** Insert a variable in the list of to-be-closed variables. |
159 | ** (can raise a memory-allocation error) | ||
160 | */ | ||
161 | static void trynewtbcupval (lua_State *L, void *ud) { | ||
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 | */ | 159 | */ |
171 | void luaF_newtbcupval (lua_State *L, StkId level) { | 160 | void luaF_newtbcupval (lua_State *L, StkId level) { |
172 | TValue *obj = s2v(level); | 161 | lua_assert(level > L->tbclist); |
173 | lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); | 162 | if (l_isfalse(s2v(level))) |
174 | if (!l_isfalse(obj)) { /* false doesn't need to be closed */ | 163 | return; /* false doesn't need to be closed */ |
175 | int status; | 164 | checkclosemth(L, level); /* value must have a close method */ |
176 | checkclosemth(L, level, obj); | 165 | while (level - L->tbclist > USHRT_MAX) { /* is delta too large? */ |
177 | status = luaD_rawrunprotected(L, trynewtbcupval, level); | 166 | L->tbclist += USHRT_MAX; /* create a dummy node at maximum delta */ |
178 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ | 167 | L->tbclist->tbclist.delta = USHRT_MAX; |
179 | lua_assert(status == LUA_ERRMEM); | 168 | L->tbclist->tbclist.isdummy = 1; |
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 | } | 169 | } |
170 | level->tbclist.delta = level - L->tbclist; | ||
171 | level->tbclist.isdummy = 0; | ||
172 | L->tbclist = level; | ||
185 | } | 173 | } |
186 | 174 | ||
187 | 175 | ||
@@ -194,11 +182,9 @@ void luaF_unlinkupval (UpVal *uv) { | |||
194 | 182 | ||
195 | 183 | ||
196 | /* | 184 | /* |
197 | ** Close all upvalues up to the given stack level. A 'status' equal | 185 | ** Close all upvalues up to the given stack level. |
198 | ** to NOCLOSINGMETH closes upvalues without running any __close | ||
199 | ** metamethods. | ||
200 | */ | 186 | */ |
201 | void luaF_close (lua_State *L, StkId level, int status, int yy) { | 187 | void luaF_closeupval (lua_State *L, StkId level) { |
202 | UpVal *uv; | 188 | UpVal *uv; |
203 | StkId upl; /* stack index pointed by 'uv' */ | 189 | StkId upl; /* stack index pointed by 'uv' */ |
204 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { | 190 | while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { |
@@ -211,9 +197,22 @@ void luaF_close (lua_State *L, StkId level, int status, int yy) { | |||
211 | nw2black(uv); /* closed upvalues cannot be gray */ | 197 | nw2black(uv); /* closed upvalues cannot be gray */ |
212 | luaC_barrier(L, uv, slot); | 198 | luaC_barrier(L, uv, slot); |
213 | } | 199 | } |
214 | if (uv->tbc && status != NOCLOSINGMETH) { | 200 | } |
215 | ptrdiff_t levelrel = savestack(L, level); | 201 | } |
216 | prepcallclosemth(L, upl, status, yy); /* may change the stack */ | 202 | |
203 | |||
204 | /* | ||
205 | ** Close all upvalues and to-be-closed variables up to the given stack | ||
206 | ** level. | ||
207 | */ | ||
208 | void luaF_close (lua_State *L, StkId level, int status, int yy) { | ||
209 | ptrdiff_t levelrel = savestack(L, level); | ||
210 | luaF_closeupval(L, level); /* first, close the upvalues */ | ||
211 | while (L->tbclist >= level) { /* traverse tbc's down to that level */ | ||
212 | StkId tbc = L->tbclist; /* get variable index */ | ||
213 | L->tbclist -= tbc->tbclist.delta; /* remove it from list */ | ||
214 | if (!tbc->tbclist.isdummy) { /* not a dummy entry? */ | ||
215 | prepcallclosemth(L, tbc, status, yy); /* close variable */ | ||
217 | level = restorestack(L, levelrel); | 216 | level = restorestack(L, levelrel); |
218 | } | 217 | } |
219 | } | 218 | } |
diff --git a/src/lua/lfunc.h b/src/lua/lfunc.h index 2e6df53..dc1cebc 100644 --- a/src/lua/lfunc.h +++ b/src/lua/lfunc.h | |||
@@ -42,15 +42,9 @@ | |||
42 | #define MAXMISS 10 | 42 | #define MAXMISS 10 |
43 | 43 | ||
44 | 44 | ||
45 | /* | ||
46 | ** Special "status" for 'luaF_close' | ||
47 | */ | ||
48 | |||
49 | /* close upvalues without running their closing methods */ | ||
50 | #define NOCLOSINGMETH (-1) | ||
51 | 45 | ||
52 | /* special status to close upvalues preserving the top of the stack */ | 46 | /* special status to close upvalues preserving the top of the stack */ |
53 | #define CLOSEKTOP (-2) | 47 | #define CLOSEKTOP (-1) |
54 | 48 | ||
55 | 49 | ||
56 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); | 50 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); |
@@ -59,6 +53,7 @@ LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals); | |||
59 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); | 53 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); |
60 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); | 54 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); |
61 | LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); | 55 | LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); |
56 | LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); | ||
62 | LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); | 57 | LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); |
63 | LUAI_FUNC void luaF_unlinkupval (UpVal *uv); | 58 | LUAI_FUNC void luaF_unlinkupval (UpVal *uv); |
64 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); | 59 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); |
diff --git a/src/lua/lgc.c b/src/lua/lgc.c index bab9beb..b360eed 100644 --- a/src/lua/lgc.c +++ b/src/lua/lgc.c | |||
@@ -916,7 +916,7 @@ static void GCTM (lua_State *L) { | |||
916 | L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ | 916 | L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ |
917 | L->allowhook = oldah; /* restore hooks */ | 917 | L->allowhook = oldah; /* restore hooks */ |
918 | g->gcrunning = running; /* restore state */ | 918 | g->gcrunning = running; /* restore state */ |
919 | if (unlikely(status != LUA_OK)) { /* error while running __gc? */ | 919 | if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ |
920 | luaE_warnerror(L, "__gc metamethod"); | 920 | luaE_warnerror(L, "__gc metamethod"); |
921 | L->top--; /* pops error object */ | 921 | L->top--; /* pops error object */ |
922 | } | 922 | } |
@@ -1575,52 +1575,64 @@ static int sweepstep (lua_State *L, global_State *g, | |||
1575 | 1575 | ||
1576 | static lu_mem singlestep (lua_State *L) { | 1576 | static lu_mem singlestep (lua_State *L) { |
1577 | global_State *g = G(L); | 1577 | global_State *g = G(L); |
1578 | lu_mem work; | ||
1579 | lua_assert(!g->gcstopem); /* collector is not reentrant */ | ||
1580 | g->gcstopem = 1; /* no emergency collections while collecting */ | ||
1578 | switch (g->gcstate) { | 1581 | switch (g->gcstate) { |
1579 | case GCSpause: { | 1582 | case GCSpause: { |
1580 | restartcollection(g); | 1583 | restartcollection(g); |
1581 | g->gcstate = GCSpropagate; | 1584 | g->gcstate = GCSpropagate; |
1582 | return 1; | 1585 | work = 1; |
1586 | break; | ||
1583 | } | 1587 | } |
1584 | case GCSpropagate: { | 1588 | case GCSpropagate: { |
1585 | if (g->gray == NULL) { /* no more gray objects? */ | 1589 | if (g->gray == NULL) { /* no more gray objects? */ |
1586 | g->gcstate = GCSenteratomic; /* finish propagate phase */ | 1590 | g->gcstate = GCSenteratomic; /* finish propagate phase */ |
1587 | return 0; | 1591 | work = 0; |
1588 | } | 1592 | } |
1589 | else | 1593 | else |
1590 | return propagatemark(g); /* traverse one gray object */ | 1594 | work = propagatemark(g); /* traverse one gray object */ |
1595 | break; | ||
1591 | } | 1596 | } |
1592 | case GCSenteratomic: { | 1597 | case GCSenteratomic: { |
1593 | lu_mem work = atomic(L); /* work is what was traversed by 'atomic' */ | 1598 | work = atomic(L); /* work is what was traversed by 'atomic' */ |
1594 | entersweep(L); | 1599 | entersweep(L); |
1595 | g->GCestimate = gettotalbytes(g); /* first estimate */; | 1600 | g->GCestimate = gettotalbytes(g); /* first estimate */; |
1596 | return work; | 1601 | break; |
1597 | } | 1602 | } |
1598 | case GCSswpallgc: { /* sweep "regular" objects */ | 1603 | case GCSswpallgc: { /* sweep "regular" objects */ |
1599 | return sweepstep(L, g, GCSswpfinobj, &g->finobj); | 1604 | work = sweepstep(L, g, GCSswpfinobj, &g->finobj); |
1605 | break; | ||
1600 | } | 1606 | } |
1601 | case GCSswpfinobj: { /* sweep objects with finalizers */ | 1607 | case GCSswpfinobj: { /* sweep objects with finalizers */ |
1602 | return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); | 1608 | work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz); |
1609 | break; | ||
1603 | } | 1610 | } |
1604 | case GCSswptobefnz: { /* sweep objects to be finalized */ | 1611 | case GCSswptobefnz: { /* sweep objects to be finalized */ |
1605 | return sweepstep(L, g, GCSswpend, NULL); | 1612 | work = sweepstep(L, g, GCSswpend, NULL); |
1613 | break; | ||
1606 | } | 1614 | } |
1607 | case GCSswpend: { /* finish sweeps */ | 1615 | case GCSswpend: { /* finish sweeps */ |
1608 | checkSizes(L, g); | 1616 | checkSizes(L, g); |
1609 | g->gcstate = GCScallfin; | 1617 | g->gcstate = GCScallfin; |
1610 | return 0; | 1618 | work = 0; |
1619 | break; | ||
1611 | } | 1620 | } |
1612 | case GCScallfin: { /* call remaining finalizers */ | 1621 | case GCScallfin: { /* call remaining finalizers */ |
1613 | if (g->tobefnz && !g->gcemergency) { | 1622 | if (g->tobefnz && !g->gcemergency) { |
1614 | int n = runafewfinalizers(L, GCFINMAX); | 1623 | g->gcstopem = 0; /* ok collections during finalizers */ |
1615 | return n * GCFINALIZECOST; | 1624 | work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; |
1616 | } | 1625 | } |
1617 | else { /* emergency mode or no more finalizers */ | 1626 | else { /* emergency mode or no more finalizers */ |
1618 | g->gcstate = GCSpause; /* finish collection */ | 1627 | g->gcstate = GCSpause; /* finish collection */ |
1619 | return 0; | 1628 | work = 0; |
1620 | } | 1629 | } |
1630 | break; | ||
1621 | } | 1631 | } |
1622 | default: lua_assert(0); return 0; | 1632 | default: lua_assert(0); return 0; |
1623 | } | 1633 | } |
1634 | g->gcstopem = 0; | ||
1635 | return work; | ||
1624 | } | 1636 | } |
1625 | 1637 | ||
1626 | 1638 | ||
diff --git a/src/lua/liolib.c b/src/lua/liolib.c index 7951672..b08397d 100644 --- a/src/lua/liolib.c +++ b/src/lua/liolib.c | |||
@@ -186,7 +186,7 @@ static int f_tostring (lua_State *L) { | |||
186 | 186 | ||
187 | static FILE *tofile (lua_State *L) { | 187 | static FILE *tofile (lua_State *L) { |
188 | LStream *p = tolstream(L); | 188 | LStream *p = tolstream(L); |
189 | if (isclosed(p)) | 189 | if (l_unlikely(isclosed(p))) |
190 | luaL_error(L, "attempt to use a closed file"); | 190 | luaL_error(L, "attempt to use a closed file"); |
191 | lua_assert(p->f); | 191 | lua_assert(p->f); |
192 | return p->f; | 192 | return p->f; |
@@ -261,7 +261,7 @@ static LStream *newfile (lua_State *L) { | |||
261 | static void opencheck (lua_State *L, const char *fname, const char *mode) { | 261 | static void opencheck (lua_State *L, const char *fname, const char *mode) { |
262 | LStream *p = newfile(L); | 262 | LStream *p = newfile(L); |
263 | p->f = fopen(fname, mode); | 263 | p->f = fopen(fname, mode); |
264 | if (p->f == NULL) | 264 | if (l_unlikely(p->f == NULL)) |
265 | luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); | 265 | luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); |
266 | } | 266 | } |
267 | 267 | ||
@@ -309,7 +309,7 @@ static FILE *getiofile (lua_State *L, const char *findex) { | |||
309 | LStream *p; | 309 | LStream *p; |
310 | lua_getfield(L, LUA_REGISTRYINDEX, findex); | 310 | lua_getfield(L, LUA_REGISTRYINDEX, findex); |
311 | p = (LStream *)lua_touserdata(L, -1); | 311 | p = (LStream *)lua_touserdata(L, -1); |
312 | if (isclosed(p)) | 312 | if (l_unlikely(isclosed(p))) |
313 | luaL_error(L, "default %s file is closed", findex + IOPREF_LEN); | 313 | luaL_error(L, "default %s file is closed", findex + IOPREF_LEN); |
314 | return p->f; | 314 | return p->f; |
315 | } | 315 | } |
@@ -436,7 +436,7 @@ typedef struct { | |||
436 | ** Add current char to buffer (if not out of space) and read next one | 436 | ** Add current char to buffer (if not out of space) and read next one |
437 | */ | 437 | */ |
438 | static int nextc (RN *rn) { | 438 | static int nextc (RN *rn) { |
439 | if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ | 439 | if (l_unlikely(rn->n >= L_MAXLENNUM)) { /* buffer overflow? */ |
440 | rn->buff[0] = '\0'; /* invalidate result */ | 440 | rn->buff[0] = '\0'; /* invalidate result */ |
441 | return 0; /* fail */ | 441 | return 0; /* fail */ |
442 | } | 442 | } |
@@ -499,8 +499,8 @@ static int read_number (lua_State *L, FILE *f) { | |||
499 | ungetc(rn.c, rn.f); /* unread look-ahead char */ | 499 | ungetc(rn.c, rn.f); /* unread look-ahead char */ |
500 | l_unlockfile(rn.f); | 500 | l_unlockfile(rn.f); |
501 | rn.buff[rn.n] = '\0'; /* finish string */ | 501 | rn.buff[rn.n] = '\0'; /* finish string */ |
502 | if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ | 502 | if (l_likely(lua_stringtonumber(L, rn.buff))) |
503 | return 1; /* ok */ | 503 | return 1; /* ok, it is a valid number */ |
504 | else { /* invalid format */ | 504 | else { /* invalid format */ |
505 | lua_pushnil(L); /* "result" to be removed */ | 505 | lua_pushnil(L); /* "result" to be removed */ |
506 | return 0; /* read fails */ | 506 | return 0; /* read fails */ |
@@ -676,7 +676,8 @@ static int g_write (lua_State *L, FILE *f, int arg) { | |||
676 | status = status && (fwrite(s, sizeof(char), l, f) == l); | 676 | status = status && (fwrite(s, sizeof(char), l, f) == l); |
677 | } | 677 | } |
678 | } | 678 | } |
679 | if (status) return 1; /* file handle already on stack top */ | 679 | if (l_likely(status)) |
680 | return 1; /* file handle already on stack top */ | ||
680 | else return luaL_fileresult(L, status, NULL); | 681 | else return luaL_fileresult(L, status, NULL); |
681 | } | 682 | } |
682 | 683 | ||
@@ -703,7 +704,7 @@ static int f_seek (lua_State *L) { | |||
703 | luaL_argcheck(L, (lua_Integer)offset == p3, 3, | 704 | luaL_argcheck(L, (lua_Integer)offset == p3, 3, |
704 | "not an integer in proper range"); | 705 | "not an integer in proper range"); |
705 | op = l_fseek(f, offset, mode[op]); | 706 | op = l_fseek(f, offset, mode[op]); |
706 | if (op) | 707 | if (l_unlikely(op)) |
707 | return luaL_fileresult(L, 0, NULL); /* error */ | 708 | return luaL_fileresult(L, 0, NULL); /* error */ |
708 | else { | 709 | else { |
709 | lua_pushinteger(L, (lua_Integer)l_ftell(f)); | 710 | lua_pushinteger(L, (lua_Integer)l_ftell(f)); |
diff --git a/src/lua/llimits.h b/src/lua/llimits.h index d039483..025f1c8 100644 --- a/src/lua/llimits.h +++ b/src/lua/llimits.h | |||
@@ -150,22 +150,6 @@ typedef LUAI_UACINT l_uacInt; | |||
150 | 150 | ||
151 | 151 | ||
152 | /* | 152 | /* |
153 | ** macros to improve jump prediction (used mainly for error handling) | ||
154 | */ | ||
155 | #if !defined(likely) | ||
156 | |||
157 | #if defined(__GNUC__) | ||
158 | #define likely(x) (__builtin_expect(((x) != 0), 1)) | ||
159 | #define unlikely(x) (__builtin_expect(((x) != 0), 0)) | ||
160 | #else | ||
161 | #define likely(x) (x) | ||
162 | #define unlikely(x) (x) | ||
163 | #endif | ||
164 | |||
165 | #endif | ||
166 | |||
167 | |||
168 | /* | ||
169 | ** non-return type | 153 | ** non-return type |
170 | */ | 154 | */ |
171 | #if !defined(l_noret) | 155 | #if !defined(l_noret) |
diff --git a/src/lua/lmathlib.c b/src/lua/lmathlib.c index 86def47..5f5983a 100644 --- a/src/lua/lmathlib.c +++ b/src/lua/lmathlib.c | |||
@@ -73,7 +73,7 @@ static int math_atan (lua_State *L) { | |||
73 | static int math_toint (lua_State *L) { | 73 | static int math_toint (lua_State *L) { |
74 | int valid; | 74 | int valid; |
75 | lua_Integer n = lua_tointegerx(L, 1, &valid); | 75 | lua_Integer n = lua_tointegerx(L, 1, &valid); |
76 | if (valid) | 76 | if (l_likely(valid)) |
77 | lua_pushinteger(L, n); | 77 | lua_pushinteger(L, n); |
78 | else { | 78 | else { |
79 | luaL_checkany(L, 1); | 79 | luaL_checkany(L, 1); |
@@ -175,7 +175,8 @@ static int math_log (lua_State *L) { | |||
175 | lua_Number base = luaL_checknumber(L, 2); | 175 | lua_Number base = luaL_checknumber(L, 2); |
176 | #if !defined(LUA_USE_C89) | 176 | #if !defined(LUA_USE_C89) |
177 | if (base == l_mathop(2.0)) | 177 | if (base == l_mathop(2.0)) |
178 | res = l_mathop(log2)(x); else | 178 | res = l_mathop(log2)(x); |
179 | else | ||
179 | #endif | 180 | #endif |
180 | if (base == l_mathop(10.0)) | 181 | if (base == l_mathop(10.0)) |
181 | res = l_mathop(log10)(x); | 182 | res = l_mathop(log10)(x); |
diff --git a/src/lua/lmem.c b/src/lua/lmem.c index 43739bf..9029d58 100644 --- a/src/lua/lmem.c +++ b/src/lua/lmem.c | |||
@@ -24,12 +24,12 @@ | |||
24 | 24 | ||
25 | #if defined(EMERGENCYGCTESTS) | 25 | #if defined(EMERGENCYGCTESTS) |
26 | /* | 26 | /* |
27 | ** First allocation will fail whenever not building initial state | 27 | ** First allocation will fail whenever not building initial state. |
28 | ** and not shrinking a block. (This fail will trigger 'tryagain' and | 28 | ** (This fail will trigger 'tryagain' and a full GC cycle at every |
29 | ** a full GC cycle at every allocation.) | 29 | ** allocation.) |
30 | */ | 30 | */ |
31 | static void *firsttry (global_State *g, void *block, size_t os, size_t ns) { | 31 | static void *firsttry (global_State *g, void *block, size_t os, size_t ns) { |
32 | if (ttisnil(&g->nilvalue) && ns > os) | 32 | if (completestate(g) && ns > 0) /* frees never fail */ |
33 | return NULL; /* fail */ | 33 | return NULL; /* fail */ |
34 | else /* normal allocation */ | 34 | else /* normal allocation */ |
35 | return (*g->frealloc)(g->ud, block, os, ns); | 35 | return (*g->frealloc)(g->ud, block, os, ns); |
@@ -83,7 +83,7 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, | |||
83 | if (nelems + 1 <= size) /* does one extra element still fit? */ | 83 | if (nelems + 1 <= size) /* does one extra element still fit? */ |
84 | return block; /* nothing to be done */ | 84 | return block; /* nothing to be done */ |
85 | if (size >= limit / 2) { /* cannot double it? */ | 85 | if (size >= limit / 2) { /* cannot double it? */ |
86 | if (unlikely(size >= limit)) /* cannot grow even a little? */ | 86 | if (l_unlikely(size >= limit)) /* cannot grow even a little? */ |
87 | luaG_runerror(L, "too many %s (limit is %d)", what, limit); | 87 | luaG_runerror(L, "too many %s (limit is %d)", what, limit); |
88 | size = limit; /* still have at least one free place */ | 88 | size = limit; /* still have at least one free place */ |
89 | } | 89 | } |
@@ -138,15 +138,17 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) { | |||
138 | 138 | ||
139 | 139 | ||
140 | /* | 140 | /* |
141 | ** In case of allocation fail, this function will call the GC to try | 141 | ** In case of allocation fail, this function will do an emergency |
142 | ** to free some memory and then try the allocation again. | 142 | ** collection to free some memory and then try the allocation again. |
143 | ** (It should not be called when shrinking a block, because then the | 143 | ** The GC should not be called while state is not fully built, as the |
144 | ** interpreter may be in the middle of a collection step.) | 144 | ** collector is not yet fully initialized. Also, it should not be called |
145 | ** when 'gcstopem' is true, because then the interpreter is in the | ||
146 | ** middle of a collection step. | ||
145 | */ | 147 | */ |
146 | static void *tryagain (lua_State *L, void *block, | 148 | static void *tryagain (lua_State *L, void *block, |
147 | size_t osize, size_t nsize) { | 149 | size_t osize, size_t nsize) { |
148 | global_State *g = G(L); | 150 | global_State *g = G(L); |
149 | if (ttisnil(&g->nilvalue)) { /* is state fully build? */ | 151 | if (completestate(g) && !g->gcstopem) { |
150 | luaC_fullgc(L, 1); /* try to free some memory... */ | 152 | luaC_fullgc(L, 1); /* try to free some memory... */ |
151 | return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ | 153 | return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ |
152 | } | 154 | } |
@@ -156,17 +158,14 @@ static void *tryagain (lua_State *L, void *block, | |||
156 | 158 | ||
157 | /* | 159 | /* |
158 | ** Generic allocation routine. | 160 | ** Generic allocation routine. |
159 | ** If allocation fails while shrinking a block, do not try again; the | ||
160 | ** GC shrinks some blocks and it is not reentrant. | ||
161 | */ | 161 | */ |
162 | void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { | 162 | void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { |
163 | void *newblock; | 163 | void *newblock; |
164 | global_State *g = G(L); | 164 | global_State *g = G(L); |
165 | lua_assert((osize == 0) == (block == NULL)); | 165 | lua_assert((osize == 0) == (block == NULL)); |
166 | newblock = firsttry(g, block, osize, nsize); | 166 | newblock = firsttry(g, block, osize, nsize); |
167 | if (unlikely(newblock == NULL && nsize > 0)) { | 167 | if (l_unlikely(newblock == NULL && nsize > 0)) { |
168 | if (nsize > osize) /* not shrinking a block? */ | 168 | newblock = tryagain(L, block, osize, nsize); |
169 | newblock = tryagain(L, block, osize, nsize); | ||
170 | if (newblock == NULL) /* still no memory? */ | 169 | if (newblock == NULL) /* still no memory? */ |
171 | return NULL; /* do not update 'GCdebt' */ | 170 | return NULL; /* do not update 'GCdebt' */ |
172 | } | 171 | } |
@@ -179,7 +178,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { | |||
179 | void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, | 178 | void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, |
180 | size_t nsize) { | 179 | size_t nsize) { |
181 | void *newblock = luaM_realloc_(L, block, osize, nsize); | 180 | void *newblock = luaM_realloc_(L, block, osize, nsize); |
182 | if (unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ | 181 | if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ |
183 | luaM_error(L); | 182 | luaM_error(L); |
184 | return newblock; | 183 | return newblock; |
185 | } | 184 | } |
@@ -191,7 +190,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) { | |||
191 | else { | 190 | else { |
192 | global_State *g = G(L); | 191 | global_State *g = G(L); |
193 | void *newblock = firsttry(g, NULL, tag, size); | 192 | void *newblock = firsttry(g, NULL, tag, size); |
194 | if (unlikely(newblock == NULL)) { | 193 | if (l_unlikely(newblock == NULL)) { |
195 | newblock = tryagain(L, NULL, tag, size); | 194 | newblock = tryagain(L, NULL, tag, size); |
196 | if (newblock == NULL) | 195 | if (newblock == NULL) |
197 | luaM_error(L); | 196 | luaM_error(L); |
diff --git a/src/lua/loadlib.c b/src/lua/loadlib.c index c0ec9a1..6f9fa37 100644 --- a/src/lua/loadlib.c +++ b/src/lua/loadlib.c | |||
@@ -132,14 +132,16 @@ static void lsys_unloadlib (void *lib) { | |||
132 | 132 | ||
133 | static void *lsys_load (lua_State *L, const char *path, int seeglb) { | 133 | static void *lsys_load (lua_State *L, const char *path, int seeglb) { |
134 | void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); | 134 | void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); |
135 | if (lib == NULL) lua_pushstring(L, dlerror()); | 135 | if (l_unlikely(lib == NULL)) |
136 | lua_pushstring(L, dlerror()); | ||
136 | return lib; | 137 | return lib; |
137 | } | 138 | } |
138 | 139 | ||
139 | 140 | ||
140 | static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { | 141 | static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { |
141 | lua_CFunction f = cast_func(dlsym(lib, sym)); | 142 | lua_CFunction f = cast_func(dlsym(lib, sym)); |
142 | if (f == NULL) lua_pushstring(L, dlerror()); | 143 | if (l_unlikely(f == NULL)) |
144 | lua_pushstring(L, dlerror()); | ||
143 | return f; | 145 | return f; |
144 | } | 146 | } |
145 | 147 | ||
@@ -410,7 +412,7 @@ static int ll_loadlib (lua_State *L) { | |||
410 | const char *path = luaL_checkstring(L, 1); | 412 | const char *path = luaL_checkstring(L, 1); |
411 | const char *init = luaL_checkstring(L, 2); | 413 | const char *init = luaL_checkstring(L, 2); |
412 | int stat = lookforfunc(L, path, init); | 414 | int stat = lookforfunc(L, path, init); |
413 | if (stat == 0) /* no errors? */ | 415 | if (l_likely(stat == 0)) /* no errors? */ |
414 | return 1; /* return the loaded function */ | 416 | return 1; /* return the loaded function */ |
415 | else { /* error; error message is on stack top */ | 417 | else { /* error; error message is on stack top */ |
416 | luaL_pushfail(L); | 418 | luaL_pushfail(L); |
@@ -523,14 +525,14 @@ static const char *findfile (lua_State *L, const char *name, | |||
523 | const char *path; | 525 | const char *path; |
524 | lua_getfield(L, lua_upvalueindex(1), pname); | 526 | lua_getfield(L, lua_upvalueindex(1), pname); |
525 | path = lua_tostring(L, -1); | 527 | path = lua_tostring(L, -1); |
526 | if (path == NULL) | 528 | if (l_unlikely(path == NULL)) |
527 | luaL_error(L, "'package.%s' must be a string", pname); | 529 | luaL_error(L, "'package.%s' must be a string", pname); |
528 | return searchpath(L, name, path, ".", dirsep); | 530 | return searchpath(L, name, path, ".", dirsep); |
529 | } | 531 | } |
530 | 532 | ||
531 | 533 | ||
532 | static int checkload (lua_State *L, int stat, const char *filename) { | 534 | static int checkload (lua_State *L, int stat, const char *filename) { |
533 | if (stat) { /* module loaded successfully? */ | 535 | if (l_likely(stat)) { /* module loaded successfully? */ |
534 | lua_pushstring(L, filename); /* will be 2nd argument to module */ | 536 | lua_pushstring(L, filename); /* will be 2nd argument to module */ |
535 | return 2; /* return open function and file name */ | 537 | return 2; /* return open function and file name */ |
536 | } | 538 | } |
@@ -623,13 +625,14 @@ static void findloader (lua_State *L, const char *name) { | |||
623 | int i; | 625 | int i; |
624 | luaL_Buffer msg; /* to build error message */ | 626 | luaL_Buffer msg; /* to build error message */ |
625 | /* push 'package.searchers' to index 3 in the stack */ | 627 | /* push 'package.searchers' to index 3 in the stack */ |
626 | if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) | 628 | if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers") |
629 | != LUA_TTABLE)) | ||
627 | luaL_error(L, "'package.searchers' must be a table"); | 630 | luaL_error(L, "'package.searchers' must be a table"); |
628 | luaL_buffinit(L, &msg); | 631 | luaL_buffinit(L, &msg); |
629 | /* iterate over available searchers to find a loader */ | 632 | /* iterate over available searchers to find a loader */ |
630 | for (i = 1; ; i++) { | 633 | for (i = 1; ; i++) { |
631 | luaL_addstring(&msg, "\n\t"); /* error-message prefix */ | 634 | luaL_addstring(&msg, "\n\t"); /* error-message prefix */ |
632 | if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ | 635 | if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */ |
633 | lua_pop(L, 1); /* remove nil */ | 636 | lua_pop(L, 1); /* remove nil */ |
634 | luaL_buffsub(&msg, 2); /* remove prefix */ | 637 | luaL_buffsub(&msg, 2); /* remove prefix */ |
635 | luaL_pushresult(&msg); /* create error message */ | 638 | luaL_pushresult(&msg); /* create error message */ |
diff --git a/src/lua/lobject.h b/src/lua/lobject.h index 470b17d..1a7a737 100644 --- a/src/lua/lobject.h +++ b/src/lua/lobject.h | |||
@@ -136,10 +136,18 @@ typedef struct TValue { | |||
136 | 136 | ||
137 | 137 | ||
138 | /* | 138 | /* |
139 | ** Entries in the Lua stack | 139 | ** Entries in a Lua stack. Field 'tbclist' forms a list of all |
140 | ** to-be-closed variables active in this stack. Dummy entries are | ||
141 | ** used when the distance between two tbc variables does not fit | ||
142 | ** in an unsigned short. | ||
140 | */ | 143 | */ |
141 | typedef union StackValue { | 144 | typedef union StackValue { |
142 | TValue val; | 145 | TValue val; |
146 | struct { | ||
147 | TValuefields; | ||
148 | lu_byte isdummy; | ||
149 | unsigned short delta; | ||
150 | } tbclist; | ||
143 | } StackValue; | 151 | } StackValue; |
144 | 152 | ||
145 | 153 | ||
diff --git a/src/lua/lopcodes.h b/src/lua/lopcodes.h index 120cdd9..d6a47e5 100644 --- a/src/lua/lopcodes.h +++ b/src/lua/lopcodes.h | |||
@@ -225,13 +225,13 @@ OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */ | |||
225 | 225 | ||
226 | OP_ADDI,/* A B sC R[A] := R[B] + sC */ | 226 | OP_ADDI,/* A B sC R[A] := R[B] + sC */ |
227 | 227 | ||
228 | OP_ADDK,/* A B C R[A] := R[B] + K[C] */ | 228 | OP_ADDK,/* A B C R[A] := R[B] + K[C]:number */ |
229 | OP_SUBK,/* A B C R[A] := R[B] - K[C] */ | 229 | OP_SUBK,/* A B C R[A] := R[B] - K[C]:number */ |
230 | OP_MULK,/* A B C R[A] := R[B] * K[C] */ | 230 | OP_MULK,/* A B C R[A] := R[B] * K[C]:number */ |
231 | OP_MODK,/* A B C R[A] := R[B] % K[C] */ | 231 | OP_MODK,/* A B C R[A] := R[B] % K[C]:number */ |
232 | OP_POWK,/* A B C R[A] := R[B] ^ K[C] */ | 232 | OP_POWK,/* A B C R[A] := R[B] ^ K[C]:number */ |
233 | OP_DIVK,/* A B C R[A] := R[B] / K[C] */ | 233 | OP_DIVK,/* A B C R[A] := R[B] / K[C]:number */ |
234 | OP_IDIVK,/* A B C R[A] := R[B] // K[C] */ | 234 | OP_IDIVK,/* A B C R[A] := R[B] // K[C]:number */ |
235 | 235 | ||
236 | OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */ | 236 | OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */ |
237 | OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */ | 237 | OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */ |
diff --git a/src/lua/loslib.c b/src/lua/loslib.c index e65e188..3e20d62 100644 --- a/src/lua/loslib.c +++ b/src/lua/loslib.c | |||
@@ -170,7 +170,7 @@ static int os_tmpname (lua_State *L) { | |||
170 | char buff[LUA_TMPNAMBUFSIZE]; | 170 | char buff[LUA_TMPNAMBUFSIZE]; |
171 | int err; | 171 | int err; |
172 | lua_tmpnam(buff, err); | 172 | lua_tmpnam(buff, err); |
173 | if (err) | 173 | if (l_unlikely(err)) |
174 | return luaL_error(L, "unable to generate a unique filename"); | 174 | return luaL_error(L, "unable to generate a unique filename"); |
175 | lua_pushstring(L, buff); | 175 | lua_pushstring(L, buff); |
176 | return 1; | 176 | return 1; |
@@ -208,7 +208,7 @@ static int os_clock (lua_State *L) { | |||
208 | */ | 208 | */ |
209 | static void setfield (lua_State *L, const char *key, int value, int delta) { | 209 | static void setfield (lua_State *L, const char *key, int value, int delta) { |
210 | #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX) | 210 | #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX) |
211 | if (value > LUA_MAXINTEGER - delta) | 211 | if (l_unlikely(value > LUA_MAXINTEGER - delta)) |
212 | luaL_error(L, "field '%s' is out-of-bound", key); | 212 | luaL_error(L, "field '%s' is out-of-bound", key); |
213 | #endif | 213 | #endif |
214 | lua_pushinteger(L, (lua_Integer)value + delta); | 214 | lua_pushinteger(L, (lua_Integer)value + delta); |
@@ -253,9 +253,9 @@ static int getfield (lua_State *L, const char *key, int d, int delta) { | |||
253 | int t = lua_getfield(L, -1, key); /* get field and its type */ | 253 | int t = lua_getfield(L, -1, key); /* get field and its type */ |
254 | lua_Integer res = lua_tointegerx(L, -1, &isnum); | 254 | lua_Integer res = lua_tointegerx(L, -1, &isnum); |
255 | if (!isnum) { /* field is not an integer? */ | 255 | if (!isnum) { /* field is not an integer? */ |
256 | if (t != LUA_TNIL) /* some other value? */ | 256 | if (l_unlikely(t != LUA_TNIL)) /* some other value? */ |
257 | return luaL_error(L, "field '%s' is not an integer", key); | 257 | return luaL_error(L, "field '%s' is not an integer", key); |
258 | else if (d < 0) /* absent field; no default? */ | 258 | else if (l_unlikely(d < 0)) /* absent field; no default? */ |
259 | return luaL_error(L, "field '%s' missing in date table", key); | 259 | return luaL_error(L, "field '%s' missing in date table", key); |
260 | res = d; | 260 | res = d; |
261 | } | 261 | } |
diff --git a/src/lua/lparser.c b/src/lua/lparser.c index 249ba9a..284ef1f 100644 --- a/src/lua/lparser.c +++ b/src/lua/lparser.c | |||
@@ -128,7 +128,7 @@ static void checknext (LexState *ls, int c) { | |||
128 | ** in line 'where' (if that is not the current line). | 128 | ** in line 'where' (if that is not the current line). |
129 | */ | 129 | */ |
130 | static void check_match (LexState *ls, int what, int who, int where) { | 130 | static void check_match (LexState *ls, int what, int who, int where) { |
131 | if (unlikely(!testnext(ls, what))) { | 131 | if (l_unlikely(!testnext(ls, what))) { |
132 | if (where == ls->linenumber) /* all in the same line? */ | 132 | if (where == ls->linenumber) /* all in the same line? */ |
133 | error_expected(ls, what); /* do not need a complex message */ | 133 | error_expected(ls, what); /* do not need a complex message */ |
134 | else { | 134 | else { |
@@ -517,7 +517,7 @@ static void solvegoto (LexState *ls, int g, Labeldesc *label) { | |||
517 | Labellist *gl = &ls->dyd->gt; /* list of goto's */ | 517 | Labellist *gl = &ls->dyd->gt; /* list of goto's */ |
518 | Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ | 518 | Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ |
519 | lua_assert(eqstr(gt->name, label->name)); | 519 | lua_assert(eqstr(gt->name, label->name)); |
520 | if (unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ | 520 | if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ |
521 | jumpscopeerror(ls, gt); | 521 | jumpscopeerror(ls, gt); |
522 | luaK_patchlist(ls->fs, gt->pc, label->pc); | 522 | luaK_patchlist(ls->fs, gt->pc, label->pc); |
523 | for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */ | 523 | for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */ |
@@ -1435,7 +1435,7 @@ static void breakstat (LexState *ls) { | |||
1435 | */ | 1435 | */ |
1436 | static void checkrepeated (LexState *ls, TString *name) { | 1436 | static void checkrepeated (LexState *ls, TString *name) { |
1437 | Labeldesc *lb = findlabel(ls, name); | 1437 | Labeldesc *lb = findlabel(ls, name); |
1438 | if (unlikely(lb != NULL)) { /* already defined? */ | 1438 | if (l_unlikely(lb != NULL)) { /* already defined? */ |
1439 | const char *msg = "label '%s' already defined on line %d"; | 1439 | const char *msg = "label '%s' already defined on line %d"; |
1440 | msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line); | 1440 | msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line); |
1441 | luaK_semerror(ls, msg); /* error */ | 1441 | luaK_semerror(ls, msg); /* error */ |
@@ -1520,7 +1520,7 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) { | |||
1520 | int offset = dest - (pc + 1); | 1520 | int offset = dest - (pc + 1); |
1521 | if (back) | 1521 | if (back) |
1522 | offset = -offset; | 1522 | offset = -offset; |
1523 | if (unlikely(offset > MAXARG_Bx)) | 1523 | if (l_unlikely(offset > MAXARG_Bx)) |
1524 | luaX_syntaxerror(fs->ls, "control structure too long"); | 1524 | luaX_syntaxerror(fs->ls, "control structure too long"); |
1525 | SETARG_Bx(*jmp, offset); | 1525 | SETARG_Bx(*jmp, offset); |
1526 | } | 1526 | } |
diff --git a/src/lua/lstate.c b/src/lua/lstate.c index 92ccbf9..c5e3b43 100644 --- a/src/lua/lstate.c +++ b/src/lua/lstate.c | |||
@@ -172,7 +172,7 @@ void luaE_checkcstack (lua_State *L) { | |||
172 | 172 | ||
173 | LUAI_FUNC void luaE_incCstack (lua_State *L) { | 173 | LUAI_FUNC void luaE_incCstack (lua_State *L) { |
174 | L->nCcalls++; | 174 | L->nCcalls++; |
175 | if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) | 175 | if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) |
176 | luaE_checkcstack(L); | 176 | luaE_checkcstack(L); |
177 | } | 177 | } |
178 | 178 | ||
@@ -181,6 +181,7 @@ static void stack_init (lua_State *L1, lua_State *L) { | |||
181 | int i; CallInfo *ci; | 181 | int i; CallInfo *ci; |
182 | /* initialize stack array */ | 182 | /* initialize stack array */ |
183 | L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); | 183 | L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); |
184 | L1->tbclist = L1->stack; | ||
184 | for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) | 185 | for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) |
185 | setnilvalue(s2v(L1->stack + i)); /* erase new stack */ | 186 | setnilvalue(s2v(L1->stack + i)); /* erase new stack */ |
186 | L1->top = L1->stack; | 187 | L1->top = L1->stack; |
@@ -226,8 +227,6 @@ static void init_registry (lua_State *L, global_State *g) { | |||
226 | 227 | ||
227 | /* | 228 | /* |
228 | ** open parts of the state that may cause memory-allocation errors. | 229 | ** open parts of the state that may cause memory-allocation errors. |
229 | ** ('g->nilvalue' being a nil value flags that the state was completely | ||
230 | ** build.) | ||
231 | */ | 230 | */ |
232 | static void f_luaopen (lua_State *L, void *ud) { | 231 | static void f_luaopen (lua_State *L, void *ud) { |
233 | global_State *g = G(L); | 232 | global_State *g = G(L); |
@@ -238,7 +237,7 @@ static void f_luaopen (lua_State *L, void *ud) { | |||
238 | luaT_init(L); | 237 | luaT_init(L); |
239 | luaX_init(L); | 238 | luaX_init(L); |
240 | g->gcrunning = 1; /* allow gc */ | 239 | g->gcrunning = 1; /* allow gc */ |
241 | setnilvalue(&g->nilvalue); | 240 | setnilvalue(&g->nilvalue); /* now state is complete */ |
242 | luai_userstateopen(L); | 241 | luai_userstateopen(L); |
243 | } | 242 | } |
244 | 243 | ||
@@ -253,6 +252,7 @@ static void preinit_thread (lua_State *L, global_State *g) { | |||
253 | L->ci = NULL; | 252 | L->ci = NULL; |
254 | L->nci = 0; | 253 | L->nci = 0; |
255 | L->twups = L; /* thread has no upvalues */ | 254 | L->twups = L; /* thread has no upvalues */ |
255 | L->nCcalls = 0; | ||
256 | L->errorJmp = NULL; | 256 | L->errorJmp = NULL; |
257 | L->hook = NULL; | 257 | L->hook = NULL; |
258 | L->hookmask = 0; | 258 | L->hookmask = 0; |
@@ -268,10 +268,13 @@ static void preinit_thread (lua_State *L, global_State *g) { | |||
268 | 268 | ||
269 | static void close_state (lua_State *L) { | 269 | static void close_state (lua_State *L) { |
270 | global_State *g = G(L); | 270 | global_State *g = G(L); |
271 | luaD_closeprotected(L, 0, LUA_OK); /* close all upvalues */ | 271 | if (!completestate(g)) /* closing a partially built state? */ |
272 | luaC_freeallobjects(L); /* collect all objects */ | 272 | luaC_freeallobjects(L); /* jucst collect its objects */ |
273 | if (ttisnil(&g->nilvalue)) /* closing a fully built state? */ | 273 | else { /* closing a fully built state */ |
274 | luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ | ||
275 | luaC_freeallobjects(L); /* collect all objects */ | ||
274 | luai_userstateclose(L); | 276 | luai_userstateclose(L); |
277 | } | ||
275 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); | 278 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); |
276 | freestack(L); | 279 | freestack(L); |
277 | lua_assert(gettotalbytes(g) == sizeof(LG)); | 280 | lua_assert(gettotalbytes(g) == sizeof(LG)); |
@@ -296,7 +299,6 @@ LUA_API lua_State *lua_newthread (lua_State *L) { | |||
296 | setthvalue2s(L, L->top, L1); | 299 | setthvalue2s(L, L->top, L1); |
297 | api_incr_top(L); | 300 | api_incr_top(L); |
298 | preinit_thread(L1, g); | 301 | preinit_thread(L1, g); |
299 | L1->nCcalls = 0; | ||
300 | L1->hookmask = L->hookmask; | 302 | L1->hookmask = L->hookmask; |
301 | L1->basehookcount = L->basehookcount; | 303 | L1->basehookcount = L->basehookcount; |
302 | L1->hook = L->hook; | 304 | L1->hook = L->hook; |
@@ -313,7 +315,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { | |||
313 | 315 | ||
314 | void luaE_freethread (lua_State *L, lua_State *L1) { | 316 | void luaE_freethread (lua_State *L, lua_State *L1) { |
315 | LX *l = fromstate(L1); | 317 | LX *l = fromstate(L1); |
316 | luaF_close(L1, L1->stack, NOCLOSINGMETH, 0); /* close all upvalues */ | 318 | luaF_closeupval(L1, L1->stack); /* close all upvalues */ |
317 | lua_assert(L1->openupval == NULL); | 319 | lua_assert(L1->openupval == NULL); |
318 | luai_userstatefree(L, L1); | 320 | luai_userstatefree(L, L1); |
319 | freestack(L1); | 321 | freestack(L1); |
@@ -328,7 +330,7 @@ int luaE_resetthread (lua_State *L, int status) { | |||
328 | ci->callstatus = CIST_C; | 330 | ci->callstatus = CIST_C; |
329 | if (status == LUA_YIELD) | 331 | if (status == LUA_YIELD) |
330 | status = LUA_OK; | 332 | status = LUA_OK; |
331 | status = luaD_closeprotected(L, 0, status); | 333 | status = luaD_closeprotected(L, 1, status); |
332 | if (status != LUA_OK) /* errors? */ | 334 | if (status != LUA_OK) /* errors? */ |
333 | luaD_seterrorobj(L, status, L->stack + 1); | 335 | luaD_seterrorobj(L, status, L->stack + 1); |
334 | else | 336 | else |
@@ -363,7 +365,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
363 | preinit_thread(L, g); | 365 | preinit_thread(L, g); |
364 | g->allgc = obj2gco(L); /* by now, only object is the main thread */ | 366 | g->allgc = obj2gco(L); /* by now, only object is the main thread */ |
365 | L->next = NULL; | 367 | L->next = NULL; |
366 | L->nCcalls = 0; | ||
367 | incnny(L); /* main thread is always non yieldable */ | 368 | incnny(L); /* main thread is always non yieldable */ |
368 | g->frealloc = f; | 369 | g->frealloc = f; |
369 | g->ud = ud; | 370 | g->ud = ud; |
@@ -378,6 +379,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
378 | g->panic = NULL; | 379 | g->panic = NULL; |
379 | g->gcstate = GCSpause; | 380 | g->gcstate = GCSpause; |
380 | g->gckind = KGC_INC; | 381 | g->gckind = KGC_INC; |
382 | g->gcstopem = 0; | ||
381 | g->gcemergency = 0; | 383 | g->gcemergency = 0; |
382 | g->finobj = g->tobefnz = g->fixedgc = NULL; | 384 | g->finobj = g->tobefnz = g->fixedgc = NULL; |
383 | g->firstold1 = g->survival = g->old1 = g->reallyold = NULL; | 385 | g->firstold1 = g->survival = g->old1 = g->reallyold = NULL; |
diff --git a/src/lua/lstate.h b/src/lua/lstate.h index 38a6c9b..c1283bb 100644 --- a/src/lua/lstate.h +++ b/src/lua/lstate.h | |||
@@ -156,6 +156,18 @@ typedef struct stringtable { | |||
156 | 156 | ||
157 | /* | 157 | /* |
158 | ** Information about a call. | 158 | ** Information about a call. |
159 | ** About union 'u': | ||
160 | ** - field 'l' is used only for Lua functions; | ||
161 | ** - field 'c' is used only for C functions. | ||
162 | ** About union 'u2': | ||
163 | ** - field 'funcidx' is used only by C functions while doing a | ||
164 | ** protected call; | ||
165 | ** - field 'nyield' is used only while a function is "doing" an | ||
166 | ** yield (from the yield until the next resume); | ||
167 | ** - field 'nres' is used only while closing tbc variables when | ||
168 | ** returning from a C function; | ||
169 | ** - field 'transferinfo' is used only during call/returnhooks, | ||
170 | ** before the function starts or after it ends. | ||
159 | */ | 171 | */ |
160 | typedef struct CallInfo { | 172 | typedef struct CallInfo { |
161 | StkId func; /* function index in the stack */ | 173 | StkId func; /* function index in the stack */ |
@@ -176,6 +188,7 @@ typedef struct CallInfo { | |||
176 | union { | 188 | union { |
177 | int funcidx; /* called-function index */ | 189 | int funcidx; /* called-function index */ |
178 | int nyield; /* number of values yielded */ | 190 | int nyield; /* number of values yielded */ |
191 | int nres; /* number of values returned */ | ||
179 | struct { /* info about transferred values (for call/return hooks) */ | 192 | struct { /* info about transferred values (for call/return hooks) */ |
180 | unsigned short ftransfer; /* offset of first value transferred */ | 193 | unsigned short ftransfer; /* offset of first value transferred */ |
181 | unsigned short ntransfer; /* number of values transferred */ | 194 | unsigned short ntransfer; /* number of values transferred */ |
@@ -191,17 +204,34 @@ typedef struct CallInfo { | |||
191 | */ | 204 | */ |
192 | #define CIST_OAH (1<<0) /* original value of 'allowhook' */ | 205 | #define CIST_OAH (1<<0) /* original value of 'allowhook' */ |
193 | #define CIST_C (1<<1) /* call is running a C function */ | 206 | #define CIST_C (1<<1) /* call is running a C function */ |
194 | #define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */ | 207 | #define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */ |
195 | #define CIST_HOOKED (1<<3) /* call is running a debug hook */ | 208 | #define CIST_HOOKED (1<<3) /* call is running a debug hook */ |
196 | #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ | 209 | #define CIST_YPCALL (1<<4) /* doing a yieldable protected call */ |
197 | #define CIST_TAIL (1<<5) /* call was tail called */ | 210 | #define CIST_TAIL (1<<5) /* call was tail called */ |
198 | #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ | 211 | #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ |
199 | #define CIST_FIN (1<<7) /* call is running a finalizer */ | 212 | #define CIST_FIN (1<<7) /* call is running a finalizer */ |
200 | #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ | 213 | #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ |
214 | #define CIST_CLSRET (1<<9) /* function is closing tbc variables */ | ||
215 | /* Bits 10-12 are used for CIST_RECST (see below) */ | ||
216 | #define CIST_RECST 10 | ||
201 | #if defined(LUA_COMPAT_LT_LE) | 217 | #if defined(LUA_COMPAT_LT_LE) |
202 | #define CIST_LEQ (1<<9) /* using __lt for __le */ | 218 | #define CIST_LEQ (1<<13) /* using __lt for __le */ |
203 | #endif | 219 | #endif |
204 | 220 | ||
221 | |||
222 | /* | ||
223 | ** Field CIST_RECST stores the "recover status", used to keep the error | ||
224 | ** status while closing to-be-closed variables in coroutines, so that | ||
225 | ** Lua can correctly resume after an yield from a __close method called | ||
226 | ** because of an error. (Three bits are enough for error status.) | ||
227 | */ | ||
228 | #define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7) | ||
229 | #define setcistrecst(ci,st) \ | ||
230 | check_exp(((st) & 7) == (st), /* status must fit in three bits */ \ | ||
231 | ((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \ | ||
232 | | ((st) << CIST_RECST))) | ||
233 | |||
234 | |||
205 | /* active function is a Lua function */ | 235 | /* active function is a Lua function */ |
206 | #define isLua(ci) (!((ci)->callstatus & CIST_C)) | 236 | #define isLua(ci) (!((ci)->callstatus & CIST_C)) |
207 | 237 | ||
@@ -230,6 +260,7 @@ typedef struct global_State { | |||
230 | lu_byte currentwhite; | 260 | lu_byte currentwhite; |
231 | lu_byte gcstate; /* state of garbage collector */ | 261 | lu_byte gcstate; /* state of garbage collector */ |
232 | lu_byte gckind; /* kind of GC running */ | 262 | lu_byte gckind; /* kind of GC running */ |
263 | lu_byte gcstopem; /* stops emergency collections */ | ||
233 | lu_byte genminormul; /* control for minor generational collections */ | 264 | lu_byte genminormul; /* control for minor generational collections */ |
234 | lu_byte genmajormul; /* control for major generational collections */ | 265 | lu_byte genmajormul; /* control for major generational collections */ |
235 | lu_byte gcrunning; /* true if GC is running */ | 266 | lu_byte gcrunning; /* true if GC is running */ |
@@ -281,6 +312,7 @@ struct lua_State { | |||
281 | StkId stack_last; /* end of stack (last element + 1) */ | 312 | StkId stack_last; /* end of stack (last element + 1) */ |
282 | StkId stack; /* stack base */ | 313 | StkId stack; /* stack base */ |
283 | UpVal *openupval; /* list of open upvalues in this stack */ | 314 | UpVal *openupval; /* list of open upvalues in this stack */ |
315 | StkId tbclist; /* list of to-be-closed variables */ | ||
284 | GCObject *gclist; | 316 | GCObject *gclist; |
285 | struct lua_State *twups; /* list of threads with open upvalues */ | 317 | struct lua_State *twups; /* list of threads with open upvalues */ |
286 | struct lua_longjmp *errorJmp; /* current error recover point */ | 318 | struct lua_longjmp *errorJmp; /* current error recover point */ |
@@ -297,6 +329,12 @@ struct lua_State { | |||
297 | 329 | ||
298 | #define G(L) (L->l_G) | 330 | #define G(L) (L->l_G) |
299 | 331 | ||
332 | /* | ||
333 | ** 'g->nilvalue' being a nil value flags that the state was completely | ||
334 | ** build. | ||
335 | */ | ||
336 | #define completestate(g) ttisnil(&g->nilvalue) | ||
337 | |||
300 | 338 | ||
301 | /* | 339 | /* |
302 | ** Union of all collectable objects (only for conversions) | 340 | ** Union of all collectable objects (only for conversions) |
diff --git a/src/lua/lstring.c b/src/lua/lstring.c index 138871c..13dcaf4 100644 --- a/src/lua/lstring.c +++ b/src/lua/lstring.c | |||
@@ -89,7 +89,7 @@ void luaS_resize (lua_State *L, int nsize) { | |||
89 | if (nsize < osize) /* shrinking table? */ | 89 | if (nsize < osize) /* shrinking table? */ |
90 | tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ | 90 | tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ |
91 | newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); | 91 | newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); |
92 | if (unlikely(newvect == NULL)) { /* reallocation failed? */ | 92 | if (l_unlikely(newvect == NULL)) { /* reallocation failed? */ |
93 | if (nsize < osize) /* was it shrinking table? */ | 93 | if (nsize < osize) /* was it shrinking table? */ |
94 | tablerehash(tb->hash, nsize, osize); /* restore to original size */ | 94 | tablerehash(tb->hash, nsize, osize); /* restore to original size */ |
95 | /* leave table as it was */ | 95 | /* leave table as it was */ |
@@ -172,7 +172,7 @@ void luaS_remove (lua_State *L, TString *ts) { | |||
172 | 172 | ||
173 | 173 | ||
174 | static void growstrtab (lua_State *L, stringtable *tb) { | 174 | static void growstrtab (lua_State *L, stringtable *tb) { |
175 | if (unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ | 175 | if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ |
176 | luaC_fullgc(L, 1); /* try to free some... */ | 176 | luaC_fullgc(L, 1); /* try to free some... */ |
177 | if (tb->nuse == MAX_INT) /* still too many? */ | 177 | if (tb->nuse == MAX_INT) /* still too many? */ |
178 | luaM_error(L); /* cannot even create a message... */ | 178 | luaM_error(L); /* cannot even create a message... */ |
@@ -223,7 +223,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { | |||
223 | return internshrstr(L, str, l); | 223 | return internshrstr(L, str, l); |
224 | else { | 224 | else { |
225 | TString *ts; | 225 | TString *ts; |
226 | if (unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) | 226 | if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) |
227 | luaM_toobig(L); | 227 | luaM_toobig(L); |
228 | ts = luaS_createlngstrobj(L, l); | 228 | ts = luaS_createlngstrobj(L, l); |
229 | memcpy(getstr(ts), str, l * sizeof(char)); | 229 | memcpy(getstr(ts), str, l * sizeof(char)); |
@@ -259,7 +259,7 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) { | |||
259 | Udata *u; | 259 | Udata *u; |
260 | int i; | 260 | int i; |
261 | GCObject *o; | 261 | GCObject *o; |
262 | if (unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) | 262 | if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) |
263 | luaM_toobig(L); | 263 | luaM_toobig(L); |
264 | o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s)); | 264 | o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s)); |
265 | u = gco2u(o); | 265 | u = gco2u(o); |
diff --git a/src/lua/lstrlib.c b/src/lua/lstrlib.c index c7242ea..47e5b27 100644 --- a/src/lua/lstrlib.c +++ b/src/lua/lstrlib.c | |||
@@ -152,8 +152,9 @@ static int str_rep (lua_State *L) { | |||
152 | const char *s = luaL_checklstring(L, 1, &l); | 152 | const char *s = luaL_checklstring(L, 1, &l); |
153 | lua_Integer n = luaL_checkinteger(L, 2); | 153 | lua_Integer n = luaL_checkinteger(L, 2); |
154 | const char *sep = luaL_optlstring(L, 3, "", &lsep); | 154 | const char *sep = luaL_optlstring(L, 3, "", &lsep); |
155 | if (n <= 0) lua_pushliteral(L, ""); | 155 | if (n <= 0) |
156 | else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ | 156 | lua_pushliteral(L, ""); |
157 | else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n)) | ||
157 | return luaL_error(L, "resulting string too large"); | 158 | return luaL_error(L, "resulting string too large"); |
158 | else { | 159 | else { |
159 | size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; | 160 | size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; |
@@ -181,7 +182,7 @@ static int str_byte (lua_State *L) { | |||
181 | size_t pose = getendpos(L, 3, pi, l); | 182 | size_t pose = getendpos(L, 3, pi, l); |
182 | int n, i; | 183 | int n, i; |
183 | if (posi > pose) return 0; /* empty interval; return no values */ | 184 | if (posi > pose) return 0; /* empty interval; return no values */ |
184 | if (pose - posi >= (size_t)INT_MAX) /* arithmetic overflow? */ | 185 | if (l_unlikely(pose - posi >= (size_t)INT_MAX)) /* arithmetic overflow? */ |
185 | return luaL_error(L, "string slice too long"); | 186 | return luaL_error(L, "string slice too long"); |
186 | n = (int)(pose - posi) + 1; | 187 | n = (int)(pose - posi) + 1; |
187 | luaL_checkstack(L, n, "string slice too long"); | 188 | luaL_checkstack(L, n, "string slice too long"); |
@@ -235,7 +236,7 @@ static int str_dump (lua_State *L) { | |||
235 | luaL_checktype(L, 1, LUA_TFUNCTION); | 236 | luaL_checktype(L, 1, LUA_TFUNCTION); |
236 | lua_settop(L, 1); /* ensure function is on the top of the stack */ | 237 | lua_settop(L, 1); /* ensure function is on the top of the stack */ |
237 | state.init = 0; | 238 | state.init = 0; |
238 | if (lua_dump(L, writer, &state, strip) != 0) | 239 | if (l_unlikely(lua_dump(L, writer, &state, strip) != 0)) |
239 | return luaL_error(L, "unable to dump given function"); | 240 | return luaL_error(L, "unable to dump given function"); |
240 | luaL_pushresult(&state.B); | 241 | luaL_pushresult(&state.B); |
241 | return 1; | 242 | return 1; |
@@ -275,7 +276,8 @@ static int tonum (lua_State *L, int arg) { | |||
275 | 276 | ||
276 | static void trymt (lua_State *L, const char *mtname) { | 277 | static void trymt (lua_State *L, const char *mtname) { |
277 | lua_settop(L, 2); /* back to the original arguments */ | 278 | lua_settop(L, 2); /* back to the original arguments */ |
278 | if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname)) | 279 | if (l_unlikely(lua_type(L, 2) == LUA_TSTRING || |
280 | !luaL_getmetafield(L, 2, mtname))) | ||
279 | luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, | 281 | luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, |
280 | luaL_typename(L, -2), luaL_typename(L, -1)); | 282 | luaL_typename(L, -2), luaL_typename(L, -1)); |
281 | lua_insert(L, -3); /* put metamethod before arguments */ | 283 | lua_insert(L, -3); /* put metamethod before arguments */ |
@@ -383,7 +385,8 @@ static const char *match (MatchState *ms, const char *s, const char *p); | |||
383 | 385 | ||
384 | static int check_capture (MatchState *ms, int l) { | 386 | static int check_capture (MatchState *ms, int l) { |
385 | l -= '1'; | 387 | l -= '1'; |
386 | if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) | 388 | if (l_unlikely(l < 0 || l >= ms->level || |
389 | ms->capture[l].len == CAP_UNFINISHED)) | ||
387 | return luaL_error(ms->L, "invalid capture index %%%d", l + 1); | 390 | return luaL_error(ms->L, "invalid capture index %%%d", l + 1); |
388 | return l; | 391 | return l; |
389 | } | 392 | } |
@@ -400,14 +403,14 @@ static int capture_to_close (MatchState *ms) { | |||
400 | static const char *classend (MatchState *ms, const char *p) { | 403 | static const char *classend (MatchState *ms, const char *p) { |
401 | switch (*p++) { | 404 | switch (*p++) { |
402 | case L_ESC: { | 405 | case L_ESC: { |
403 | if (p == ms->p_end) | 406 | if (l_unlikely(p == ms->p_end)) |
404 | luaL_error(ms->L, "malformed pattern (ends with '%%')"); | 407 | luaL_error(ms->L, "malformed pattern (ends with '%%')"); |
405 | return p+1; | 408 | return p+1; |
406 | } | 409 | } |
407 | case '[': { | 410 | case '[': { |
408 | if (*p == '^') p++; | 411 | if (*p == '^') p++; |
409 | do { /* look for a ']' */ | 412 | do { /* look for a ']' */ |
410 | if (p == ms->p_end) | 413 | if (l_unlikely(p == ms->p_end)) |
411 | luaL_error(ms->L, "malformed pattern (missing ']')"); | 414 | luaL_error(ms->L, "malformed pattern (missing ']')"); |
412 | if (*(p++) == L_ESC && p < ms->p_end) | 415 | if (*(p++) == L_ESC && p < ms->p_end) |
413 | p++; /* skip escapes (e.g. '%]') */ | 416 | p++; /* skip escapes (e.g. '%]') */ |
@@ -482,7 +485,7 @@ static int singlematch (MatchState *ms, const char *s, const char *p, | |||
482 | 485 | ||
483 | static const char *matchbalance (MatchState *ms, const char *s, | 486 | static const char *matchbalance (MatchState *ms, const char *s, |
484 | const char *p) { | 487 | const char *p) { |
485 | if (p >= ms->p_end - 1) | 488 | if (l_unlikely(p >= ms->p_end - 1)) |
486 | luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); | 489 | luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); |
487 | if (*s != *p) return NULL; | 490 | if (*s != *p) return NULL; |
488 | else { | 491 | else { |
@@ -565,7 +568,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) { | |||
565 | 568 | ||
566 | 569 | ||
567 | static const char *match (MatchState *ms, const char *s, const char *p) { | 570 | static const char *match (MatchState *ms, const char *s, const char *p) { |
568 | if (ms->matchdepth-- == 0) | 571 | if (l_unlikely(ms->matchdepth-- == 0)) |
569 | luaL_error(ms->L, "pattern too complex"); | 572 | luaL_error(ms->L, "pattern too complex"); |
570 | init: /* using goto's to optimize tail recursion */ | 573 | init: /* using goto's to optimize tail recursion */ |
571 | if (p != ms->p_end) { /* end of pattern? */ | 574 | if (p != ms->p_end) { /* end of pattern? */ |
@@ -599,7 +602,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { | |||
599 | case 'f': { /* frontier? */ | 602 | case 'f': { /* frontier? */ |
600 | const char *ep; char previous; | 603 | const char *ep; char previous; |
601 | p += 2; | 604 | p += 2; |
602 | if (*p != '[') | 605 | if (l_unlikely(*p != '[')) |
603 | luaL_error(ms->L, "missing '[' after '%%f' in pattern"); | 606 | luaL_error(ms->L, "missing '[' after '%%f' in pattern"); |
604 | ep = classend(ms, p); /* points to what is next */ | 607 | ep = classend(ms, p); /* points to what is next */ |
605 | previous = (s == ms->src_init) ? '\0' : *(s - 1); | 608 | previous = (s == ms->src_init) ? '\0' : *(s - 1); |
@@ -699,7 +702,7 @@ static const char *lmemfind (const char *s1, size_t l1, | |||
699 | static size_t get_onecapture (MatchState *ms, int i, const char *s, | 702 | static size_t get_onecapture (MatchState *ms, int i, const char *s, |
700 | const char *e, const char **cap) { | 703 | const char *e, const char **cap) { |
701 | if (i >= ms->level) { | 704 | if (i >= ms->level) { |
702 | if (i != 0) | 705 | if (l_unlikely(i != 0)) |
703 | luaL_error(ms->L, "invalid capture index %%%d", i + 1); | 706 | luaL_error(ms->L, "invalid capture index %%%d", i + 1); |
704 | *cap = s; | 707 | *cap = s; |
705 | return e - s; | 708 | return e - s; |
@@ -707,7 +710,7 @@ static size_t get_onecapture (MatchState *ms, int i, const char *s, | |||
707 | else { | 710 | else { |
708 | ptrdiff_t capl = ms->capture[i].len; | 711 | ptrdiff_t capl = ms->capture[i].len; |
709 | *cap = ms->capture[i].init; | 712 | *cap = ms->capture[i].init; |
710 | if (capl == CAP_UNFINISHED) | 713 | if (l_unlikely(capl == CAP_UNFINISHED)) |
711 | luaL_error(ms->L, "unfinished capture"); | 714 | luaL_error(ms->L, "unfinished capture"); |
712 | else if (capl == CAP_POSITION) | 715 | else if (capl == CAP_POSITION) |
713 | lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); | 716 | lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); |
@@ -926,7 +929,7 @@ static int add_value (MatchState *ms, luaL_Buffer *b, const char *s, | |||
926 | luaL_addlstring(b, s, e - s); /* keep original text */ | 929 | luaL_addlstring(b, s, e - s); /* keep original text */ |
927 | return 0; /* no changes */ | 930 | return 0; /* no changes */ |
928 | } | 931 | } |
929 | else if (!lua_isstring(L, -1)) | 932 | else if (l_unlikely(!lua_isstring(L, -1))) |
930 | return luaL_error(L, "invalid replacement value (a %s)", | 933 | return luaL_error(L, "invalid replacement value (a %s)", |
931 | luaL_typename(L, -1)); | 934 | luaL_typename(L, -1)); |
932 | else { | 935 | else { |
@@ -1058,7 +1061,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, | |||
1058 | for (i = 0; i < n; i++) | 1061 | for (i = 0; i < n; i++) |
1059 | buff[i] = toupper(uchar(buff[i])); | 1062 | buff[i] = toupper(uchar(buff[i])); |
1060 | } | 1063 | } |
1061 | else if (fmt[SIZELENMOD] != 'a') | 1064 | else if (l_unlikely(fmt[SIZELENMOD] != 'a')) |
1062 | return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); | 1065 | return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); |
1063 | return n; | 1066 | return n; |
1064 | } | 1067 | } |
@@ -1411,7 +1414,7 @@ static int getnum (const char **fmt, int df) { | |||
1411 | */ | 1414 | */ |
1412 | static int getnumlimit (Header *h, const char **fmt, int df) { | 1415 | static int getnumlimit (Header *h, const char **fmt, int df) { |
1413 | int sz = getnum(fmt, df); | 1416 | int sz = getnum(fmt, df); |
1414 | if (sz > MAXINTSIZE || sz <= 0) | 1417 | if (l_unlikely(sz > MAXINTSIZE || sz <= 0)) |
1415 | return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", | 1418 | return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", |
1416 | sz, MAXINTSIZE); | 1419 | sz, MAXINTSIZE); |
1417 | return sz; | 1420 | return sz; |
@@ -1452,7 +1455,7 @@ static KOption getoption (Header *h, const char **fmt, int *size) { | |||
1452 | case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; | 1455 | case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; |
1453 | case 'c': | 1456 | case 'c': |
1454 | *size = getnum(fmt, -1); | 1457 | *size = getnum(fmt, -1); |
1455 | if (*size == -1) | 1458 | if (l_unlikely(*size == -1)) |
1456 | luaL_error(h->L, "missing size for format option 'c'"); | 1459 | luaL_error(h->L, "missing size for format option 'c'"); |
1457 | return Kchar; | 1460 | return Kchar; |
1458 | case 'z': return Kzstr; | 1461 | case 'z': return Kzstr; |
@@ -1491,7 +1494,7 @@ static KOption getdetails (Header *h, size_t totalsize, | |||
1491 | else { | 1494 | else { |
1492 | if (align > h->maxalign) /* enforce maximum alignment */ | 1495 | if (align > h->maxalign) /* enforce maximum alignment */ |
1493 | align = h->maxalign; | 1496 | align = h->maxalign; |
1494 | if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ | 1497 | if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */ |
1495 | luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); | 1498 | luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); |
1496 | *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); | 1499 | *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); |
1497 | } | 1500 | } |
@@ -1683,7 +1686,7 @@ static lua_Integer unpackint (lua_State *L, const char *str, | |||
1683 | else if (size > SZINT) { /* must check unread bytes */ | 1686 | else if (size > SZINT) { /* must check unread bytes */ |
1684 | int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; | 1687 | int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; |
1685 | for (i = limit; i < size; i++) { | 1688 | for (i = limit; i < size; i++) { |
1686 | if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) | 1689 | if (l_unlikely((unsigned char)str[islittle ? i : size - 1 - i] != mask)) |
1687 | luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); | 1690 | luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); |
1688 | } | 1691 | } |
1689 | } | 1692 | } |
diff --git a/src/lua/ltable.c b/src/lua/ltable.c index e98bab7..b520cdf 100644 --- a/src/lua/ltable.c +++ b/src/lua/ltable.c | |||
@@ -307,7 +307,7 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key, | |||
307 | return i; /* yes; that's the index */ | 307 | return i; /* yes; that's the index */ |
308 | else { | 308 | else { |
309 | const TValue *n = getgeneric(t, key, 1); | 309 | const TValue *n = getgeneric(t, key, 1); |
310 | if (unlikely(isabstkey(n))) | 310 | if (l_unlikely(isabstkey(n))) |
311 | luaG_runerror(L, "invalid key to 'next'"); /* key not found */ | 311 | luaG_runerror(L, "invalid key to 'next'"); /* key not found */ |
312 | i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ | 312 | i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ |
313 | /* hash elements are numbered after array ones */ | 313 | /* hash elements are numbered after array ones */ |
@@ -541,7 +541,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
541 | } | 541 | } |
542 | /* allocate new array */ | 542 | /* allocate new array */ |
543 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); | 543 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); |
544 | if (unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ | 544 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ |
545 | freehash(L, &newt); /* release new hash part */ | 545 | freehash(L, &newt); /* release new hash part */ |
546 | luaM_error(L); /* raise error (with array unchanged) */ | 546 | luaM_error(L); /* raise error (with array unchanged) */ |
547 | } | 547 | } |
@@ -635,7 +635,7 @@ static Node *getfreepos (Table *t) { | |||
635 | void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { | 635 | void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { |
636 | Node *mp; | 636 | Node *mp; |
637 | TValue aux; | 637 | TValue aux; |
638 | if (unlikely(ttisnil(key))) | 638 | if (l_unlikely(ttisnil(key))) |
639 | luaG_runerror(L, "table index is nil"); | 639 | luaG_runerror(L, "table index is nil"); |
640 | else if (ttisfloat(key)) { | 640 | else if (ttisfloat(key)) { |
641 | lua_Number f = fltvalue(key); | 641 | lua_Number f = fltvalue(key); |
@@ -644,7 +644,7 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { | |||
644 | setivalue(&aux, k); | 644 | setivalue(&aux, k); |
645 | key = &aux; /* insert it as an integer */ | 645 | key = &aux; /* insert it as an integer */ |
646 | } | 646 | } |
647 | else if (unlikely(luai_numisnan(f))) | 647 | else if (l_unlikely(luai_numisnan(f))) |
648 | luaG_runerror(L, "table index is NaN"); | 648 | luaG_runerror(L, "table index is NaN"); |
649 | } | 649 | } |
650 | if (ttisnil(value)) | 650 | if (ttisnil(value)) |
diff --git a/src/lua/ltablib.c b/src/lua/ltablib.c index d344a47..d80eb80 100644 --- a/src/lua/ltablib.c +++ b/src/lua/ltablib.c | |||
@@ -145,8 +145,8 @@ static int tmove (lua_State *L) { | |||
145 | 145 | ||
146 | static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { | 146 | static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { |
147 | lua_geti(L, 1, i); | 147 | lua_geti(L, 1, i); |
148 | if (!lua_isstring(L, -1)) | 148 | if (l_unlikely(!lua_isstring(L, -1))) |
149 | luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", | 149 | luaL_error(L, "invalid value (%s) at index %I in table for 'concat'", |
150 | luaL_typename(L, -1), i); | 150 | luaL_typename(L, -1), i); |
151 | luaL_addvalue(b); | 151 | luaL_addvalue(b); |
152 | } | 152 | } |
@@ -196,7 +196,8 @@ static int tunpack (lua_State *L) { | |||
196 | lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); | 196 | lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); |
197 | if (i > e) return 0; /* empty range */ | 197 | if (i > e) return 0; /* empty range */ |
198 | n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ | 198 | n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ |
199 | if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) | 199 | if (l_unlikely(n >= (unsigned int)INT_MAX || |
200 | !lua_checkstack(L, (int)(++n)))) | ||
200 | return luaL_error(L, "too many results to unpack"); | 201 | return luaL_error(L, "too many results to unpack"); |
201 | for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ | 202 | for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ |
202 | lua_geti(L, 1, i); | 203 | lua_geti(L, 1, i); |
@@ -300,14 +301,14 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) { | |||
300 | for (;;) { | 301 | for (;;) { |
301 | /* next loop: repeat ++i while a[i] < P */ | 302 | /* next loop: repeat ++i while a[i] < P */ |
302 | while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { | 303 | while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { |
303 | if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ | 304 | if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */ |
304 | luaL_error(L, "invalid order function for sorting"); | 305 | luaL_error(L, "invalid order function for sorting"); |
305 | lua_pop(L, 1); /* remove a[i] */ | 306 | lua_pop(L, 1); /* remove a[i] */ |
306 | } | 307 | } |
307 | /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ | 308 | /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ |
308 | /* next loop: repeat --j while P < a[j] */ | 309 | /* next loop: repeat --j while P < a[j] */ |
309 | while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { | 310 | while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { |
310 | if (j < i) /* j < i but a[j] > P ?? */ | 311 | if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */ |
311 | luaL_error(L, "invalid order function for sorting"); | 312 | luaL_error(L, "invalid order function for sorting"); |
312 | lua_pop(L, 1); /* remove a[j] */ | 313 | lua_pop(L, 1); /* remove a[j] */ |
313 | } | 314 | } |
diff --git a/src/lua/ltm.c b/src/lua/ltm.c index 4770f96..b657b78 100644 --- a/src/lua/ltm.c +++ b/src/lua/ltm.c | |||
@@ -147,7 +147,7 @@ static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
147 | 147 | ||
148 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | 148 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, |
149 | StkId res, TMS event) { | 149 | StkId res, TMS event) { |
150 | if (!callbinTM(L, p1, p2, res, event)) { | 150 | if (l_unlikely(!callbinTM(L, p1, p2, res, event))) { |
151 | switch (event) { | 151 | switch (event) { |
152 | case TM_BAND: case TM_BOR: case TM_BXOR: | 152 | case TM_BAND: case TM_BOR: case TM_BXOR: |
153 | case TM_SHL: case TM_SHR: case TM_BNOT: { | 153 | case TM_SHL: case TM_SHR: case TM_BNOT: { |
@@ -166,7 +166,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
166 | 166 | ||
167 | void luaT_tryconcatTM (lua_State *L) { | 167 | void luaT_tryconcatTM (lua_State *L) { |
168 | StkId top = L->top; | 168 | StkId top = L->top; |
169 | if (!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, TM_CONCAT)) | 169 | if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, |
170 | TM_CONCAT))) | ||
170 | luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); | 171 | luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); |
171 | } | 172 | } |
172 | 173 | ||
diff --git a/src/lua/luaconf.h b/src/lua/luaconf.h index d9cf18c..ae73e2f 100644 --- a/src/lua/luaconf.h +++ b/src/lua/luaconf.h | |||
@@ -16,13 +16,13 @@ | |||
16 | ** =================================================================== | 16 | ** =================================================================== |
17 | ** General Configuration File for Lua | 17 | ** General Configuration File for Lua |
18 | ** | 18 | ** |
19 | ** Some definitions here can be changed externally, through the | 19 | ** Some definitions here can be changed externally, through the compiler |
20 | ** compiler (e.g., with '-D' options). Those are protected by | 20 | ** (e.g., with '-D' options): They are commented out or protected |
21 | ** '#if !defined' guards. However, several other definitions should | 21 | ** by '#if !defined' guards. However, several other definitions |
22 | ** be changed directly here, either because they affect the Lua | 22 | ** should be changed directly here, either because they affect the |
23 | ** ABI (by making the changes here, you ensure that all software | 23 | ** Lua ABI (by making the changes here, you ensure that all software |
24 | ** connected to Lua, such as C libraries, will be compiled with the | 24 | ** connected to Lua, such as C libraries, will be compiled with the same |
25 | ** same configuration); or because they are seldom changed. | 25 | ** configuration); or because they are seldom changed. |
26 | ** | 26 | ** |
27 | ** Search for "@@" to find all configurable definitions. | 27 | ** Search for "@@" to find all configurable definitions. |
28 | ** =================================================================== | 28 | ** =================================================================== |
@@ -81,27 +81,13 @@ | |||
81 | 81 | ||
82 | /* | 82 | /* |
83 | ** {================================================================== | 83 | ** {================================================================== |
84 | ** Configuration for Number types. | 84 | ** Configuration for Number types. These options should not be |
85 | ** set externally, because any other code connected to Lua must | ||
86 | ** use the same configuration. | ||
85 | ** =================================================================== | 87 | ** =================================================================== |
86 | */ | 88 | */ |
87 | 89 | ||
88 | /* | 90 | /* |
89 | @@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. | ||
90 | */ | ||
91 | /* #define LUA_32BITS */ | ||
92 | |||
93 | |||
94 | /* | ||
95 | @@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for | ||
96 | ** C89 ('long' and 'double'); Windows always has '__int64', so it does | ||
97 | ** not need to use this case. | ||
98 | */ | ||
99 | #if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) | ||
100 | #define LUA_C89_NUMBERS | ||
101 | #endif | ||
102 | |||
103 | |||
104 | /* | ||
105 | @@ LUA_INT_TYPE defines the type for Lua integers. | 91 | @@ LUA_INT_TYPE defines the type for Lua integers. |
106 | @@ LUA_FLOAT_TYPE defines the type for Lua floats. | 92 | @@ LUA_FLOAT_TYPE defines the type for Lua floats. |
107 | ** Lua should work fine with any mix of these options supported | 93 | ** Lua should work fine with any mix of these options supported |
@@ -121,7 +107,31 @@ | |||
121 | #define LUA_FLOAT_DOUBLE 2 | 107 | #define LUA_FLOAT_DOUBLE 2 |
122 | #define LUA_FLOAT_LONGDOUBLE 3 | 108 | #define LUA_FLOAT_LONGDOUBLE 3 |
123 | 109 | ||
124 | #if defined(LUA_32BITS) /* { */ | 110 | |
111 | /* Default configuration ('long long' and 'double', for 64-bit Lua) */ | ||
112 | #define LUA_INT_DEFAULT LUA_INT_LONGLONG | ||
113 | #define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE | ||
114 | |||
115 | |||
116 | /* | ||
117 | @@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. | ||
118 | */ | ||
119 | #define LUA_32BITS 0 | ||
120 | |||
121 | |||
122 | /* | ||
123 | @@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for | ||
124 | ** C89 ('long' and 'double'); Windows always has '__int64', so it does | ||
125 | ** not need to use this case. | ||
126 | */ | ||
127 | #if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) | ||
128 | #define LUA_C89_NUMBERS 1 | ||
129 | #else | ||
130 | #define LUA_C89_NUMBERS 0 | ||
131 | #endif | ||
132 | |||
133 | |||
134 | #if LUA_32BITS /* { */ | ||
125 | /* | 135 | /* |
126 | ** 32-bit integers and 'float' | 136 | ** 32-bit integers and 'float' |
127 | */ | 137 | */ |
@@ -132,26 +142,21 @@ | |||
132 | #endif | 142 | #endif |
133 | #define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT | 143 | #define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT |
134 | 144 | ||
135 | #elif defined(LUA_C89_NUMBERS) /* }{ */ | 145 | #elif LUA_C89_NUMBERS /* }{ */ |
136 | /* | 146 | /* |
137 | ** largest types available for C89 ('long' and 'double') | 147 | ** largest types available for C89 ('long' and 'double') |
138 | */ | 148 | */ |
139 | #define LUA_INT_TYPE LUA_INT_LONG | 149 | #define LUA_INT_TYPE LUA_INT_LONG |
140 | #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE | 150 | #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE |
141 | 151 | ||
142 | #endif /* } */ | 152 | #else /* }{ */ |
153 | /* use defaults */ | ||
143 | 154 | ||
155 | #define LUA_INT_TYPE LUA_INT_DEFAULT | ||
156 | #define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT | ||
144 | 157 | ||
145 | /* | 158 | #endif /* } */ |
146 | ** default configuration for 64-bit Lua ('long long' and 'double') | ||
147 | */ | ||
148 | #if !defined(LUA_INT_TYPE) | ||
149 | #define LUA_INT_TYPE LUA_INT_LONGLONG | ||
150 | #endif | ||
151 | 159 | ||
152 | #if !defined(LUA_FLOAT_TYPE) | ||
153 | #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE | ||
154 | #endif | ||
155 | 160 | ||
156 | /* }================================================================== */ | 161 | /* }================================================================== */ |
157 | 162 | ||
@@ -373,14 +378,13 @@ | |||
373 | 378 | ||
374 | /* | 379 | /* |
375 | ** {================================================================== | 380 | ** {================================================================== |
376 | ** Configuration for Numbers. | 381 | ** Configuration for Numbers (low-level part). |
377 | ** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* | 382 | ** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* |
378 | ** satisfy your needs. | 383 | ** satisfy your needs. |
379 | ** =================================================================== | 384 | ** =================================================================== |
380 | */ | 385 | */ |
381 | 386 | ||
382 | /* | 387 | /* |
383 | @@ LUA_NUMBER is the floating-point type used by Lua. | ||
384 | @@ LUAI_UACNUMBER is the result of a 'default argument promotion' | 388 | @@ LUAI_UACNUMBER is the result of a 'default argument promotion' |
385 | @@ over a floating number. | 389 | @@ over a floating number. |
386 | @@ l_floatatt(x) corrects float attribute 'x' to the proper float type | 390 | @@ l_floatatt(x) corrects float attribute 'x' to the proper float type |
@@ -473,10 +477,7 @@ | |||
473 | 477 | ||
474 | 478 | ||
475 | /* | 479 | /* |
476 | @@ LUA_INTEGER is the integer type used by Lua. | ||
477 | ** | ||
478 | @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. | 480 | @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. |
479 | ** | ||
480 | @@ LUAI_UACINT is the result of a 'default argument promotion' | 481 | @@ LUAI_UACINT is the result of a 'default argument promotion' |
481 | @@ over a LUA_INTEGER. | 482 | @@ over a LUA_INTEGER. |
482 | @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. | 483 | @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. |
@@ -659,6 +660,26 @@ | |||
659 | #define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) | 660 | #define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) |
660 | #endif | 661 | #endif |
661 | 662 | ||
663 | |||
664 | /* | ||
665 | ** macros to improve jump prediction, used mostly for error handling | ||
666 | ** and debug facilities. | ||
667 | */ | ||
668 | #if (defined(LUA_CORE) || defined(LUA_LIB)) && !defined(l_likely) | ||
669 | |||
670 | #include <stdio.h> | ||
671 | #if defined(__GNUC__) | ||
672 | #define l_likely(x) (__builtin_expect(((x) != 0), 1)) | ||
673 | #define l_unlikely(x) (__builtin_expect(((x) != 0), 0)) | ||
674 | #else | ||
675 | #define l_likely(x) (x) | ||
676 | #define l_unlikely(x) (x) | ||
677 | #endif | ||
678 | |||
679 | #endif | ||
680 | |||
681 | |||
682 | |||
662 | /* }================================================================== */ | 683 | /* }================================================================== */ |
663 | 684 | ||
664 | 685 | ||
diff --git a/src/lua/lvm.c b/src/lua/lvm.c index d6c05bb..c9729bc 100644 --- a/src/lua/lvm.c +++ b/src/lua/lvm.c | |||
@@ -235,11 +235,11 @@ static int forprep (lua_State *L, StkId ra) { | |||
235 | } | 235 | } |
236 | else { /* try making all values floats */ | 236 | else { /* try making all values floats */ |
237 | lua_Number init; lua_Number limit; lua_Number step; | 237 | lua_Number init; lua_Number limit; lua_Number step; |
238 | if (unlikely(!tonumber(plimit, &limit))) | 238 | if (l_unlikely(!tonumber(plimit, &limit))) |
239 | luaG_forerror(L, plimit, "limit"); | 239 | luaG_forerror(L, plimit, "limit"); |
240 | if (unlikely(!tonumber(pstep, &step))) | 240 | if (l_unlikely(!tonumber(pstep, &step))) |
241 | luaG_forerror(L, pstep, "step"); | 241 | luaG_forerror(L, pstep, "step"); |
242 | if (unlikely(!tonumber(pinit, &init))) | 242 | if (l_unlikely(!tonumber(pinit, &init))) |
243 | luaG_forerror(L, pinit, "initial value"); | 243 | luaG_forerror(L, pinit, "initial value"); |
244 | if (step == 0) | 244 | if (step == 0) |
245 | luaG_runerror(L, "'for' step is zero"); | 245 | luaG_runerror(L, "'for' step is zero"); |
@@ -292,7 +292,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
292 | if (slot == NULL) { /* 't' is not a table? */ | 292 | if (slot == NULL) { /* 't' is not a table? */ |
293 | lua_assert(!ttistable(t)); | 293 | lua_assert(!ttistable(t)); |
294 | tm = luaT_gettmbyobj(L, t, TM_INDEX); | 294 | tm = luaT_gettmbyobj(L, t, TM_INDEX); |
295 | if (unlikely(notm(tm))) | 295 | if (l_unlikely(notm(tm))) |
296 | luaG_typeerror(L, t, "index"); /* no metamethod */ | 296 | luaG_typeerror(L, t, "index"); /* no metamethod */ |
297 | /* else will try the metamethod */ | 297 | /* else will try the metamethod */ |
298 | } | 298 | } |
@@ -346,7 +346,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
346 | } | 346 | } |
347 | else { /* not a table; check metamethod */ | 347 | else { /* not a table; check metamethod */ |
348 | tm = luaT_gettmbyobj(L, t, TM_NEWINDEX); | 348 | tm = luaT_gettmbyobj(L, t, TM_NEWINDEX); |
349 | if (unlikely(notm(tm))) | 349 | if (l_unlikely(notm(tm))) |
350 | luaG_typeerror(L, t, "index"); | 350 | luaG_typeerror(L, t, "index"); |
351 | } | 351 | } |
352 | /* try the metamethod */ | 352 | /* try the metamethod */ |
@@ -568,8 +568,13 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { | |||
568 | if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) | 568 | if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) |
569 | return 0; /* only numbers can be equal with different variants */ | 569 | return 0; /* only numbers can be equal with different variants */ |
570 | else { /* two numbers with different variants */ | 570 | else { /* two numbers with different variants */ |
571 | lua_Integer i1, i2; /* compare them as integers */ | 571 | /* One of them is an integer. If the other does not have an |
572 | return (tointegerns(t1, &i1) && tointegerns(t2, &i2) && i1 == i2); | 572 | integer value, they cannot be equal; otherwise, compare their |
573 | integer values. */ | ||
574 | lua_Integer i1, i2; | ||
575 | return (luaV_tointegerns(t1, &i1, F2Ieq) && | ||
576 | luaV_tointegerns(t2, &i2, F2Ieq) && | ||
577 | i1 == i2); | ||
573 | } | 578 | } |
574 | } | 579 | } |
575 | /* values have same type and same variant */ | 580 | /* values have same type and same variant */ |
@@ -651,7 +656,7 @@ void luaV_concat (lua_State *L, int total) { | |||
651 | /* collect total length and number of strings */ | 656 | /* collect total length and number of strings */ |
652 | for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { | 657 | for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { |
653 | size_t l = vslen(s2v(top - n - 1)); | 658 | size_t l = vslen(s2v(top - n - 1)); |
654 | if (unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) | 659 | if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) |
655 | luaG_runerror(L, "string length overflow"); | 660 | luaG_runerror(L, "string length overflow"); |
656 | tl += l; | 661 | tl += l; |
657 | } | 662 | } |
@@ -695,7 +700,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { | |||
695 | } | 700 | } |
696 | default: { /* try metamethod */ | 701 | default: { /* try metamethod */ |
697 | tm = luaT_gettmbyobj(L, rb, TM_LEN); | 702 | tm = luaT_gettmbyobj(L, rb, TM_LEN); |
698 | if (unlikely(notm(tm))) /* no metamethod? */ | 703 | if (l_unlikely(notm(tm))) /* no metamethod? */ |
699 | luaG_typeerror(L, rb, "get length of"); | 704 | luaG_typeerror(L, rb, "get length of"); |
700 | break; | 705 | break; |
701 | } | 706 | } |
@@ -711,7 +716,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { | |||
711 | ** otherwise 'floor(q) == trunc(q) - 1'. | 716 | ** otherwise 'floor(q) == trunc(q) - 1'. |
712 | */ | 717 | */ |
713 | lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) { | 718 | lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) { |
714 | if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ | 719 | if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ |
715 | if (n == 0) | 720 | if (n == 0) |
716 | luaG_runerror(L, "attempt to divide by zero"); | 721 | luaG_runerror(L, "attempt to divide by zero"); |
717 | return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ | 722 | return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ |
@@ -731,7 +736,7 @@ lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) { | |||
731 | ** about luaV_idiv.) | 736 | ** about luaV_idiv.) |
732 | */ | 737 | */ |
733 | lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { | 738 | lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { |
734 | if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ | 739 | if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ |
735 | if (n == 0) | 740 | if (n == 0) |
736 | luaG_runerror(L, "attempt to perform 'n%%0'"); | 741 | luaG_runerror(L, "attempt to perform 'n%%0'"); |
737 | return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ | 742 | return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ |
@@ -921,7 +926,7 @@ void luaV_finishOp (lua_State *L) { | |||
921 | */ | 926 | */ |
922 | #define op_arithfK(L,fop) { \ | 927 | #define op_arithfK(L,fop) { \ |
923 | TValue *v1 = vRB(i); \ | 928 | TValue *v1 = vRB(i); \ |
924 | TValue *v2 = KC(i); \ | 929 | TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ |
925 | op_arithf_aux(L, v1, v2, fop); } | 930 | op_arithf_aux(L, v1, v2, fop); } |
926 | 931 | ||
927 | 932 | ||
@@ -950,7 +955,7 @@ void luaV_finishOp (lua_State *L) { | |||
950 | */ | 955 | */ |
951 | #define op_arithK(L,iop,fop) { \ | 956 | #define op_arithK(L,iop,fop) { \ |
952 | TValue *v1 = vRB(i); \ | 957 | TValue *v1 = vRB(i); \ |
953 | TValue *v2 = KC(i); \ | 958 | TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ |
954 | op_arith_aux(L, v1, v2, iop, fop); } | 959 | op_arith_aux(L, v1, v2, iop, fop); } |
955 | 960 | ||
956 | 961 | ||
@@ -1049,7 +1054,8 @@ void luaV_finishOp (lua_State *L) { | |||
1049 | #define updatebase(ci) (base = ci->func + 1) | 1054 | #define updatebase(ci) (base = ci->func + 1) |
1050 | 1055 | ||
1051 | 1056 | ||
1052 | #define updatestack(ci) { if (trap) { updatebase(ci); ra = RA(i); } } | 1057 | #define updatestack(ci) \ |
1058 | { if (l_unlikely(trap)) { updatebase(ci); ra = RA(i); } } | ||
1053 | 1059 | ||
1054 | 1060 | ||
1055 | /* | 1061 | /* |
@@ -1107,7 +1113,7 @@ void luaV_finishOp (lua_State *L) { | |||
1107 | 1113 | ||
1108 | /* fetch an instruction and prepare its execution */ | 1114 | /* fetch an instruction and prepare its execution */ |
1109 | #define vmfetch() { \ | 1115 | #define vmfetch() { \ |
1110 | if (trap) { /* stack reallocation or hooks? */ \ | 1116 | if (l_unlikely(trap)) { /* stack reallocation or hooks? */ \ |
1111 | trap = luaG_traceexec(L, pc); /* handle hooks */ \ | 1117 | trap = luaG_traceexec(L, pc); /* handle hooks */ \ |
1112 | updatebase(ci); /* correct stack */ \ | 1118 | updatebase(ci); /* correct stack */ \ |
1113 | } \ | 1119 | } \ |
@@ -1135,7 +1141,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1135 | cl = clLvalue(s2v(ci->func)); | 1141 | cl = clLvalue(s2v(ci->func)); |
1136 | k = cl->p->k; | 1142 | k = cl->p->k; |
1137 | pc = ci->u.l.savedpc; | 1143 | pc = ci->u.l.savedpc; |
1138 | if (trap) { | 1144 | if (l_unlikely(trap)) { |
1139 | if (pc == cl->p->code) { /* first instruction (not resuming)? */ | 1145 | if (pc == cl->p->code) { /* first instruction (not resuming)? */ |
1140 | if (cl->p->is_vararg) | 1146 | if (cl->p->is_vararg) |
1141 | trap = 0; /* hooks will start after VARARGPREP instruction */ | 1147 | trap = 0; /* hooks will start after VARARGPREP instruction */ |
@@ -1150,6 +1156,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1150 | Instruction i; /* instruction being executed */ | 1156 | Instruction i; /* instruction being executed */ |
1151 | StkId ra; /* instruction's A register */ | 1157 | StkId ra; /* instruction's A register */ |
1152 | vmfetch(); | 1158 | vmfetch(); |
1159 | // low-level line tracing for debugging Lua | ||
1160 | // printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); | ||
1153 | lua_assert(base == ci->func + 1); | 1161 | lua_assert(base == ci->func + 1); |
1154 | lua_assert(base <= L->top && L->top < L->stack_last); | 1162 | lua_assert(base <= L->top && L->top < L->stack_last); |
1155 | /* invalidate top for instructions not expecting it */ | 1163 | /* invalidate top for instructions not expecting it */ |
@@ -1633,10 +1641,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1633 | b = cast_int(L->top - ra); | 1641 | b = cast_int(L->top - ra); |
1634 | savepc(ci); /* several calls here can raise errors */ | 1642 | savepc(ci); /* several calls here can raise errors */ |
1635 | if (TESTARG_k(i)) { | 1643 | if (TESTARG_k(i)) { |
1636 | /* close upvalues from current call; the compiler ensures | 1644 | luaF_closeupval(L, base); /* close upvalues from current call */ |
1637 | that there are no to-be-closed variables here, so this | 1645 | lua_assert(L->tbclist < base); /* no pending tbc variables */ |
1638 | call cannot change the stack */ | ||
1639 | luaF_close(L, base, NOCLOSINGMETH, 0); | ||
1640 | lua_assert(base == ci->func + 1); | 1646 | lua_assert(base == ci->func + 1); |
1641 | } | 1647 | } |
1642 | while (!ttisfunction(s2v(ra))) { /* not a function? */ | 1648 | while (!ttisfunction(s2v(ra))) { /* not a function? */ |
@@ -1678,23 +1684,23 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1678 | goto ret; | 1684 | goto ret; |
1679 | } | 1685 | } |
1680 | vmcase(OP_RETURN0) { | 1686 | vmcase(OP_RETURN0) { |
1681 | if (L->hookmask) { | 1687 | if (l_unlikely(L->hookmask)) { |
1682 | L->top = ra; | 1688 | L->top = ra; |
1683 | savepc(ci); | 1689 | savepc(ci); |
1684 | luaD_poscall(L, ci, 0); /* no hurry... */ | 1690 | luaD_poscall(L, ci, 0); /* no hurry... */ |
1685 | trap = 1; | 1691 | trap = 1; |
1686 | } | 1692 | } |
1687 | else { /* do the 'poscall' here */ | 1693 | else { /* do the 'poscall' here */ |
1688 | int nres = ci->nresults; | 1694 | int nres; |
1689 | L->ci = ci->previous; /* back to caller */ | 1695 | L->ci = ci->previous; /* back to caller */ |
1690 | L->top = base - 1; | 1696 | L->top = base - 1; |
1691 | while (nres-- > 0) | 1697 | for (nres = ci->nresults; l_unlikely(nres > 0); nres--) |
1692 | setnilvalue(s2v(L->top++)); /* all results are nil */ | 1698 | setnilvalue(s2v(L->top++)); /* all results are nil */ |
1693 | } | 1699 | } |
1694 | goto ret; | 1700 | goto ret; |
1695 | } | 1701 | } |
1696 | vmcase(OP_RETURN1) { | 1702 | vmcase(OP_RETURN1) { |
1697 | if (L->hookmask) { | 1703 | if (l_unlikely(L->hookmask)) { |
1698 | L->top = ra + 1; | 1704 | L->top = ra + 1; |
1699 | savepc(ci); | 1705 | savepc(ci); |
1700 | luaD_poscall(L, ci, 1); /* no hurry... */ | 1706 | luaD_poscall(L, ci, 1); /* no hurry... */ |
@@ -1708,8 +1714,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1708 | else { | 1714 | else { |
1709 | setobjs2s(L, base - 1, ra); /* at least this result */ | 1715 | setobjs2s(L, base - 1, ra); /* at least this result */ |
1710 | L->top = base; | 1716 | L->top = base; |
1711 | while (--nres > 0) /* complete missing results */ | 1717 | for (; l_unlikely(nres > 1); nres--) |
1712 | setnilvalue(s2v(L->top++)); | 1718 | setnilvalue(s2v(L->top++)); /* complete missing results */ |
1713 | } | 1719 | } |
1714 | } | 1720 | } |
1715 | ret: /* return from a Lua function */ | 1721 | ret: /* return from a Lua function */ |
@@ -1812,7 +1818,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1812 | } | 1818 | } |
1813 | vmcase(OP_VARARGPREP) { | 1819 | vmcase(OP_VARARGPREP) { |
1814 | ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); | 1820 | ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); |
1815 | if (trap) { | 1821 | if (l_unlikely(trap)) { /* previous "Protect" updated trap */ |
1816 | luaD_hookcall(L, ci); | 1822 | luaD_hookcall(L, ci); |
1817 | L->oldpc = 1; /* next opcode will be seen as a "new" line */ | 1823 | L->oldpc = 1; /* next opcode will be seen as a "new" line */ |
1818 | } | 1824 | } |
diff --git a/src/lua/lvm.h b/src/lua/lvm.h index 2d4ac16..1bc16f3 100644 --- a/src/lua/lvm.h +++ b/src/lua/lvm.h | |||
@@ -60,12 +60,14 @@ typedef enum { | |||
60 | 60 | ||
61 | /* convert an object to an integer (including string coercion) */ | 61 | /* convert an object to an integer (including string coercion) */ |
62 | #define tointeger(o,i) \ | 62 | #define tointeger(o,i) \ |
63 | (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) | 63 | (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \ |
64 | : luaV_tointeger(o,i,LUA_FLOORN2I)) | ||
64 | 65 | ||
65 | 66 | ||
66 | /* convert an object to an integer (without string coercion) */ | 67 | /* convert an object to an integer (without string coercion) */ |
67 | #define tointegerns(o,i) \ | 68 | #define tointegerns(o,i) \ |
68 | (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointegerns(o,i,LUA_FLOORN2I)) | 69 | (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \ |
70 | : luaV_tointegerns(o,i,LUA_FLOORN2I)) | ||
69 | 71 | ||
70 | 72 | ||
71 | #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) | 73 | #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) |
diff --git a/src/yuescript/ast.hpp b/src/yuescript/ast.hpp index c88fcf9..eb5cd69 100644 --- a/src/yuescript/ast.hpp +++ b/src/yuescript/ast.hpp | |||
@@ -100,7 +100,9 @@ public: | |||
100 | inline ast_ptr<false, T> new_ptr() const { | 100 | inline ast_ptr<false, T> new_ptr() const { |
101 | auto item = new T; | 101 | auto item = new T; |
102 | item->m_begin.m_line = m_begin.m_line; | 102 | item->m_begin.m_line = m_begin.m_line; |
103 | item->m_end.m_line = m_begin.m_line; | 103 | item->m_begin.m_col = m_begin.m_col; |
104 | item->m_end.m_line = m_end.m_line; | ||
105 | item->m_end.m_col = m_end.m_col; | ||
104 | return ast_ptr<false, T>(item); | 106 | return ast_ptr<false, T>(item); |
105 | } | 107 | } |
106 | private: | 108 | private: |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 2d4814d..535a239 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -161,10 +161,12 @@ AST_END(import_all_macro) | |||
161 | 161 | ||
162 | class variable_pair_t; | 162 | class variable_pair_t; |
163 | class normal_pair_t; | 163 | class normal_pair_t; |
164 | class meta_variable_pair_t; | ||
165 | class meta_normal_pair_t; | ||
164 | 166 | ||
165 | AST_NODE(ImportTabLit) | 167 | AST_NODE(ImportTabLit) |
166 | ast_ptr<true, Seperator_t> sep; | 168 | ast_ptr<true, Seperator_t> sep; |
167 | ast_sel_list<false, variable_pair_t, normal_pair_t, MacroName_t, macro_name_pair_t, import_all_macro_t, Exp_t> items; | 169 | ast_sel_list<false, variable_pair_t, normal_pair_t, MacroName_t, macro_name_pair_t, import_all_macro_t, Exp_t, meta_variable_pair_t, meta_normal_pair_t> items; |
168 | AST_MEMBER(ImportTabLit, &sep, &items) | 170 | AST_MEMBER(ImportTabLit, &sep, &items) |
169 | AST_END(ImportTabLit) | 171 | AST_END(ImportTabLit) |
170 | 172 | ||
@@ -423,9 +425,20 @@ AST_NODE(normal_pair) | |||
423 | AST_MEMBER(normal_pair, &key, &value) | 425 | AST_MEMBER(normal_pair, &key, &value) |
424 | AST_END(normal_pair) | 426 | AST_END(normal_pair) |
425 | 427 | ||
428 | AST_NODE(meta_variable_pair) | ||
429 | ast_ptr<true, Variable_t> name; | ||
430 | AST_MEMBER(meta_variable_pair, &name) | ||
431 | AST_END(meta_variable_pair) | ||
432 | |||
433 | AST_NODE(meta_normal_pair) | ||
434 | ast_sel<true, Name_t> key; | ||
435 | ast_sel<true, Exp_t, TableBlock_t> value; | ||
436 | AST_MEMBER(meta_normal_pair, &key, &value) | ||
437 | AST_END(meta_normal_pair) | ||
438 | |||
426 | AST_NODE(simple_table) | 439 | AST_NODE(simple_table) |
427 | ast_ptr<true, Seperator_t> sep; | 440 | ast_ptr<true, Seperator_t> sep; |
428 | ast_sel_list<true, variable_pair_t, normal_pair_t> pairs; | 441 | ast_sel_list<true, variable_pair_t, normal_pair_t, meta_variable_pair_t, meta_normal_pair_t> pairs; |
429 | AST_MEMBER(simple_table, &sep, &pairs) | 442 | AST_MEMBER(simple_table, &sep, &pairs) |
430 | AST_END(simple_table) | 443 | AST_END(simple_table) |
431 | 444 | ||
@@ -484,13 +497,21 @@ AST_NODE(String) | |||
484 | AST_MEMBER(String, &str) | 497 | AST_MEMBER(String, &str) |
485 | AST_END(String) | 498 | AST_END(String) |
486 | 499 | ||
487 | AST_NODE(DotChainItem) | 500 | AST_LEAF(Metatable) |
501 | AST_END(Metatable) | ||
502 | |||
503 | AST_NODE(Metamethod) | ||
488 | ast_ptr<true, Name_t> name; | 504 | ast_ptr<true, Name_t> name; |
505 | AST_MEMBER(Metamethod, &name) | ||
506 | AST_END(Metamethod) | ||
507 | |||
508 | AST_NODE(DotChainItem) | ||
509 | ast_sel<true, Name_t, Metatable_t, Metamethod_t> name; | ||
489 | AST_MEMBER(DotChainItem, &name) | 510 | AST_MEMBER(DotChainItem, &name) |
490 | AST_END(DotChainItem) | 511 | AST_END(DotChainItem) |
491 | 512 | ||
492 | AST_NODE(ColonChainItem) | 513 | AST_NODE(ColonChainItem) |
493 | ast_sel<true, LuaKeyword_t, Name_t> name; | 514 | ast_sel<true, LuaKeyword_t, Name_t, Metamethod_t> name; |
494 | bool switchToDot = false; | 515 | bool switchToDot = false; |
495 | AST_MEMBER(ColonChainItem, &name) | 516 | AST_MEMBER(ColonChainItem, &name) |
496 | AST_END(ColonChainItem) | 517 | AST_END(ColonChainItem) |
@@ -542,19 +563,19 @@ AST_END(default_value) | |||
542 | 563 | ||
543 | AST_NODE(TableLit) | 564 | AST_NODE(TableLit) |
544 | ast_ptr<true, Seperator_t> sep; | 565 | ast_ptr<true, Seperator_t> sep; |
545 | ast_sel_list<false, variable_pair_t, normal_pair_t, Exp_t> values; | 566 | ast_sel_list<false, variable_pair_t, normal_pair_t, Exp_t, meta_variable_pair_t, meta_normal_pair_t> values; |
546 | AST_MEMBER(TableLit, &sep, &values) | 567 | AST_MEMBER(TableLit, &sep, &values) |
547 | AST_END(TableLit) | 568 | AST_END(TableLit) |
548 | 569 | ||
549 | AST_NODE(TableBlockIndent) | 570 | AST_NODE(TableBlockIndent) |
550 | ast_ptr<true, Seperator_t> sep; | 571 | ast_ptr<true, Seperator_t> sep; |
551 | ast_sel_list<false, variable_pair_t, normal_pair_t, TableBlockIndent_t> values; | 572 | ast_sel_list<false, variable_pair_t, normal_pair_t, TableBlockIndent_t, meta_variable_pair_t, meta_normal_pair_t> values; |
552 | AST_MEMBER(TableBlockIndent, &sep, &values) | 573 | AST_MEMBER(TableBlockIndent, &sep, &values) |
553 | AST_END(TableBlockIndent) | 574 | AST_END(TableBlockIndent) |
554 | 575 | ||
555 | AST_NODE(TableBlock) | 576 | AST_NODE(TableBlock) |
556 | ast_ptr<true, Seperator_t> sep; | 577 | ast_ptr<true, Seperator_t> sep; |
557 | ast_sel_list<false, variable_pair_t, normal_pair_t, TableBlockIndent_t, Exp_t, TableBlock_t> values; | 578 | ast_sel_list<false, variable_pair_t, normal_pair_t, TableBlockIndent_t, Exp_t, TableBlock_t, meta_variable_pair_t, meta_normal_pair_t> values; |
558 | AST_MEMBER(TableBlock, &sep, &values) | 579 | AST_MEMBER(TableBlock, &sep, &values) |
559 | AST_END(TableBlock) | 580 | AST_END(TableBlock) |
560 | 581 | ||
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 0e65ae9..043c705 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -48,9 +48,9 @@ using namespace parserlib; | |||
48 | #define YUEE(msg,node) throw std::logic_error( \ | 48 | #define YUEE(msg,node) throw std::logic_error( \ |
49 | _info.errorMessage( \ | 49 | _info.errorMessage( \ |
50 | std::string("[File] ") + __FILE__ \ | 50 | std::string("[File] ") + __FILE__ \ |
51 | + ", [Func] " + __FUNCTION__ \ | 51 | + ",\n[Func] " + __FUNCTION__ \ |
52 | + ", [Line] " + std::to_string(__LINE__) \ | 52 | + ",\n[Line] " + std::to_string(__LINE__) \ |
53 | + ", [Error] " + msg, node)) | 53 | + ",\n[Error] " + msg, node)) |
54 | 54 | ||
55 | typedef std::list<std::string> str_list; | 55 | typedef std::list<std::string> str_list; |
56 | 56 | ||
@@ -58,7 +58,7 @@ inline std::string s(std::string_view sv) { | |||
58 | return std::string(sv); | 58 | return std::string(sv); |
59 | } | 59 | } |
60 | 60 | ||
61 | const std::string_view version = "0.6.10"sv; | 61 | const std::string_view version = "0.7.0"sv; |
62 | const std::string_view extension = "yue"sv; | 62 | const std::string_view extension = "yue"sv; |
63 | 63 | ||
64 | class YueCompilerImpl { | 64 | class YueCompilerImpl { |
@@ -618,13 +618,11 @@ private: | |||
618 | template <class T> | 618 | template <class T> |
619 | ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { | 619 | ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { |
620 | auto res = _parser.parse<T>(s(codes)); | 620 | auto res = _parser.parse<T>(s(codes)); |
621 | int line = parent->m_begin.m_line; | ||
622 | int col = parent->m_begin.m_line; | ||
623 | res.node->traverse([&](ast_node* node) { | 621 | res.node->traverse([&](ast_node* node) { |
624 | node->m_begin.m_line = line; | 622 | node->m_begin.m_line = parent->m_begin.m_line; |
625 | node->m_end.m_line = line; | 623 | node->m_begin.m_col = parent->m_begin.m_col; |
626 | node->m_begin.m_col = col; | 624 | node->m_end.m_line = parent->m_end.m_line; |
627 | node->m_end.m_col = col; | 625 | node->m_end.m_col = parent->m_end.m_col; |
628 | return traversal::Continue; | 626 | return traversal::Continue; |
629 | }); | 627 | }); |
630 | _codeCache.push_back(std::move(res.codes)); | 628 | _codeCache.push_back(std::move(res.codes)); |
@@ -641,7 +639,8 @@ private: | |||
641 | EndWithEOP, | 639 | EndWithEOP, |
642 | HasEOP, | 640 | HasEOP, |
643 | HasKeyword, | 641 | HasKeyword, |
644 | Macro | 642 | Macro, |
643 | Metatable | ||
645 | }; | 644 | }; |
646 | 645 | ||
647 | ChainType specialChainValue(ChainValue_t* chainValue) const { | 646 | ChainType specialChainValue(ChainValue_t* chainValue) const { |
@@ -654,6 +653,11 @@ private: | |||
654 | if (ast_is<existential_op_t>(chainValue->items.back())) { | 653 | if (ast_is<existential_op_t>(chainValue->items.back())) { |
655 | return ChainType::EndWithEOP; | 654 | return ChainType::EndWithEOP; |
656 | } | 655 | } |
656 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { | ||
657 | if (dot->name.is<Metatable_t>()) { | ||
658 | return ChainType::Metatable; | ||
659 | } | ||
660 | } | ||
657 | ChainType type = ChainType::Common; | 661 | ChainType type = ChainType::Common; |
658 | for (auto item : chainValue->items.objects()) { | 662 | for (auto item : chainValue->items.objects()) { |
659 | if (auto colonChain = ast_cast<ColonChainItem_t>(item)) { | 663 | if (auto colonChain = ast_cast<ColonChainItem_t>(item)) { |
@@ -798,6 +802,18 @@ private: | |||
798 | return false; | 802 | return false; |
799 | } | 803 | } |
800 | 804 | ||
805 | std::string globalVar(std::string_view var, ast_node* x) { | ||
806 | std::string str(var); | ||
807 | if (_config.lintGlobalVariable) { | ||
808 | if (!isDefined(str)) { | ||
809 | if (_globals.find(str) == _globals.end()) { | ||
810 | _globals[str] = {x->m_begin.m_line, x->m_begin.m_col}; | ||
811 | } | ||
812 | } | ||
813 | } | ||
814 | return str; | ||
815 | } | ||
816 | |||
801 | void transformStatement(Statement_t* statement, str_list& out) { | 817 | void transformStatement(Statement_t* statement, str_list& out) { |
802 | auto x = statement; | 818 | auto x = statement; |
803 | if (statement->appendix) { | 819 | if (statement->appendix) { |
@@ -1107,6 +1123,53 @@ private: | |||
1107 | BLOCK_START | 1123 | BLOCK_START |
1108 | auto assign = ast_cast<Assign_t>(assignment->action); | 1124 | auto assign = ast_cast<Assign_t>(assignment->action); |
1109 | BREAK_IF(!assign); | 1125 | BREAK_IF(!assign); |
1126 | auto x = assignment; | ||
1127 | const auto& exprs = assignment->expList->exprs.objects(); | ||
1128 | const auto& values = assign->values.objects(); | ||
1129 | auto vit = values.begin(); | ||
1130 | for (auto it = exprs.begin(); it != exprs.end(); ++it) { | ||
1131 | BLOCK_START | ||
1132 | auto value = singleValueFrom(*it); | ||
1133 | BREAK_IF(!value); | ||
1134 | auto chainValue = value->item.as<ChainValue_t>(); | ||
1135 | BREAK_IF(!chainValue); | ||
1136 | if (specialChainValue(chainValue) == ChainType::Metatable) { | ||
1137 | str_list args; | ||
1138 | chainValue->items.pop_back(); | ||
1139 | transformExp(static_cast<Exp_t*>(*it), args, ExpUsage::Closure); | ||
1140 | if (vit != values.end()) transformAssignItem(*vit, args); | ||
1141 | else args.push_back(s("nil"sv)); | ||
1142 | _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); | ||
1143 | str_list temp; | ||
1144 | temp.push_back(clearBuf()); | ||
1145 | auto newExpList = x->new_ptr<ExpList_t>(); | ||
1146 | auto newAssign = x->new_ptr<Assign_t>(); | ||
1147 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
1148 | newAssignment->expList.set(newExpList); | ||
1149 | newAssignment->action.set(newAssign); | ||
1150 | for (auto exp : exprs) { | ||
1151 | if (exp != *it) newExpList->exprs.push_back(exp); | ||
1152 | } | ||
1153 | for (auto value : values) { | ||
1154 | if (value != *vit) newAssign->values.push_back(value); | ||
1155 | } | ||
1156 | if (newExpList->exprs.empty() && newAssign->values.empty()) { | ||
1157 | out.push_back(temp.back()); | ||
1158 | return; | ||
1159 | } | ||
1160 | if (newExpList->exprs.size() < newAssign->values.size()) { | ||
1161 | auto exp = toAst<Exp_t>("_"sv, x); | ||
1162 | while (newExpList->exprs.size() < newAssign->values.size()) { | ||
1163 | newExpList->exprs.push_back(exp); | ||
1164 | } | ||
1165 | } | ||
1166 | transformAssignment(newAssignment, temp); | ||
1167 | out.push_back(join(temp)); | ||
1168 | return; | ||
1169 | } | ||
1170 | BLOCK_END | ||
1171 | if (vit != values.end()) ++vit; | ||
1172 | } | ||
1110 | BREAK_IF(assign->values.objects().size() != 1); | 1173 | BREAK_IF(assign->values.objects().size() != 1); |
1111 | auto value = assign->values.objects().back(); | 1174 | auto value = assign->values.objects().back(); |
1112 | if (ast_is<Exp_t>(value)) { | 1175 | if (ast_is<Exp_t>(value)) { |
@@ -1221,15 +1284,19 @@ private: | |||
1221 | return; | 1284 | return; |
1222 | case ChainType::Common: | 1285 | case ChainType::Common: |
1223 | case ChainType::EndWithEOP: | 1286 | case ChainType::EndWithEOP: |
1287 | case ChainType::Metatable: | ||
1224 | break; | 1288 | break; |
1225 | } | 1289 | } |
1226 | } | 1290 | } |
1227 | BLOCK_END | 1291 | BLOCK_END |
1228 | auto info = extractDestructureInfo(assignment); | 1292 | auto info = extractDestructureInfo(assignment, false); |
1229 | if (info.first.empty()) { | 1293 | if (info.first.empty()) { |
1230 | transformAssignmentCommon(assignment, out); | 1294 | transformAssignmentCommon(assignment, out); |
1231 | } else { | 1295 | } else { |
1232 | str_list temp; | 1296 | str_list temp; |
1297 | if (info.second) { | ||
1298 | transformAssignmentCommon(info.second, temp); | ||
1299 | } | ||
1233 | for (const auto& destruct : info.first) { | 1300 | for (const auto& destruct : info.first) { |
1234 | if (destruct.items.size() == 1) { | 1301 | if (destruct.items.size() == 1) { |
1235 | auto& pair = destruct.items.front(); | 1302 | auto& pair = destruct.items.front(); |
@@ -1240,7 +1307,7 @@ private: | |||
1240 | _buf << pair.name << " = "sv << destruct.value << pair.structure << nll(assignment); | 1307 | _buf << pair.name << " = "sv << destruct.value << pair.structure << nll(assignment); |
1241 | addToScope(pair.name); | 1308 | addToScope(pair.name); |
1242 | temp.push_back(clearBuf()); | 1309 | temp.push_back(clearBuf()); |
1243 | } else if (_parser.match<Name_t>(destruct.value)) { | 1310 | } else if (_parser.match<Name_t>(destruct.value) && isDefined(destruct.value)) { |
1244 | str_list defs, names, values; | 1311 | str_list defs, names, values; |
1245 | for (const auto& item : destruct.items) { | 1312 | for (const auto& item : destruct.items) { |
1246 | if (item.isVariable && addToScope(item.name)) { | 1313 | if (item.isVariable && addToScope(item.name)) { |
@@ -1281,9 +1348,6 @@ private: | |||
1281 | temp.push_back(clearBuf()); | 1348 | temp.push_back(clearBuf()); |
1282 | } | 1349 | } |
1283 | } | 1350 | } |
1284 | if (info.second) { | ||
1285 | transformAssignmentCommon(info.second, temp); | ||
1286 | } | ||
1287 | out.push_back(join(temp)); | 1351 | out.push_back(join(temp)); |
1288 | } | 1352 | } |
1289 | } | 1353 | } |
@@ -1426,13 +1490,13 @@ private: | |||
1426 | } | 1490 | } |
1427 | 1491 | ||
1428 | std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>> | 1492 | std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>> |
1429 | extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly = false) { | 1493 | extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly) { |
1430 | auto x = assignment; | 1494 | auto x = assignment; |
1431 | std::list<Destructure> destructs; | 1495 | std::list<Destructure> destructs; |
1432 | if (!assignment->action.is<Assign_t>()) return { destructs, nullptr }; | 1496 | if (!assignment->action.is<Assign_t>()) return {destructs, nullptr}; |
1433 | auto exprs = assignment->expList->exprs.objects(); | 1497 | auto exprs = assignment->expList->exprs.objects(); |
1434 | auto values = assignment->action.to<Assign_t>()->values.objects(); | 1498 | auto values = assignment->action.to<Assign_t>()->values.objects(); |
1435 | size_t size = std::max(exprs.size(),values.size()); | 1499 | size_t size = std::max(exprs.size(), values.size()); |
1436 | ast_ptr<false, Exp_t> var; | 1500 | ast_ptr<false, Exp_t> var; |
1437 | if (exprs.size() < size) { | 1501 | if (exprs.size() < size) { |
1438 | var = toAst<Exp_t>("_"sv, x); | 1502 | var = toAst<Exp_t>("_"sv, x); |
@@ -1445,6 +1509,8 @@ private: | |||
1445 | } | 1509 | } |
1446 | using iter = node_container::iterator; | 1510 | using iter = node_container::iterator; |
1447 | std::vector<std::pair<iter,iter>> destructPairs; | 1511 | std::vector<std::pair<iter,iter>> destructPairs; |
1512 | ast_list<false, ast_node> valueItems; | ||
1513 | if (!varDefOnly) pushScope(); | ||
1448 | str_list temp; | 1514 | str_list temp; |
1449 | for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { | 1515 | for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { |
1450 | auto expr = *i; | 1516 | auto expr = *i; |
@@ -1459,26 +1525,86 @@ private: | |||
1459 | } | 1525 | } |
1460 | } | 1526 | } |
1461 | destructPairs.push_back({i,j}); | 1527 | destructPairs.push_back({i,j}); |
1462 | auto& destruct = destructs.emplace_back(); | 1528 | auto subDestruct = destructNode->new_ptr<TableLit_t>(); |
1463 | if (!varDefOnly) { | 1529 | auto subMetaDestruct = destructNode->new_ptr<TableLit_t>(); |
1464 | pushScope(); | 1530 | const node_container* dlist = nullptr; |
1465 | transformAssignItem(*j, temp); | 1531 | switch (destructNode->getId()) { |
1466 | destruct.value = temp.back(); | 1532 | case id<TableLit_t>(): |
1467 | temp.pop_back(); | 1533 | dlist = &static_cast<TableLit_t*>(destructNode)->values.objects(); |
1468 | popScope(); | 1534 | break; |
1535 | case id<simple_table_t>(): | ||
1536 | dlist = &static_cast<simple_table_t*>(destructNode)->pairs.objects(); | ||
1537 | break; | ||
1538 | default: YUEE("AST node mismatch", destructNode); break; | ||
1539 | } | ||
1540 | for (auto item : *dlist) { | ||
1541 | switch (item->getId()) { | ||
1542 | case id<meta_variable_pair_t>(): { | ||
1543 | auto mp = static_cast<meta_variable_pair_t*>(item); | ||
1544 | auto name = _parser.toString(mp->name); | ||
1545 | _buf << "__"sv << name << ':' << name; | ||
1546 | auto newPair = toAst<normal_pair_t>(clearBuf(), item); | ||
1547 | subMetaDestruct->values.push_back(newPair); | ||
1548 | break; | ||
1549 | } | ||
1550 | case id<meta_normal_pair_t>(): { | ||
1551 | auto mp = static_cast<meta_normal_pair_t*>(item); | ||
1552 | auto key = _parser.toString(mp->key); | ||
1553 | _buf << "__"sv << key; | ||
1554 | auto newKey = toAst<KeyName_t>(clearBuf(), item); | ||
1555 | auto newPair = item->new_ptr<normal_pair_t>(); | ||
1556 | newPair->key.set(newKey); | ||
1557 | newPair->value.set(mp->value); | ||
1558 | subMetaDestruct->values.push_back(newPair); | ||
1559 | break; | ||
1560 | } | ||
1561 | default: | ||
1562 | subDestruct->values.push_back(item); | ||
1563 | break; | ||
1564 | } | ||
1469 | } | 1565 | } |
1470 | auto pairs = destructFromExp(expr); | 1566 | valueItems.push_back(*j); |
1471 | destruct.items = std::move(pairs); | 1567 | if (!varDefOnly && !subDestruct->values.empty() && !subMetaDestruct->values.empty()) { |
1472 | if (*j == nullNode) { | 1568 | auto objVar = getUnusedName("_obj_"sv); |
1473 | for (auto& item : destruct.items) { | 1569 | addToScope(objVar); |
1474 | item.structure.clear(); | 1570 | valueItems.pop_back(); |
1571 | valueItems.push_back(toAst<Exp_t>(objVar, *j)); | ||
1572 | exprs.push_back(valueItems.back()); | ||
1573 | values.push_back(*j); | ||
1574 | } | ||
1575 | TableLit_t* tabs[] = {subDestruct.get(), subMetaDestruct.get()}; | ||
1576 | for (auto tab : tabs) { | ||
1577 | if (!tab->values.empty()) { | ||
1578 | auto& destruct = destructs.emplace_back(); | ||
1579 | if (!varDefOnly) { | ||
1580 | transformAssignItem(valueItems.back(), temp); | ||
1581 | destruct.value = temp.back(); | ||
1582 | temp.pop_back(); | ||
1583 | } | ||
1584 | auto simpleValue = tab->new_ptr<SimpleValue_t>(); | ||
1585 | simpleValue->value.set(tab); | ||
1586 | auto value = tab->new_ptr<Value_t>(); | ||
1587 | value->item.set(simpleValue); | ||
1588 | auto pairs = destructFromExp(newExp(value, expr)); | ||
1589 | destruct.items = std::move(pairs); | ||
1590 | if (!varDefOnly) { | ||
1591 | if (*j == nullNode) { | ||
1592 | for (auto& item : destruct.items) { | ||
1593 | item.structure.clear(); | ||
1594 | } | ||
1595 | } else if (tab == subMetaDestruct.get()) { | ||
1596 | destruct.value.insert(0, globalVar("getmetatable"sv, tab) + '('); | ||
1597 | destruct.value.append(")"sv); | ||
1598 | } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { | ||
1599 | destruct.value.insert(0, "("sv); | ||
1600 | destruct.value.append(")"sv); | ||
1601 | } | ||
1602 | } | ||
1475 | } | 1603 | } |
1476 | } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { | ||
1477 | destruct.value.insert(0, "("sv); | ||
1478 | destruct.value.append(")"sv); | ||
1479 | } | 1604 | } |
1480 | } | 1605 | } |
1481 | } | 1606 | } |
1607 | if (!varDefOnly) popScope(); | ||
1482 | for (const auto& p : destructPairs) { | 1608 | for (const auto& p : destructPairs) { |
1483 | exprs.erase(p.first); | 1609 | exprs.erase(p.first); |
1484 | values.erase(p.second); | 1610 | values.erase(p.second); |
@@ -1511,6 +1637,8 @@ private: | |||
1511 | auto leftValue = singleValueFrom(leftExp); | 1637 | auto leftValue = singleValueFrom(leftExp); |
1512 | if (!leftValue) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftExp)); | 1638 | if (!leftValue) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftExp)); |
1513 | if (auto chain = leftValue->item.as<ChainValue_t>()) { | 1639 | if (auto chain = leftValue->item.as<ChainValue_t>()) { |
1640 | if (specialChainValue(chain) == ChainType::Metatable) {throw std::logic_error(_info.errorMessage("can not apply update to a metatable"sv, leftExp)); | ||
1641 | } | ||
1514 | auto tmpChain = x->new_ptr<ChainValue_t>(); | 1642 | auto tmpChain = x->new_ptr<ChainValue_t>(); |
1515 | for (auto item : chain->items.objects()) { | 1643 | for (auto item : chain->items.objects()) { |
1516 | bool itemAdded = false; | 1644 | bool itemAdded = false; |
@@ -1911,7 +2039,7 @@ private: | |||
1911 | switch (item->getId()) { | 2039 | switch (item->getId()) { |
1912 | case id<Variable_t>(): { | 2040 | case id<Variable_t>(): { |
1913 | transformVariable(static_cast<Variable_t*>(item), out); | 2041 | transformVariable(static_cast<Variable_t*>(item), out); |
1914 | if (_config.lintGlobalVariable && !isDefined(out.back())) { | 2042 | if (_config.lintGlobalVariable && !isSolidDefined(out.back())) { |
1915 | if (_globals.find(out.back()) == _globals.end()) { | 2043 | if (_globals.find(out.back()) == _globals.end()) { |
1916 | _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col}; | 2044 | _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col}; |
1917 | } | 2045 | } |
@@ -1920,14 +2048,7 @@ private: | |||
1920 | } | 2048 | } |
1921 | case id<SelfName_t>(): { | 2049 | case id<SelfName_t>(): { |
1922 | transformSelfName(static_cast<SelfName_t*>(item), out, invoke); | 2050 | transformSelfName(static_cast<SelfName_t*>(item), out, invoke); |
1923 | if (_config.lintGlobalVariable) { | 2051 | globalVar("self"sv, item); |
1924 | std::string self("self"sv); | ||
1925 | if (!isDefined(self)) { | ||
1926 | if (_globals.find(self) == _globals.end()) { | ||
1927 | _globals[self] = {item->m_begin.m_line, item->m_begin.m_col}; | ||
1928 | } | ||
1929 | } | ||
1930 | } | ||
1931 | break; | 2052 | break; |
1932 | } | 2053 | } |
1933 | case id<VarArg_t>(): | 2054 | case id<VarArg_t>(): |
@@ -3030,6 +3151,55 @@ private: | |||
3030 | return false; | 3151 | return false; |
3031 | } | 3152 | } |
3032 | 3153 | ||
3154 | bool transformChainWithMetatable(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { | ||
3155 | auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) { | ||
3156 | if (auto colonChain = ast_cast<ColonChainItem_t>(node)) { | ||
3157 | if (ast_is<Metamethod_t>(colonChain->name)) { | ||
3158 | return true; | ||
3159 | } | ||
3160 | } else if (auto dotChain = ast_cast<DotChainItem_t>(node)) { | ||
3161 | if (ast_is<Metatable_t, Metamethod_t>(dotChain->name)) { | ||
3162 | return true; | ||
3163 | } | ||
3164 | } | ||
3165 | return false; | ||
3166 | }); | ||
3167 | if (opIt == chainList.end()) return false; | ||
3168 | auto x = chainList.front(); | ||
3169 | auto chain = x->new_ptr<ChainValue_t>(); | ||
3170 | for (auto it = chainList.begin(); it != opIt; ++it) { | ||
3171 | chain->items.push_back(*it); | ||
3172 | } | ||
3173 | auto value = x->new_ptr<Value_t>(); | ||
3174 | value->item.set(chain); | ||
3175 | auto exp = newExp(value, x); | ||
3176 | |||
3177 | chain = toAst<ChainValue_t>("getmetatable()"sv, x); | ||
3178 | ast_to<Invoke_t>(chain->items.back())->args.push_back(exp); | ||
3179 | switch ((*opIt)->getId()) { | ||
3180 | case id<ColonChainItem_t>(): { | ||
3181 | auto colon = static_cast<ColonChainItem_t*>(*opIt); | ||
3182 | auto meta = colon->name.to<Metamethod_t>(); | ||
3183 | auto newColon = toAst<ColonChainItem_t>(s("\\__"sv) + _parser.toString(meta->name), x); | ||
3184 | chain->items.push_back(newColon); | ||
3185 | break; | ||
3186 | } | ||
3187 | case id<DotChainItem_t>(): { | ||
3188 | auto dot = static_cast<DotChainItem_t*>(*opIt); | ||
3189 | if (dot->name.is<Metatable_t>()) break; | ||
3190 | auto meta = dot->name.to<Metamethod_t>(); | ||
3191 | auto newDot = toAst<DotChainItem_t>(s(".__"sv) + _parser.toString(meta->name), x); | ||
3192 | chain->items.push_back(newDot); | ||
3193 | break; | ||
3194 | } | ||
3195 | } | ||
3196 | for (auto it = ++opIt; it != chainList.end(); ++it) { | ||
3197 | chain->items.push_back(*it); | ||
3198 | } | ||
3199 | transformChainValue(chain, out, usage, assignList); | ||
3200 | return true; | ||
3201 | } | ||
3202 | |||
3033 | void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 3203 | void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
3034 | auto x = chainList.front(); | 3204 | auto x = chainList.front(); |
3035 | str_list temp; | 3205 | str_list temp; |
@@ -3553,6 +3723,9 @@ private: | |||
3553 | #endif // YUE_NO_MACRO | 3723 | #endif // YUE_NO_MACRO |
3554 | } | 3724 | } |
3555 | const auto& chainList = chainValue->items.objects(); | 3725 | const auto& chainList = chainValue->items.objects(); |
3726 | if (transformChainWithMetatable(chainList, out, usage, assignList)) { | ||
3727 | return; | ||
3728 | } | ||
3556 | if (transformChainEndWithEOP(chainList, out, usage, assignList)) { | 3729 | if (transformChainEndWithEOP(chainList, out, usage, assignList)) { |
3557 | return; | 3730 | return; |
3558 | } | 3731 | } |
@@ -3801,7 +3974,8 @@ private: | |||
3801 | switch (loopTarget->getId()) { | 3974 | switch (loopTarget->getId()) { |
3802 | case id<star_exp_t>(): { | 3975 | case id<star_exp_t>(): { |
3803 | auto star_exp = static_cast<star_exp_t*>(loopTarget); | 3976 | auto star_exp = static_cast<star_exp_t*>(loopTarget); |
3804 | std::string listVar; | 3977 | auto listVar = singleVariableFrom(star_exp->value); |
3978 | if (!isSolidDefined(listVar)) listVar.clear(); | ||
3805 | auto indexVar = getUnusedName("_index_"sv); | 3979 | auto indexVar = getUnusedName("_index_"sv); |
3806 | varAfter.push_back(indexVar); | 3980 | varAfter.push_back(indexVar); |
3807 | auto value = singleValueFrom(star_exp->value); | 3981 | auto value = singleValueFrom(star_exp->value); |
@@ -3814,6 +3988,12 @@ private: | |||
3814 | auto slice = ast_cast<Slice_t>(chainList.back()); | 3988 | auto slice = ast_cast<Slice_t>(chainList.back()); |
3815 | BREAK_IF(!slice); | 3989 | BREAK_IF(!slice); |
3816 | endWithSlice = true; | 3990 | endWithSlice = true; |
3991 | if (listVar.empty() && chainList.size() == 2) { | ||
3992 | if (auto var = chainList.front()->getByPath<Variable_t>()) { | ||
3993 | listVar = _parser.toString(var); | ||
3994 | if (!isSolidDefined(listVar)) listVar.clear(); | ||
3995 | } | ||
3996 | } | ||
3817 | chainList.pop_back(); | 3997 | chainList.pop_back(); |
3818 | auto chain = x->new_ptr<ChainValue_t>(); | 3998 | auto chain = x->new_ptr<ChainValue_t>(); |
3819 | for (auto item : chainList) { | 3999 | for (auto item : chainList) { |
@@ -3837,10 +4017,12 @@ private: | |||
3837 | stepValue = temp.back(); | 4017 | stepValue = temp.back(); |
3838 | temp.pop_back(); | 4018 | temp.pop_back(); |
3839 | } | 4019 | } |
3840 | listVar = getUnusedName("_list_"sv); | 4020 | if (listVar.empty()) { |
3841 | varBefore.push_back(listVar); | 4021 | listVar = getUnusedName("_list_"sv); |
3842 | transformChainValue(chain, temp, ExpUsage::Closure); | 4022 | varBefore.push_back(listVar); |
3843 | _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); | 4023 | transformChainValue(chain, temp, ExpUsage::Closure); |
4024 | _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); | ||
4025 | } | ||
3844 | std::string maxVar; | 4026 | std::string maxVar; |
3845 | if (!stopValue.empty()) { | 4027 | if (!stopValue.empty()) { |
3846 | maxVar = getUnusedName("_max_"sv); | 4028 | maxVar = getUnusedName("_max_"sv); |
@@ -4248,15 +4430,7 @@ private: | |||
4248 | } | 4430 | } |
4249 | case id<Exp_t>(): { | 4431 | case id<Exp_t>(): { |
4250 | transformExp(static_cast<Exp_t*>(content), temp, ExpUsage::Closure); | 4432 | transformExp(static_cast<Exp_t*>(content), temp, ExpUsage::Closure); |
4251 | std::string tostr("tostring"sv); | 4433 | temp.back() = globalVar("tostring"sv, content) + '(' + temp.back() + s(")"sv); |
4252 | temp.back() = tostr + '(' + temp.back() + s(")"sv); | ||
4253 | if (_config.lintGlobalVariable) { | ||
4254 | if (!isDefined(tostr)) { | ||
4255 | if (_globals.find(tostr) == _globals.end()) { | ||
4256 | _globals[tostr] = {content->m_begin.m_line, content->m_begin.m_col}; | ||
4257 | } | ||
4258 | } | ||
4259 | } | ||
4260 | break; | 4434 | break; |
4261 | } | 4435 | } |
4262 | default: YUEE("AST node mismatch", content); break; | 4436 | default: YUEE("AST node mismatch", content); break; |
@@ -4460,7 +4634,7 @@ private: | |||
4460 | if (extend) { | 4634 | if (extend) { |
4461 | _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); | 4635 | _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); |
4462 | } | 4636 | } |
4463 | _buf << indent() << classVar << " = setmetatable({"sv << nll(classDecl); | 4637 | _buf << indent() << classVar << " = " << globalVar("setmetatable"sv, classDecl) << "({"sv << nll(classDecl); |
4464 | if (!builtins.empty()) { | 4638 | if (!builtins.empty()) { |
4465 | _buf << join(builtins) << ","sv << nll(classDecl); | 4639 | _buf << join(builtins) << ","sv << nll(classDecl); |
4466 | } else { | 4640 | } else { |
@@ -4673,8 +4847,14 @@ private: | |||
4673 | checkAssignable(with->valueList); | 4847 | checkAssignable(with->valueList); |
4674 | auto vars = getAssignVars(with); | 4848 | auto vars = getAssignVars(with); |
4675 | if (vars.front().empty()) { | 4849 | if (vars.front().empty()) { |
4676 | withVar = getUnusedName("_with_"sv); | 4850 | if (with->assigns->values.objects().size() == 1) { |
4677 | { | 4851 | auto var = singleVariableFrom(with->assigns->values.objects().front()); |
4852 | if (!var.empty() && isSolidDefined(var)) { | ||
4853 | withVar = var; | ||
4854 | } | ||
4855 | } | ||
4856 | if (withVar.empty()) { | ||
4857 | withVar = getUnusedName("_with_"sv); | ||
4678 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 4858 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
4679 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); | 4859 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); |
4680 | auto assign = x->new_ptr<Assign_t>(); | 4860 | auto assign = x->new_ptr<Assign_t>(); |
@@ -4714,18 +4894,21 @@ private: | |||
4714 | transformAssignment(assignment, temp); | 4894 | transformAssignment(assignment, temp); |
4715 | } | 4895 | } |
4716 | } else { | 4896 | } else { |
4717 | withVar = getUnusedName("_with_"sv); | 4897 | withVar = singleVariableFrom(with->valueList); |
4718 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 4898 | if (withVar.empty() || !isSolidDefined(withVar)) { |
4719 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); | 4899 | withVar = getUnusedName("_with_"sv); |
4720 | auto assign = x->new_ptr<Assign_t>(); | 4900 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
4721 | assign->values.dup(with->valueList->exprs); | 4901 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); |
4722 | assignment->action.set(assign); | 4902 | auto assign = x->new_ptr<Assign_t>(); |
4723 | if (!returnValue) { | 4903 | assign->values.dup(with->valueList->exprs); |
4724 | scoped = true; | 4904 | assignment->action.set(assign); |
4725 | temp.push_back(indent() + s("do"sv) + nll(with)); | 4905 | if (!returnValue) { |
4726 | pushScope(); | 4906 | scoped = true; |
4907 | temp.push_back(indent() + s("do"sv) + nll(with)); | ||
4908 | pushScope(); | ||
4909 | } | ||
4910 | transformAssignment(assignment, temp); | ||
4727 | } | 4911 | } |
4728 | transformAssignment(assignment, temp); | ||
4729 | } | 4912 | } |
4730 | if (!with->eop && !scoped && !returnValue) { | 4913 | if (!with->eop && !scoped && !returnValue) { |
4731 | pushScope(); | 4914 | pushScope(); |
@@ -4953,20 +5136,64 @@ private: | |||
4953 | } | 5136 | } |
4954 | str_list temp; | 5137 | str_list temp; |
4955 | incIndentOffset(); | 5138 | incIndentOffset(); |
5139 | auto metatable = table->new_ptr<simple_table_t>(); | ||
4956 | for (auto pair : pairs) { | 5140 | for (auto pair : pairs) { |
5141 | bool isMetamethod = false; | ||
4957 | switch (pair->getId()) { | 5142 | switch (pair->getId()) { |
4958 | case id<Exp_t>(): transformExp(static_cast<Exp_t*>(pair), temp, ExpUsage::Closure); break; | 5143 | case id<Exp_t>(): transformExp(static_cast<Exp_t*>(pair), temp, ExpUsage::Closure); break; |
4959 | case id<variable_pair_t>(): transform_variable_pair(static_cast<variable_pair_t*>(pair), temp); break; | 5144 | case id<variable_pair_t>(): transform_variable_pair(static_cast<variable_pair_t*>(pair), temp); break; |
4960 | case id<normal_pair_t>(): transform_normal_pair(static_cast<normal_pair_t*>(pair), temp); break; | 5145 | case id<normal_pair_t>(): transform_normal_pair(static_cast<normal_pair_t*>(pair), temp); break; |
4961 | case id<TableBlockIndent_t>(): transformTableBlockIndent(static_cast<TableBlockIndent_t*>(pair), temp); break; | 5146 | case id<TableBlockIndent_t>(): transformTableBlockIndent(static_cast<TableBlockIndent_t*>(pair), temp); break; |
4962 | case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(pair), temp); break; | 5147 | case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(pair), temp); break; |
5148 | case id<meta_variable_pair_t>(): { | ||
5149 | isMetamethod = true; | ||
5150 | auto mp = static_cast<meta_variable_pair_t*>(pair); | ||
5151 | auto name = _parser.toString(mp->name); | ||
5152 | _buf << "__"sv << name << ':' << name; | ||
5153 | auto newPair = toAst<normal_pair_t>(clearBuf(), pair); | ||
5154 | metatable->pairs.push_back(newPair); | ||
5155 | break; | ||
5156 | } | ||
5157 | case id<meta_normal_pair_t>(): { | ||
5158 | isMetamethod = true; | ||
5159 | auto mp = static_cast<meta_normal_pair_t*>(pair); | ||
5160 | auto key = _parser.toString(mp->key); | ||
5161 | _buf << "__"sv << key; | ||
5162 | auto newKey = toAst<KeyName_t>(clearBuf(), pair); | ||
5163 | auto newPair = pair->new_ptr<normal_pair_t>(); | ||
5164 | newPair->key.set(newKey); | ||
5165 | newPair->value.set(mp->value); | ||
5166 | metatable->pairs.push_back(newPair); | ||
5167 | break; | ||
5168 | } | ||
4963 | default: YUEE("AST node mismatch", pair); break; | 5169 | default: YUEE("AST node mismatch", pair); break; |
4964 | } | 5170 | } |
4965 | temp.back() = indent() + temp.back() + (pair == pairs.back() ? Empty : s(","sv)) + nll(pair); | 5171 | if (!isMetamethod) { |
5172 | temp.back() = indent() + temp.back() + (pair == pairs.back() ? Empty : s(","sv)) + nll(pair); | ||
5173 | } | ||
5174 | } | ||
5175 | if (metatable->pairs.empty()) { | ||
5176 | out.push_back(s("{"sv) + nll(table) + join(temp)); | ||
5177 | decIndentOffset(); | ||
5178 | out.back() += (indent() + s("}"sv)); | ||
5179 | } else { | ||
5180 | auto tabStr = globalVar("setmetatable"sv, table); | ||
5181 | tabStr += '('; | ||
5182 | if (temp.empty()) { | ||
5183 | decIndentOffset(); | ||
5184 | tabStr += "{ }"sv; | ||
5185 | } else { | ||
5186 | tabStr += (s("{"sv) + nll(table) + join(temp)); | ||
5187 | decIndentOffset(); | ||
5188 | tabStr += (indent() + s("}"sv)); | ||
5189 | } | ||
5190 | tabStr += ", "sv; | ||
5191 | str_list tmp; | ||
5192 | transform_simple_table(metatable, tmp); | ||
5193 | tabStr += tmp.back(); | ||
5194 | tabStr += s(")"sv); | ||
5195 | out.push_back(tabStr); | ||
4966 | } | 5196 | } |
4967 | out.push_back(s("{"sv) + nll(table) + join(temp)); | ||
4968 | decIndentOffset(); | ||
4969 | out.back() += (indent() + s("}"sv)); | ||
4970 | } | 5197 | } |
4971 | 5198 | ||
4972 | void transform_simple_table(simple_table_t* table, str_list& out) { | 5199 | void transform_simple_table(simple_table_t* table, str_list& out) { |
@@ -5236,6 +5463,8 @@ private: | |||
5236 | break; | 5463 | break; |
5237 | case id<variable_pair_t>(): | 5464 | case id<variable_pair_t>(): |
5238 | case id<normal_pair_t>(): | 5465 | case id<normal_pair_t>(): |
5466 | case id<meta_variable_pair_t>(): | ||
5467 | case id<meta_normal_pair_t>(): | ||
5239 | case id<Exp_t>(): | 5468 | case id<Exp_t>(): |
5240 | newTab->items.push_back(item); | 5469 | newTab->items.push_back(item); |
5241 | break; | 5470 | break; |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 7cf2ebe..c72c005 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
@@ -412,6 +412,9 @@ YueParser::YueParser() { | |||
412 | FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) | | 412 | FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) | |
413 | (sym('!') >> not_(expr('='))); | 413 | (sym('!') >> not_(expr('='))); |
414 | 414 | ||
415 | Metatable = expr('#'); | ||
416 | Metamethod = Name >> expr('#'); | ||
417 | |||
415 | existential_op = expr('?'); | 418 | existential_op = expr('?'); |
416 | chain_call = (Callable | String) >> -existential_op >> ChainItems; | 419 | chain_call = (Callable | String) >> -existential_op >> ChainItems; |
417 | chain_item = and_(set(".\\")) >> ChainItems; | 420 | chain_item = and_(set(".\\")) >> ChainItems; |
@@ -427,8 +430,8 @@ YueParser::YueParser() { | |||
427 | 430 | ||
428 | Index = symx('[') >> Exp >> sym(']'); | 431 | Index = symx('[') >> Exp >> sym(']'); |
429 | ChainItem = Invoke >> -existential_op | DotChainItem >> -existential_op | Slice | Index >> -existential_op; | 432 | ChainItem = Invoke >> -existential_op | DotChainItem >> -existential_op | Slice | Index >> -existential_op; |
430 | DotChainItem = symx('.') >> Name; | 433 | DotChainItem = symx('.') >> (Name >> not_('#') | Metatable | Metamethod); |
431 | ColonChainItem = symx('\\') >> (LuaKeyword | Name); | 434 | ColonChainItem = symx('\\') >> ((LuaKeyword | Name) >> not_('#') | Metamethod); |
432 | invoke_chain = Invoke >> -existential_op >> -ChainItems; | 435 | invoke_chain = Invoke >> -existential_op >> -ChainItems; |
433 | ColonChain = ColonChainItem >> -existential_op >> -invoke_chain; | 436 | ColonChain = ColonChainItem >> -existential_op >> -invoke_chain; |
434 | 437 | ||
@@ -508,7 +511,7 @@ YueParser::YueParser() { | |||
508 | }) >> ExpList >> -Assign) | 511 | }) >> ExpList >> -Assign) |
509 | | Macro) >> not_(Space >> statement_appendix); | 512 | | Macro) >> not_(Space >> statement_appendix); |
510 | 513 | ||
511 | variable_pair = sym(':') >> Variable; | 514 | variable_pair = sym(':') >> Variable >> not_('#'); |
512 | 515 | ||
513 | normal_pair = ( | 516 | normal_pair = ( |
514 | KeyName | | 517 | KeyName | |
@@ -520,7 +523,12 @@ YueParser::YueParser() { | |||
520 | symx(':') >> | 523 | symx(':') >> |
521 | (Exp | TableBlock | +(SpaceBreak) >> Exp); | 524 | (Exp | TableBlock | +(SpaceBreak) >> Exp); |
522 | 525 | ||
523 | KeyValue = variable_pair | normal_pair; | 526 | meta_variable_pair = sym(':') >> Variable >> expr('#'); |
527 | |||
528 | meta_normal_pair = Space >> Name >> expr("#:") >> | ||
529 | (Exp | TableBlock | +(SpaceBreak) >> Exp); | ||
530 | |||
531 | KeyValue = variable_pair | normal_pair | meta_variable_pair | meta_normal_pair; | ||
524 | 532 | ||
525 | KeyValueList = KeyValue >> *(sym(',') >> KeyValue); | 533 | KeyValueList = KeyValue >> *(sym(',') >> KeyValue); |
526 | KeyValueLine = CheckIndent >> (KeyValueList >> -sym(',') | TableBlockIndent | Space >> expr('*') >> (Exp | TableBlock)); | 534 | KeyValueLine = CheckIndent >> (KeyValueList >> -sym(',') | TableBlockIndent | Space >> expr('*') >> (Exp | TableBlock)); |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index f9a0d54..729304a 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
@@ -265,6 +265,8 @@ private: | |||
265 | AST_RULE(Parens) | 265 | AST_RULE(Parens) |
266 | AST_RULE(DotChainItem) | 266 | AST_RULE(DotChainItem) |
267 | AST_RULE(ColonChainItem) | 267 | AST_RULE(ColonChainItem) |
268 | AST_RULE(Metatable) | ||
269 | AST_RULE(Metamethod) | ||
268 | AST_RULE(default_value) | 270 | AST_RULE(default_value) |
269 | AST_RULE(Slice) | 271 | AST_RULE(Slice) |
270 | AST_RULE(Invoke) | 272 | AST_RULE(Invoke) |
@@ -282,6 +284,8 @@ private: | |||
282 | AST_RULE(Export) | 284 | AST_RULE(Export) |
283 | AST_RULE(variable_pair) | 285 | AST_RULE(variable_pair) |
284 | AST_RULE(normal_pair) | 286 | AST_RULE(normal_pair) |
287 | AST_RULE(meta_variable_pair) | ||
288 | AST_RULE(meta_normal_pair) | ||
285 | AST_RULE(FnArgDef) | 289 | AST_RULE(FnArgDef) |
286 | AST_RULE(FnArgDefList) | 290 | AST_RULE(FnArgDefList) |
287 | AST_RULE(outer_var_shadow) | 291 | AST_RULE(outer_var_shadow) |