| /* | 
 |  * Copyright (C) 2017-2018 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.  | 
 |  */ | 
 |  | 
 | #pragma once | 
 |  | 
 | #include "BlockDirectoryInlines.h" | 
 | #include "HeapCellType.h" | 
 | #include "JSCast.h" | 
 | #include "MarkedBlock.h" | 
 | #include "MarkedSpace.h" | 
 | #include "Subspace.h" | 
 |  | 
 | namespace JSC { | 
 |  | 
 | template<typename Func> | 
 | void Subspace::forEachDirectory(const Func& func) | 
 | { | 
 |     for (BlockDirectory* directory = m_firstDirectory; directory; directory = directory->nextDirectoryInSubspace()) | 
 |         func(*directory); | 
 | } | 
 |  | 
 | template<typename Func> | 
 | void Subspace::forEachMarkedBlock(const Func& func) | 
 | { | 
 |     forEachDirectory( | 
 |         [&] (BlockDirectory& directory) { | 
 |             directory.forEachBlock(func); | 
 |         }); | 
 | } | 
 |  | 
 | template<typename Func> | 
 | void Subspace::forEachNotEmptyMarkedBlock(const Func& func) | 
 | { | 
 |     forEachDirectory( | 
 |         [&] (BlockDirectory& directory) { | 
 |             directory.forEachNotEmptyBlock(func); | 
 |         }); | 
 | } | 
 |  | 
 | template<typename Func> | 
 | void Subspace::forEachLargeAllocation(const Func& func) | 
 | { | 
 |     for (LargeAllocation* allocation = m_largeAllocations.begin(); allocation != m_largeAllocations.end(); allocation = allocation->next()) | 
 |         func(allocation); | 
 | } | 
 |  | 
 | template<typename Func> | 
 | void Subspace::forEachMarkedCell(const Func& func) | 
 | { | 
 |     forEachNotEmptyMarkedBlock( | 
 |         [&] (MarkedBlock::Handle* handle) { | 
 |             handle->forEachMarkedCell( | 
 |                 [&] (size_t, HeapCell* cell, HeapCell::Kind kind) -> IterationStatus { | 
 |                     func(cell, kind); | 
 |                     return IterationStatus::Continue; | 
 |                 }); | 
 |         }); | 
 |     CellAttributes attributes = this->attributes(); | 
 |     forEachLargeAllocation( | 
 |         [&] (LargeAllocation* allocation) { | 
 |             if (allocation->isMarked()) | 
 |                 func(allocation->cell(), attributes.cellKind); | 
 |         }); | 
 | } | 
 |  | 
 | template<typename Func> | 
 | Ref<SharedTask<void(SlotVisitor&)>> Subspace::forEachMarkedCellInParallel(const Func& func) | 
 | { | 
 |     class Task : public SharedTask<void(SlotVisitor&)> { | 
 |     public: | 
 |         Task(Subspace& subspace, const Func& func) | 
 |             : m_subspace(subspace) | 
 |             , m_blockSource(subspace.parallelNotEmptyMarkedBlockSource()) | 
 |             , m_func(func) | 
 |         { | 
 |         } | 
 |          | 
 |         void run(SlotVisitor& visitor) override | 
 |         { | 
 |             while (MarkedBlock::Handle* handle = m_blockSource->run()) { | 
 |                 handle->forEachMarkedCell( | 
 |                     [&] (size_t, HeapCell* cell, HeapCell::Kind kind) -> IterationStatus { | 
 |                         m_func(visitor, cell, kind); | 
 |                         return IterationStatus::Continue; | 
 |                     }); | 
 |             } | 
 |              | 
 |             { | 
 |                 auto locker = holdLock(m_lock); | 
 |                 if (!m_needToVisitLargeAllocations) | 
 |                     return; | 
 |                 m_needToVisitLargeAllocations = false; | 
 |             } | 
 |              | 
 |             CellAttributes attributes = m_subspace.attributes(); | 
 |             m_subspace.forEachLargeAllocation( | 
 |                 [&] (LargeAllocation* allocation) { | 
 |                     if (allocation->isMarked()) | 
 |                         m_func(visitor, allocation->cell(), attributes.cellKind); | 
 |                 }); | 
 |         } | 
 |          | 
 |     private: | 
 |         Subspace& m_subspace; | 
 |         Ref<SharedTask<MarkedBlock::Handle*()>> m_blockSource; | 
 |         Func m_func; | 
 |         Lock m_lock; | 
 |         bool m_needToVisitLargeAllocations { true }; | 
 |     }; | 
 |      | 
 |     return adoptRef(*new Task(*this, func)); | 
 | } | 
 |  | 
 | template<typename Func> | 
 | void Subspace::forEachLiveCell(const Func& func) | 
 | { | 
 |     forEachMarkedBlock( | 
 |         [&] (MarkedBlock::Handle* handle) { | 
 |             handle->forEachLiveCell( | 
 |                 [&] (size_t, HeapCell* cell, HeapCell::Kind kind) -> IterationStatus { | 
 |                     func(cell, kind); | 
 |                     return IterationStatus::Continue; | 
 |                 }); | 
 |         }); | 
 |     CellAttributes attributes = this->attributes(); | 
 |     forEachLargeAllocation( | 
 |         [&] (LargeAllocation* allocation) { | 
 |             if (allocation->isLive()) | 
 |                 func(allocation->cell(), attributes.cellKind); | 
 |         }); | 
 | } | 
 |  | 
 | inline const CellAttributes& Subspace::attributes() const | 
 | { | 
 |     return m_heapCellType->attributes(); | 
 | } | 
 |  | 
 | } // namespace JSC | 
 |  |