aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/rt.zc
diff options
context:
space:
mode:
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.