aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/rt.zc
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 21:44:40 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 21:44:40 +0330
commitf3dcfd9805e1bd23b002f648d4391ec397122d9c (patch)
tree91acab7da09c9225a2d838791d70e5c2e7db54b9 /src/runtime/rt.zc
parentmerge work/small-oob: bytes test out-of-bounds read (diff)
parentexamples/actors_demo: print the fan-out replies in worker order, not arrival ... (diff)
merge work/known-bugs: constant-expression precedence, local const in constant expressions, duplicate case labels, unterminated strings, droppable cycles in one collection, js vm exit, docs, actors_demo orderHEADmain
Diffstat (limited to 'src/runtime/rt.zc')
-rw-r--r--src/runtime/rt.zc14
1 files changed, 9 insertions, 5 deletions
diff --git a/src/runtime/rt.zc b/src/runtime/rt.zc
index 149138b..4f96320 100644
--- a/src/runtime/rt.zc
+++ b/src/runtime/rt.zc
@@ -428,7 +428,7 @@ const int F_SHARE = 8;
// table (dtab), its drop has run (it never runs again), and the collector found it
// unreachable and runs its drop once the sweep is over.
const int F_HASDROP = 16, F_DROPPED = 32, F_FINAL = 64, F_CYCLE = 128; // F_CYCLE: during gc_drops only, a candidate its own contents reach
-int o3_depth, gc_pending;
+int o3_depth, gc_pending, gc_cyc; // gc_cyc: the last sweep found a cycle with drops to run
// flags live in these bits; the size class is above them.
const int F_LOW = 65535;
int hbump; word[32] freel; int gc_runs, gc_freed, gc_auto = 1;
@@ -1456,7 +1456,7 @@ int o3_leave() {
// an unreachable value with a drop that hasn't run is kept for one more cycle and
// flagged F_FINAL, unless another such value reaches it (its parent drops first and
// it waits for a later collection) and it doesn't reach itself (a cycle drops one
-// value per collection). nothing runs user code here.
+// value per sweep, and gc() repeats the sweep until the cycle is done). nothing runs user code here.
int gc_drops() {
int i, again = 1; word k;
while (again) {
@@ -1486,9 +1486,9 @@ int gc_drops() {
k = dtab[i * 3];
if (k > 1 && (k[-4] & F_FINAL)) {
// reached from another candidate: later. one in a cycle has nothing outside it
- // to drop first, so it drops now (it is marked, so kept), and the rest of the
- // cycle in later collections, one each, never twice
- if ((k[-4] & 7) == 1) mark(k); else if (!(k[-4] & F_CYCLE)) k[-4] = k[-4] & ~F_FINAL;
+ // to drop first, so it drops now (it is marked, so kept); gc() then sweeps again
+ // for the rest of the cycle, one each, never twice
+ if ((k[-4] & 7) == 1) mark(k); else if (!(k[-4] & F_CYCLE)) k[-4] = k[-4] & ~F_FINAL; else gc_cyc = 1;
k[-4] = k[-4] & ~F_CYCLE;
}
i++;
@@ -1549,8 +1549,12 @@ unchecked int gc_sweep() {
unchecked int gc() {
int n;
if (o3_depth) { gc_pending = 1; return 0; }
+ gc_cyc = 0;
n = gc_sweep();
if (dcount) gc_finalize();
+ // an unreachable cycle with drops finishes in this collection: each sweep drops one
+ // member (nothing outside the cycle has to go first), and every value drops once
+ while (gc_cyc) { gc_cyc = 0; n = n + gc_sweep(); if (dcount) gc_finalize(); }
return n;
}
// the number of live heap objects, for tests and leak checks.