diff options
author | Li Jin <dragon-fly@qq.com> | 2020-09-11 15:31:51 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2020-09-11 15:31:51 +0800 |
commit | 85b9ec82247f6e06b802188af35d09d3159625df (patch) | |
tree | 487152fb9639a74e323f7db962f558ba0514322d | |
parent | dfd4e3b2b2abc0137d26ed3df303a398741bb6a0 (diff) | |
download | yuescript-85b9ec82247f6e06b802188af35d09d3159625df.tar.gz yuescript-85b9ec82247f6e06b802188af35d09d3159625df.tar.bz2 yuescript-85b9ec82247f6e06b802188af35d09d3159625df.zip |
update Lua.
-rw-r--r-- | src/lua/lfunc.c | 2 | ||||
-rw-r--r-- | src/lua/lgc.c | 143 | ||||
-rw-r--r-- | src/lua/lgc.h | 29 | ||||
-rw-r--r-- | src/lua/lobject.h | 6 | ||||
-rw-r--r-- | src/lua/lstate.h | 14 | ||||
-rw-r--r-- | src/lua/ltable.c | 2 | ||||
-rw-r--r-- | src/lua/ltable.h | 7 | ||||
-rw-r--r-- | src/lua/ltm.h | 9 | ||||
-rw-r--r-- | src/lua/lundump.c | 3 |
9 files changed, 121 insertions, 94 deletions
diff --git a/src/lua/lfunc.c b/src/lua/lfunc.c index f8c3c44..88d4532 100644 --- a/src/lua/lfunc.c +++ b/src/lua/lfunc.c | |||
@@ -235,7 +235,7 @@ int luaF_close (lua_State *L, StkId level, int status) { | |||
235 | setobj(L, slot, uv->v); /* move value to upvalue slot */ | 235 | setobj(L, slot, uv->v); /* move value to upvalue slot */ |
236 | uv->v = slot; /* now current value lives here */ | 236 | uv->v = slot; /* now current value lives here */ |
237 | if (!iswhite(uv)) { /* neither white nor dead? */ | 237 | if (!iswhite(uv)) { /* neither white nor dead? */ |
238 | gray2black(uv); /* closed upvalues cannot be gray */ | 238 | nw2black(uv); /* closed upvalues cannot be gray */ |
239 | luaC_barrier(L, uv, slot); | 239 | luaC_barrier(L, uv, slot); |
240 | } | 240 | } |
241 | } | 241 | } |
diff --git a/src/lua/lgc.c b/src/lua/lgc.c index cb820f9..4a7bcae 100644 --- a/src/lua/lgc.c +++ b/src/lua/lgc.c | |||
@@ -60,19 +60,24 @@ | |||
60 | #define PAUSEADJ 100 | 60 | #define PAUSEADJ 100 |
61 | 61 | ||
62 | 62 | ||
63 | /* mask to erase all color bits */ | 63 | /* mask with all color bits */ |
64 | #define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) | 64 | #define maskcolors (bitmask(BLACKBIT) | WHITEBITS) |
65 | 65 | ||
66 | /* mask to erase all GC bits */ | 66 | /* mask with all GC bits */ |
67 | #define maskgcbits (maskcolors & ~AGEBITS) | 67 | #define maskgcbits (maskcolors | AGEBITS) |
68 | 68 | ||
69 | 69 | ||
70 | /* macro to erase all color bits then set only the current white bit */ | 70 | /* macro to erase all color bits then set only the current white bit */ |
71 | #define makewhite(g,x) \ | 71 | #define makewhite(g,x) \ |
72 | (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) | 72 | (x->marked = cast_byte((x->marked & ~maskcolors) | luaC_white(g))) |
73 | 73 | ||
74 | #define white2gray(x) resetbits(x->marked, WHITEBITS) | 74 | /* make an object gray (neither white nor black) */ |
75 | #define black2gray(x) resetbit(x->marked, BLACKBIT) | 75 | #define set2gray(x) resetbits(x->marked, maskcolors) |
76 | |||
77 | |||
78 | /* make an object black (coming from any color) */ | ||
79 | #define set2black(x) \ | ||
80 | (x->marked = cast_byte((x->marked & ~WHITEBITS) | bitmask(BLACKBIT))) | ||
76 | 81 | ||
77 | 82 | ||
78 | #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) | 83 | #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) |
@@ -135,15 +140,23 @@ static GCObject **getgclist (GCObject *o) { | |||
135 | 140 | ||
136 | 141 | ||
137 | /* | 142 | /* |
138 | ** Link a collectable object 'o' with a known type into list pointed by 'p'. | 143 | ** Link a collectable object 'o' with a known type into the list 'p'. |
144 | ** (Must be a macro to access the 'gclist' field in different types.) | ||
139 | */ | 145 | */ |
140 | #define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) | 146 | #define linkgclist(o,p) linkgclist_(obj2gco(o), &(o)->gclist, &(p)) |
147 | |||
148 | static void linkgclist_ (GCObject *o, GCObject **pnext, GCObject **list) { | ||
149 | lua_assert(!isgray(o)); /* cannot be in a gray list */ | ||
150 | *pnext = *list; | ||
151 | *list = o; | ||
152 | set2gray(o); /* now it is */ | ||
153 | } | ||
141 | 154 | ||
142 | 155 | ||
143 | /* | 156 | /* |
144 | ** Link a generic collectable object 'o' into list pointed by 'p'. | 157 | ** Link a generic collectable object 'o' into the list 'p'. |
145 | */ | 158 | */ |
146 | #define linkobjgclist(o,p) (*getgclist(o) = (p), (p) = obj2gco(o)) | 159 | #define linkobjgclist(o,p) linkgclist_(obj2gco(o), getgclist(o), &(p)) |
147 | 160 | ||
148 | 161 | ||
149 | 162 | ||
@@ -219,9 +232,10 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) { | |||
219 | global_State *g = G(L); | 232 | global_State *g = G(L); |
220 | lua_assert(isblack(o) && !isdead(g, o)); | 233 | lua_assert(isblack(o) && !isdead(g, o)); |
221 | lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1)); | 234 | lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1)); |
222 | if (getage(o) != G_TOUCHED2) /* not already in gray list? */ | 235 | if (getage(o) == G_TOUCHED2) /* already in gray list? */ |
223 | linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */ | 236 | set2gray(o); /* make it gray to become touched1 */ |
224 | black2gray(o); /* make object gray (again) */ | 237 | else /* link it in 'grayagain' and paint it gray */ |
238 | linkobjgclist(o, g->grayagain); | ||
225 | if (isold(o)) /* generational mode? */ | 239 | if (isold(o)) /* generational mode? */ |
226 | setage(o, G_TOUCHED1); /* touched in current cycle */ | 240 | setage(o, G_TOUCHED1); /* touched in current cycle */ |
227 | } | 241 | } |
@@ -230,7 +244,7 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) { | |||
230 | void luaC_fix (lua_State *L, GCObject *o) { | 244 | void luaC_fix (lua_State *L, GCObject *o) { |
231 | global_State *g = G(L); | 245 | global_State *g = G(L); |
232 | lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ | 246 | lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ |
233 | white2gray(o); /* they will be gray forever */ | 247 | set2gray(o); /* they will be gray forever */ |
234 | setage(o, G_OLD); /* and old forever */ | 248 | setage(o, G_OLD); /* and old forever */ |
235 | g->allgc = o->next; /* remove object from 'allgc' list */ | 249 | g->allgc = o->next; /* remove object from 'allgc' list */ |
236 | o->next = g->fixedgc; /* link it to 'fixedgc' list */ | 250 | o->next = g->fixedgc; /* link it to 'fixedgc' list */ |
@@ -264,24 +278,30 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { | |||
264 | 278 | ||
265 | 279 | ||
266 | /* | 280 | /* |
267 | ** Mark an object. Userdata, strings, and closed upvalues are visited | 281 | ** Mark an object. Userdata with no user values, strings, and closed |
268 | ** and turned black here. Other objects are marked gray and added | 282 | ** upvalues are visited and turned black here. Open upvalues are |
269 | ** to appropriate list to be visited (and turned black) later. (Open | 283 | ** already indirectly linked through their respective threads in the |
270 | ** upvalues are already linked in 'headuv' list. They are kept gray | 284 | ** 'twups' list, so they don't go to the gray list; nevertheless, they |
271 | ** to avoid barriers, as their values will be revisited by the thread.) | 285 | ** are kept gray to avoid barriers, as their values will be revisited |
286 | ** by the thread or by 'remarkupvals'. Other objects are added to the | ||
287 | ** gray list to be visited (and turned black) later. Both userdata and | ||
288 | ** upvalues can call this function recursively, but this recursion goes | ||
289 | ** for at most two levels: An upvalue cannot refer to another upvalue | ||
290 | ** (only closures can), and a userdata's metatable must be a table. | ||
272 | */ | 291 | */ |
273 | static void reallymarkobject (global_State *g, GCObject *o) { | 292 | static void reallymarkobject (global_State *g, GCObject *o) { |
274 | white2gray(o); | ||
275 | switch (o->tt) { | 293 | switch (o->tt) { |
276 | case LUA_VSHRSTR: | 294 | case LUA_VSHRSTR: |
277 | case LUA_VLNGSTR: { | 295 | case LUA_VLNGSTR: { |
278 | gray2black(o); | 296 | set2black(o); /* nothing to visit */ |
279 | break; | 297 | break; |
280 | } | 298 | } |
281 | case LUA_VUPVAL: { | 299 | case LUA_VUPVAL: { |
282 | UpVal *uv = gco2upv(o); | 300 | UpVal *uv = gco2upv(o); |
283 | if (!upisopen(uv)) /* open upvalues are kept gray */ | 301 | if (upisopen(uv)) |
284 | gray2black(o); | 302 | set2gray(uv); /* open upvalues are kept gray */ |
303 | else | ||
304 | set2black(o); /* closed upvalues are visited here */ | ||
285 | markvalue(g, uv->v); /* mark its content */ | 305 | markvalue(g, uv->v); /* mark its content */ |
286 | break; | 306 | break; |
287 | } | 307 | } |
@@ -289,14 +309,14 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
289 | Udata *u = gco2u(o); | 309 | Udata *u = gco2u(o); |
290 | if (u->nuvalue == 0) { /* no user values? */ | 310 | if (u->nuvalue == 0) { /* no user values? */ |
291 | markobjectN(g, u->metatable); /* mark its metatable */ | 311 | markobjectN(g, u->metatable); /* mark its metatable */ |
292 | gray2black(o); /* nothing else to mark */ | 312 | set2black(o); /* nothing else to mark */ |
293 | break; | 313 | break; |
294 | } | 314 | } |
295 | /* else... */ | 315 | /* else... */ |
296 | } /* FALLTHROUGH */ | 316 | } /* FALLTHROUGH */ |
297 | case LUA_VLCL: case LUA_VCCL: case LUA_VTABLE: | 317 | case LUA_VLCL: case LUA_VCCL: case LUA_VTABLE: |
298 | case LUA_VTHREAD: case LUA_VPROTO: { | 318 | case LUA_VTHREAD: case LUA_VPROTO: { |
299 | linkobjgclist(o, g->gray); | 319 | linkobjgclist(o, g->gray); /* to be visited later */ |
300 | break; | 320 | break; |
301 | } | 321 | } |
302 | default: lua_assert(0); break; | 322 | default: lua_assert(0); break; |
@@ -355,8 +375,10 @@ static int remarkupvals (global_State *g) { | |||
355 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { | 375 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { |
356 | lua_assert(getage(uv) <= getage(thread)); | 376 | lua_assert(getage(uv) <= getage(thread)); |
357 | work++; | 377 | work++; |
358 | if (!iswhite(uv)) /* upvalue already visited? */ | 378 | if (!iswhite(uv)) { /* upvalue already visited? */ |
379 | lua_assert(upisopen(uv) && isgray(uv)); | ||
359 | markvalue(g, uv->v); /* mark its value */ | 380 | markvalue(g, uv->v); /* mark its value */ |
381 | } | ||
360 | } | 382 | } |
361 | } | 383 | } |
362 | } | 384 | } |
@@ -399,17 +421,11 @@ static void restartcollection (global_State *g) { | |||
399 | ** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go | 421 | ** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go |
400 | ** back to a gray list, but then it must become OLD. (That is what | 422 | ** back to a gray list, but then it must become OLD. (That is what |
401 | ** 'correctgraylist' does when it finds a TOUCHED2 object.) | 423 | ** 'correctgraylist' does when it finds a TOUCHED2 object.) |
402 | ** It is defined as a macro because 'gclist' is not a unique field in | ||
403 | ** different collectable objects. | ||
404 | */ | 424 | */ |
405 | #define genlink(g,o) genlink_(g, obj2gco(o), &(o)->gclist) | 425 | static void genlink (global_State *g, GCObject *o) { |
406 | |||
407 | static void genlink_ (global_State *g, GCObject *o, GCObject **pnext) { | ||
408 | lua_assert(isblack(o)); | 426 | lua_assert(isblack(o)); |
409 | if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */ | 427 | if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */ |
410 | *pnext = g->grayagain; /* link it back in 'grayagain' */ | 428 | linkobjgclist(o, g->grayagain); /* link it back in 'grayagain' */ |
411 | g->grayagain = o; | ||
412 | black2gray(o); | ||
413 | } /* everything else do not need to be linked back */ | 429 | } /* everything else do not need to be linked back */ |
414 | else if (getage(o) == G_TOUCHED2) | 430 | else if (getage(o) == G_TOUCHED2) |
415 | changeage(o, G_TOUCHED2, G_OLD); /* advance age */ | 431 | changeage(o, G_TOUCHED2, G_OLD); /* advance age */ |
@@ -493,10 +509,8 @@ static int traverseephemeron (global_State *g, Table *h, int inv) { | |||
493 | linkgclist(h, g->ephemeron); /* have to propagate again */ | 509 | linkgclist(h, g->ephemeron); /* have to propagate again */ |
494 | else if (hasclears) /* table has white keys? */ | 510 | else if (hasclears) /* table has white keys? */ |
495 | linkgclist(h, g->allweak); /* may have to clean white keys */ | 511 | linkgclist(h, g->allweak); /* may have to clean white keys */ |
496 | else { | 512 | else |
497 | gray2black(h); /* 'genlink' expects black objects */ | 513 | genlink(g, obj2gco(h)); /* check whether collector still needs to see it */ |
498 | genlink(g, h); /* check whether collector still needs to see it */ | ||
499 | } | ||
500 | return marked; | 514 | return marked; |
501 | } | 515 | } |
502 | 516 | ||
@@ -516,7 +530,7 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
516 | markvalue(g, gval(n)); | 530 | markvalue(g, gval(n)); |
517 | } | 531 | } |
518 | } | 532 | } |
519 | genlink(g, h); | 533 | genlink(g, obj2gco(h)); |
520 | } | 534 | } |
521 | 535 | ||
522 | 536 | ||
@@ -528,7 +542,6 @@ static lu_mem traversetable (global_State *g, Table *h) { | |||
528 | (cast_void(weakkey = strchr(svalue(mode), 'k')), | 542 | (cast_void(weakkey = strchr(svalue(mode), 'k')), |
529 | cast_void(weakvalue = strchr(svalue(mode), 'v')), | 543 | cast_void(weakvalue = strchr(svalue(mode), 'v')), |
530 | (weakkey || weakvalue))) { /* is really weak? */ | 544 | (weakkey || weakvalue))) { /* is really weak? */ |
531 | black2gray(h); /* turn it back to gray, as it probably goes to a list */ | ||
532 | if (!weakkey) /* strong keys? */ | 545 | if (!weakkey) /* strong keys? */ |
533 | traverseweakvalue(g, h); | 546 | traverseweakvalue(g, h); |
534 | else if (!weakvalue) /* strong values? */ | 547 | else if (!weakvalue) /* strong values? */ |
@@ -547,7 +560,7 @@ static int traverseudata (global_State *g, Udata *u) { | |||
547 | markobjectN(g, u->metatable); /* mark its metatable */ | 560 | markobjectN(g, u->metatable); /* mark its metatable */ |
548 | for (i = 0; i < u->nuvalue; i++) | 561 | for (i = 0; i < u->nuvalue; i++) |
549 | markvalue(g, &u->uv[i].uv); | 562 | markvalue(g, &u->uv[i].uv); |
550 | genlink(g, u); | 563 | genlink(g, obj2gco(u)); |
551 | return 1 + u->nuvalue; | 564 | return 1 + u->nuvalue; |
552 | } | 565 | } |
553 | 566 | ||
@@ -609,10 +622,8 @@ static int traverseLclosure (global_State *g, LClosure *cl) { | |||
609 | static int traversethread (global_State *g, lua_State *th) { | 622 | static int traversethread (global_State *g, lua_State *th) { |
610 | UpVal *uv; | 623 | UpVal *uv; |
611 | StkId o = th->stack; | 624 | StkId o = th->stack; |
612 | if (isold(th) || g->gcstate == GCSpropagate) { | 625 | if (isold(th) || g->gcstate == GCSpropagate) |
613 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ | 626 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
614 | black2gray(th); | ||
615 | } | ||
616 | if (o == NULL) | 627 | if (o == NULL) |
617 | return 1; /* stack not completely built yet */ | 628 | return 1; /* stack not completely built yet */ |
618 | lua_assert(g->gcstate == GCSatomic || | 629 | lua_assert(g->gcstate == GCSatomic || |
@@ -638,12 +649,11 @@ static int traversethread (global_State *g, lua_State *th) { | |||
638 | 649 | ||
639 | 650 | ||
640 | /* | 651 | /* |
641 | ** traverse one gray object, turning it to black (except for threads, | 652 | ** traverse one gray object, turning it to black. |
642 | ** which are always gray). | ||
643 | */ | 653 | */ |
644 | static lu_mem propagatemark (global_State *g) { | 654 | static lu_mem propagatemark (global_State *g) { |
645 | GCObject *o = g->gray; | 655 | GCObject *o = g->gray; |
646 | gray2black(o); | 656 | nw2black(o); |
647 | g->gray = *getgclist(o); /* remove from 'gray' list */ | 657 | g->gray = *getgclist(o); /* remove from 'gray' list */ |
648 | switch (o->tt) { | 658 | switch (o->tt) { |
649 | case LUA_VTABLE: return traversetable(g, gco2t(o)); | 659 | case LUA_VTABLE: return traversetable(g, gco2t(o)); |
@@ -681,8 +691,10 @@ static void convergeephemerons (global_State *g) { | |||
681 | g->ephemeron = NULL; /* tables may return to this list when traversed */ | 691 | g->ephemeron = NULL; /* tables may return to this list when traversed */ |
682 | changed = 0; | 692 | changed = 0; |
683 | while ((w = next) != NULL) { /* for each ephemeron table */ | 693 | while ((w = next) != NULL) { /* for each ephemeron table */ |
684 | next = gco2t(w)->gclist; /* list is rebuilt during loop */ | 694 | Table *h = gco2t(w); |
685 | if (traverseephemeron(g, gco2t(w), dir)) { /* marked some value? */ | 695 | next = h->gclist; /* list is rebuilt during loop */ |
696 | nw2black(h); /* out of the list (for now) */ | ||
697 | if (traverseephemeron(g, h, dir)) { /* marked some value? */ | ||
686 | propagateall(g); /* propagate changes */ | 698 | propagateall(g); /* propagate changes */ |
687 | changed = 1; /* will have to revisit all ephemeron tables */ | 699 | changed = 1; /* will have to revisit all ephemeron tables */ |
688 | } | 700 | } |
@@ -809,7 +821,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, | |||
809 | freeobj(L, curr); /* erase 'curr' */ | 821 | freeobj(L, curr); /* erase 'curr' */ |
810 | } | 822 | } |
811 | else { /* change mark to 'white' */ | 823 | else { /* change mark to 'white' */ |
812 | curr->marked = cast_byte((marked & maskgcbits) | white); | 824 | curr->marked = cast_byte((marked & ~maskgcbits) | white); |
813 | p = &curr->next; /* go to next element */ | 825 | p = &curr->next; /* go to next element */ |
814 | } | 826 | } |
815 | } | 827 | } |
@@ -1028,8 +1040,8 @@ static void setpause (global_State *g); | |||
1028 | /* | 1040 | /* |
1029 | ** Sweep a list of objects to enter generational mode. Deletes dead | 1041 | ** Sweep a list of objects to enter generational mode. Deletes dead |
1030 | ** objects and turns the non dead to old. All non-dead threads---which | 1042 | ** objects and turns the non dead to old. All non-dead threads---which |
1031 | ** are now old---must be in a gray list. Everything else is not in a | 1043 | ** are now old---must be in a gray list. Everything else is not in a |
1032 | ** gray list. | 1044 | ** gray list. Open upvalues are also kept gray. |
1033 | */ | 1045 | */ |
1034 | static void sweep2old (lua_State *L, GCObject **p) { | 1046 | static void sweep2old (lua_State *L, GCObject **p) { |
1035 | GCObject *curr; | 1047 | GCObject *curr; |
@@ -1045,10 +1057,11 @@ static void sweep2old (lua_State *L, GCObject **p) { | |||
1045 | if (curr->tt == LUA_VTHREAD) { /* threads must be watched */ | 1057 | if (curr->tt == LUA_VTHREAD) { /* threads must be watched */ |
1046 | lua_State *th = gco2th(curr); | 1058 | lua_State *th = gco2th(curr); |
1047 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ | 1059 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
1048 | black2gray(th); /* OK if already gray */ | ||
1049 | } | 1060 | } |
1061 | else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr))) | ||
1062 | set2gray(curr); /* open upvalues are always gray */ | ||
1050 | else /* everything else is black */ | 1063 | else /* everything else is black */ |
1051 | gray2black(curr); /* OK if already black */ | 1064 | nw2black(curr); |
1052 | p = &curr->next; /* go to next element */ | 1065 | p = &curr->next; /* go to next element */ |
1053 | } | 1066 | } |
1054 | } | 1067 | } |
@@ -1087,7 +1100,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | |||
1087 | } | 1100 | } |
1088 | else { /* correct mark and age */ | 1101 | else { /* correct mark and age */ |
1089 | if (getage(curr) == G_NEW) { /* new objects go back to white */ | 1102 | if (getage(curr) == G_NEW) { /* new objects go back to white */ |
1090 | int marked = curr->marked & maskgcbits; /* erase GC bits */ | 1103 | int marked = curr->marked & ~maskgcbits; /* erase GC bits */ |
1091 | curr->marked = cast_byte(marked | G_SURVIVAL | white); | 1104 | curr->marked = cast_byte(marked | G_SURVIVAL | white); |
1092 | } | 1105 | } |
1093 | else { /* all other objects will be old, and so keep their color */ | 1106 | else { /* all other objects will be old, and so keep their color */ |
@@ -1110,7 +1123,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | |||
1110 | static void whitelist (global_State *g, GCObject *p) { | 1123 | static void whitelist (global_State *g, GCObject *p) { |
1111 | int white = luaC_white(g); | 1124 | int white = luaC_white(g); |
1112 | for (; p != NULL; p = p->next) | 1125 | for (; p != NULL; p = p->next) |
1113 | p->marked = cast_byte((p->marked & maskgcbits) | white); | 1126 | p->marked = cast_byte((p->marked & ~maskgcbits) | white); |
1114 | } | 1127 | } |
1115 | 1128 | ||
1116 | 1129 | ||
@@ -1131,7 +1144,7 @@ static GCObject **correctgraylist (GCObject **p) { | |||
1131 | goto remove; /* remove all white objects */ | 1144 | goto remove; /* remove all white objects */ |
1132 | else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ | 1145 | else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ |
1133 | lua_assert(isgray(curr)); | 1146 | lua_assert(isgray(curr)); |
1134 | gray2black(curr); /* make it black, for next barrier */ | 1147 | nw2black(curr); /* make it black, for next barrier */ |
1135 | changeage(curr, G_TOUCHED1, G_TOUCHED2); | 1148 | changeage(curr, G_TOUCHED1, G_TOUCHED2); |
1136 | goto remain; /* keep it in the list and go to next element */ | 1149 | goto remain; /* keep it in the list and go to next element */ |
1137 | } | 1150 | } |
@@ -1141,15 +1154,9 @@ static GCObject **correctgraylist (GCObject **p) { | |||
1141 | } | 1154 | } |
1142 | else { /* everything else is removed */ | 1155 | else { /* everything else is removed */ |
1143 | lua_assert(isold(curr)); /* young objects should be white here */ | 1156 | lua_assert(isold(curr)); /* young objects should be white here */ |
1144 | if (getage(curr) == G_TOUCHED2) { /* advance from TOUCHED2... */ | 1157 | if (getage(curr) == G_TOUCHED2) /* advance from TOUCHED2... */ |
1145 | changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */ | 1158 | changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */ |
1146 | lua_assert(isblack(curr)); /* TOUCHED2 objects are always black */ | 1159 | nw2black(curr); /* make object black (to be removed) */ |
1147 | } | ||
1148 | else { | ||
1149 | /* everything else in a gray list should be gray */ | ||
1150 | lua_assert(isgray(curr)); | ||
1151 | gray2black(curr); /* make object black (to be removed) */ | ||
1152 | } | ||
1153 | goto remove; | 1160 | goto remove; |
1154 | } | 1161 | } |
1155 | remove: *p = *next; continue; | 1162 | remove: *p = *next; continue; |
@@ -1184,10 +1191,8 @@ static void markold (global_State *g, GCObject *from, GCObject *to) { | |||
1184 | if (getage(p) == G_OLD1) { | 1191 | if (getage(p) == G_OLD1) { |
1185 | lua_assert(!iswhite(p)); | 1192 | lua_assert(!iswhite(p)); |
1186 | changeage(p, G_OLD1, G_OLD); /* now they are old */ | 1193 | changeage(p, G_OLD1, G_OLD); /* now they are old */ |
1187 | if (isblack(p)) { | 1194 | if (isblack(p)) |
1188 | black2gray(p); /* should be '2white', but gray works too */ | ||
1189 | reallymarkobject(g, p); | 1195 | reallymarkobject(g, p); |
1190 | } | ||
1191 | } | 1196 | } |
1192 | } | 1197 | } |
1193 | } | 1198 | } |
diff --git a/src/lua/lgc.h b/src/lua/lgc.h index b972472..073e2a4 100644 --- a/src/lua/lgc.h +++ b/src/lua/lgc.h | |||
@@ -12,16 +12,16 @@ | |||
12 | #include "lstate.h" | 12 | #include "lstate.h" |
13 | 13 | ||
14 | /* | 14 | /* |
15 | ** Collectable objects may have one of three colors: white, which | 15 | ** Collectable objects may have one of three colors: white, which means |
16 | ** means the object is not marked; gray, which means the | 16 | ** the object is not marked; gray, which means the object is marked, but |
17 | ** object is marked, but its references may be not marked; and | 17 | ** its references may be not marked; and black, which means that the |
18 | ** black, which means that the object and all its references are marked. | 18 | ** object and all its references are marked. The main invariant of the |
19 | ** The main invariant of the garbage collector, while marking objects, | 19 | ** garbage collector, while marking objects, is that a black object can |
20 | ** is that a black object can never point to a white one. Moreover, | 20 | ** never point to a white one. Moreover, any gray object must be in a |
21 | ** any gray object must be in a "gray list" (gray, grayagain, weak, | 21 | ** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it |
22 | ** allweak, ephemeron) so that it can be visited again before finishing | 22 | ** can be visited again before finishing the collection cycle. (Open |
23 | ** the collection cycle. These lists have no meaning when the invariant | 23 | ** upvalues are an exception to this rule.) These lists have no meaning |
24 | ** is not being enforced (e.g., sweep phase). | 24 | ** when the invariant is not being enforced (e.g., sweep phase). |
25 | */ | 25 | */ |
26 | 26 | ||
27 | 27 | ||
@@ -69,14 +69,16 @@ | |||
69 | 69 | ||
70 | /* | 70 | /* |
71 | ** Layout for bit use in 'marked' field. First three bits are | 71 | ** Layout for bit use in 'marked' field. First three bits are |
72 | ** used for object "age" in generational mode. Last bit is free | 72 | ** used for object "age" in generational mode. Last bit is used |
73 | ** to be used by respective objects. | 73 | ** by tests. |
74 | */ | 74 | */ |
75 | #define WHITE0BIT 3 /* object is white (type 0) */ | 75 | #define WHITE0BIT 3 /* object is white (type 0) */ |
76 | #define WHITE1BIT 4 /* object is white (type 1) */ | 76 | #define WHITE1BIT 4 /* object is white (type 1) */ |
77 | #define BLACKBIT 5 /* object is black */ | 77 | #define BLACKBIT 5 /* object is black */ |
78 | #define FINALIZEDBIT 6 /* object has been marked for finalization */ | 78 | #define FINALIZEDBIT 6 /* object has been marked for finalization */ |
79 | 79 | ||
80 | #define TESTBIT 7 | ||
81 | |||
80 | 82 | ||
81 | 83 | ||
82 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) | 84 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) |
@@ -94,7 +96,8 @@ | |||
94 | #define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) | 96 | #define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) |
95 | 97 | ||
96 | #define changewhite(x) ((x)->marked ^= WHITEBITS) | 98 | #define changewhite(x) ((x)->marked ^= WHITEBITS) |
97 | #define gray2black(x) l_setbit((x)->marked, BLACKBIT) | 99 | #define nw2black(x) \ |
100 | check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT)) | ||
98 | 101 | ||
99 | #define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS) | 102 | #define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS) |
100 | 103 | ||
diff --git a/src/lua/lobject.h b/src/lua/lobject.h index 1620223..a9d4578 100644 --- a/src/lua/lobject.h +++ b/src/lua/lobject.h | |||
@@ -704,9 +704,9 @@ typedef union Node { | |||
704 | */ | 704 | */ |
705 | 705 | ||
706 | #define BITRAS (1 << 7) | 706 | #define BITRAS (1 << 7) |
707 | #define isrealasize(t) (!((t)->marked & BITRAS)) | 707 | #define isrealasize(t) (!((t)->flags & BITRAS)) |
708 | #define setrealasize(t) ((t)->marked &= cast_byte(~BITRAS)) | 708 | #define setrealasize(t) ((t)->flags &= cast_byte(~BITRAS)) |
709 | #define setnorealasize(t) ((t)->marked |= BITRAS) | 709 | #define setnorealasize(t) ((t)->flags |= BITRAS) |
710 | 710 | ||
711 | 711 | ||
712 | typedef struct Table { | 712 | typedef struct Table { |
diff --git a/src/lua/lstate.h b/src/lua/lstate.h index 697d73b..1b6bcdf 100644 --- a/src/lua/lstate.h +++ b/src/lua/lstate.h | |||
@@ -63,7 +63,7 @@ | |||
63 | ** can become gray have such a field. The field is not the same | 63 | ** can become gray have such a field. The field is not the same |
64 | ** in all objects, but it always has this name.) Any gray object | 64 | ** in all objects, but it always has this name.) Any gray object |
65 | ** must belong to one of these lists, and all objects in these lists | 65 | ** must belong to one of these lists, and all objects in these lists |
66 | ** must be gray (with one exception explained below): | 66 | ** must be gray (with two exceptions explained below): |
67 | ** | 67 | ** |
68 | ** 'gray': regular gray objects, still waiting to be visited. | 68 | ** 'gray': regular gray objects, still waiting to be visited. |
69 | ** 'grayagain': objects that must be revisited at the atomic phase. | 69 | ** 'grayagain': objects that must be revisited at the atomic phase. |
@@ -75,11 +75,13 @@ | |||
75 | ** 'ephemeron': ephemeron tables with white->white entries; | 75 | ** 'ephemeron': ephemeron tables with white->white entries; |
76 | ** 'allweak': tables with weak keys and/or weak values to be cleared. | 76 | ** 'allweak': tables with weak keys and/or weak values to be cleared. |
77 | ** | 77 | ** |
78 | ** The exception to that "gray rule" is the TOUCHED2 objects in | 78 | ** The exceptions to that "gray rule" are: |
79 | ** generational mode. Those objects stay in a gray list (because they | 79 | ** - TOUCHED2 objects in generational mode stay in a gray list (because |
80 | ** must be visited again at the end of the cycle), but they are marked | 80 | ** they must be visited again at the end of the cycle), but they are |
81 | ** black (because assignments to them must activate barriers, to move | 81 | ** marked black because assignments to them must activate barriers (to |
82 | ** them back to TOUCHED1). | 82 | ** move them back to TOUCHED1). |
83 | ** - Open upvales are kept gray to avoid barriers, but they stay out | ||
84 | ** of gray lists. (They don't even have a 'gclist' field.) | ||
83 | */ | 85 | */ |
84 | 86 | ||
85 | 87 | ||
diff --git a/src/lua/ltable.c b/src/lua/ltable.c index d7eb69a..5a0d066 100644 --- a/src/lua/ltable.c +++ b/src/lua/ltable.c | |||
@@ -583,7 +583,7 @@ Table *luaH_new (lua_State *L) { | |||
583 | GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table)); | 583 | GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table)); |
584 | Table *t = gco2t(o); | 584 | Table *t = gco2t(o); |
585 | t->metatable = NULL; | 585 | t->metatable = NULL; |
586 | t->flags = cast_byte(~0); | 586 | t->flags = cast_byte(maskflags); /* table has no metamethod fields */ |
587 | t->array = NULL; | 587 | t->array = NULL; |
588 | t->alimit = 0; | 588 | t->alimit = 0; |
589 | setnodevector(L, t, 0); | 589 | setnodevector(L, t, 0); |
diff --git a/src/lua/ltable.h b/src/lua/ltable.h index ebd7f8e..c0060f4 100644 --- a/src/lua/ltable.h +++ b/src/lua/ltable.h | |||
@@ -15,7 +15,12 @@ | |||
15 | #define gnext(n) ((n)->u.next) | 15 | #define gnext(n) ((n)->u.next) |
16 | 16 | ||
17 | 17 | ||
18 | #define invalidateTMcache(t) ((t)->flags = 0) | 18 | /* |
19 | ** Clear all bits of fast-access metamethods, which means that the table | ||
20 | ** may have any of these metamethods. (First access that fails after the | ||
21 | ** clearing will set the bit again.) | ||
22 | */ | ||
23 | #define invalidateTMcache(t) ((t)->flags &= ~maskflags) | ||
19 | 24 | ||
20 | 25 | ||
21 | /* true when 't' is using 'dummynode' as its hash part */ | 26 | /* true when 't' is using 'dummynode' as its hash part */ |
diff --git a/src/lua/ltm.h b/src/lua/ltm.h index 99b545e..73b833c 100644 --- a/src/lua/ltm.h +++ b/src/lua/ltm.h | |||
@@ -46,6 +46,15 @@ typedef enum { | |||
46 | 46 | ||
47 | 47 | ||
48 | /* | 48 | /* |
49 | ** Mask with 1 in all fast-access methods. A 1 in any of these bits | ||
50 | ** in the flag of a (meta)table means the metatable does not have the | ||
51 | ** corresponding metamethod field. (Bit 7 of the flag is used for | ||
52 | ** 'isrealasize'.) | ||
53 | */ | ||
54 | #define maskflags (~(~0u << (TM_EQ + 1))) | ||
55 | |||
56 | |||
57 | /* | ||
49 | ** Test whether there is no tagmethod. | 58 | ** Test whether there is no tagmethod. |
50 | ** (Because tagmethods use raw accesses, the result may be an "empty" nil.) | 59 | ** (Because tagmethods use raw accesses, the result may be an "empty" nil.) |
51 | */ | 60 | */ |
diff --git a/src/lua/lundump.c b/src/lua/lundump.c index cb124d6..5aa55c4 100644 --- a/src/lua/lundump.c +++ b/src/lua/lundump.c | |||
@@ -120,7 +120,10 @@ static TString *loadStringN (LoadState *S, Proto *p) { | |||
120 | } | 120 | } |
121 | else { /* long string */ | 121 | else { /* long string */ |
122 | ts = luaS_createlngstrobj(L, size); /* create string */ | 122 | ts = luaS_createlngstrobj(L, size); /* create string */ |
123 | setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */ | ||
124 | luaD_inctop(L); | ||
123 | loadVector(S, getstr(ts), size); /* load directly in final place */ | 125 | loadVector(S, getstr(ts), size); /* load directly in final place */ |
126 | L->top--; /* pop string */ | ||
124 | } | 127 | } |
125 | luaC_objbarrier(L, p, ts); | 128 | luaC_objbarrier(L, p, ts); |
126 | return ts; | 129 | return ts; |