** Traverse a thread, marking the elements in the stack up to its top ** and cleaning the rest of the stack in the final traversal. That ** ensures that the entire stack have valid (non-dead) objects. ** Threads have no barriers. In gen. mode, old threads must be visited ** at every cycle, because they might point to young objects. In inc. ** mode, the thread can still be modified before the end
| 693 | ** the propagate phase (which can only happen in incremental mode). |
| 694 | */ |
| 695 | static l_mem traversethread (global_State *g, lua_State *th) { |
| 696 | UpVal *uv; |
| 697 | StkId o = th->stack.p; |
| 698 | if (isold(th) || g->gcstate == GCSpropagate) |
| 699 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
| 700 | if (o == NULL) |
| 701 | return 0; /* stack not completely built yet */ |
| 702 | lua_assert(g->gcstate == GCSatomic || |
| 703 | th->openupval == NULL || isintwups(th)); |
| 704 | for (; o < th->top.p; o++) /* mark live elements in the stack */ |
| 705 | markvalue(g, s2v(o)); |
| 706 | for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) |
| 707 | markobject(g, uv); /* open upvalues cannot be collected */ |
| 708 | if (g->gcstate == GCSatomic) { /* final traversal? */ |
| 709 | if (!g->gcemergency) |
| 710 | luaD_shrinkstack(th); /* do not change stack in emergency cycle */ |
| 711 | for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++) |
| 712 | setnilvalue(s2v(o)); /* clear dead stack slice */ |
| 713 | /* 'remarkupvals' may have removed thread from 'twups' list */ |
| 714 | if (!isintwups(th) && th->openupval != NULL) { |
| 715 | th->twups = g->twups; /* link it back to the list */ |
| 716 | g->twups = th; |
| 717 | } |
| 718 | } |
| 719 | return 1 + (th->top.p - th->stack.p); |
| 720 | } |
| 721 | |
| 722 | |
| 723 | /* |
no test coverage detected