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 34namespace JSC { 35 36static const bool verbose = false; 37 38CodeBlockSet::CodeBlockSet(BlockAllocator& blockAllocator) 39 : m_currentlyExecuting(blockAllocator) 40{ 41} 42 43CodeBlockSet::~CodeBlockSet() 44{ 45 for (CodeBlock* codeBlock : m_oldCodeBlocks) 46 codeBlock->deref(); 47 48 for (CodeBlock* codeBlock : m_newCodeBlocks) 49 codeBlock->deref(); 50} 51 52void 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 59void CodeBlockSet::promoteYoungCodeBlocks() 60{ 61 m_oldCodeBlocks.add(m_newCodeBlocks.begin(), m_newCodeBlocks.end()); 62 m_newCodeBlocks.clear(); 63} 64 65void 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 77void 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 91void 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 125void 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 136void 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 146void 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 161void 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 180