Changeset 206314 in webkit
- Timestamp:
- Sep 23, 2016 11:09:44 AM (8 years ago)
- Location:
- trunk/Source
- Files:
-
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r206297 r206314 1 2016-09-22 Filip Pizlo <fpizlo@apple.com> 2 3 Need a store-load fence between setting cell state and visiting the object in SlotVisitor 4 https://bugs.webkit.org/show_bug.cgi?id=162354 5 6 Reviewed by Mark Lam. 7 8 This was meant to be a small change, but then it became bigger as I found small 9 opportunities for improving this code. This adds a store-load fence and is performance- 10 neutral. That's probably partly due to other optimizations that I did to visitChildren(). 11 12 Initially, I found that adding an mfence as a store-load fence was terribly expensive. So, 13 I thought that I needed to buffer up a bunch of objects, set their states, do one mfence, 14 and then visit all of them. This seemed like a win, so I went with it. Unfortunately, this 15 made no sense for two reasons: 16 17 - I shouldn't use mfence. I should use ortop (lock orl $0, (%rsp)) instead. Ortop is 18 basically free, and it's what WTF now uses for storeLoadFence(). 19 20 - My data saying that buffering up objects was not a slow-down was wrong. That was actually 21 almost as expensive as the mfence. 22 23 But in order to implement that, I made some other improvements that I think we should stick 24 with: 25 26 - SlotVisitor::visitChildren() now uses a switch on type. This replaces what used to be 27 some nasty ClassInfo look-ups. 28 29 - We no longer save the object's old CellState. We would do that so that we would know what 30 state the object had been before we blackened it. But I believe that the more logical 31 solution is to have two kinds of black - one for black-for-the-first-time objects and one 32 for repeat offenders. This is a lot easier to reason about, since you can now just figure 33 this out by looking at the cell directly. 34 35 The latter change meant rewiring a bunch of barriers. It didn't make them any more 36 expensive. 37 38 * ftl/FTLLowerDFGToB3.cpp: 39 (JSC::FTL::DFG::LowerDFGToB3::emitStoreBarrier): 40 * heap/CellState.h: 41 (JSC::blacken): 42 * heap/Heap.cpp: 43 (JSC::Heap::addToRememberedSet): 44 * heap/Heap.h: 45 * heap/HeapInlines.h: 46 (JSC::Heap::writeBarrier): 47 (JSC::Heap::reportExtraMemoryVisited): 48 (JSC::Heap::reportExternalMemoryVisited): 49 * heap/MarkStack.cpp: 50 * heap/MarkStack.h: 51 * heap/SlotVisitor.cpp: 52 (JSC::SlotVisitor::visitChildren): 53 * heap/SlotVisitor.h: 54 * heap/SlotVisitorInlines.h: 55 (JSC::SlotVisitor::reportExtraMemoryVisited): 56 (JSC::SlotVisitor::reportExternalMemoryVisited): 57 * jit/AssemblyHelpers.h: 58 (JSC::AssemblyHelpers::jumpIfIsRememberedOrInEden): 59 * llint/LLIntData.cpp: 60 (JSC::LLInt::Data::performAssertions): 61 * llint/LowLevelInterpreter.asm: 62 * llint/LowLevelInterpreter32_64.asm: 63 * llint/LowLevelInterpreter64.asm: 64 * runtime/JSObject.h: 65 (JSC::isJSFinalObject): 66 1 67 2016-09-23 Csaba Osztrogonác <ossy@webkit.org> 2 68 -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r206289 r206314 11436 11436 11437 11437 m_out.branch( 11438 m_out.notZero32(loadCellState(base)), usually(continuation), rarely(slowPath)); 11438 m_out.above(loadCellState(base), m_out.constInt32(blackThreshold)), 11439 usually(continuation), rarely(slowPath)); 11439 11440 11440 11441 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation); -
trunk/Source/JavaScriptCore/heap/CellState.h
r190569 r206314 1 1 /* 2 * Copyright (C) 2015 Apple Inc. All rights reserved.2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 #define CellState_h 28 28 29 #include <wtf/Assertions.h> 30 29 31 namespace JSC { 30 32 31 33 enum class CellState : uint8_t { 32 // The object is black as far as this GC is concerned. When not in GC, this just means that it's an 33 // old gen object. Note that we deliberately arrange OldBlack to be zero, so that the store barrier on 34 // a target object "from" is just: 35 // 36 // if (!from->cellState()) 37 // slowPath(from); 38 // 39 // There is a bunch of code in the LLInt and JITs that rely on this being the case. You'd have to 40 // change a lot of code if you ever wanted the store barrier to be anything but a non-zero check on 41 // cellState. 42 OldBlack = 0, 34 // The object is black for the first time during this GC. 35 NewBlack = 0, 36 37 // The object is black for the Nth time during this full GC cycle (N > 1). An object may get to 38 // this state if it transitions from black back to grey during a concurrent GC, or because it 39 // wound up in the remembered set because of a generational barrier. 40 OldBlack = 1, 43 41 44 42 // The object is in eden. During GC, this means that the object has not been marked yet. 45 NewWhite = 1, 43 NewWhite = 2, 44 45 // The object is grey - i.e. it will be scanned - and this is the first time in this GC that we are 46 // going to scan it. If this is an eden GC, this also means that the object is in eden. 47 NewGrey = 3, 46 48 47 49 // The object is grey - i.e. it will be scanned - but it either belongs to old gen (if this is eden 48 50 // GC) or it is grey a second time in this current GC (because a concurrent store barrier requested 49 51 // re-greying). 50 OldGrey = 2, 52 OldGrey = 4 53 }; 51 54 52 // The object is grey - i.e. it will be scanned - and this is the first time in this GC that we are 53 // going to scan it. If this is an eden GC, this also means that the object is in eden. 54 NewGrey = 3 55 }; 55 static const unsigned blackThreshold = 1; // x <= blackThreshold means x is black. 56 57 inline bool isBlack(CellState cellState) 58 { 59 return static_cast<unsigned>(cellState) <= blackThreshold; 60 } 61 62 inline CellState blacken(CellState cellState) 63 { 64 if (cellState == CellState::NewGrey) 65 return CellState::NewBlack; 66 ASSERT(cellState == CellState::NewBlack || cellState == CellState::OldBlack || cellState == CellState::OldGrey); 67 return CellState::OldBlack; 68 } 56 69 57 70 } // namespace JSC -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r206154 r206314 29 29 #include "GCActivityCallback.h" 30 30 #include "GCIncomingRefCountedSetInlines.h" 31 #include "GCSegmentedArrayInlines.h" 31 32 #include "GCTypeMap.h" 32 33 #include "HasOwnPropertyCache.h" … … 915 916 ASSERT(cell); 916 917 ASSERT(!Options::useConcurrentJIT() || !isCompilationThread()); 917 ASSERT( cell->cellState() == CellState::OldBlack);918 ASSERT(isBlack(cell->cellState())); 918 919 // Indicate that this object is grey and that it's one of the following: 919 920 // - A re-greyed object during a concurrent collection. -
trunk/Source/JavaScriptCore/heap/Heap.h
r206154 r206314 176 176 // memory growth. 177 177 void reportExtraMemoryAllocated(size_t); 178 void reportExtraMemoryVisited( CellState cellStateBeforeVisiting, size_t);178 void reportExtraMemoryVisited(JSCell*, size_t); 179 179 180 180 #if ENABLE(RESOURCE_USAGE) 181 181 // Use this API to report the subset of extra memory that lives outside this process. 182 void reportExternalMemoryVisited( CellState cellStateBeforeVisiting, size_t);182 void reportExternalMemoryVisited(JSCell*, size_t); 183 183 size_t externalMemorySize() { return m_externalMemorySize; } 184 184 #endif -
trunk/Source/JavaScriptCore/heap/HeapInlines.h
r206172 r206314 126 126 WriteBarrierCounters::countWriteBarrier(); 127 127 #endif 128 if (!from || from->cellState() != CellState::OldBlack)128 if (!from || !isBlack(from->cellState())) 129 129 return; 130 130 if (!to || to->cellState() != CellState::NewWhite) … … 136 136 { 137 137 ASSERT_GC_OBJECT_LOOKS_VALID(const_cast<JSCell*>(from)); 138 if (!from || from->cellState() != CellState::OldBlack)138 if (!from || !isBlack(from->cellState())) 139 139 return; 140 140 addToRememberedSet(from); … … 147 147 } 148 148 149 inline void Heap::reportExtraMemoryVisited( CellState dataBeforeVisiting, size_t size)149 inline void Heap::reportExtraMemoryVisited(JSCell* cell, size_t size) 150 150 { 151 151 // We don't want to double-count the extra memory that was reported in previous collections. 152 if (operationInProgress() == EdenCollection && dataBeforeVisiting == CellState::OldGrey)152 if (operationInProgress() == EdenCollection && cell->cellState() == CellState::OldBlack) 153 153 return; 154 154 … … 163 163 164 164 #if ENABLE(RESOURCE_USAGE) 165 inline void Heap::reportExternalMemoryVisited( CellState dataBeforeVisiting, size_t size)165 inline void Heap::reportExternalMemoryVisited(JSCell* cell, size_t size) 166 166 { 167 167 // We don't want to double-count the external memory that was reported in previous collections. 168 if (operationInProgress() == EdenCollection && dataBeforeVisiting == CellState::OldGrey)168 if (operationInProgress() == EdenCollection && cell->cellState() == CellState::OldBlack) 169 169 return; 170 170 -
trunk/Source/JavaScriptCore/heap/MarkStack.cpp
r190267 r206314 27 27 #include "MarkStack.h" 28 28 29 #include "GCSegmentedArrayInlines.h" 29 30 #include "JSCInlines.h" 30 31 -
trunk/Source/JavaScriptCore/heap/MarkStack.h
r179348 r206314 27 27 #define MarkStack_h 28 28 29 #include "GCSegmentedArray Inlines.h"29 #include "GCSegmentedArray.h" 30 30 31 31 namespace JSC { -
trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp
r206172 r206314 26 26 #include "config.h" 27 27 #include "SlotVisitor.h" 28 #include "SlotVisitorInlines.h"29 28 30 29 #include "ConservativeRoots.h" 30 #include "GCSegmentedArrayInlines.h" 31 31 #include "HeapCellInlines.h" 32 32 #include "HeapProfiler.h" … … 37 37 #include "JSString.h" 38 38 #include "JSCInlines.h" 39 #include "SlotVisitorInlines.h" 39 40 #include "SuperSampler.h" 40 41 #include "VM.h" … … 297 298 SetCurrentCellScope currentCellScope(*this, cell); 298 299 299 m_currentObjectCellStateBeforeVisiting = cell->cellState(); 300 cell->setCellState(CellState::OldBlack); 301 302 if (isJSString(cell)) { 300 cell->setCellState(blacken(cell->cellState())); 301 302 // FIXME: Make this work on ARM also. 303 // https://bugs.webkit.org/show_bug.cgi?id=162461 304 if (isX86()) 305 WTF::storeLoadFence(); 306 307 switch (cell->type()) { 308 case StringType: 303 309 JSString::visitChildren(const_cast<JSCell*>(cell), *this); 304 return; 305 } 306 307 if (isJSFinalObject(cell)) { 310 break; 311 312 case FinalObjectType: 308 313 JSFinalObject::visitChildren(const_cast<JSCell*>(cell), *this); 309 return; 310 } 311 312 if (isJSArray(cell)) { 314 break; 315 316 case ArrayType: 313 317 JSArray::visitChildren(const_cast<JSCell*>(cell), *this); 314 return; 315 } 316 317 cell->methodTable()->visitChildren(const_cast<JSCell*>(cell), *this); 318 break; 319 320 default: 321 // FIXME: This could be so much better. 322 // https://bugs.webkit.org/show_bug.cgi?id=162462 323 cell->methodTable()->visitChildren(const_cast<JSCell*>(cell), *this); 324 break; 325 } 318 326 } 319 327 -
trunk/Source/JavaScriptCore/heap/SlotVisitor.h
r206172 r206314 169 169 JSCell* m_currentCell { nullptr }; 170 170 171 CellState m_currentObjectCellStateBeforeVisiting { CellState::NewWhite };172 173 171 public: 174 172 #if !ASSERT_DISABLED -
trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h
r202394 r206314 107 107 inline void SlotVisitor::reportExtraMemoryVisited(size_t size) 108 108 { 109 heap()->reportExtraMemoryVisited(m_current ObjectCellStateBeforeVisiting, size);109 heap()->reportExtraMemoryVisited(m_currentCell, size); 110 110 } 111 111 … … 113 113 inline void SlotVisitor::reportExternalMemoryVisited(size_t size) 114 114 { 115 heap()->reportExternalMemoryVisited(m_current ObjectCellStateBeforeVisiting, size);115 heap()->reportExternalMemoryVisited(m_currentCell, size); 116 116 } 117 117 #endif -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h
r205675 r206314 1309 1309 Jump jumpIfIsRememberedOrInEden(GPRReg cell) 1310 1310 { 1311 return branch Test8(MacroAssembler::NonZero, MacroAssembler::Address(cell, JSCell::cellStateOffset()));1311 return branch8(Above, Address(cell, JSCell::cellStateOffset()), TrustedImm32(blackThreshold)); 1312 1312 } 1313 1313 … … 1315 1315 { 1316 1316 uint8_t* address = reinterpret_cast<uint8_t*>(cell) + JSCell::cellStateOffset(); 1317 return branch Test8(MacroAssembler::NonZero, MacroAssembler::AbsoluteAddress(address));1317 return branch8(Above, AbsoluteAddress(address), TrustedImm32(blackThreshold)); 1318 1318 } 1319 1319 -
trunk/Source/JavaScriptCore/llint/LLIntData.cpp
r206098 r206314 215 215 216 216 STATIC_ASSERT(MarkedBlock::blockSize == 16 * 1024); 217 STATIC_ASSERT(blackThreshold == 1); 217 218 218 219 ASSERT(bitwise_cast<uintptr_t>(ShadowChicken::Packet::tailMarker()) == static_cast<uintptr_t>(0x7a11)); -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r206289 r206314 409 409 const MarkedBlockSize = 16 * 1024 410 410 const MarkedBlockMask = ~(MarkedBlockSize - 1) 411 412 const BlackThreshold = 1 411 413 412 414 # Allocation constants … … 889 891 end 890 892 891 macro skipIfIsRememberedOrInEden(cell, scratch1, scratch2, continuation) 892 loadb JSCell::m_cellState[cell], scratch1 893 continuation(scratch1) 893 macro skipIfIsRememberedOrInEden(cell, slowPath) 894 bba JSCell::m_cellState[cell], BlackThreshold, .done 895 slowPath() 896 .done: 894 897 end 895 898 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
r206289 r206314 501 501 loadisFromInstruction(cellOperand, t1) 502 502 loadConstantOrVariablePayload(t1, CellTag, t2, .writeBarrierDone) 503 skipIfIsRememberedOrInEden( t2, t1, t3,504 macro(cellState)505 btbnz cellState, .writeBarrierDone503 skipIfIsRememberedOrInEden( 504 t2, 505 macro() 506 506 push cfr, PC 507 507 # We make two extra slots because cCall2 will poke. … … 512 512 addp 8, sp 513 513 pop PC, cfr 514 end 515 ) 514 end) 516 515 .writeBarrierDone: 517 516 end … … 533 532 loadHelper(t3) 534 533 535 skipIfIsRememberedOrInEden( t3, t1, t2,536 macro(gcData)537 btbnz gcData, .writeBarrierDone534 skipIfIsRememberedOrInEden( 535 t3, 536 macro() 538 537 push cfr, PC 539 538 # We make two extra slots because cCall2 will poke. … … 544 543 addp 8, sp 545 544 pop PC, cfr 546 end 547 ) 545 end) 548 546 .writeBarrierDone: 549 547 end -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r206289 r206314 405 405 loadisFromInstruction(cellOperand, t1) 406 406 loadConstantOrVariableCell(t1, t2, .writeBarrierDone) 407 skipIfIsRememberedOrInEden( t2, t1, t3,408 macro(cellState)409 btbnz cellState, .writeBarrierDone407 skipIfIsRememberedOrInEden( 408 t2, 409 macro() 410 410 push PB, PC 411 411 move t2, a1 # t2 can be a0 (not on 64 bits, but better safe than sorry) … … 413 413 cCall2Void(_llint_write_barrier_slow) 414 414 pop PC, PB 415 end 416 ) 415 end) 417 416 .writeBarrierDone: 418 417 end … … 433 432 434 433 loadHelper(t3) 435 skipIfIsRememberedOrInEden( t3, t1, t2,436 macro(gcData)437 btbnz gcData, .writeBarrierDone434 skipIfIsRememberedOrInEden( 435 t3, 436 macro() 438 437 push PB, PC 439 438 move cfr, a0 -
trunk/Source/JavaScriptCore/runtime/JSObject.h
r206136 r206314 1094 1094 inline bool isJSFinalObject(JSCell* cell) 1095 1095 { 1096 return cell-> classInfo() == JSFinalObject::info();1096 return cell->type() == FinalObjectType; 1097 1097 } 1098 1098 -
trunk/Source/WTF/ChangeLog
r206295 r206314 12 12 * wtf/PlatformUserPreferredLanguagesUnix.cpp: 13 13 (WTF::platformLanguage): 14 15 2016-09-22 Filip Pizlo <fpizlo@apple.com> 16 17 Need a store-load fence between setting cell state and visiting the object in SlotVisitor 18 https://bugs.webkit.org/show_bug.cgi?id=162354 19 20 Reviewed by Mark Lam. 21 22 Fix this on x86-32. 23 24 * wtf/Atomics.h: 25 (WTF::x86_ortop): 14 26 15 27 2016-09-22 Filip Pizlo <fpizlo@apple.com> -
trunk/Source/WTF/wtf/Atomics.h
r206274 r206314 176 176 // investigate if that is actually better. 177 177 MemoryBarrier(); 178 #el se178 #elif CPU(X86_64) 179 179 // This has acqrel semantics and is much cheaper than mfence. For exampe, in the JSC GC, using 180 180 // mfence as a store-load fence was a 9% slow-down on Octane/splay while using this was neutral. 181 181 asm volatile("lock; orl $0, (%%rsp)" ::: "memory"); 182 #else 183 asm volatile("lock; orl $0, (%%esp)" ::: "memory"); 182 184 #endif 183 185 }
Note: See TracChangeset
for help on using the changeset viewer.