Title: [209766] trunk/Source
Revision
209766
Author
[email protected]
Date
2016-12-13 11:54:15 -0800 (Tue, 13 Dec 2016)

Log Message

Make opaque root scanning truly constraint-based
https://bugs.webkit.org/show_bug.cgi?id=165760

Reviewed by Saam Barati.
Source/_javascript_Core:

        
We have bugs when visitChildren() changes its mind about what opaque root to add, since
we don't have barriers on opaque roots. This supposedly once worked for generational GC,
and I started adding more barriers to support concurrent GC. But I think that the real
bug here is that we want the JSObject->OpaqueRoot to be evaluated as a constraint that
participates in the fixpoint. A constraint is different from the normal visiting in that
the GC will not wait for a barrier to rescan the object.
        
So, it's now possible for any visitChildren() method to become a constraint by calling
slotVisitor.rescanAsConstraint(). Because opaque roots are constraints, addOpaqueRoot()
does rescanAsConstraint() for you.
        
The constraint set is simply a HashSet<JSCell*> that accumulates with every
rescanAsConstraint() call and is only cleared at the start of full GC. This trivially
resolves most classes of GC bugs that would have arisen from opaque roots being changed
in a way that the GC did not anticipate.
        
Looks like this is perf-neutral.
        
* heap/Heap.cpp:
(JSC::Heap::markToFixpoint):
(JSC::Heap::setMutatorShouldBeFenced):
(JSC::Heap::writeBarrierOpaqueRootSlow): Deleted.
(JSC::Heap::addMutatorShouldBeFencedCache): Deleted.
* heap/Heap.h:
* heap/HeapInlines.h:
(JSC::Heap::writeBarrierOpaqueRoot): Deleted.
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::visitWeakSets):
* heap/MarkedSpace.h:
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::visitChildren):
(JSC::SlotVisitor::visitSubsequently):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::addOpaqueRoot):
(JSC::SlotVisitor::rescanAsConstraint):
(JSC::SlotVisitor::mergeIfNecessary):
(JSC::SlotVisitor::mergeOpaqueRootsAndConstraints):
(JSC::SlotVisitor::mergeOpaqueRootsIfNecessary): Deleted.
* heap/SlotVisitor.h:
* heap/SlotVisitorInlines.h:
(JSC::SlotVisitor::reportExtraMemoryVisited):
(JSC::SlotVisitor::reportExternalMemoryVisited):
(JSC::SlotVisitor::didNotRace):
* heap/WeakBlock.cpp:
(JSC::WeakBlock::specializedVisit):
(JSC::WeakBlock::visit):
* heap/WeakBlock.h:
* heap/WeakSet.h:
(JSC::WeakSet::visit):

Source/WebCore:


No new tests yet. I think that writing tests for this is a big investigation:
https://bugs.webkit.org/show_bug.cgi?id=165808
        
Remove the previous advancing wavefront DOM write barrier. I don't think this will scale
very well. It's super confusing.
        
This change makes it so that visitChildren can become a GC constraint that executes as
part of the fixpoint. This changes all WebCore visitChildren methods that do opaque
roots into constraints.

* bindings/js/CommonVM.cpp:
(WebCore::commonVMSlow):
(WebCore::writeBarrierOpaqueRootSlow): Deleted.
* bindings/js/CommonVM.h:
(WebCore::writeBarrierOpaqueRoot): Deleted.
* bindings/js/JSAttrCustom.cpp:
(WebCore::JSAttr::visitAdditionalChildren):
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::visitAdditionalChildren):
* bindings/js/JSIDBCursorCustom.cpp:
(WebCore::JSIDBCursor::visitAdditionalChildren):
* bindings/js/JSMessageChannelCustom.cpp:
(WebCore::JSMessageChannel::visitAdditionalChildren):
* bindings/js/JSMessagePortCustom.cpp:
(WebCore::JSMessagePort::visitAdditionalChildren):
* bindings/js/JSNodeIteratorCustom.cpp:
(WebCore::JSNodeIterator::visitAdditionalChildren):
* bindings/js/JSTextTrackCueCustom.cpp:
(WebCore::JSTextTrackCue::visitAdditionalChildren):
* bindings/js/JSTreeWalkerCustom.cpp:
(WebCore::JSTreeWalker::visitAdditionalChildren):
* bindings/js/JSWorkerGlobalScopeCustom.cpp:
(WebCore::JSWorkerGlobalScope::visitAdditionalChildren):
* bindings/js/JSXMLHttpRequestCustom.cpp:
(WebCore::JSXMLHttpRequest::visitAdditionalChildren):
* bindings/js/JSXPathResultCustom.cpp:
(WebCore::JSXPathResult::visitAdditionalChildren):
* dom/ContainerNodeAlgorithms.cpp:
(WebCore::notifyChildNodeInserted):
(WebCore::notifyChildNodeRemoved):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (209765 => 209766)


--- trunk/Source/_javascript_Core/ChangeLog	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-12-13 19:54:15 UTC (rev 209766)
@@ -1,3 +1,60 @@
+2016-12-13  Filip Pizlo  <[email protected]>
+
+        Make opaque root scanning truly constraint-based
+        https://bugs.webkit.org/show_bug.cgi?id=165760
+
+        Reviewed by Saam Barati.
+        
+        We have bugs when visitChildren() changes its mind about what opaque root to add, since
+        we don't have barriers on opaque roots. This supposedly once worked for generational GC,
+        and I started adding more barriers to support concurrent GC. But I think that the real
+        bug here is that we want the JSObject->OpaqueRoot to be evaluated as a constraint that
+        participates in the fixpoint. A constraint is different from the normal visiting in that
+        the GC will not wait for a barrier to rescan the object.
+        
+        So, it's now possible for any visitChildren() method to become a constraint by calling
+        slotVisitor.rescanAsConstraint(). Because opaque roots are constraints, addOpaqueRoot()
+        does rescanAsConstraint() for you.
+        
+        The constraint set is simply a HashSet<JSCell*> that accumulates with every
+        rescanAsConstraint() call and is only cleared at the start of full GC. This trivially
+        resolves most classes of GC bugs that would have arisen from opaque roots being changed
+        in a way that the GC did not anticipate.
+        
+        Looks like this is perf-neutral.
+        
+        * heap/Heap.cpp:
+        (JSC::Heap::markToFixpoint):
+        (JSC::Heap::setMutatorShouldBeFenced):
+        (JSC::Heap::writeBarrierOpaqueRootSlow): Deleted.
+        (JSC::Heap::addMutatorShouldBeFencedCache): Deleted.
+        * heap/Heap.h:
+        * heap/HeapInlines.h:
+        (JSC::Heap::writeBarrierOpaqueRoot): Deleted.
+        * heap/MarkedSpace.cpp:
+        (JSC::MarkedSpace::visitWeakSets):
+        * heap/MarkedSpace.h:
+        * heap/SlotVisitor.cpp:
+        (JSC::SlotVisitor::visitChildren):
+        (JSC::SlotVisitor::visitSubsequently):
+        (JSC::SlotVisitor::drain):
+        (JSC::SlotVisitor::addOpaqueRoot):
+        (JSC::SlotVisitor::rescanAsConstraint):
+        (JSC::SlotVisitor::mergeIfNecessary):
+        (JSC::SlotVisitor::mergeOpaqueRootsAndConstraints):
+        (JSC::SlotVisitor::mergeOpaqueRootsIfNecessary): Deleted.
+        * heap/SlotVisitor.h:
+        * heap/SlotVisitorInlines.h:
+        (JSC::SlotVisitor::reportExtraMemoryVisited):
+        (JSC::SlotVisitor::reportExternalMemoryVisited):
+        (JSC::SlotVisitor::didNotRace):
+        * heap/WeakBlock.cpp:
+        (JSC::WeakBlock::specializedVisit):
+        (JSC::WeakBlock::visit):
+        * heap/WeakBlock.h:
+        * heap/WeakSet.h:
+        (JSC::WeakSet::visit):
+
 2016-12-13  Commit Queue  <[email protected]>
 
         Unreviewed, rolling out r209725.

Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/Heap.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -519,6 +519,7 @@
     
     if (m_collectionScope == CollectionScope::Full) {
         m_opaqueRoots.clear();
+        m_constraints.clear();
         m_collectorSlotVisitor->clearMarkStacks();
         m_mutatorMarkStack->clear();
     }
@@ -617,11 +618,15 @@
                 
         m_jitStubRoutines->traceMarkedStubRoutines(*m_collectorSlotVisitor);
 
-        m_collectorSlotVisitor->mergeOpaqueRootsIfNecessary();
+        m_collectorSlotVisitor->mergeIfNecessary();
         for (auto& parallelVisitor : m_parallelSlotVisitors)
-            parallelVisitor->mergeOpaqueRootsIfNecessary();
+            parallelVisitor->mergeIfNecessary();
+        
+        for (JSCell* cell : m_constraints)
+            m_collectorSlotVisitor->visitSubsequently(cell);
+        m_collectorSlotVisitor->mergeIfNecessary();
 
-        m_objectSpace.visitWeakSets(heapRootVisitor);
+        size_t weakSetCount = m_objectSpace.visitWeakSets(heapRootVisitor);
         harvestWeakReferences();
         visitCompilerWorklistWeakReferences();
         DFG::markCodeBlocks(*m_vm, *m_collectorSlotVisitor);
@@ -628,7 +633,7 @@
         bool shouldTerminate = m_collectorSlotVisitor->isEmpty() && m_mutatorMarkStack->isEmpty();
         
         if (Options::logGC()) {
-            dataLog(m_collectorSlotVisitor->collectorMarkStack().size(), "+", m_mutatorMarkStack->size() + m_collectorSlotVisitor->mutatorMarkStack().size(), ", a=", m_bytesAllocatedThisCycle / 1024, " kb, b=", m_barriersExecuted, ", mu=", scheduler.currentDecision().targetMutatorUtilization(), " ");
+            dataLog(m_collectorSlotVisitor->collectorMarkStack().size(), "+", m_mutatorMarkStack->size() + m_collectorSlotVisitor->mutatorMarkStack().size(), ", a=", m_bytesAllocatedThisCycle / 1024, " kb, b=", m_barriersExecuted, ", mu=", scheduler.currentDecision().targetMutatorUtilization(), ", ws=", weakSetCount, ", cs=", m_constraints.size(), " ");
         }
         
         // We want to do this to conservatively ensure that we rescan any code blocks that are
@@ -2220,27 +2225,10 @@
         func(*slotVisitor);
 }
 
-void Heap::writeBarrierOpaqueRootSlow(void* root)
-{
-    ASSERT(mutatorShouldBeFenced());
-    
-    auto locker = holdLock(m_opaqueRootsMutex);
-    m_opaqueRoots.add(root);
-}
-
-void Heap::addMutatorShouldBeFencedCache(bool& cache)
-{
-    ASSERT(hasHeapAccess());
-    cache = m_mutatorShouldBeFenced;
-    m_mutatorShouldBeFencedCaches.append(&cache);
-}
-
 void Heap::setMutatorShouldBeFenced(bool value)
 {
     m_mutatorShouldBeFenced = value;
     m_barrierThreshold = value ? tautologicalThreshold : blackThreshold;
-    for (bool* cache : m_mutatorShouldBeFencedCaches)
-        *cache = value;
 }
     
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/heap/Heap.h (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/Heap.h	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/Heap.h	2016-12-13 19:54:15 UTC (rev 209766)
@@ -127,8 +127,6 @@
     WriteBarrierBuffer& writeBarrierBuffer() { return m_writeBarrierBuffer; }
     void flushWriteBarrierBuffer(JSCell*);
     
-    void writeBarrierOpaqueRoot(void*);
-
     Heap(VM*, HeapType);
     ~Heap();
     void lastChanceToFinalize();
@@ -352,8 +350,6 @@
     void preventCollection();
     void allowCollection();
     
-    JS_EXPORT_PRIVATE void addMutatorShouldBeFencedCache(bool&);
-    
 #if USE(CF)
     CFRunLoopRef runLoop() const { return m_runLoop.get(); }
     JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef);
@@ -497,8 +493,6 @@
     
     void forEachCodeBlockImpl(const ScopedLambda<bool(CodeBlock*)>&);
     
-    JS_EXPORT_PRIVATE void writeBarrierOpaqueRootSlow(void*);
-    
     void setMutatorShouldBeFenced(bool value);
 
     const HeapType m_heapType;
@@ -559,7 +553,6 @@
     WriteBarrierBuffer m_writeBarrierBuffer;
     bool m_mutatorShouldBeFenced { Options::forceFencedBarrier() };
     unsigned m_barrierThreshold { Options::forceFencedBarrier() ? tautologicalThreshold : blackThreshold };
-    Vector<bool*> m_mutatorShouldBeFencedCaches;
 
     VM* m_vm;
     double m_lastFullGCLength;
@@ -603,7 +596,8 @@
     bool m_parallelMarkersShouldExit { false };
 
     Lock m_opaqueRootsMutex;
-    HashSet<void*> m_opaqueRoots;
+    HashSet<const void*> m_opaqueRoots;
+    HashSet<JSCell*> m_constraints;
 
     static const size_t s_blockFragmentLength = 32;
 

Modified: trunk/Source/_javascript_Core/heap/HeapInlines.h (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/HeapInlines.h	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/HeapInlines.h	2016-12-13 19:54:15 UTC (rev 209766)
@@ -370,10 +370,4 @@
     stopIfNecessarySlow();
 }
 
-inline void Heap::writeBarrierOpaqueRoot(void* root)
-{
-    if (mutatorShouldBeFenced())
-        writeBarrierOpaqueRootSlow(root);
-}
-
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/heap/MarkedSpace.cpp (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/MarkedSpace.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/MarkedSpace.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -359,10 +359,11 @@
     m_allocatorForEmptyAllocation = m_firstAllocator;
 }
 
-void MarkedSpace::visitWeakSets(HeapRootVisitor& heapRootVisitor)
+size_t MarkedSpace::visitWeakSets(HeapRootVisitor& heapRootVisitor)
 {
+    size_t count = 0;
     auto visit = [&] (WeakSet* weakSet) {
-        weakSet->visit(heapRootVisitor);
+        count += weakSet->visit(heapRootVisitor);
     };
     
     m_newActiveWeakSets.forEach(visit);
@@ -369,6 +370,7 @@
     
     if (m_heap->collectionScope() == CollectionScope::Full)
         m_activeWeakSets.forEach(visit);
+    return count;
 }
 
 void MarkedSpace::reapWeakSets()

Modified: trunk/Source/_javascript_Core/heap/MarkedSpace.h (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/MarkedSpace.h	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/MarkedSpace.h	2016-12-13 19:54:15 UTC (rev 209766)
@@ -129,7 +129,7 @@
     
     void prepareForAllocation();
 
-    void visitWeakSets(HeapRootVisitor&);
+    size_t visitWeakSets(HeapRootVisitor&);
     void reapWeakSets();
 
     MarkedBlockSet& blocks() { return m_blocks; }

Modified: trunk/Source/_javascript_Core/heap/SlotVisitor.cpp (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/SlotVisitor.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/SlotVisitor.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -356,8 +356,8 @@
     
     if (false) {
         dataLog("Visiting ", RawPointer(cell));
-        if (m_isVisitingMutatorStack)
-            dataLog(" (mutator)");
+        if (!m_isFirstVisit)
+            dataLog(" (subsequent)");
         dataLog("\n");
     }
     
@@ -391,11 +391,17 @@
     }
     
     if (UNLIKELY(m_heapSnapshotBuilder)) {
-        if (!m_isVisitingMutatorStack)
+        if (m_isFirstVisit)
             m_heapSnapshotBuilder->appendNode(const_cast<JSCell*>(cell));
     }
 }
 
+void SlotVisitor::visitSubsequently(JSCell* cell)
+{
+    m_isFirstVisit = false;
+    visitChildren(cell);
+}
+
 void SlotVisitor::donateKnownParallel(MarkStackArray& from, MarkStackArray& to)
 {
     // NOTE: Because we re-try often, we can afford to be conservative, and
@@ -465,7 +471,7 @@
         updateMutatorIsStopped(locker);
         if (!m_collectorStack.isEmpty()) {
             m_collectorStack.refill();
-            m_isVisitingMutatorStack = false;
+            m_isFirstVisit = true;
             for (unsigned countdown = Options::minimumNumberOfScansBetweenRebalance(); m_collectorStack.canRemoveLast() && countdown--;)
                 visitChildren(m_collectorStack.removeLast());
         } else if (!m_mutatorStack.isEmpty()) {
@@ -473,7 +479,7 @@
             // We know for sure that we are visiting objects because of the barrier, not because of
             // marking. Marking will visit an object exactly once. The barrier will visit it
             // possibly many times, and always after it was already marked.
-            m_isVisitingMutatorStack = true;
+            m_isFirstVisit = false;
             for (unsigned countdown = Options::minimumNumberOfScansBetweenRebalance(); m_mutatorStack.canRemoveLast() && countdown--;)
                 visitChildren(m_mutatorStack.removeLast());
         }
@@ -481,7 +487,7 @@
         donateKnownParallel();
     }
     
-    mergeOpaqueRootsIfNecessary();
+    mergeIfNecessary();
 }
 
 bool SlotVisitor::didReachTermination()
@@ -597,6 +603,7 @@
     if (Options::numberOfGCMarkers() == 1) {
         // Put directly into the shared HashSet.
         m_heap.m_opaqueRoots.add(root);
+        m_heap.m_constraints.add(m_currentCell);
         return;
     }
     // Put into the local set, but merge with the shared one every once in
@@ -603,8 +610,19 @@
     // a while to make sure that the local sets don't grow too large.
     mergeOpaqueRootsIfProfitable();
     m_opaqueRoots.add(root);
+    m_constraints.add(m_currentCell);
 }
 
+void SlotVisitor::rescanAsConstraint()
+{
+    if (Options::numberOfGCMarkers() == 1) {
+        m_heap.m_constraints.add(m_currentCell);
+        return;
+    }
+    
+    m_constraints.add(m_currentCell);
+}
+
 bool SlotVisitor::containsOpaqueRoot(void* root) const
 {
     ASSERT(!m_isInParallelMode);
@@ -621,13 +639,13 @@
     return MixedTriState;
 }
 
-void SlotVisitor::mergeOpaqueRootsIfNecessary()
+void SlotVisitor::mergeIfNecessary()
 {
-    if (m_opaqueRoots.isEmpty())
+    if (m_opaqueRoots.isEmpty() && m_constraints.isEmpty())
         return;
-    mergeOpaqueRoots();
+    mergeOpaqueRootsAndConstraints();
 }
-    
+
 void SlotVisitor::mergeOpaqueRootsIfProfitable()
 {
     if (static_cast<unsigned>(m_opaqueRoots.size()) < Options::opaqueRootMergeThreshold())
@@ -660,6 +678,19 @@
     m_opaqueRoots.clear();
 }
 
+void SlotVisitor::mergeOpaqueRootsAndConstraints()
+{
+    {
+        std::lock_guard<Lock> lock(m_heap.m_opaqueRootsMutex);
+        for (const void* root : m_opaqueRoots)
+            m_heap.m_opaqueRoots.add(root);
+        for (JSCell* constraint : m_constraints)
+            m_heap.m_constraints.add(constraint);
+    }
+    m_opaqueRoots.clear();
+    m_constraints.clear();
+}
+
 void SlotVisitor::addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
 {
     m_heap.m_weakReferenceHarvesters.addThreadSafe(weakReferenceHarvester);

Modified: trunk/Source/_javascript_Core/heap/SlotVisitor.h (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/SlotVisitor.h	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/SlotVisitor.h	2016-12-13 19:54:15 UTC (rev 209766)
@@ -85,7 +85,18 @@
     void appendUnbarrieredReadOnlyPointer(T*);
     void appendUnbarrieredReadOnlyValue(JSValue);
     
+    void visitSubsequently(JSCell*);
+    
+    // Does your visitChildren do logic that depends on non-JS-object state that can
+    // change during the course of a GC, or in between GCs? Then you should call this
+    // method! It will cause the GC to invoke your visitChildren method again just before
+    // terminating with the world stopped.
+    JS_EXPORT_PRIVATE void rescanAsConstraint();
+    
+    // Implies rescanAsConstraint, so you don't have to call rescanAsConstraint() if you
+    // call this unconditionally.
     JS_EXPORT_PRIVATE void addOpaqueRoot(void*);
+    
     JS_EXPORT_PRIVATE bool containsOpaqueRoot(void*) const;
     TriState containsOpaqueRootTriState(void*) const;
 
@@ -108,6 +119,8 @@
 
     SharedDrainResult drainInParallel(MonotonicTime timeout = MonotonicTime::infinity());
     SharedDrainResult drainInParallelPassively(MonotonicTime timeout = MonotonicTime::infinity());
+    
+    void mergeIfNecessary();
 
     // This informs the GC about auxiliary of some size that we are keeping alive. If you don't do
     // this then the space will be freed at end of GC.
@@ -127,8 +140,6 @@
     
     HeapVersion markingVersion() const { return m_markingVersion; }
 
-    void mergeOpaqueRootsIfNecessary();
-    
     bool mutatorIsStopped() const { return m_mutatorIsStopped; }
     
     Lock& rightToRun() { return m_rightToRun; }
@@ -167,7 +178,9 @@
     
     void noteLiveAuxiliaryCell(HeapCell*);
     
-    JS_EXPORT_PRIVATE void mergeOpaqueRoots();
+    void mergeOpaqueRoots();
+    void mergeOpaqueRootsAndConstraints();
+
     void mergeOpaqueRootsIfProfitable();
 
     void visitChildren(const JSCell*);
@@ -181,6 +194,7 @@
     MarkStackArray m_collectorStack;
     MarkStackArray m_mutatorStack;
     OpaqueRootSet m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector.
+    HashSet<JSCell*> m_constraints;
     
     size_t m_bytesVisited;
     size_t m_visitCount;
@@ -192,7 +206,7 @@
 
     HeapSnapshotBuilder* m_heapSnapshotBuilder { nullptr };
     JSCell* m_currentCell { nullptr };
-    bool m_isVisitingMutatorStack { false };
+    bool m_isFirstVisit { false };
     bool m_mutatorIsStopped { false };
     bool m_canOptimizeForStoppedMutator { false };
     Lock m_rightToRun;

Modified: trunk/Source/_javascript_Core/heap/SlotVisitorInlines.h (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/SlotVisitorInlines.h	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/SlotVisitorInlines.h	2016-12-13 19:54:15 UTC (rev 209766)
@@ -95,7 +95,7 @@
 
 inline void SlotVisitor::reportExtraMemoryVisited(size_t size)
 {
-    if (!m_isVisitingMutatorStack)
+    if (m_isFirstVisit)
         heap()->reportExtraMemoryVisited(size);
 }
 
@@ -102,7 +102,7 @@
 #if ENABLE(RESOURCE_USAGE)
 inline void SlotVisitor::reportExternalMemoryVisited(size_t size)
 {
-    if (!m_isVisitingMutatorStack)
+    if (m_isFirstVisit)
         heap()->reportExternalMemoryVisited(size);
 }
 #endif
@@ -127,7 +127,7 @@
     if (ASSERT_DISABLED)
         return;
     
-    if (!m_isVisitingMutatorStack) {
+    if (m_isFirstVisit) {
         // This is the first visit so we don't need to remove anything.
         return;
     }

Modified: trunk/Source/_javascript_Core/heap/WeakBlock.cpp (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/WeakBlock.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/WeakBlock.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -97,13 +97,14 @@
 }
 
 template<typename ContainerType>
-void WeakBlock::specializedVisit(ContainerType& container, HeapRootVisitor& heapRootVisitor)
+size_t WeakBlock::specializedVisit(ContainerType& container, HeapRootVisitor& heapRootVisitor)
 {
     SlotVisitor& visitor = heapRootVisitor.visitor();
     
     HeapVersion markingVersion = visitor.markingVersion();
 
-    for (size_t i = 0; i < weakImplCount(); ++i) {
+    size_t count = weakImplCount();
+    for (size_t i = 0; i < count; ++i) {
         WeakImpl* weakImpl = &weakImpls()[i];
         if (weakImpl->state() != WeakImpl::Live)
             continue;
@@ -121,21 +122,22 @@
 
         heapRootVisitor.visit(&const_cast<JSValue&>(jsValue));
     }
+    
+    return count;
 }
 
-void WeakBlock::visit(HeapRootVisitor& heapRootVisitor)
+size_t WeakBlock::visit(HeapRootVisitor& heapRootVisitor)
 {
     // If a block is completely empty, a visit won't have any effect.
     if (isEmpty())
-        return;
+        return 0;
 
     // If this WeakBlock doesn't belong to a CellContainer, we won't even be here.
     ASSERT(m_container);
     
     if (m_container.isLargeAllocation())
-        specializedVisit(m_container.largeAllocation(), heapRootVisitor);
-    else
-        specializedVisit(m_container.markedBlock(), heapRootVisitor);
+        return specializedVisit(m_container.largeAllocation(), heapRootVisitor);
+    return specializedVisit(m_container.markedBlock(), heapRootVisitor);
 }
 
 void WeakBlock::reap()

Modified: trunk/Source/_javascript_Core/heap/WeakBlock.h (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/WeakBlock.h	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/WeakBlock.h	2016-12-13 19:54:15 UTC (rev 209766)
@@ -63,7 +63,7 @@
     void sweep();
     SweepResult takeSweepResult();
 
-    void visit(HeapRootVisitor&);
+    size_t visit(HeapRootVisitor&);
     void reap();
 
     void lastChanceToFinalize();
@@ -73,7 +73,7 @@
     static FreeCell* asFreeCell(WeakImpl*);
     
     template<typename ContainerType>
-    void specializedVisit(ContainerType&, HeapRootVisitor&);
+    size_t specializedVisit(ContainerType&, HeapRootVisitor&);
 
     explicit WeakBlock(CellContainer);
     void finalize(WeakImpl*);

Modified: trunk/Source/_javascript_Core/heap/WeakSet.h (209765 => 209766)


--- trunk/Source/_javascript_Core/heap/WeakSet.h	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/_javascript_Core/heap/WeakSet.h	2016-12-13 19:54:15 UTC (rev 209766)
@@ -53,7 +53,7 @@
 
     bool isEmpty() const;
 
-    unsigned visit(HeapRootVisitor&);
+    size_t visit(HeapRootVisitor&);
     void reap();
     void sweep();
     void shrink();
@@ -106,13 +106,11 @@
         block->lastChanceToFinalize();
 }
 
-inline unsigned WeakSet::visit(HeapRootVisitor& visitor)
+inline size_t WeakSet::visit(HeapRootVisitor& visitor)
 {
-    unsigned count = 0;
-    for (WeakBlock* block = m_blocks.head(); block; block = block->next()) {
-        count++;
-        block->visit(visitor);
-    }
+    size_t count = 0;
+    for (WeakBlock* block = m_blocks.head(); block; block = block->next())
+        count += block->visit(visitor);
     return count;
 }
 

Modified: trunk/Source/WebCore/ChangeLog (209765 => 209766)


--- trunk/Source/WebCore/ChangeLog	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/ChangeLog	2016-12-13 19:54:15 UTC (rev 209766)
@@ -1,3 +1,51 @@
+2016-12-13  Filip Pizlo  <[email protected]>
+
+        Make opaque root scanning truly constraint-based
+        https://bugs.webkit.org/show_bug.cgi?id=165760
+
+        Reviewed by Saam Barati.
+
+        No new tests yet. I think that writing tests for this is a big investigation:
+        https://bugs.webkit.org/show_bug.cgi?id=165808
+        
+        Remove the previous advancing wavefront DOM write barrier. I don't think this will scale
+        very well. It's super confusing.
+        
+        This change makes it so that visitChildren can become a GC constraint that executes as
+        part of the fixpoint. This changes all WebCore visitChildren methods that do opaque
+        roots into constraints.
+
+        * bindings/js/CommonVM.cpp:
+        (WebCore::commonVMSlow):
+        (WebCore::writeBarrierOpaqueRootSlow): Deleted.
+        * bindings/js/CommonVM.h:
+        (WebCore::writeBarrierOpaqueRoot): Deleted.
+        * bindings/js/JSAttrCustom.cpp:
+        (WebCore::JSAttr::visitAdditionalChildren):
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::visitAdditionalChildren):
+        * bindings/js/JSIDBCursorCustom.cpp:
+        (WebCore::JSIDBCursor::visitAdditionalChildren):
+        * bindings/js/JSMessageChannelCustom.cpp:
+        (WebCore::JSMessageChannel::visitAdditionalChildren):
+        * bindings/js/JSMessagePortCustom.cpp:
+        (WebCore::JSMessagePort::visitAdditionalChildren):
+        * bindings/js/JSNodeIteratorCustom.cpp:
+        (WebCore::JSNodeIterator::visitAdditionalChildren):
+        * bindings/js/JSTextTrackCueCustom.cpp:
+        (WebCore::JSTextTrackCue::visitAdditionalChildren):
+        * bindings/js/JSTreeWalkerCustom.cpp:
+        (WebCore::JSTreeWalker::visitAdditionalChildren):
+        * bindings/js/JSWorkerGlobalScopeCustom.cpp:
+        (WebCore::JSWorkerGlobalScope::visitAdditionalChildren):
+        * bindings/js/JSXMLHttpRequestCustom.cpp:
+        (WebCore::JSXMLHttpRequest::visitAdditionalChildren):
+        * bindings/js/JSXPathResultCustom.cpp:
+        (WebCore::JSXPathResult::visitAdditionalChildren):
+        * dom/ContainerNodeAlgorithms.cpp:
+        (WebCore::notifyChildNodeInserted):
+        (WebCore::notifyChildNodeRemoved):
+
 2016-12-12  Sam Weinig  <[email protected]>
 
         [WebIDL] Remove use of Dictionary in ApplePaySession

Modified: trunk/Source/WebCore/bindings/js/CommonVM.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/CommonVM.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/CommonVM.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -38,7 +38,6 @@
 namespace WebCore {
 
 VM* g_commonVMOrNull;
-bool g_opaqueRootWriteBarrierEnabled;
 
 VM& commonVMSlow()
 {
@@ -56,7 +55,6 @@
 #endif
     
     g_commonVMOrNull->setGlobalConstRedeclarationShouldThrow(Settings::globalConstRedeclarationShouldThrow());
-    g_commonVMOrNull->heap.addMutatorShouldBeFencedCache(g_opaqueRootWriteBarrierEnabled);
     
     initNormalWorldClientData(g_commonVMOrNull);
     
@@ -63,11 +61,5 @@
     return *g_commonVMOrNull;
 }
 
-void writeBarrierOpaqueRootSlow(void* root)
-{
-    if (VM* vm = g_commonVMOrNull)
-        vm->heap.writeBarrierOpaqueRoot(root);
-}
-
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/bindings/js/CommonVM.h (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/CommonVM.h	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/CommonVM.h	2016-12-13 19:54:15 UTC (rev 209766)
@@ -32,10 +32,8 @@
 namespace WebCore {
 
 WEBCORE_EXPORT extern JSC::VM* g_commonVMOrNull;
-WEBCORE_EXPORT extern bool g_opaqueRootWriteBarrierEnabled;
 
 WEBCORE_EXPORT JSC::VM& commonVMSlow();
-WEBCORE_EXPORT void writeBarrierOpaqueRootSlow(void*);
 
 inline JSC::VM& commonVM()
 {
@@ -44,12 +42,5 @@
     return commonVMSlow();
 }
 
-template<typename Func>
-void writeBarrierOpaqueRoot(const Func& rootThunk)
-{
-    if (g_opaqueRootWriteBarrierEnabled)
-        writeBarrierOpaqueRootSlow(rootThunk());
-}
-
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/bindings/js/JSAttrCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSAttrCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSAttrCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -35,6 +35,7 @@
 
 void JSAttr::visitAdditionalChildren(JSC::SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
     if (Element* element = wrapped().ownerElement())
         visitor.addOpaqueRoot(root(element));
 }

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -51,6 +51,7 @@
 
 void JSDOMWindow::visitAdditionalChildren(SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
     if (Frame* frame = wrapped().frame())
         visitor.addOpaqueRoot(frame);
 }

Modified: trunk/Source/WebCore/bindings/js/JSIDBCursorCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSIDBCursorCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSIDBCursorCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -39,6 +39,7 @@
 
 void JSIDBCursor::visitAdditionalChildren(SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
     auto& cursor = wrapped();
     if (auto* request = cursor.request())
         visitor.addOpaqueRoot(request);

Modified: trunk/Source/WebCore/bindings/js/JSMessageChannelCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSMessageChannelCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSMessageChannelCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -35,6 +35,8 @@
 
 void JSMessageChannel::visitAdditionalChildren(JSC::SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
+    
     if (MessagePort* port = wrapped().port1())
         visitor.addOpaqueRoot(port);
 

Modified: trunk/Source/WebCore/bindings/js/JSMessagePortCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSMessagePortCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSMessagePortCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -33,6 +33,8 @@
 
 void JSMessagePort::visitAdditionalChildren(SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
+    
     // If we have a locally entangled port, we can directly mark it as reachable. Ports that are remotely entangled are marked in-use by markActiveObjectsForContext().
     if (MessagePort* port = wrapped().locallyEntangledPort())
         visitor.addOpaqueRoot(port);

Modified: trunk/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -27,6 +27,8 @@
 
 void JSNodeIterator::visitAdditionalChildren(JSC::SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
+    
     if (NodeFilter* filter = wrapped().filter())
         visitor.addOpaqueRoot(filter);
 }

Modified: trunk/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -77,6 +77,8 @@
 
 void JSTextTrackCue::visitAdditionalChildren(SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
+    
     if (TextTrack* textTrack = wrapped().track())
         visitor.addOpaqueRoot(root(textTrack));
 }

Modified: trunk/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -27,6 +27,8 @@
 
 void JSTreeWalker::visitAdditionalChildren(JSC::SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
+    
     if (NodeFilter* filter = wrapped().filter())
         visitor.addOpaqueRoot(filter);
 }

Modified: trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -36,6 +36,8 @@
 
 void JSWorkerGlobalScope::visitAdditionalChildren(SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
+    
     if (auto* location = wrapped().optionalLocation())
         visitor.addOpaqueRoot(location);
     if (auto* navigator = wrapped().optionalNavigator())

Modified: trunk/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -58,6 +58,8 @@
 
 void JSXMLHttpRequest::visitAdditionalChildren(SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
+    
     if (XMLHttpRequestUpload* upload = wrapped().optionalUpload())
         visitor.addOpaqueRoot(upload);
 

Modified: trunk/Source/WebCore/bindings/js/JSXPathResultCustom.cpp (209765 => 209766)


--- trunk/Source/WebCore/bindings/js/JSXPathResultCustom.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/bindings/js/JSXPathResultCustom.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -33,6 +33,8 @@
 
 void JSXPathResult::visitAdditionalChildren(JSC::SlotVisitor& visitor)
 {
+    visitor.rescanAsConstraint();
+    
     auto& value = wrapped().value();
     if (value.isNodeSet()) {
         // FIXME: This looks like it might race, but I'm not sure.

Modified: trunk/Source/WebCore/dom/ContainerNodeAlgorithms.cpp (209765 => 209766)


--- trunk/Source/WebCore/dom/ContainerNodeAlgorithms.cpp	2016-12-13 19:44:06 UTC (rev 209765)
+++ trunk/Source/WebCore/dom/ContainerNodeAlgorithms.cpp	2016-12-13 19:54:15 UTC (rev 209766)
@@ -26,7 +26,6 @@
 #include "config.h"
 #include "ContainerNodeAlgorithms.h"
 
-#include "CommonVM.h"
 #include "HTMLFrameOwnerElement.h"
 #include "InspectorInstrumentation.h"
 #include "NoEventDispatchAssertion.h"
@@ -102,8 +101,6 @@
         notifyNodeInsertedIntoDocument(insertionPoint, node, postInsertionNotificationTargets);
     else if (is<ContainerNode>(node))
         notifyNodeInsertedIntoTree(insertionPoint, downcast<ContainerNode>(node), postInsertionNotificationTargets);
-
-    writeBarrierOpaqueRoot([&insertionPoint] () -> void* { return insertionPoint.opaqueRoot(); });
 }
 
 void notifyNodeRemovedFromDocument(ContainerNode& insertionPoint, Node& node)
@@ -155,8 +152,6 @@
 
 void notifyChildNodeRemoved(ContainerNode& insertionPoint, Node& child)
 {
-    writeBarrierOpaqueRoot([&child] () -> void* { return &child; });
-
     if (!child.inDocument()) {
         if (is<ContainerNode>(child))
             notifyNodeRemovedFromTree(insertionPoint, downcast<ContainerNode>(child));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to