1 | /* |
2 | * Copyright (C) 2012-2017 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 | #include "config.h" |
27 | #include "WeakBlock.h" |
28 | |
29 | #include "CellContainerInlines.h" |
30 | #include "Heap.h" |
31 | #include "HeapSnapshotBuilder.h" |
32 | #include "JSCInlines.h" |
33 | #include "JSObject.h" |
34 | #include "WeakHandleOwner.h" |
35 | |
36 | namespace JSC { |
37 | |
38 | WeakBlock* WeakBlock::create(Heap& heap, CellContainer container) |
39 | { |
40 | heap.didAllocateBlock(WeakBlock::blockSize); |
41 | return new (NotNull, fastMalloc(blockSize)) WeakBlock(container); |
42 | } |
43 | |
44 | void WeakBlock::destroy(Heap& heap, WeakBlock* block) |
45 | { |
46 | block->~WeakBlock(); |
47 | fastFree(block); |
48 | heap.didFreeBlock(WeakBlock::blockSize); |
49 | } |
50 | |
51 | WeakBlock::WeakBlock(CellContainer container) |
52 | : DoublyLinkedListNode<WeakBlock>() |
53 | , m_container(container) |
54 | { |
55 | for (size_t i = 0; i < weakImplCount(); ++i) { |
56 | WeakImpl* weakImpl = &weakImpls()[i]; |
57 | new (NotNull, weakImpl) WeakImpl; |
58 | addToFreeList(&m_sweepResult.freeList, weakImpl); |
59 | } |
60 | |
61 | ASSERT(isEmpty()); |
62 | } |
63 | |
64 | void WeakBlock::lastChanceToFinalize() |
65 | { |
66 | for (size_t i = 0; i < weakImplCount(); ++i) { |
67 | WeakImpl* weakImpl = &weakImpls()[i]; |
68 | if (weakImpl->state() >= WeakImpl::Finalized) |
69 | continue; |
70 | weakImpl->setState(WeakImpl::Dead); |
71 | finalize(weakImpl); |
72 | } |
73 | } |
74 | |
75 | void WeakBlock::sweep() |
76 | { |
77 | // If a block is completely empty, a sweep won't have any effect. |
78 | if (isEmpty()) |
79 | return; |
80 | |
81 | SweepResult sweepResult; |
82 | for (size_t i = 0; i < weakImplCount(); ++i) { |
83 | WeakImpl* weakImpl = &weakImpls()[i]; |
84 | if (weakImpl->state() == WeakImpl::Dead) |
85 | finalize(weakImpl); |
86 | if (weakImpl->state() == WeakImpl::Deallocated) |
87 | addToFreeList(&sweepResult.freeList, weakImpl); |
88 | else { |
89 | sweepResult.blockIsFree = false; |
90 | if (weakImpl->state() == WeakImpl::Live) |
91 | sweepResult.blockIsLogicallyEmpty = false; |
92 | } |
93 | } |
94 | |
95 | m_sweepResult = sweepResult; |
96 | ASSERT(!m_sweepResult.isNull()); |
97 | } |
98 | |
99 | template<typename ContainerType> |
100 | void WeakBlock::specializedVisit(ContainerType& container, SlotVisitor& visitor) |
101 | { |
102 | HeapVersion markingVersion = visitor.markingVersion(); |
103 | |
104 | size_t count = weakImplCount(); |
105 | for (size_t i = 0; i < count; ++i) { |
106 | WeakImpl* weakImpl = &weakImpls()[i]; |
107 | if (weakImpl->state() != WeakImpl::Live) |
108 | continue; |
109 | |
110 | WeakHandleOwner* weakHandleOwner = weakImpl->weakHandleOwner(); |
111 | if (!weakHandleOwner) |
112 | continue; |
113 | |
114 | JSValue jsValue = weakImpl->jsValue(); |
115 | if (container.isMarked(markingVersion, jsValue.asCell())) |
116 | continue; |
117 | |
118 | const char* reason = "" ; |
119 | const char** reasonPtr = nullptr; |
120 | if (UNLIKELY(visitor.isBuildingHeapSnapshot())) |
121 | reasonPtr = &reason; |
122 | |
123 | if (!weakHandleOwner->isReachableFromOpaqueRoots(Handle<Unknown>::wrapSlot(&const_cast<JSValue&>(jsValue)), weakImpl->context(), visitor, reasonPtr)) |
124 | continue; |
125 | |
126 | visitor.appendUnbarriered(jsValue); |
127 | |
128 | if (UNLIKELY(visitor.isBuildingHeapSnapshot())) { |
129 | if (jsValue.isCell()) |
130 | visitor.heapSnapshotBuilder()->setOpaqueRootReachabilityReasonForCell(jsValue.asCell(), *reasonPtr); |
131 | } |
132 | } |
133 | } |
134 | |
135 | void WeakBlock::visit(SlotVisitor& visitor) |
136 | { |
137 | // If a block is completely empty, a visit won't have any effect. |
138 | if (isEmpty()) |
139 | return; |
140 | |
141 | // If this WeakBlock doesn't belong to a CellContainer, we won't even be here. |
142 | ASSERT(m_container); |
143 | |
144 | if (m_container.isLargeAllocation()) |
145 | specializedVisit(m_container.largeAllocation(), visitor); |
146 | else |
147 | specializedVisit(m_container.markedBlock(), visitor); |
148 | } |
149 | |
150 | void WeakBlock::reap() |
151 | { |
152 | // If a block is completely empty, a reaping won't have any effect. |
153 | if (isEmpty()) |
154 | return; |
155 | |
156 | // If this WeakBlock doesn't belong to a CellContainer, we won't even be here. |
157 | ASSERT(m_container); |
158 | |
159 | HeapVersion markingVersion = m_container.heap()->objectSpace().markingVersion(); |
160 | |
161 | for (size_t i = 0; i < weakImplCount(); ++i) { |
162 | WeakImpl* weakImpl = &weakImpls()[i]; |
163 | if (weakImpl->state() > WeakImpl::Dead) |
164 | continue; |
165 | |
166 | if (m_container.isMarked(markingVersion, weakImpl->jsValue().asCell())) { |
167 | ASSERT(weakImpl->state() == WeakImpl::Live); |
168 | continue; |
169 | } |
170 | |
171 | weakImpl->setState(WeakImpl::Dead); |
172 | } |
173 | } |
174 | |
175 | } // namespace JSC |
176 | |