1/*
2 * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "BlockDirectoryInlines.h"
29#include "HeapCellType.h"
30#include "JSCast.h"
31#include "MarkedBlock.h"
32#include "MarkedSpace.h"
33#include "Subspace.h"
34
35namespace JSC {
36
37template<typename Func>
38void Subspace::forEachDirectory(const Func& func)
39{
40 for (BlockDirectory* directory = m_firstDirectory; directory; directory = directory->nextDirectoryInSubspace())
41 func(*directory);
42}
43
44template<typename Func>
45void Subspace::forEachMarkedBlock(const Func& func)
46{
47 forEachDirectory(
48 [&] (BlockDirectory& directory) {
49 directory.forEachBlock(func);
50 });
51}
52
53template<typename Func>
54void Subspace::forEachNotEmptyMarkedBlock(const Func& func)
55{
56 forEachDirectory(
57 [&] (BlockDirectory& directory) {
58 directory.forEachNotEmptyBlock(func);
59 });
60}
61
62template<typename Func>
63void Subspace::forEachLargeAllocation(const Func& func)
64{
65 for (LargeAllocation* allocation = m_largeAllocations.begin(); allocation != m_largeAllocations.end(); allocation = allocation->next())
66 func(allocation);
67}
68
69template<typename Func>
70void Subspace::forEachMarkedCell(const Func& func)
71{
72 forEachNotEmptyMarkedBlock(
73 [&] (MarkedBlock::Handle* handle) {
74 handle->forEachMarkedCell(
75 [&] (size_t, HeapCell* cell, HeapCell::Kind kind) -> IterationStatus {
76 func(cell, kind);
77 return IterationStatus::Continue;
78 });
79 });
80 CellAttributes attributes = this->attributes();
81 forEachLargeAllocation(
82 [&] (LargeAllocation* allocation) {
83 if (allocation->isMarked())
84 func(allocation->cell(), attributes.cellKind);
85 });
86}
87
88template<typename Func>
89Ref<SharedTask<void(SlotVisitor&)>> Subspace::forEachMarkedCellInParallel(const Func& func)
90{
91 class Task : public SharedTask<void(SlotVisitor&)> {
92 public:
93 Task(Subspace& subspace, const Func& func)
94 : m_subspace(subspace)
95 , m_blockSource(subspace.parallelNotEmptyMarkedBlockSource())
96 , m_func(func)
97 {
98 }
99
100 void run(SlotVisitor& visitor) override
101 {
102 while (MarkedBlock::Handle* handle = m_blockSource->run()) {
103 handle->forEachMarkedCell(
104 [&] (size_t, HeapCell* cell, HeapCell::Kind kind) -> IterationStatus {
105 m_func(visitor, cell, kind);
106 return IterationStatus::Continue;
107 });
108 }
109
110 {
111 auto locker = holdLock(m_lock);
112 if (!m_needToVisitLargeAllocations)
113 return;
114 m_needToVisitLargeAllocations = false;
115 }
116
117 CellAttributes attributes = m_subspace.attributes();
118 m_subspace.forEachLargeAllocation(
119 [&] (LargeAllocation* allocation) {
120 if (allocation->isMarked())
121 m_func(visitor, allocation->cell(), attributes.cellKind);
122 });
123 }
124
125 private:
126 Subspace& m_subspace;
127 Ref<SharedTask<MarkedBlock::Handle*()>> m_blockSource;
128 Func m_func;
129 Lock m_lock;
130 bool m_needToVisitLargeAllocations { true };
131 };
132
133 return adoptRef(*new Task(*this, func));
134}
135
136template<typename Func>
137void Subspace::forEachLiveCell(const Func& func)
138{
139 forEachMarkedBlock(
140 [&] (MarkedBlock::Handle* handle) {
141 handle->forEachLiveCell(
142 [&] (size_t, HeapCell* cell, HeapCell::Kind kind) -> IterationStatus {
143 func(cell, kind);
144 return IterationStatus::Continue;
145 });
146 });
147 CellAttributes attributes = this->attributes();
148 forEachLargeAllocation(
149 [&] (LargeAllocation* allocation) {
150 if (allocation->isLive())
151 func(allocation->cell(), attributes.cellKind);
152 });
153}
154
155inline const CellAttributes& Subspace::attributes() const
156{
157 return m_heapCellType->attributes();
158}
159
160} // namespace JSC
161
162