Changeset 222380 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Sep 22, 2017, 1:22:44 AM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r222356 r222380 1 2017-09-21 Yusuke Suzuki <[email protected]> 2 3 [DFG][FTL] Profile array vector length for array allocation 4 https://bugs.webkit.org/show_bug.cgi?id=177051 5 6 Reviewed by Saam Barati. 7 8 Currently, NewArrayBuffer allocation is penalized by JSC: While empty array gets 25 vector size (BASE_CONTIGUOUS_VECTOR_LEN), 9 new_array_buffer case gets 3 vector size (BASE_CONTIGUOUS_VECTOR_LEN). Surely, new_array_buffer can get larger vector size 10 if the number of its constant elements is larger than 3. But these created array may be grown by `push()` operation after 11 the allocation. In this case, new_array_buffer is penalized compared to empty array allocation. 12 13 empty array allocation, 14 15 var array = []; 16 array.push(0); 17 array.push(1); 18 array.push(2); 19 array.push(3); 20 array.push(4); 21 22 v.s. new_array_buffer case, 23 24 var array = [0]; 25 array.push(1); 26 array.push(2); 27 array.push(3); 28 array.push(4); 29 30 In this case, the latter becomes slow. While we have a chance to reduce memory usage if new_array_buffer is not grown (and a bit likely), 31 we should allocate 3 to 25 vector size if it is likely grown. So we should get profile on the resulted array. 32 33 We select 25 to make it fit to one of size classes. 34 35 In this patch, we extend ArrayAllocationProfile to record vector length. And use this information when allocating array for new_array_buffer. 36 If the number of new_array_buffer constants is <= 25, array vector size would become 3 to 25 based on profiling. If the number of its constants 37 is larger than 25, we just use it for allocation as before. 38 39 Added microbenchmark and SixSpeed spread-literal.es5 shows improvement. 40 41 new-array-buffer-vector-profile 67.4706+-3.7625 ^ 28.4249+-1.9025 ^ definitely 2.3736x faster 42 spread-literal.es5 133.1443+-9.2253 ^ 95.2667+-0.5740 ^ definitely 1.3976x faster 43 44 * bytecode/ArrayAllocationProfile.cpp: 45 (JSC::ArrayAllocationProfile::updateProfile): 46 (JSC::ArrayAllocationProfile::updateIndexingType): Deleted. 47 * bytecode/ArrayAllocationProfile.h: 48 (JSC::ArrayAllocationProfile::selectIndexingType): 49 (JSC::ArrayAllocationProfile::vectorLengthHint): 50 (JSC::ArrayAllocationProfile::ArrayAllocationProfile): Deleted. 51 * bytecode/CodeBlock.cpp: 52 (JSC::CodeBlock::updateAllArrayPredictions): 53 * dfg/DFGByteCodeParser.cpp: 54 (JSC::DFG::ByteCodeParser::parseBlock): 55 * dfg/DFGGraph.cpp: 56 (JSC::DFG::Graph::dump): 57 * dfg/DFGNode.h: 58 (JSC::DFG::Node::vectorLengthHint): 59 * dfg/DFGOperations.cpp: 60 * dfg/DFGOperations.h: 61 * dfg/DFGSpeculativeJIT64.cpp: 62 (JSC::DFG::SpeculativeJIT::compile): 63 * ftl/FTLLowerDFGToB3.cpp: 64 (JSC::FTL::DFG::LowerDFGToB3::compileArraySlice): 65 (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayBuffer): 66 (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSize): 67 (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): 68 (JSC::FTL::DFG::LowerDFGToB3::allocateUninitializedContiguousJSArrayInternal): 69 (JSC::FTL::DFG::LowerDFGToB3::allocateUninitializedContiguousJSArray): 70 * runtime/ArrayConventions.h: 71 * runtime/JSArray.h: 72 (JSC::JSArray::tryCreate): 73 1 74 2017-09-21 Joseph Pecoraro <[email protected]> 2 75 -
trunk/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp
r219187 r222380 31 31 namespace JSC { 32 32 33 void ArrayAllocationProfile::update IndexingType()33 void ArrayAllocationProfile::updateProfile() 34 34 { 35 35 // This is awkwardly racy but totally sound even when executed concurrently. The … … 50 50 if (!lastArray) 51 51 return; 52 if (LIKELY(Options::useArrayAllocationProfiling())) 52 if (LIKELY(Options::useArrayAllocationProfiling())) { 53 53 m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, lastArray->indexingType()); 54 m_lastArray = 0; 54 m_largestSeenVectorLength = std::min(std::max(m_largestSeenVectorLength, lastArray->getVectorLength()), BASE_CONTIGUOUS_VECTOR_LEN_MAX); 55 } 56 m_lastArray = nullptr; 55 57 } 56 58 -
trunk/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h
r206525 r222380 33 33 class ArrayAllocationProfile { 34 34 public: 35 ArrayAllocationProfile()36 : m_currentIndexingType(ArrayWithUndecided)37 , m_lastArray(0)38 {39 }40 41 35 IndexingType selectIndexingType() 42 36 { 43 37 JSArray* lastArray = m_lastArray; 44 38 if (lastArray && UNLIKELY(lastArray->indexingType() != m_currentIndexingType)) 45 update IndexingType();39 updateProfile(); 46 40 return m_currentIndexingType; 41 } 42 43 // vector length hint becomes [0, BASE_CONTIGUOUS_VECTOR_LEN_MAX]. 44 unsigned vectorLengthHint() 45 { 46 JSArray* lastArray = m_lastArray; 47 if (lastArray && (m_largestSeenVectorLength != BASE_CONTIGUOUS_VECTOR_LEN_MAX) && UNLIKELY(lastArray->getVectorLength() > m_largestSeenVectorLength)) 48 updateProfile(); 49 return m_largestSeenVectorLength; 47 50 } 48 51 … … 53 56 } 54 57 55 JS_EXPORT_PRIVATE void update IndexingType();58 JS_EXPORT_PRIVATE void updateProfile(); 56 59 57 60 static IndexingType selectIndexingTypeFor(ArrayAllocationProfile* profile) … … 71 74 private: 72 75 73 IndexingType m_currentIndexingType; 74 JSArray* m_lastArray; 76 IndexingType m_currentIndexingType { ArrayWithUndecided }; 77 unsigned m_largestSeenVectorLength { 0 }; 78 JSArray* m_lastArray { nullptr }; 75 79 }; 76 80 -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r222009 r222380 2569 2569 // Don't count these either, for similar reasons. 2570 2570 for (unsigned i = m_arrayAllocationProfiles.size(); i--;) 2571 m_arrayAllocationProfiles[i].update IndexingType();2571 m_arrayAllocationProfiles[i].updateProfile(); 2572 2572 } 2573 2573 -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r222115 r222380 4400 4400 data.numConstants = numConstants; 4401 4401 data.indexingType = profile->selectIndexingType(); 4402 data.vectorLengthHint = std::max<unsigned>(profile->vectorLengthHint(), numConstants); 4402 4403 4403 4404 // If this statement has never executed, we'll have the wrong indexing type in the profile. … … 4409 4410 } 4410 4411 4411 m_graph.m_newArrayBufferData.append( data);4412 m_graph.m_newArrayBufferData.append(WTFMove(data)); 4412 4413 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewArrayBuffer, OpInfo(&m_graph.m_newArrayBufferData.last()))); 4413 4414 NEXT_OPCODE(op_new_array_buffer); -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r222066 r222380 322 322 out.print(anotherComma, pointerDumpInContext(freeze(m_codeBlock->constantBuffer(node->startConstant())[i]), context)); 323 323 out.print("]"); 324 out.print(comma, "vectorLengthHint = ", node->vectorLengthHint()); 324 325 } 325 326 if (node->hasLazyJSValue()) -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r222143 r222380 100 100 unsigned startConstant; 101 101 unsigned numConstants; 102 unsigned vectorLengthHint; 102 103 IndexingType indexingType; 103 104 }; … … 1115 1116 { 1116 1117 return newArrayBufferData()->numConstants; 1118 } 1119 1120 unsigned vectorLengthHint() 1121 { 1122 return newArrayBufferData()->vectorLengthHint; 1117 1123 } 1118 1124 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r222009 r222380 1312 1312 } 1313 1313 1314 char* JIT_OPERATION operationNewArrayWithSizeAndHint(ExecState* exec, Structure* arrayStructure, int32_t size, int32_t vectorLengthHint, Butterfly* butterfly) 1315 { 1316 VM& vm = exec->vm(); 1317 NativeCallFrameTracer tracer(&vm, exec); 1318 auto scope = DECLARE_THROW_SCOPE(vm); 1319 1320 if (UNLIKELY(size < 0)) 1321 return bitwise_cast<char*>(throwException(exec, scope, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")))); 1322 1323 JSArray* result; 1324 if (butterfly) 1325 result = JSArray::createWithButterfly(vm, nullptr, arrayStructure, butterfly); 1326 else { 1327 result = JSArray::tryCreate(vm, arrayStructure, size, vectorLengthHint); 1328 ASSERT(result); 1329 } 1330 return bitwise_cast<char*>(result); 1331 } 1332 1314 1333 char* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size) 1315 1334 { -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r222009 r222380 82 82 char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL; 83 83 char* JIT_OPERATION operationNewArrayWithSize(ExecState*, Structure*, int32_t, Butterfly*) WTF_INTERNAL; 84 char* JIT_OPERATION operationNewArrayWithSizeAndHint(ExecState*, Structure*, int32_t, int32_t, Butterfly*) WTF_INTERNAL; 84 85 char* JIT_OPERATION operationNewInt8ArrayWithSize(ExecState*, Structure*, int32_t, char*) WTF_INTERNAL; 85 86 char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r222143 r222380 4239 4239 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingType)) { 4240 4240 unsigned numElements = node->numConstants(); 4241 unsigned vectorLengthHint = node->vectorLengthHint(); 4242 ASSERT(vectorLengthHint >= numElements); 4241 4243 4242 4244 GPRTemporary result(this); … … 4246 4248 GPRReg storageGPR = storage.gpr(); 4247 4249 4248 emitAllocateRawObject(resultGPR, m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), storageGPR, numElements, numElements);4250 emitAllocateRawObject(resultGPR, m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), storageGPR, numElements, vectorLengthHint); 4249 4251 4250 4252 DFG_ASSERT(m_jit.graph(), node, indexingType & IsArray); -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r222143 r222380 4190 4190 weakStructure(m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous))), 4191 4191 weakStructure(m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble))))); 4192 arrayResult = allocateJSArray(resultLength, structure, indexingType, false, false);4192 arrayResult = allocateJSArray(resultLength, resultLength, structure, indexingType, false, false); 4193 4193 } 4194 4194 … … 5115 5115 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) { 5116 5116 unsigned numElements = m_node->numConstants(); 5117 5117 unsigned vectorLengthHint = m_node->vectorLengthHint(); 5118 5119 ASSERT(vectorLengthHint >= numElements); 5118 5120 ArrayValues arrayValues = 5119 allocateUninitializedContiguousJSArray( m_out.constInt32(numElements), structure);5121 allocateUninitializedContiguousJSArray(numElements, vectorLengthHint, structure); 5120 5122 5121 5123 JSValue* data = codeBlock()->constantBuffer(m_node->startConstant()); … … 5156 5158 setJSValue( 5157 5159 allocateJSArray( 5158 publicLength, weakPointer(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), m_out.constInt32(indexingType)).array);5160 publicLength, publicLength, weakPointer(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), m_out.constInt32(indexingType)).array); 5159 5161 mutatorFence(); 5160 5162 return; … … 11442 11444 }; 11443 11445 11444 ArrayValues allocateJSArray(LValue publicLength, LValue structure, LValue indexingType, bool shouldInitializeElements = true, bool shouldLargeArraySizeCreateArrayStorage = true)11446 ArrayValues allocateJSArray(LValue publicLength, LValue vectorLength, LValue structure, LValue indexingType, bool shouldInitializeElements = true, bool shouldLargeArraySizeCreateArrayStorage = true) 11445 11447 { 11446 11448 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); … … 11461 11463 11462 11464 LBasicBlock lastNext = m_out.insertNewBlocksBefore(fastCase); 11465 11466 if (vectorLength->hasInt32() && structure->hasIntPtr()) { 11467 unsigned vectorLengthConst = static_cast<unsigned>(vectorLength->asInt32()); 11468 if (vectorLengthConst <= MAX_STORAGE_VECTOR_LENGTH) { 11469 vectorLength = m_out.constInt32( 11470 Butterfly::optimalContiguousVectorLength( 11471 bitwise_cast<Structure*>(structure->asIntPtr())->outOfLineCapacity(), vectorLengthConst)); 11472 } 11473 } else { 11474 // We don't compute the optimal vector length for new Array(blah) where blah is not 11475 // statically known, since the compute effort of doing it here is probably not worth it. 11476 } 11463 11477 11464 11478 ValueFromBlock noButterfly = m_out.anchor(m_out.intPtrZero); … … 11473 11487 11474 11488 m_out.appendTo(fastCase, largeCase); 11475 11476 LValue vectorLength = nullptr;11477 if (publicLength->hasInt32() && structure->hasIntPtr()) {11478 unsigned publicLengthConst = static_cast<unsigned>(publicLength->asInt32());11479 if (publicLengthConst <= MAX_STORAGE_VECTOR_LENGTH) {11480 vectorLength = m_out.constInt32(11481 Butterfly::optimalContiguousVectorLength(11482 bitwise_cast<Structure*>(structure->asIntPtr())->outOfLineCapacity(), publicLengthConst));11483 }11484 }11485 11486 if (!vectorLength) {11487 // We don't compute the optimal vector length for new Array(blah) where blah is not11488 // statically known, since the compute effort of doing it here is probably not worth it.11489 vectorLength = publicLength;11490 }11491 11489 11492 11490 LValue payloadSize = … … 11534 11532 [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> { 11535 11533 return createLazyCallGenerator(vm, 11536 operationNewArrayWithSize , locations[0].directGPR(),11537 locations[1].directGPR(), locations[2].directGPR(), locations[3].directGPR() );11534 operationNewArrayWithSizeAndHint, locations[0].directGPR(), 11535 locations[1].directGPR(), locations[2].directGPR(), locations[3].directGPR(), locations[4].directGPR()); 11538 11536 }, 11539 structureValue, publicLength, butterflyValue);11537 structureValue, publicLength, vectorLength, butterflyValue); 11540 11538 ValueFromBlock slowResult = m_out.anchor(slowResultValue); 11541 11539 ValueFromBlock slowButterfly = m_out.anchor( … … 11549 11547 } 11550 11548 11551 ArrayValues allocateUninitializedContiguousJSArray (LValue publicLength, RegisteredStructure structure)11549 ArrayValues allocateUninitializedContiguousJSArrayInternal(LValue publicLength, LValue vectorLength, RegisteredStructure structure) 11552 11550 { 11553 11551 bool shouldInitializeElements = false; 11554 11552 bool shouldLargeArraySizeCreateArrayStorage = false; 11555 11553 return allocateJSArray( 11556 publicLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,11554 publicLength, vectorLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements, 11557 11555 shouldLargeArraySizeCreateArrayStorage); 11556 } 11557 11558 ArrayValues allocateUninitializedContiguousJSArray(LValue publicLength, RegisteredStructure structure) 11559 { 11560 return allocateUninitializedContiguousJSArrayInternal(publicLength, publicLength, structure); 11561 } 11562 11563 ArrayValues allocateUninitializedContiguousJSArray(unsigned publicLength, unsigned vectorLength, RegisteredStructure structure) 11564 { 11565 ASSERT(vectorLength >= publicLength); 11566 return allocateUninitializedContiguousJSArrayInternal(m_out.constInt32(publicLength), m_out.constInt32(vectorLength), structure); 11558 11567 } 11559 11568 -
trunk/Source/JavaScriptCore/runtime/ArrayConventions.h
r218794 r222380 78 78 #define BASE_CONTIGUOUS_VECTOR_LEN 3U 79 79 #define BASE_CONTIGUOUS_VECTOR_LEN_EMPTY 5U 80 #define BASE_CONTIGUOUS_VECTOR_LEN_MIN 3U 81 #define BASE_CONTIGUOUS_VECTOR_LEN_MAX 25U 80 82 #define BASE_ARRAY_STORAGE_VECTOR_LEN 4U 81 83 -
trunk/Source/JavaScriptCore/runtime/JSArray.h
r221822 r222380 55 55 public: 56 56 static JSArray* tryCreate(VM&, Structure*, unsigned initialLength = 0); 57 static JSArray* tryCreate(VM&, Structure*, unsigned initialLength, unsigned vectorLengthHint); 57 58 static JSArray* create(VM&, Structure*, unsigned initialLength = 0); 58 59 static JSArray* createWithButterfly(VM&, GCDeferralContext*, Structure*, Butterfly*); … … 216 217 VM&, JSCell* intendedOwner, unsigned initialLength); 217 218 218 inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength) 219 { 219 inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength, unsigned vectorLengthHint) 220 { 221 ASSERT(vectorLengthHint >= initialLength); 220 222 unsigned outOfLineStorage = structure->outOfLineCapacity(); 221 223 … … 229 231 || hasContiguous(indexingType)); 230 232 231 if (UNLIKELY( initialLength> MAX_STORAGE_VECTOR_LENGTH))233 if (UNLIKELY(vectorLengthHint > MAX_STORAGE_VECTOR_LENGTH)) 232 234 return nullptr; 233 235 234 unsigned vectorLength = Butterfly::optimalContiguousVectorLength(structure, initialLength);236 unsigned vectorLength = Butterfly::optimalContiguousVectorLength(structure, vectorLengthHint); 235 237 void* temp = vm.jsValueGigacageAuxiliarySpace.tryAllocate(nullptr, Butterfly::totalSize(0, outOfLineStorage, true, vectorLength * sizeof(EncodedJSValue))); 236 238 if (!temp) … … 257 259 } 258 260 261 inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength) 262 { 263 return tryCreate(vm, structure, initialLength, initialLength); 264 } 265 259 266 inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength) 260 267 {
Note:
See TracChangeset
for help on using the changeset viewer.