diff --git a/src/gc.js b/src/gc.js index f07bd1f..1d7329c 100644 --- a/src/gc.js +++ b/src/gc.js @@ -220,7 +220,7 @@ function h$gc(t) { while((nt = iter.next()) !== null) h$follow(nt.root); // now we've marked all the regular Haskell data, continue marking weak references - h$markRetained(); + var toFinalize = h$markRetained(); // now all running threads and threads blocked on something that's excpected // to make them runnable at some point have been marked, including other threads @@ -229,18 +229,8 @@ function h$gc(t) { // clean up threads waiting on unreachable synchronization primitives h$resolveDeadlocks(); - // now everything has been marked, bring out your dead references - - // run finalizers for all weak references with unreachable keys - var finalizers = h$finalizeWeaks(); - h$clearWeaks(); - for(i=0;i=0;i--) { - var w = h$scannedWeaks[i]; - if(w.keym.m === mark && w.val !== null && !IS_MARKED(w.val)) { - TRACE_GC("marking weak value"); - h$follow(w.val); - marked = true; - } - } - // continue for a next round if we have marked something more - // note: this will be slow for very deep chains of weak refs, - // change this if that becomes a problem. + for (var i = 0; i < h$weakPointerList.length; ++i) { + w = h$weakPointerList[i]; + if (w === null) { + // don't handle items deleted in earlier iteration + continue; + } + if (IS_MARKED(w.keym)) { + TRACE_GC("recursively marking weak: " + h$collectProps(c.finalizer)); + + if (w.val !== null && !IS_MARKED(w.val)) { + h$follow(w.val); + } + + if (w.finalizer !== null && !IS_MARKED(w.finalizer)) { + h$follow(w.finalizer); + } + + newList.push(w); + // instead of removing the item from the h$weakpointerList + // we set it to null if we push it to newList. + h$weakPointerList[i] = null; + + marked = true; + } + } + + /* + 3. Repeat from step (2), until a complete scan of Weak Pointer List finds + no weak pointer object with a marked keym. + */ } while(marked); + + + /* + 4. Scan the Weak Pointer List again. If the weak pointer object is reachable + then tombstone it. If the weak pointer object has a finalizer then move + it to the Finalization Pending List, and mark all the heap reachable + from the finalizer. If the finalizer referes to the key (and/or value), + this step will "resurrect" it. + */ + for (var i = 0; i < h$weakPointerList.length; ++i) { + w = h$weakPointerList[i]; + if (w === null) { + // don't handle items deleted in step 2 + continue; + } + + TRACE_GC("mark retained iteration 2/2"); + + if (IS_MARKED(w)) { + if(w.val !== null) { + w.val = null; + } + if (w.finalizer !== null) { + if (!IS_MARKED(w.finalizer)) + h$follow(w.finalizer); + + toFinalize.push(w.finalizer); + } + } + } + + /* + 5. The list accumulated in step (3) becomes the new Weak Pointer List. + Mark any unreachable weak pointer objects on this list as reachable. + */ + h$weakPointerList = newList; + newList = null; + + for (var i = 0; i < h$weakPointerList.length; ++i) { + w = h$weakPointerList[i]; + if (!IS_MARKED(w)) { + MARK_OBJ(w); + } + } + + return toFinalize; } function h$markThread(t) { @@ -375,15 +428,8 @@ function h$follow(obj, sp) { for(var i=0;i 0) { @@ -46,8 +35,6 @@ function h$finalizeWeaks() { } h$wakeupThread(t); } - return toFinalize; - } // clear references for reachable weak refs with unreachable keys