2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "CodeBlockSet.h"
29 #include "CodeBlock.h"
30 #include "JSCInlines.h"
31 #include "SlotVisitor.h"
32 #include <wtf/CommaPrinter.h>
36 static const bool verbose
= false;
38 CodeBlockSet::CodeBlockSet()
42 CodeBlockSet::~CodeBlockSet()
44 for (CodeBlock
* codeBlock
: m_oldCodeBlocks
)
47 for (CodeBlock
* codeBlock
: m_newCodeBlocks
)
51 void CodeBlockSet::add(PassRefPtr
<CodeBlock
> codeBlock
)
53 CodeBlock
* block
= codeBlock
.leakRef();
54 bool isNewEntry
= m_newCodeBlocks
.add(block
).isNewEntry
;
55 ASSERT_UNUSED(isNewEntry
, isNewEntry
);
58 void CodeBlockSet::promoteYoungCodeBlocks()
60 m_oldCodeBlocks
.add(m_newCodeBlocks
.begin(), m_newCodeBlocks
.end());
61 m_newCodeBlocks
.clear();
64 void CodeBlockSet::clearMarksForFullCollection()
66 for (CodeBlock
* codeBlock
: m_oldCodeBlocks
) {
67 codeBlock
->m_mayBeExecuting
= false;
68 codeBlock
->m_visitAggregateHasBeenCalled
.store(false, std::memory_order_relaxed
);
71 // We promote after we clear marks on the old generation CodeBlocks because
72 // none of the young generations CodeBlocks need to be cleared.
73 promoteYoungCodeBlocks();
76 void CodeBlockSet::clearMarksForEdenCollection(const Vector
<const JSCell
*>& rememberedSet
)
78 // This ensures that we will revisit CodeBlocks in remembered Executables even if they were previously marked.
79 for (const JSCell
* cell
: rememberedSet
) {
80 ScriptExecutable
* executable
= const_cast<ScriptExecutable
*>(jsDynamicCast
<const ScriptExecutable
*>(cell
));
83 executable
->forEachCodeBlock([](CodeBlock
* codeBlock
) {
84 codeBlock
->m_mayBeExecuting
= false;
85 codeBlock
->m_visitAggregateHasBeenCalled
.store(false, std::memory_order_relaxed
);
90 void CodeBlockSet::deleteUnmarkedAndUnreferenced(HeapOperation collectionType
)
92 HashSet
<CodeBlock
*>& set
= collectionType
== EdenCollection
? m_newCodeBlocks
: m_oldCodeBlocks
;
94 // This needs to be a fixpoint because code blocks that are unmarked may
95 // refer to each other. For example, a DFG code block that is owned by
96 // the GC may refer to an FTL for-entry code block that is also owned by
98 Vector
<CodeBlock
*, 16> toRemove
;
100 dataLog("Fixpointing over unmarked, set size = ", set
.size(), "...\n");
102 for (CodeBlock
* codeBlock
: set
) {
103 if (!codeBlock
->hasOneRef())
105 if (codeBlock
->m_mayBeExecuting
)
108 toRemove
.append(codeBlock
);
111 dataLog(" Removing ", toRemove
.size(), " blocks.\n");
112 if (toRemove
.isEmpty())
114 for (CodeBlock
* codeBlock
: toRemove
)
115 set
.remove(codeBlock
);
119 // Any remaining young CodeBlocks are live and need to be promoted to the set of old CodeBlocks.
120 if (collectionType
== EdenCollection
)
121 promoteYoungCodeBlocks();
124 void CodeBlockSet::remove(CodeBlock
* codeBlock
)
127 if (m_oldCodeBlocks
.contains(codeBlock
)) {
128 m_oldCodeBlocks
.remove(codeBlock
);
131 ASSERT(m_newCodeBlocks
.contains(codeBlock
));
132 m_newCodeBlocks
.remove(codeBlock
);
135 void CodeBlockSet::traceMarked(SlotVisitor
& visitor
)
138 dataLog("Tracing ", m_currentlyExecuting
.size(), " code blocks.\n");
139 for (CodeBlock
* codeBlock
: m_currentlyExecuting
) {
140 ASSERT(codeBlock
->m_mayBeExecuting
);
141 codeBlock
->visitAggregate(visitor
);
145 void CodeBlockSet::rememberCurrentlyExecutingCodeBlocks(Heap
* heap
)
149 dataLog("Remembering ", m_currentlyExecuting
.size(), " code blocks.\n");
150 for (CodeBlock
* codeBlock
: m_currentlyExecuting
) {
151 heap
->addToRememberedSet(codeBlock
->ownerExecutable());
152 ASSERT(codeBlock
->m_mayBeExecuting
);
154 m_currentlyExecuting
.clear();
157 #endif // ENABLE(GGC)
160 void CodeBlockSet::dump(PrintStream
& out
) const
163 out
.print("{old = [");
164 for (CodeBlock
* codeBlock
: m_oldCodeBlocks
)
165 out
.print(comma
, pointerDump(codeBlock
));
166 out
.print("], new = [");
167 comma
= CommaPrinter();
168 for (CodeBlock
* codeBlock
: m_newCodeBlocks
)
169 out
.print(comma
, pointerDump(codeBlock
));
170 out
.print("], currentlyExecuting = [");
171 comma
= CommaPrinter();
172 for (CodeBlock
* codeBlock
: m_currentlyExecuting
)
173 out
.print(comma
, pointerDump(codeBlock
));