Ignore:
Timestamp:
Sep 22, 2017, 5:19:54 AM (8 years ago)
Author:
Yusuke Suzuki
Message:

[DFG][FTL] Profile array vector length for array allocation
https://bugs.webkit.org/show_bug.cgi?id=177051

Reviewed by Saam Barati.

JSTests:

  • microbenchmarks/new-array-buffer-vector-profile.js: Added.

(target):

Source/JavaScriptCore:

Currently, NewArrayBuffer allocation is penalized by JSC: While empty array gets 25 vector size (BASE_CONTIGUOUS_VECTOR_LEN),
new_array_buffer case gets 3 vector size (BASE_CONTIGUOUS_VECTOR_LEN). Surely, new_array_buffer can get larger vector size
if the number of its constant elements is larger than 3. But these created array may be grown by push() operation after
the allocation. In this case, new_array_buffer is penalized compared to empty array allocation.

empty array allocation,

var array = [];
array.push(0);
array.push(1);
array.push(2);
array.push(3);
array.push(4);

v.s. new_array_buffer case,

var array = [0];
array.push(1);
array.push(2);
array.push(3);
array.push(4);

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),
we should allocate 3 to 25 vector size if it is likely grown. So we should get profile on the resulted array.

We select 25 to make it fit to one of size classes.

In this patch, we extend ArrayAllocationProfile to record vector length. And use this information when allocating array for new_array_buffer.
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
is larger than 25, we just use it for allocation as before.

Added microbenchmark and SixSpeed spread-literal.es5 shows improvement.

new-array-buffer-vector-profile 67.4706+-3.7625 28.4249+-1.9025 definitely 2.3736x faster
spread-literal.es5 133.1443+-9.2253 95.2667+-0.5740 definitely 1.3976x faster

  • bytecode/ArrayAllocationProfile.cpp:

(JSC::ArrayAllocationProfile::updateProfile):
(JSC::ArrayAllocationProfile::updateIndexingType): Deleted.

  • bytecode/ArrayAllocationProfile.h:

(JSC::ArrayAllocationProfile::selectIndexingType):
(JSC::ArrayAllocationProfile::vectorLengthHint):
(JSC::ArrayAllocationProfile::ArrayAllocationProfile): Deleted.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::updateAllArrayPredictions):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):

  • dfg/DFGNode.h:

(JSC::DFG::Node::vectorLengthHint):

  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
(JSC::FTL::DFG::LowerDFGToB3::compileNewArrayBuffer):
(JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSize):
(JSC::FTL::DFG::LowerDFGToB3::allocateJSArray):
(JSC::FTL::DFG::LowerDFGToB3::allocateUninitializedContiguousJSArrayInternal):
(JSC::FTL::DFG::LowerDFGToB3::allocateUninitializedContiguousJSArray):

  • runtime/ArrayConventions.h:
  • runtime/JSArray.h:

(JSC::JSArray::tryCreate):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r222382 r222384  
    41904190                    weakStructure(m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous))),
    41914191                    weakStructure(m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble)))));
    4192             arrayResult = allocateJSArray(resultLength, structure, indexingType, false, false);
     4192            arrayResult = allocateJSArray(resultLength, resultLength, structure, indexingType, false, false);
    41934193        }
    41944194
     
    51155115        if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
    51165116            unsigned numElements = m_node->numConstants();
    5117            
     5117            unsigned vectorLengthHint = m_node->vectorLengthHint();
     5118           
     5119            ASSERT(vectorLengthHint >= numElements);
    51185120            ArrayValues arrayValues =
    5119                 allocateUninitializedContiguousJSArray(m_out.constInt32(numElements), structure);
     5121                allocateUninitializedContiguousJSArray(numElements, vectorLengthHint, structure);
    51205122           
    51215123            JSValue* data = codeBlock()->constantBuffer(m_node->startConstant());
     
    51565158            setJSValue(
    51575159                allocateJSArray(
    5158                     publicLength, weakPointer(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), m_out.constInt32(indexingType)).array);
     5160                    publicLength, publicLength, weakPointer(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), m_out.constInt32(indexingType)).array);
    51595161            mutatorFence();
    51605162            return;
     
    1144211444    };
    1144311445
    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)
    1144511447    {
    1144611448        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
     
    1146111463       
    1146211464        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        }
    1146311491       
    1146411492        ValueFromBlock noButterfly = m_out.anchor(m_out.intPtrZero);
     
    1147311501       
    1147411502        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 not
    11488             // statically known, since the compute effort of doing it here is probably not worth it.
    11489             vectorLength = publicLength;
    11490         }
    1149111503           
    1149211504        LValue payloadSize =
     
    1153111543
    1153211544        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
    1154011565        ValueFromBlock slowResult = m_out.anchor(slowResultValue);
    1154111566        ValueFromBlock slowButterfly = m_out.anchor(
     
    1154911574    }
    1155011575   
    11551     ArrayValues allocateUninitializedContiguousJSArray(LValue publicLength, RegisteredStructure structure)
     11576    ArrayValues allocateUninitializedContiguousJSArrayInternal(LValue publicLength, LValue vectorLength, RegisteredStructure structure)
    1155211577    {
    1155311578        bool shouldInitializeElements = false;
    1155411579        bool shouldLargeArraySizeCreateArrayStorage = false;
    1155511580        return allocateJSArray(
    11556             publicLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,
     11581            publicLength, vectorLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,
    1155711582            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);
    1155811594    }
    1155911595   
Note: See TracChangeset for help on using the changeset viewer.