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(BlockAllocator
& blockAllocator
)
39 : m_currentlyExecuting(blockAllocator
)
43 CodeBlockSet::~CodeBlockSet()
45 for (CodeBlock
* codeBlock
: m_oldCodeBlocks
)
48 for (CodeBlock
* codeBlock
: m_newCodeBlocks
)
52 void CodeBlockSet::add(PassRefPtr
<CodeBlock
> codeBlock
)
54 CodeBlock
* block
= codeBlock
.leakRef();
55 bool isNewEntry
= m_newCodeBlocks
.add(block
).isNewEntry
;
56 ASSERT_UNUSED(isNewEntry
, isNewEntry
);
59 void CodeBlockSet::promoteYoungCodeBlocks()
61 m_oldCodeBlocks
.add(m_newCodeBlocks
.begin(), m_newCodeBlocks
.end());
62 m_newCodeBlocks
.clear();
65 void CodeBlockSet::clearMarksForFullCollection()
67 for (CodeBlock
* codeBlock
: m_oldCodeBlocks
) {
68 codeBlock
->m_mayBeExecuting
= false;
69 codeBlock
->m_visitAggregateHasBeenCalled
= false;
72 // We promote after we clear marks on the old generation CodeBlocks because
73 // none of the young generations CodeBlocks need to be cleared.
74 promoteYoungCodeBlocks();
77 void CodeBlockSet::clearMarksForEdenCollection(const Vector
<const JSCell
*>& rememberedSet
)
79 // This ensures that we will revisit CodeBlocks in remembered Executables even if they were previously marked.
80 for (const JSCell
* cell
: rememberedSet
) {
81 ScriptExecutable
* executable
= const_cast<ScriptExecutable
*>(jsDynamicCast
<const ScriptExecutable
*>(cell
));
84 executable
->forEachCodeBlock([](CodeBlock
* codeBlock
) {
85 codeBlock
->m_mayBeExecuting
= false;
86 codeBlock
->m_visitAggregateHasBeenCalled
= false;
91 void CodeBlockSet::deleteUnmarkedAndUnreferenced(HeapOperation collectionType
)
93 HashSet
<CodeBlock
*>& set
= collectionType
== EdenCollection
? m_newCodeBlocks
: m_oldCodeBlocks
;
95 // This needs to be a fixpoint because code blocks that are unmarked may
96 // refer to each other. For example, a DFG code block that is owned by
97 // the GC may refer to an FTL for-entry code block that is also owned by
99 Vector
<CodeBlock
*, 16> toRemove
;
101 dataLog("Fixpointing over unmarked, set size = ", set
.size(), "...\n");
103 for (CodeBlock
* codeBlock
: set
) {
104 if (!codeBlock
->hasOneRef())
106 if (codeBlock
->m_mayBeExecuting
)
109 toRemove
.append(codeBlock
);
112 dataLog(" Removing ", toRemove
.size(), " blocks.\n");
113 if (toRemove
.isEmpty())
115 for (CodeBlock
* codeBlock
: toRemove
)
116 set
.remove(codeBlock
);
120 // Any remaining young CodeBlocks are live and need to be promoted to the set of old CodeBlocks.
121 if (collectionType
== EdenCollection
)
122 promoteYoungCodeBlocks();
125 void CodeBlockSet::remove(CodeBlock
* codeBlock
)
128 if (m_oldCodeBlocks
.contains(codeBlock
)) {
129 m_oldCodeBlocks
.remove(codeBlock
);
132 ASSERT(m_newCodeBlocks
.contains(codeBlock
));
133 m_newCodeBlocks
.remove(codeBlock
);
136 void CodeBlockSet::traceMarked(SlotVisitor
& visitor
)
139 dataLog("Tracing ", m_currentlyExecuting
.size(), " code blocks.\n");
140 for (CodeBlock
* codeBlock
: m_currentlyExecuting
) {
141 ASSERT(codeBlock
->m_mayBeExecuting
);
142 codeBlock
->visitAggregate(visitor
);
146 void CodeBlockSet::rememberCurrentlyExecutingCodeBlocks(Heap
* heap
)
150 dataLog("Remembering ", m_currentlyExecuting
.size(), " code blocks.\n");
151 for (CodeBlock
* codeBlock
: m_currentlyExecuting
) {
152 heap
->addToRememberedSet(codeBlock
->ownerExecutable());
153 ASSERT(codeBlock
->m_mayBeExecuting
);
155 m_currentlyExecuting
.clear();
158 #endif // ENABLE(GGC)
161 void CodeBlockSet::dump(PrintStream
& out
) const
164 out
.print("{old = [");
165 for (CodeBlock
* codeBlock
: m_oldCodeBlocks
)
166 out
.print(comma
, pointerDump(codeBlock
));
167 out
.print("], new = [");
168 comma
= CommaPrinter();
169 for (CodeBlock
* codeBlock
: m_newCodeBlocks
)
170 out
.print(comma
, pointerDump(codeBlock
));
171 out
.print("], currentlyExecuting = [");
172 comma
= CommaPrinter();
173 for (CodeBlock
* codeBlock
: m_currentlyExecuting
)
174 out
.print(comma
, pointerDump(codeBlock
));