Changeset 222384 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Sep 22, 2017, 5:19:54 AM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r222382 r222384 1 2017-09-22 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-22 Commit Queue <[email protected]> 2 75 -
trunk/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp
r222382 r222384 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
r222382 r222384 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
r222382 r222384 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
r222382 r222384 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
r222382 r222384 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
r222382 r222384 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
r222382 r222384 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
r222382 r222384 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
r222382 r222384 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
r222382 r222384 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 std::optional<unsigned> staticVectorLength; 11467 std::optional<unsigned> staticVectorLengthFromPublicLength; 11468 if (structure->hasIntPtr()) { 11469 if (publicLength->hasInt32()) { 11470 unsigned publicLengthConst = static_cast<unsigned>(publicLength->asInt32()); 11471 if (publicLengthConst <= MAX_STORAGE_VECTOR_LENGTH) { 11472 publicLengthConst = Butterfly::optimalContiguousVectorLength( 11473 bitwise_cast<Structure*>(structure->asIntPtr())->outOfLineCapacity(), publicLengthConst); 11474 staticVectorLengthFromPublicLength = publicLengthConst; 11475 } 11476 11477 } 11478 if (vectorLength->hasInt32()) { 11479 unsigned vectorLengthConst = static_cast<unsigned>(vectorLength->asInt32()); 11480 if (vectorLengthConst <= MAX_STORAGE_VECTOR_LENGTH) { 11481 vectorLengthConst = Butterfly::optimalContiguousVectorLength( 11482 bitwise_cast<Structure*>(structure->asIntPtr())->outOfLineCapacity(), vectorLengthConst); 11483 vectorLength = m_out.constInt32(vectorLengthConst); 11484 staticVectorLength = vectorLengthConst; 11485 } 11486 } 11487 } else { 11488 // We don't compute the optimal vector length for new Array(blah) where blah is not 11489 // statically known, since the compute effort of doing it here is probably not worth it. 11490 } 11463 11491 11464 11492 ValueFromBlock noButterfly = m_out.anchor(m_out.intPtrZero); … … 11473 11501 11474 11502 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 11503 11492 11504 LValue payloadSize = … … 11531 11543 11532 11544 VM& vm = this->vm(); 11533 LValue slowResultValue = lazySlowPath( 11534 [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> { 11535 return createLazyCallGenerator(vm, 11536 operationNewArrayWithSize, locations[0].directGPR(), 11537 locations[1].directGPR(), locations[2].directGPR(), locations[3].directGPR()); 11538 }, 11539 structureValue, publicLength, butterflyValue); 11545 LValue slowResultValue = nullptr; 11546 if (vectorLength == publicLength 11547 || (staticVectorLengthFromPublicLength && staticVectorLength && staticVectorLength.value() == staticVectorLengthFromPublicLength.value())) { 11548 slowResultValue = lazySlowPath( 11549 [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> { 11550 return createLazyCallGenerator(vm, 11551 operationNewArrayWithSize, locations[0].directGPR(), 11552 locations[1].directGPR(), locations[2].directGPR(), locations[3].directGPR()); 11553 }, 11554 structureValue, publicLength, butterflyValue); 11555 } else { 11556 slowResultValue = lazySlowPath( 11557 [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> { 11558 return createLazyCallGenerator(vm, 11559 operationNewArrayWithSizeAndHint, locations[0].directGPR(), 11560 locations[1].directGPR(), locations[2].directGPR(), locations[3].directGPR(), locations[4].directGPR()); 11561 }, 11562 structureValue, publicLength, vectorLength, butterflyValue); 11563 } 11564 11540 11565 ValueFromBlock slowResult = m_out.anchor(slowResultValue); 11541 11566 ValueFromBlock slowButterfly = m_out.anchor( … … 11549 11574 } 11550 11575 11551 ArrayValues allocateUninitializedContiguousJSArray (LValue publicLength, RegisteredStructure structure)11576 ArrayValues allocateUninitializedContiguousJSArrayInternal(LValue publicLength, LValue vectorLength, RegisteredStructure structure) 11552 11577 { 11553 11578 bool shouldInitializeElements = false; 11554 11579 bool shouldLargeArraySizeCreateArrayStorage = false; 11555 11580 return allocateJSArray( 11556 publicLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,11581 publicLength, vectorLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements, 11557 11582 shouldLargeArraySizeCreateArrayStorage); 11583 } 11584 11585 ArrayValues allocateUninitializedContiguousJSArray(LValue publicLength, RegisteredStructure structure) 11586 { 11587 return allocateUninitializedContiguousJSArrayInternal(publicLength, publicLength, structure); 11588 } 11589 11590 ArrayValues allocateUninitializedContiguousJSArray(unsigned publicLength, unsigned vectorLength, RegisteredStructure structure) 11591 { 11592 ASSERT(vectorLength >= publicLength); 11593 return allocateUninitializedContiguousJSArrayInternal(m_out.constInt32(publicLength), m_out.constInt32(vectorLength), structure); 11558 11594 } 11559 11595 -
trunk/Source/JavaScriptCore/runtime/ArrayConventions.h
r222382 r222384 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
r222382 r222384 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.