Changeset 190569 in webkit for trunk/Source/JavaScriptCore/ChangeLog
- Timestamp:
- Oct 5, 2015, 12:35:32 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r190563 r190569 1 2015-10-03 Filip Pizlo <[email protected]> 2 3 Allow an object's marking state to track The Three Colors 4 https://bugs.webkit.org/show_bug.cgi?id=149654 5 6 Reviewed by Geoffrey Garen. 7 8 I want to make GC marking concurrent (see https://bugs.webkit.org/show_bug.cgi?id=149432). 9 Concurrent GC require barriers to be executed during certain heap operations. We already have a 10 generational GC. Generational GCs also need barriers, and we already have those. The generational 11 GC barrier that we use is the "sticky mark bit" barrier. Ordinarily, mark bits get reset after a 12 collection. In our collector, there is a secondary mark bit that "sticks" - i.e. it does not get 13 reset. If the sticky mark bit is set in between two collections, then we know that the object is in 14 old space. This is sufficient to determine when to put things into remembered sets. Additionally, 15 the sticky mark bit is actually a tri-state that can also tell us if the object has been placed on 16 a remembered set. 17 18 This is awfully similar to what you want in a concurrent GC. Concurrent GCs typically want writes 19 to the heap that change the object graph to do different things depending on an object's marking 20 state, which is usually referred to as its color. White means that the object has never been seen 21 by the collector. All white objects are presumed dead at the flip. Grey objects are those that are 22 known to the collector but have not been scanned. Black objects are those that have been scanned, 23 and will not be scanned again. White is exactly just "not being marked", and both grey and black 24 mean "marked" - with "black" meaning "marked but not on any worklist". That's quite a bit like the 25 current "Marked" and "MarkedAndRemembered" states that we have for generational GC. 26 "MarkedAndRemembered" is a lot like "grey", and "Marked" is a lot like "black". 27 28 I want to make a concurrent GC that unifies the generational and concurrent barriers into a single 29 fast path check. Even better if the two barriers are entirely identical. You can do this using 30 Pirinen's technique #2 [1], originally due to Guy Steele [2]: when doing o.f=v where o is black and 31 v is white, turn o grey again. This is like remembering an object, in the sense that our gen GC 32 "rememberes" o when o is old and v is new. It remembers objects by putting them on the mark stack, 33 setting the generational state to MarkedAndRemembered, and doing nothing to the primary mark bit. 34 35 This makes our concurrent GC approach pretty obvious. We want to use one barrier for concurrent and 36 generational, and we want to basically keep our current barriers unchanged. The only things missing 37 are just some small changes to allow the concurrent GC to know precisely when an object is black, 38 and to know during object visiting if we are visiting the object for the first time during a 39 collection or a subsequent time due to barrier re-greying (concurrent GC) or barrier remembering 40 (generational GC). So, this patch does the following: 41 42 - Changes the terminology used for the gcData header byte in JSCell. This changes the name of this 43 to cellState, and introduces a new enumeration called CellState. This new enumeration behaves a 44 lot like the old GCData did. It has the following members, with the following correspondence to 45 the old GCData: 46 47 OldBlack: this is like Marked, with the exception that we ensure that an object becomes OldBlack 48 as soon as the object starts to be scanned. Previously, an object might be 49 MarkedAndRemembered during scanning and we'd turn all MarkedAndRemembered objects into Marked 50 objects during a post-processing step at the end of GC. This patch gets rid of that 51 post-processing. The act of visiting an object unconditionally makes it OldBlack. Note that 52 our definition of "black" is not that the object is done being scanned, but that it is either 53 being scanned right now or it has already been scanned. This is like a combination of 54 Siebert's anthracite and black states [3]. 55 56 NewWhite: this is exactly NotMarked. It's the state that objects get when they are allocated. 57 It's impossible for an object to return to this state. 58 59 OldGrey: the object is on the mark stack and will be scanned at some point in the future. This 60 also means that this isn't the first time in this cycle that the object has been grey. In an 61 eden collection, an old object that has been remembered is thought of as being OldGrey, even 62 if this is the first time during this eden collection that it is grey. That's because an eden 63 collection must behave "as if" the grey->black transition for old objects magically happened 64 at the start of GC. Remembered objects are like old objects that underwent a concurrent 65 barrier re-greying just after the magical old object grey->black transition at the start of 66 GC. This state is almost exactly like MarkedAndRemembered, except that an object now 67 transitions from OldGrey to OldBlack at the beginning of visiting, rather than how previously 68 we transitioned from MarkedAndRemembered to Marked at the bitter end of GC. 69 70 NewGray: the object is on the mark stack and will be scanned at some point in the future. This 71 state has no clear relative in the old state system. It means that the object became grey due 72 to ordinary marking. Previously, ordinary marking would make the object Marked. 73 74 - Removal of the post-processing phase that "clears" the remembered set by moving all remembered 75 objects to the Marked state. This now happens magically during visiting, as described above. 76 77 - SlotVisitor now remembers the state that the object did have just before visiting. While visiting 78 that object, it's possible to query what the state was. This is used for copy space decisions and 79 for extra memory usage accounting. We don't want to put the backing store on the copy worklist, 80 and we don't want to count extra memory usage, if the object was OldGrey at the start of 81 visiting. Previously, we would be able to just ask if the object was MarkedAndRemembered since 82 that state wouldn't get cleared until after all marking finished. This change also simplifies 83 some APIs, because there is no need to pass the JSCell* pointer, since these SlotVisitor methods 84 no longer ask the cell for its state - instead they use the saved pre-visiting state. 85 86 - Removal of a bunch of helpers and abstractions. Previously we had various methods for asking if 87 an object was "marked" and if an object was "remembered". We had helpers for adjusting these 88 states, and those helpers would assert that they were being used the right way. This is not very 89 useful for concurrent GC, since now the set of possible state transitions is much larger. Also, 90 the previous use of the word "marked" was pretty bad - for example in Heap, "marked" refers to 91 the primary mark bit (that gets cleared at the flip), while in JSCell, "marked" refers to the 92 sticky mark bit (that does not get cleared, ever). This change gets rid of a lot of those helpers 93 and inlines their logic. This actually makes the code easier and more fun to read, since you can 94 now look at the marking and barrier code and see how that code uses the four CellStates. For 95 example, it's fun to see that the barrier gets fired for o.f=v exactly when o is OldBlack and v 96 is NewWhite. 97 98 This change shouldn't have any effect on performance or GC behavior. It does put our code in a 99 weird state where we now have states and comments referencing a concurrent GC that doesn't exist 100 yet. 101 102 Finally, some thoughts about the concurrent GC barrier and its implications for performance. This 103 barrier exhibits very poor guarantees about collector progress, but maximizes throughput by just 104 reusing the existing barrier code we already emit and optimize. I believe that even our epoch-based 105 barrier insertion DFG phase is correct for the concurrent interpretation of our existing barrier. 106 But, the barrier can regress the progress that the collector has made for two reasons: 107 108 Incremental update: you don't want to use this barrier with a black stack, since that would mean 109 that heap loads of white objects will have to explicitly re-grey the stack. The way you implement 110 this kind of collector is that collector termination will rescan the stack. Termination is reached 111 only if the at-termination re-scan greys no objects. This means that the collector is a fixpoint. 112 Luckily, our collector is already a fixpoint because of opaque roots and structure transitions. 113 114 Marking ain't monotonic: normally, once an object is black, it stays that way. In this collector, 115 black objects may become grey again. I don't have personal experience with such concurrent GCs, but 116 I suspect that this will basically be fine. Concurrent collections finish pretty quickly, and the 117 mutator usually touches only a subset of the heap. Only that subset of the heap that the mutator is 118 touching could be re-greyed. Probably, the GC will have to be hybrid incremental and concurrent, 119 and towards the end of GC when we do the termination stack re-scan, we can ensure that the 120 collector does some minimal amount of marking. If the minimal amount of marking done by the 121 collector is large enough, we can ensure that we reach termination before the mutator can regress 122 progress. The barrier cannot un-terminate the collector; if the collector reaches termination and 123 the barrier re-greys an object then it's actually doing a generational remembering rather than a 124 concurrent re-greying. 125 126 That's sort of the cute thing about the barrier - it is exactly a re-greying barrier during GC and 127 it is exactly a remembering barrier in between GCs. 128 129 [1] http://www.cs.utexas.edu/ftp/garbage/submit/readable/ppirinen11.ps 130 [2] http://dl.acm.org/citation.cfm?id=361005 131 [3] http://www.aicas.com/papers/ISMM132-siebert.pdf 132 133 * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: 134 * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: 135 * JavaScriptCore.xcodeproj/project.pbxproj: 136 * bytecode/CodeBlock.cpp: 137 (JSC::CodeBlock::visitChildren): 138 * ftl/FTLAbstractHeapRepository.cpp: 139 (JSC::FTL::AbstractHeapRepository::AbstractHeapRepository): 140 * ftl/FTLAbstractHeapRepository.h: 141 * ftl/FTLLowerDFGToLLVM.cpp: 142 (JSC::FTL::DFG::LowerDFGToLLVM::masqueradesAsUndefinedWatchpointIsStillValid): 143 (JSC::FTL::DFG::LowerDFGToLLVM::loadCellState): 144 (JSC::FTL::DFG::LowerDFGToLLVM::emitStoreBarrier): 145 (JSC::FTL::DFG::LowerDFGToLLVM::loadMarkByte): Deleted. 146 * heap/CellState.h: Added. 147 * heap/CodeBlockSet.cpp: 148 (JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks): 149 * heap/CopiedBlock.h: 150 * heap/CopiedBlockInlines.h: 151 (JSC::CopiedBlock::reportLiveBytes): 152 (JSC::CopiedBlock::shouldReportLiveBytes): Deleted. 153 * heap/GCLogging.cpp: 154 (JSC::LoggingFunctor::reviveCells): 155 * heap/Heap.cpp: 156 (JSC::Heap::markRoots): 157 (JSC::Heap::visitWeakHandles): 158 (JSC::Heap::updateObjectCounts): 159 (JSC::Heap::addToRememberedSet): 160 (JSC::Heap::clearRememberedSet): Deleted. 161 * heap/Heap.h: 162 * heap/HeapInlines.h: 163 (JSC::Heap::isLive): 164 (JSC::Heap::isMarked): 165 (JSC::Heap::writeBarrier): 166 (JSC::Heap::reportExtraMemoryAllocated): 167 (JSC::Heap::reportExtraMemoryVisited): 168 (JSC::Heap::isRemembered): Deleted. 169 * heap/SlotVisitor.cpp: 170 (JSC::SlotVisitor::append): 171 (JSC::SlotVisitor::visitChildren): 172 (JSC::SlotVisitor::donateKnownParallel): 173 (JSC::SlotVisitor::drain): 174 (JSC::visitChildren): Deleted. 175 * heap/SlotVisitor.h: 176 (JSC::SlotVisitor::childCount): 177 (JSC::SlotVisitor::incrementChildCount): 178 (JSC::SlotVisitor::dataBeforeVisitingCurrentObject): 179 * heap/SlotVisitorInlines.h: 180 (JSC::SlotVisitor::internalAppend): 181 (JSC::SlotVisitor::copyLater): 182 (JSC::SlotVisitor::reportExtraMemoryVisited): 183 (JSC::SlotVisitor::heap): 184 * jit/AssemblyHelpers.h: 185 (JSC::AssemblyHelpers::jumpIfIsRememberedOrInEden): 186 * llint/LowLevelInterpreter.asm: 187 * llint/LowLevelInterpreter32_64.asm: 188 * llint/LowLevelInterpreter64.asm: 189 * runtime/JSCell.h: 190 (JSC::JSCell::cellState): 191 (JSC::JSCell::setCellState): 192 (JSC::JSCell::structureIDOffset): 193 (JSC::JSCell::indexingTypeOffset): 194 (JSC::JSCell::cellStateOffset): 195 (JSC::JSCell::setMarked): Deleted. 196 (JSC::JSCell::setRemembered): Deleted. 197 (JSC::JSCell::isMarked): Deleted. 198 (JSC::JSCell::isRemembered): Deleted. 199 (JSC::JSCell::gcDataOffset): Deleted. 200 * runtime/JSCellInlines.h: 201 (JSC::JSCell::JSCell): 202 * runtime/JSGenericTypedArrayViewInlines.h: 203 (JSC::JSGenericTypedArrayView<Adaptor>::visitChildren): 204 * runtime/JSObject.cpp: 205 (JSC::JSObject::copyBackingStore): 206 * runtime/JSString.cpp: 207 (JSC::JSString::visitChildren): 208 * runtime/StructureIDBlob.h: 209 (JSC::StructureIDBlob::StructureIDBlob): 210 (JSC::StructureIDBlob::operator=): 211 * runtime/WeakMapData.cpp: 212 (JSC::WeakMapData::visitChildren): 213 (JSC::WeakMapData::set): 214 * tests/stress/basic-eden-gc-test.js: Added. 215 Hilariously, an earlier version of this patch that didn't have the NewGrey/OldGrey distinction 216 would only crash super-big tests that GCd twice but it didn't crash any small focused test. All 217 it took to show the need for the NewGrey/OldGrey distinction was this super simple test. 218 1 219 2015-10-05 Geoffrey Garen <[email protected]> 2 220
Note:
See TracChangeset
for help on using the changeset viewer.