/* * Copyright (C) 2017-2022 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "JavaScriptCore/WeakInlines.h" #include "JavaScriptCore/AbstractSlotVisitorInlines.h" #include "JavaScriptCore/VM.h" #include "JavaScriptCore/MarkingConstraint.h" // namespace JSC { // class VisitCounter { // public: // VisitCounter() {} // VisitCounter(AbstractSlotVisitor& visitor) // : m_visitor(&visitor) // , m_initialVisitCount(visitor.visitCount()) // { // } // AbstractSlotVisitor& visitor() const { return *m_visitor; } // size_t visitCount() const // { // return m_visitor->visitCount() - m_initialVisitCount; // } // private: // AbstractSlotVisitor* m_visitor { nullptr }; // size_t m_initialVisitCount { 0 }; // }; // static constexpr bool verboseMarkingConstraint = false; // MarkingConstraint::MarkingConstraint(CString abbreviatedName, CString name, ConstraintVolatility volatility, ConstraintConcurrency concurrency, ConstraintParallelism parallelism) // : m_abbreviatedName(abbreviatedName) // , m_name(WTFMove(name)) // , m_volatility(volatility) // , m_concurrency(concurrency) // , m_parallelism(parallelism) // { // } // MarkingConstraint::~MarkingConstraint() // { // } // void MarkingConstraint::resetStats() // { // m_lastVisitCount = 0; // } // void MarkingConstraint::execute(SlotVisitor& visitor) // { // ASSERT(!visitor.heap()->isMarkingForGCVerifier()); // VisitCounter visitCounter(visitor); // executeImpl(visitor); // m_lastVisitCount += visitCounter.visitCount(); // if (verboseMarkingConstraint && visitCounter.visitCount()) // dataLog("(", abbreviatedName(), " visited ", visitCounter.visitCount(), " in execute)"); // } // void MarkingConstraint::executeSynchronously(AbstractSlotVisitor& visitor) // { // prepareToExecuteImpl(NoLockingNecessary, visitor); // executeImpl(visitor); // } // double MarkingConstraint::quickWorkEstimate(SlotVisitor&) // { // return 0; // } // double MarkingConstraint::workEstimate(SlotVisitor& visitor) // { // return lastVisitCount() + quickWorkEstimate(visitor); // } // void MarkingConstraint::prepareToExecute(const AbstractLocker& constraintSolvingLocker, SlotVisitor& visitor) // { // ASSERT(!visitor.heap()->isMarkingForGCVerifier()); // dataLogIf(Options::logGC(), abbreviatedName()); // VisitCounter visitCounter(visitor); // prepareToExecuteImpl(constraintSolvingLocker, visitor); // m_lastVisitCount = visitCounter.visitCount(); // if (verboseMarkingConstraint && visitCounter.visitCount()) // dataLog("(", abbreviatedName(), " visited ", visitCounter.visitCount(), " in prepareToExecute)"); // } // void MarkingConstraint::doParallelWork(SlotVisitor& visitor, SharedTask& task) // { // ASSERT(!visitor.heap()->isMarkingForGCVerifier()); // VisitCounter visitCounter(visitor); // task.run(visitor); // if (verboseMarkingConstraint && visitCounter.visitCount()) // dataLog("(", abbreviatedName(), " visited ", visitCounter.visitCount(), " in doParallelWork)"); // { // Locker locker { m_lock }; // m_lastVisitCount += visitCounter.visitCount(); // } // } // void MarkingConstraint::prepareToExecuteImpl(const AbstractLocker&, AbstractSlotVisitor&) // { // } // } // namespace JSC #include "BunGCOutputConstraint.h" #include "WebCoreJSClientData.h" #include "JavaScriptCore/BlockDirectoryInlines.h" #include "JavaScriptCore/HeapInlines.h" #include "JavaScriptCore/MarkedBlockInlines.h" #include "JavaScriptCore/SubspaceInlines.h" namespace WebCore { using namespace JSC; DOMGCOutputConstraint::DOMGCOutputConstraint(VM& vm, JSHeapData& heapData) : MarkingConstraint("Domo", "DOM Output", ConstraintVolatility::SeldomGreyed, ConstraintConcurrency::Concurrent, ConstraintParallelism::Parallel) , m_vm(vm) , m_heapData(heapData) , m_lastExecutionVersion(vm.heap.mutatorExecutionVersion()) { } DOMGCOutputConstraint::~DOMGCOutputConstraint() { } template void DOMGCOutputConstraint::executeImplImpl(Visitor& visitor) { Heap& heap = m_vm.heap; if (heap.mutatorExecutionVersion() == m_lastExecutionVersion) return; m_lastExecutionVersion = heap.mutatorExecutionVersion(); m_heapData.forEachOutputConstraintSpace( [&](Subspace& subspace) { auto func = [](Visitor& visitor, HeapCell* heapCell, HeapCell::Kind) { SetRootMarkReasonScope rootScope(visitor, RootMarkReason::DOMGCOutput); JSCell* cell = static_cast(heapCell); cell->methodTable()->visitOutputConstraints(cell, visitor); }; RefPtr> task = subspace.template forEachMarkedCellInParallel(func); visitor.addParallelConstraintTask(task); }); } void DOMGCOutputConstraint::executeImpl(AbstractSlotVisitor& visitor) { executeImplImpl(visitor); } void DOMGCOutputConstraint::executeImpl(SlotVisitor& visitor) { executeImplImpl(visitor); } } // namespace WebCore