2a818f0e1ac8bdbc99885f020ff057bb970ecd72
[WebKit-https.git] / Source / JavaScriptCore / heap / CodeBlockSet.cpp
1 /*
2  * Copyright (C) 2013, 2014 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 #include "config.h"
27 #include "CodeBlockSet.h"
28
29 #include "CodeBlock.h"
30 #include "JSCInlines.h"
31 #include "SlotVisitor.h"
32 #include <wtf/CommaPrinter.h>
33
34 namespace JSC {
35
36 static const bool verbose = false;
37
38 CodeBlockSet::CodeBlockSet(BlockAllocator& blockAllocator)
39     : m_currentlyExecuting(blockAllocator)
40 {
41 }
42
43 CodeBlockSet::~CodeBlockSet()
44 {
45     for (CodeBlock* codeBlock : m_oldCodeBlocks)
46         codeBlock->deref();
47
48     for (CodeBlock* codeBlock : m_newCodeBlocks)
49         codeBlock->deref();
50 }
51
52 void CodeBlockSet::add(PassRefPtr<CodeBlock> codeBlock)
53 {
54     CodeBlock* block = codeBlock.leakRef();
55     bool isNewEntry = m_newCodeBlocks.add(block).isNewEntry;
56     ASSERT_UNUSED(isNewEntry, isNewEntry);
57 }
58
59 void CodeBlockSet::promoteYoungCodeBlocks()
60 {
61     m_oldCodeBlocks.add(m_newCodeBlocks.begin(), m_newCodeBlocks.end());
62     m_newCodeBlocks.clear();
63 }
64
65 void CodeBlockSet::clearMarksForFullCollection()
66 {
67     for (CodeBlock* codeBlock : m_oldCodeBlocks) {
68         codeBlock->m_mayBeExecuting = false;
69         codeBlock->m_visitAggregateHasBeenCalled = false;
70     }
71
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();
75 }
76
77 void CodeBlockSet::clearMarksForEdenCollection(const Vector<const JSCell*>& rememberedSet)
78 {
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));
82         if (!executable)
83             continue;
84         executable->forEachCodeBlock([](CodeBlock* codeBlock) {
85             codeBlock->m_mayBeExecuting = false;
86             codeBlock->m_visitAggregateHasBeenCalled = false;
87         });
88     }
89 }
90
91 void CodeBlockSet::deleteUnmarkedAndUnreferenced(HeapOperation collectionType)
92 {
93     HashSet<CodeBlock*>& set = collectionType == EdenCollection ? m_newCodeBlocks : m_oldCodeBlocks;
94
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
98     // the GC.
99     Vector<CodeBlock*, 16> toRemove;
100     if (verbose)
101         dataLog("Fixpointing over unmarked, set size = ", set.size(), "...\n");
102     for (;;) {
103         for (CodeBlock* codeBlock : set) {
104             if (!codeBlock->hasOneRef())
105                 continue;
106             if (codeBlock->m_mayBeExecuting)
107                 continue;
108             codeBlock->deref();
109             toRemove.append(codeBlock);
110         }
111         if (verbose)
112             dataLog("    Removing ", toRemove.size(), " blocks.\n");
113         if (toRemove.isEmpty())
114             break;
115         for (CodeBlock* codeBlock : toRemove)
116             set.remove(codeBlock);
117         toRemove.resize(0);
118     }
119
120     // Any remaining young CodeBlocks are live and need to be promoted to the set of old CodeBlocks.
121     if (collectionType == EdenCollection)
122         promoteYoungCodeBlocks();
123 }
124
125 void CodeBlockSet::remove(CodeBlock* codeBlock)
126 {
127     codeBlock->deref();
128     if (m_oldCodeBlocks.contains(codeBlock)) {
129         m_oldCodeBlocks.remove(codeBlock);
130         return;
131     }
132     ASSERT(m_newCodeBlocks.contains(codeBlock));
133     m_newCodeBlocks.remove(codeBlock);
134 }
135
136 void CodeBlockSet::traceMarked(SlotVisitor& visitor)
137 {
138     if (verbose)
139         dataLog("Tracing ", m_currentlyExecuting.size(), " code blocks.\n");
140     for (CodeBlock* codeBlock : m_currentlyExecuting) {
141         ASSERT(codeBlock->m_mayBeExecuting);
142         codeBlock->visitAggregate(visitor);
143     }
144 }
145
146 void CodeBlockSet::rememberCurrentlyExecutingCodeBlocks(Heap* heap)
147 {
148 #if ENABLE(GGC)
149     if (verbose)
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);
154     }
155     m_currentlyExecuting.clear();
156 #else
157     UNUSED_PARAM(heap);
158 #endif // ENABLE(GGC)
159 }
160
161 void CodeBlockSet::dump(PrintStream& out) const
162 {
163     CommaPrinter comma;
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));
175     out.print("]}");
176 }
177
178 } // namespace JSC
179