1/*
2 * Copyright (C) 2012-2019 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "SlotVisitor.h"
29#include "Weak.h"
30#include "WeakInlines.h"
31
32namespace JSC {
33
34ALWAYS_INLINE void SlotVisitor::appendUnbarriered(JSValue* slot, size_t count)
35{
36 for (size_t i = count; i--;)
37 appendUnbarriered(slot[i]);
38}
39
40ALWAYS_INLINE void SlotVisitor::appendUnbarriered(JSCell* cell)
41{
42 // This needs to be written in a very specific way to ensure that it gets inlined
43 // properly. In particular, it appears that using templates here breaks ALWAYS_INLINE.
44
45 if (!cell)
46 return;
47
48 Dependency dependency;
49 if (UNLIKELY(cell->isPreciseAllocation())) {
50 if (LIKELY(cell->preciseAllocation().isMarked())) {
51 if (LIKELY(!m_heapAnalyzer))
52 return;
53 }
54 } else {
55 MarkedBlock& block = cell->markedBlock();
56 dependency = block.aboutToMark(m_markingVersion);
57 if (LIKELY(block.isMarked(cell, dependency))) {
58 if (LIKELY(!m_heapAnalyzer))
59 return;
60 }
61 }
62
63 appendSlow(cell, dependency);
64}
65
66ALWAYS_INLINE void SlotVisitor::appendUnbarriered(JSValue value)
67{
68 if (value.isCell())
69 appendUnbarriered(value.asCell());
70}
71
72ALWAYS_INLINE void SlotVisitor::appendHiddenUnbarriered(JSValue value)
73{
74 if (value.isCell())
75 appendHiddenUnbarriered(value.asCell());
76}
77
78ALWAYS_INLINE void SlotVisitor::appendHiddenUnbarriered(JSCell* cell)
79{
80 // This needs to be written in a very specific way to ensure that it gets inlined
81 // properly. In particular, it appears that using templates here breaks ALWAYS_INLINE.
82
83 if (!cell)
84 return;
85
86 Dependency dependency;
87 if (UNLIKELY(cell->isPreciseAllocation())) {
88 if (LIKELY(cell->preciseAllocation().isMarked()))
89 return;
90 } else {
91 MarkedBlock& block = cell->markedBlock();
92 dependency = block.aboutToMark(m_markingVersion);
93 if (LIKELY(block.isMarked(cell, dependency)))
94 return;
95 }
96
97 appendHiddenSlow(cell, dependency);
98}
99
100template<typename T>
101ALWAYS_INLINE void SlotVisitor::append(const Weak<T>& weak)
102{
103 appendUnbarriered(weak.get());
104}
105
106template<typename T, typename Traits>
107ALWAYS_INLINE void SlotVisitor::append(const WriteBarrierBase<T, Traits>& slot)
108{
109 appendUnbarriered(slot.get());
110}
111
112template<typename T, typename Traits>
113ALWAYS_INLINE void SlotVisitor::appendHidden(const WriteBarrierBase<T, Traits>& slot)
114{
115 appendHiddenUnbarriered(slot.get());
116}
117
118template<typename Iterator>
119ALWAYS_INLINE void SlotVisitor::append(Iterator begin, Iterator end)
120{
121 for (auto it = begin; it != end; ++it)
122 append(*it);
123}
124
125ALWAYS_INLINE void SlotVisitor::appendValues(const WriteBarrierBase<Unknown>* barriers, size_t count)
126{
127 for (size_t i = 0; i < count; ++i)
128 append(barriers[i]);
129}
130
131ALWAYS_INLINE void SlotVisitor::appendValuesHidden(const WriteBarrierBase<Unknown>* barriers, size_t count)
132{
133 for (size_t i = 0; i < count; ++i)
134 appendHidden(barriers[i]);
135}
136
137inline bool SlotVisitor::addOpaqueRoot(void* ptr)
138{
139 if (!ptr)
140 return false;
141 if (m_ignoreNewOpaqueRoots)
142 return false;
143 if (!heap()->m_opaqueRoots.add(ptr))
144 return false;
145 m_visitCount++;
146 return true;
147}
148
149inline bool SlotVisitor::containsOpaqueRoot(void* ptr) const
150{
151 return heap()->m_opaqueRoots.contains(ptr);
152}
153
154inline void SlotVisitor::reportExtraMemoryVisited(size_t size)
155{
156 if (m_isFirstVisit) {
157 m_nonCellVisitCount += size;
158 // FIXME: Change this to use SaturatedArithmetic when available.
159 // https://bugs.webkit.org/show_bug.cgi?id=170411
160 m_extraMemorySize += size;
161 }
162}
163
164#if ENABLE(RESOURCE_USAGE)
165inline void SlotVisitor::reportExternalMemoryVisited(size_t size)
166{
167 if (m_isFirstVisit)
168 heap()->reportExternalMemoryVisited(size);
169}
170#endif
171
172inline Heap* SlotVisitor::heap() const
173{
174 return &m_heap;
175}
176
177inline VM& SlotVisitor::vm()
178{
179 return m_heap.vm();
180}
181
182inline const VM& SlotVisitor::vm() const
183{
184 return m_heap.vm();
185}
186
187template<typename Func>
188IterationStatus SlotVisitor::forEachMarkStack(const Func& func)
189{
190 if (func(m_collectorStack) == IterationStatus::Done)
191 return IterationStatus::Done;
192 if (func(m_mutatorStack) == IterationStatus::Done)
193 return IterationStatus::Done;
194 return IterationStatus::Continue;
195}
196
197} // namespace JSC
198