Changeset 166678 in webkit
- Timestamp:
- Apr 2, 2014 4:50:25 PM (10 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r166662 r166678 1 2014-04-02 Mark Hahnenberg <mhahnenberg@apple.com> 2 3 CodeBlockSet should be generational 4 https://bugs.webkit.org/show_bug.cgi?id=127152 5 6 Reviewed by Geoffrey Garen. 7 8 During EdenCollections we now only visit those CodeBlocks that: 9 a) Are new since the last collection if they were somehow otherwise reachable. 10 b) Are reachable from an Executable that is part of the remembered set. 11 12 * bytecode/CodeBlock.cpp: 13 (JSC::CodeBlock::CodeBlock): Initialize uninitialized variables. 14 (JSC::CodeBlock::visitAggregate): Move the addition of the weak reference harvester after the 15 shouldImmediatelyAssumeLivenessDuringScan check since it's redundant if we assume liveness. 16 * bytecode/CodeBlock.h: 17 (JSC::CodeBlock::forEachRelatedCodeBlock): Executes a functor for each CodeBlock reachable from the current CodeBlock (including this). 18 We use this to clear marks for the CodeBlocks of remembered Executables (see: CodeBlockSet::clearMarksForEdenCollection). 19 (JSC::CodeBlockSet::mark): Also check the set of new CodeBlocks for memebership when doing conservative scanning. 20 (JSC::ScriptExecutable::forEachCodeBlock): Executes a functor for each of this Executable's CodeBlocks. 21 * heap/CodeBlockSet.cpp: 22 (JSC::CodeBlockSet::~CodeBlockSet): 23 (JSC::CodeBlockSet::add): 24 (JSC::CodeBlockSet::promoteYoungCodeBlocks): Moves all CodeBlocks currently in the set of new CodeBlocks into 25 the set of old CodeBlocks. 26 (JSC::CodeBlockSet::clearMarksForFullCollection): Clears the marks for all CodeBlocks. 27 (JSC::CodeBlockSet::clearMarksForEdenCollection): Clears the marks for CodeBlocks owned by Executables in the 28 remembered set. When an Executable is added to the remembered set it's typically because we need to do something 29 with its CodeBlock. 30 (JSC::CodeBlockSet::clearMarks): 31 (JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced): Fixpoints over either just the new CodeBlocks or all CodeBlocks 32 to determine which CodeBlocks are dead and eagerly finalizes/deletes them. 33 (JSC::CodeBlockSet::remove): 34 (JSC::CodeBlockSet::traceMarked): Iterate only the currently executing CodeBlocks instead of all CodeBlocks. 35 (JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks): Clear m_mayBeExecuting for all currently executing 36 CodeBlocks because we no longer always do this at the beginning of EdenCollections. 37 * heap/CodeBlockSet.h: 38 (JSC::CodeBlockSet::iterate): 39 * heap/Heap.cpp: 40 (JSC::Heap::markRoots): 41 (JSC::Heap::deleteAllCompiledCode): 42 (JSC::Heap::deleteUnmarkedCompiledCode): 43 * runtime/Executable.cpp: 44 (JSC::ScriptExecutable::installCode): Write barrier code on installation. We do this due to the following situation: 45 a) A CodeBlock is created and is compiled on a DFG worker thread. 46 b) No GC happens. 47 c) The CodeBlock has finished being compiled and is installed in the Executable. 48 d) The function never executes before the next GC. 49 e) The next GC needs needs to visit the new CodeBlock but the Executable won't be revisited unless 50 it's added to the remembered set. 51 1 52 2014-04-02 Mark Lam <mark.lam@apple.com> 2 53 -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r166392 r166678 1447 1447 , m_isStrictMode(other.m_isStrictMode) 1448 1448 , m_needsActivation(other.m_needsActivation) 1449 , m_mayBeExecuting(false) 1450 , m_visitAggregateHasBeenCalled(false) 1449 1451 , m_source(other.m_source) 1450 1452 , m_sourceOffset(other.m_sourceOffset) … … 1504 1506 , m_isStrictMode(unlinkedCodeBlock->isStrictMode()) 1505 1507 , m_needsActivation(unlinkedCodeBlock->hasActivationRegister() && unlinkedCodeBlock->codeType() == FunctionCode) 1508 , m_mayBeExecuting(false) 1509 , m_visitAggregateHasBeenCalled(false) 1506 1510 , m_source(sourceProvider) 1507 1511 , m_sourceOffset(sourceOffset) … … 1938 1942 visitor.addUnconditionalFinalizer(this); 1939 1943 1940 // There are two things that we use weak reference harvesters for: DFG fixpoint for1941 // jettisoning, and trying to find structures that would be live based on some1942 // inline cache. So it makes sense to register them regardless.1943 visitor.addWeakReferenceHarvester(this);1944 1944 m_allTransitionsHaveBeenMarked = false; 1945 1945 … … 1952 1952 } 1953 1953 1954 // There are two things that we use weak reference harvesters for: DFG fixpoint for 1955 // jettisoning, and trying to find structures that would be live based on some 1956 // inline cache. So it makes sense to register them regardless. 1957 visitor.addWeakReferenceHarvester(this); 1958 1954 1959 #if ENABLE(DFG_JIT) 1955 1960 // We get here if we're live in the sense that our owner executable is live, -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.h
r166178 r166678 133 133 PassRefPtr<CodeBlock> releaseAlternative() { return m_alternative.release(); } 134 134 void setAlternative(PassRefPtr<CodeBlock> alternative) { m_alternative = alternative; } 135 136 template <typename Functor> void forEachRelatedCodeBlock(Functor&& functor) 137 { 138 Functor f(std::forward<Functor>(functor)); 139 Vector<CodeBlock*, 4> codeBlocks; 140 codeBlocks.append(this); 141 142 while (!codeBlocks.isEmpty()) { 143 CodeBlock* currentCodeBlock = codeBlocks.takeLast(); 144 f(currentCodeBlock); 145 146 if (CodeBlock* alternative = currentCodeBlock->alternative()) 147 codeBlocks.append(alternative); 148 if (CodeBlock* osrEntryBlock = currentCodeBlock->specialOSREntryBlockOrNull()) 149 codeBlocks.append(osrEntryBlock); 150 } 151 } 135 152 136 153 CodeSpecializationKind specializationKind() const … … 1276 1293 if (value + 1 <= 1) 1277 1294 return; 1278 1279 HashSet<CodeBlock*>::iterator iter = m_set.find(static_cast<CodeBlock*>(candidateCodeBlock));1280 if ( iter == m_set.end())1295 1296 CodeBlock* codeBlock = static_cast<CodeBlock*>(candidateCodeBlock); 1297 if (!m_oldCodeBlocks.contains(codeBlock) && !m_newCodeBlocks.contains(codeBlock)) 1281 1298 return; 1282 1283 mark( *iter);1299 1300 mark(codeBlock); 1284 1301 } 1285 1302 … … 1293 1310 1294 1311 codeBlock->m_mayBeExecuting = true; 1312 // We might not have cleared the marks for this CodeBlock, but we need to visit it. 1313 codeBlock->m_visitAggregateHasBeenCalled = false; 1295 1314 #if ENABLE(GGC) 1296 1315 m_currentlyExecuting.append(codeBlock); … … 1298 1317 } 1299 1318 1319 template <typename Functor> inline void ScriptExecutable::forEachCodeBlock(Functor&& functor) 1320 { 1321 switch (type()) { 1322 case ProgramExecutableType: { 1323 jsCast<ProgramExecutable*>(this)->m_programCodeBlock->forEachRelatedCodeBlock(std::forward<Functor>(functor)); 1324 break; 1325 } 1326 1327 case EvalExecutableType: { 1328 jsCast<EvalExecutable*>(this)->m_evalCodeBlock->forEachRelatedCodeBlock(std::forward<Functor>(functor)); 1329 break; 1330 } 1331 1332 case FunctionExecutableType: { 1333 Functor f(std::forward<Functor>(functor)); 1334 FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); 1335 if (CodeBlock* codeBlock = executable->m_codeBlockForCall.get()) 1336 codeBlock->forEachRelatedCodeBlock(f); 1337 if (CodeBlock* codeBlock = executable->m_codeBlockForConstruct.get()) 1338 codeBlock->forEachRelatedCodeBlock(f); 1339 break; 1340 } 1341 default: 1342 RELEASE_ASSERT_NOT_REACHED(); 1343 } 1344 } 1345 1300 1346 } // namespace JSC 1301 1347 -
trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp
r165109 r166678 42 42 CodeBlockSet::~CodeBlockSet() 43 43 { 44 for (CodeBlock* codeBlock : m_set) 44 for (CodeBlock* codeBlock : m_oldCodeBlocks) 45 codeBlock->deref(); 46 47 for (CodeBlock* codeBlock : m_newCodeBlocks) 45 48 codeBlock->deref(); 46 49 } … … 49 52 { 50 53 CodeBlock* block = codeBlock.leakRef(); 51 bool isNewEntry = m_ set.add(block).isNewEntry;54 bool isNewEntry = m_newCodeBlocks.add(block).isNewEntry; 52 55 ASSERT_UNUSED(isNewEntry, isNewEntry); 53 56 } 54 57 55 void CodeBlockSet:: clearMarks()58 void CodeBlockSet::promoteYoungCodeBlocks() 56 59 { 57 for (CodeBlock* codeBlock : m_set) { 60 m_oldCodeBlocks.add(m_newCodeBlocks.begin(), m_newCodeBlocks.end()); 61 m_newCodeBlocks.clear(); 62 } 63 64 void CodeBlockSet::clearMarksForFullCollection() 65 { 66 for (CodeBlock* codeBlock : m_oldCodeBlocks) { 58 67 codeBlock->m_mayBeExecuting = false; 59 68 codeBlock->m_visitAggregateHasBeenCalled = false; 60 69 } 70 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(); 61 74 } 62 75 63 void CodeBlockSet:: deleteUnmarkedAndUnreferenced()76 void CodeBlockSet::clearMarksForEdenCollection(const Vector<const JSCell*>& rememberedSet) 64 77 { 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)); 81 if (!executable) 82 continue; 83 executable->forEachCodeBlock([](CodeBlock* codeBlock) { 84 codeBlock->m_mayBeExecuting = false; 85 codeBlock->m_visitAggregateHasBeenCalled = false; 86 }); 87 } 88 } 89 90 void CodeBlockSet::deleteUnmarkedAndUnreferenced(HeapOperation collectionType) 91 { 92 HashSet<CodeBlock*>& set = collectionType == EdenCollection ? m_newCodeBlocks : m_oldCodeBlocks; 93 65 94 // This needs to be a fixpoint because code blocks that are unmarked may 66 95 // refer to each other. For example, a DFG code block that is owned by … … 69 98 Vector<CodeBlock*, 16> toRemove; 70 99 if (verbose) 71 dataLog("Fixpointing over unmarked, set size = ", m_set.size(), "...\n");100 dataLog("Fixpointing over unmarked, set size = ", set.size(), "...\n"); 72 101 for (;;) { 73 for (CodeBlock* codeBlock : m_set) {102 for (CodeBlock* codeBlock : set) { 74 103 if (!codeBlock->hasOneRef()) 75 104 continue; … … 84 113 break; 85 114 for (CodeBlock* codeBlock : toRemove) 86 m_set.remove(codeBlock);115 set.remove(codeBlock); 87 116 toRemove.resize(0); 88 117 } 118 119 // Any remaining young CodeBlocks are live and need to be promoted to the set of old CodeBlocks. 120 if (collectionType == EdenCollection) 121 promoteYoungCodeBlocks(); 89 122 } 90 123 … … 92 125 { 93 126 codeBlock->deref(); 94 m_set.remove(codeBlock); 127 if (m_oldCodeBlocks.contains(codeBlock)) { 128 m_oldCodeBlocks.remove(codeBlock); 129 return; 130 } 131 ASSERT(m_newCodeBlocks.contains(codeBlock)); 132 m_newCodeBlocks.remove(codeBlock); 95 133 } 96 134 … … 98 136 { 99 137 if (verbose) 100 dataLog("Tracing ", m_set.size(), " code blocks.\n"); 101 for (CodeBlock* codeBlock : m_set) { 102 if (!codeBlock->m_mayBeExecuting) 103 continue; 138 dataLog("Tracing ", m_currentlyExecuting.size(), " code blocks.\n"); 139 for (CodeBlock* codeBlock : m_currentlyExecuting) { 140 ASSERT(codeBlock->m_mayBeExecuting); 104 141 codeBlock->visitAggregate(visitor); 105 142 } … … 109 146 { 110 147 #if ENABLE(GGC) 111 for (CodeBlock* codeBlock : m_currentlyExecuting) 148 for (CodeBlock* codeBlock : m_currentlyExecuting) { 112 149 heap->addToRememberedSet(codeBlock->ownerExecutable()); 150 ASSERT(codeBlock->m_mayBeExecuting); 151 } 113 152 m_currentlyExecuting.clear(); 114 153 #else -
trunk/Source/JavaScriptCore/heap/CodeBlockSet.h
r165546 r166678 28 28 29 29 #include "GCSegmentedArray.h" 30 #include "HeapOperation.h" 30 31 #include <wtf/HashSet.h> 31 32 #include <wtf/Noncopyable.h> … … 38 39 class CodeBlock; 39 40 class Heap; 41 class JSCell; 40 42 class SlotVisitor; 41 43 … … 54 56 void add(PassRefPtr<CodeBlock>); 55 57 56 // Clear all mark bits associated with DFG code blocks. 57 void clearMarks(); 58 58 // Clear mark bits for certain CodeBlocks depending on the type of collection. 59 void clearMarksForEdenCollection(const Vector<const JSCell*>&); 60 61 // Clear all mark bits for all CodeBlocks. 62 void clearMarksForFullCollection(); 63 59 64 // Mark a pointer that may be a CodeBlock that belongs to the set of DFG 60 65 // blocks. This is defined in CodeBlock.h. … … 64 69 // Delete all code blocks that are only referenced by this set (i.e. owned 65 70 // by this set), and that have not been marked. 66 void deleteUnmarkedAndUnreferenced( );71 void deleteUnmarkedAndUnreferenced(HeapOperation); 67 72 68 73 void remove(CodeBlock*); … … 81 86 template<typename Functor> void iterate(Functor& functor) 82 87 { 83 for (auto& codeBlock : m_ set) {88 for (auto& codeBlock : m_oldCodeBlocks) { 84 89 bool done = functor(codeBlock); 85 90 if (done) 86 break; 91 return; 92 } 93 94 for (auto& codeBlock : m_newCodeBlocks) { 95 bool done = functor(codeBlock); 96 if (done) 97 return; 87 98 } 88 99 } 89 100 90 101 private: 102 void clearMarksForCodeBlocksInRememberedExecutables(const Vector<const JSCell*>&); 103 void promoteYoungCodeBlocks(); 104 91 105 // This is not a set of RefPtr<CodeBlock> because we need to be able to find 92 106 // arbitrary bogus pointers. I could have written a thingy that had peek types 93 107 // and all, but that seemed like overkill. 94 HashSet<CodeBlock* > m_set; 108 HashSet<CodeBlock*> m_oldCodeBlocks; 109 HashSet<CodeBlock*> m_newCodeBlocks; 95 110 GCSegmentedArray<CodeBlock*> m_currentlyExecuting; 96 111 }; -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r166544 r166678 486 486 #endif 487 487 488 m_codeBlocks.clearMarks(); 488 #if ENABLE(GGC) 489 Vector<const JSCell*> rememberedSet(m_slotVisitor.markStack().size()); 490 m_slotVisitor.markStack().fillVector(rememberedSet); 491 #else 492 Vector<const JSCell*> rememberedSet; 493 #endif 494 495 if (m_operationInProgress == EdenCollection) 496 m_codeBlocks.clearMarksForEdenCollection(rememberedSet); 497 else 498 m_codeBlocks.clearMarksForFullCollection(); 489 499 490 500 // We gather conservative roots before clearing mark bits because conservative … … 503 513 m_slotVisitor.didStartMarking(); 504 514 HeapRootVisitor heapRootVisitor(m_slotVisitor); 505 506 #if ENABLE(GGC)507 Vector<const JSCell*> rememberedSet(m_slotVisitor.markStack().size());508 m_slotVisitor.markStack().fillVector(rememberedSet);509 #else510 Vector<const JSCell*> rememberedSet;511 #endif512 515 513 516 { … … 853 856 } 854 857 855 m_codeBlocks.clearMarks(); 856 m_codeBlocks.deleteUnmarkedAndUnreferenced(); 858 ASSERT(m_operationInProgress == FullCollection); 859 m_codeBlocks.clearMarksForFullCollection(); 860 m_codeBlocks.deleteUnmarkedAndUnreferenced(FullCollection); 857 861 } 858 862 … … 866 870 } 867 871 868 void Heap:: deleteUnmarkedCompiledCode()869 { 870 GCPHASE( DeleteCodeBlocks);872 void Heap::clearUnmarkedExecutables() 873 { 874 GCPHASE(ClearUnmarkedExecutables); 871 875 ExecutableBase* next; 872 876 for (ExecutableBase* current = m_compiledCode.head(); current; current = next) { … … 880 884 m_compiledCode.remove(current); 881 885 } 882 883 m_codeBlocks.deleteUnmarkedAndUnreferenced(); 886 } 887 888 void Heap::deleteUnmarkedCompiledCode() 889 { 890 GCPHASE(DeleteCodeBlocks); 891 clearUnmarkedExecutables(); 892 m_codeBlocks.deleteUnmarkedAndUnreferenced(m_operationInProgress); 884 893 m_jitStubRoutines.deleteUnmarkedJettisonedStubRoutines(); 885 894 } … … 1012 1021 void Heap::deleteOldCode(double gcStartTime) 1013 1022 { 1023 if (m_operationInProgress == EdenCollection) 1024 return; 1025 1014 1026 GCPHASE(DeleteOldCode); 1015 1027 if (gcStartTime - m_lastCodeDiscardTime > minute) { -
trunk/Source/JavaScriptCore/heap/Heap.h
r166375 r166678 293 293 void harvestWeakReferences(); 294 294 void finalizeUnconditionalFinalizers(); 295 void clearUnmarkedExecutables(); 295 296 void deleteUnmarkedCompiledCode(); 296 297 void updateAllocationLimits(); -
trunk/Source/JavaScriptCore/runtime/Executable.cpp
r166366 r166678 179 179 if (debugger) 180 180 debugger->registerCodeBlock(genericCodeBlock); 181 182 Heap::heap(this)->writeBarrier(this); 181 183 } 182 184 -
trunk/Source/JavaScriptCore/runtime/Executable.h
r164764 r166678 430 430 } 431 431 432 template <typename Functor> void forEachCodeBlock(Functor&&); 433 432 434 private: 433 435 JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope**, CodeSpecializationKind);
Note: See TracChangeset
for help on using the changeset viewer.