Title: [222380] trunk
Revision
222380
Author
[email protected]
Date
2017-09-22 01:22:44 -0700 (Fri, 22 Sep 2017)

Log 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/_javascript_Core:

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):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (222379 => 222380)


--- trunk/JSTests/ChangeLog	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/JSTests/ChangeLog	2017-09-22 08:22:44 UTC (rev 222380)
@@ -1,3 +1,13 @@
+2017-09-21  Yusuke Suzuki  <[email protected]>
+
+        [DFG][FTL] Profile array vector length for array allocation
+        https://bugs.webkit.org/show_bug.cgi?id=177051
+
+        Reviewed by Saam Barati.
+
+        * microbenchmarks/new-array-buffer-vector-profile.js: Added.
+        (target):
+
 2017-09-21  Joseph Pecoraro  <[email protected]>
 
         Skip new hanging test262 tests.

Added: trunk/JSTests/microbenchmarks/new-array-buffer-vector-profile.js (0 => 222380)


--- trunk/JSTests/microbenchmarks/new-array-buffer-vector-profile.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/new-array-buffer-vector-profile.js	2017-09-22 08:22:44 UTC (rev 222380)
@@ -0,0 +1,12 @@
+function target()
+{
+    var array = [0];
+    array.push(1);
+    array.push(2);
+    array.push(3);
+    array.push(4);
+    return array;
+}
+noInline(target);
+for (var i = 0; i < 1e6; ++i)
+    target();

Modified: trunk/Source/_javascript_Core/ChangeLog (222379 => 222380)


--- trunk/Source/_javascript_Core/ChangeLog	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-09-22 08:22:44 UTC (rev 222380)
@@ -1,3 +1,76 @@
+2017-09-21  Yusuke Suzuki  <[email protected]>
+
+        [DFG][FTL] Profile array vector length for array allocation
+        https://bugs.webkit.org/show_bug.cgi?id=177051
+
+        Reviewed by Saam Barati.
+
+        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):
+
 2017-09-21  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: Remove support for CSS Regions

Modified: trunk/Source/_javascript_Core/bytecode/ArrayAllocationProfile.cpp (222379 => 222380)


--- trunk/Source/_javascript_Core/bytecode/ArrayAllocationProfile.cpp	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/bytecode/ArrayAllocationProfile.cpp	2017-09-22 08:22:44 UTC (rev 222380)
@@ -30,7 +30,7 @@
 
 namespace JSC {
 
-void ArrayAllocationProfile::updateIndexingType()
+void ArrayAllocationProfile::updateProfile()
 {
     // This is awkwardly racy but totally sound even when executed concurrently. The
     // worst cases go something like this:
@@ -49,9 +49,11 @@
     JSArray* lastArray = m_lastArray;
     if (!lastArray)
         return;
-    if (LIKELY(Options::useArrayAllocationProfiling()))
+    if (LIKELY(Options::useArrayAllocationProfiling())) {
         m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, lastArray->indexingType());
-    m_lastArray = 0;
+        m_largestSeenVectorLength = std::min(std::max(m_largestSeenVectorLength, lastArray->getVectorLength()), BASE_CONTIGUOUS_VECTOR_LEN_MAX);
+    }
+    m_lastArray = nullptr;
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/bytecode/ArrayAllocationProfile.h (222379 => 222380)


--- trunk/Source/_javascript_Core/bytecode/ArrayAllocationProfile.h	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/bytecode/ArrayAllocationProfile.h	2017-09-22 08:22:44 UTC (rev 222380)
@@ -32,19 +32,22 @@
 
 class ArrayAllocationProfile {
 public:
-    ArrayAllocationProfile()
-        : m_currentIndexingType(ArrayWithUndecided)
-        , m_lastArray(0)
-    {
-    }
-    
     IndexingType selectIndexingType()
     {
         JSArray* lastArray = m_lastArray;
         if (lastArray && UNLIKELY(lastArray->indexingType() != m_currentIndexingType))
-            updateIndexingType();
+            updateProfile();
         return m_currentIndexingType;
     }
+
+    // vector length hint becomes [0, BASE_CONTIGUOUS_VECTOR_LEN_MAX].
+    unsigned vectorLengthHint()
+    {
+        JSArray* lastArray = m_lastArray;
+        if (lastArray && (m_largestSeenVectorLength != BASE_CONTIGUOUS_VECTOR_LEN_MAX) && UNLIKELY(lastArray->getVectorLength() > m_largestSeenVectorLength))
+            updateProfile();
+        return m_largestSeenVectorLength;
+    }
     
     JSArray* updateLastAllocation(JSArray* lastArray)
     {
@@ -52,7 +55,7 @@
         return lastArray;
     }
     
-    JS_EXPORT_PRIVATE void updateIndexingType();
+    JS_EXPORT_PRIVATE void updateProfile();
     
     static IndexingType selectIndexingTypeFor(ArrayAllocationProfile* profile)
     {
@@ -70,8 +73,9 @@
 
 private:
     
-    IndexingType m_currentIndexingType;
-    JSArray* m_lastArray;
+    IndexingType m_currentIndexingType { ArrayWithUndecided };
+    unsigned m_largestSeenVectorLength { 0 };
+    JSArray* m_lastArray { nullptr };
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (222379 => 222380)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2017-09-22 08:22:44 UTC (rev 222380)
@@ -2568,7 +2568,7 @@
     
     // Don't count these either, for similar reasons.
     for (unsigned i = m_arrayAllocationProfiles.size(); i--;)
-        m_arrayAllocationProfiles[i].updateIndexingType();
+        m_arrayAllocationProfiles[i].updateProfile();
 }
 
 void CodeBlock::updateAllPredictions()

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (222379 => 222380)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-09-22 08:22:44 UTC (rev 222380)
@@ -4399,6 +4399,7 @@
             data.startConstant = m_inlineStackTop->m_constantBufferRemap[startConstant];
             data.numConstants = numConstants;
             data.indexingType = profile->selectIndexingType();
+            data.vectorLengthHint = std::max<unsigned>(profile->vectorLengthHint(), numConstants);
 
             // If this statement has never executed, we'll have the wrong indexing type in the profile.
             for (int i = 0; i < numConstants; ++i) {
@@ -4408,7 +4409,7 @@
                         m_codeBlock->constantBuffer(data.startConstant)[i]);
             }
             
-            m_graph.m_newArrayBufferData.append(data);
+            m_graph.m_newArrayBufferData.append(WTFMove(data));
             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewArrayBuffer, OpInfo(&m_graph.m_newArrayBufferData.last())));
             NEXT_OPCODE(op_new_array_buffer);
         }

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (222379 => 222380)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2017-09-22 08:22:44 UTC (rev 222380)
@@ -321,6 +321,7 @@
         for (unsigned i = 0; i < node->numConstants(); ++i)
             out.print(anotherComma, pointerDumpInContext(freeze(m_codeBlock->constantBuffer(node->startConstant())[i]), context));
         out.print("]");
+        out.print(comma, "vectorLengthHint = ", node->vectorLengthHint());
     }
     if (node->hasLazyJSValue())
         out.print(comma, node->lazyJSValue());

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (222379 => 222380)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2017-09-22 08:22:44 UTC (rev 222380)
@@ -99,6 +99,7 @@
 struct NewArrayBufferData {
     unsigned startConstant;
     unsigned numConstants;
+    unsigned vectorLengthHint;
     IndexingType indexingType;
 };
 
@@ -1115,6 +1116,11 @@
     {
         return newArrayBufferData()->numConstants;
     }
+
+    unsigned vectorLengthHint()
+    {
+        return newArrayBufferData()->vectorLengthHint;
+    }
     
     bool hasIndexingType()
     {

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (222379 => 222380)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2017-09-22 08:22:44 UTC (rev 222380)
@@ -1311,6 +1311,25 @@
     return bitwise_cast<char*>(result);
 }
 
+char* JIT_OPERATION operationNewArrayWithSizeAndHint(ExecState* exec, Structure* arrayStructure, int32_t size, int32_t vectorLengthHint, Butterfly* butterfly)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (UNLIKELY(size < 0))
+        return bitwise_cast<char*>(throwException(exec, scope, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer."))));
+
+    JSArray* result;
+    if (butterfly)
+        result = JSArray::createWithButterfly(vm, nullptr, arrayStructure, butterfly);
+    else {
+        result = JSArray::tryCreate(vm, arrayStructure, size, vectorLengthHint);
+        ASSERT(result);
+    }
+    return bitwise_cast<char*>(result);
+}
+
 char* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size)
 {
     VM& vm = exec->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (222379 => 222380)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2017-09-22 08:22:44 UTC (rev 222380)
@@ -81,6 +81,7 @@
 char* JIT_OPERATION operationNewArrayBuffer(ExecState*, Structure*, size_t, size_t) WTF_INTERNAL;
 char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
 char* JIT_OPERATION operationNewArrayWithSize(ExecState*, Structure*, int32_t, Butterfly*) WTF_INTERNAL;
+char* JIT_OPERATION operationNewArrayWithSizeAndHint(ExecState*, Structure*, int32_t, int32_t, Butterfly*) WTF_INTERNAL;
 char* JIT_OPERATION operationNewInt8ArrayWithSize(ExecState*, Structure*, int32_t, char*) WTF_INTERNAL;
 char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
 char* JIT_OPERATION operationNewInt16ArrayWithSize(ExecState*, Structure*, int32_t, char*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (222379 => 222380)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-09-22 08:22:44 UTC (rev 222380)
@@ -4238,6 +4238,8 @@
         IndexingType indexingType = node->indexingType();
         if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingType)) {
             unsigned numElements = node->numConstants();
+            unsigned vectorLengthHint = node->vectorLengthHint();
+            ASSERT(vectorLengthHint >= numElements);
             
             GPRTemporary result(this);
             GPRTemporary storage(this);
@@ -4245,7 +4247,7 @@
             GPRReg resultGPR = result.gpr();
             GPRReg storageGPR = storage.gpr();
 
-            emitAllocateRawObject(resultGPR, m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), storageGPR, numElements, numElements);
+            emitAllocateRawObject(resultGPR, m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), storageGPR, numElements, vectorLengthHint);
             
             DFG_ASSERT(m_jit.graph(), node, indexingType & IsArray);
             JSValue* data = ""

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (222379 => 222380)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-09-22 08:22:44 UTC (rev 222380)
@@ -4189,7 +4189,7 @@
                 m_out.select(m_out.equal(indexingType, m_out.constInt32(ArrayWithContiguous)),
                     weakStructure(m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous))),
                     weakStructure(m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble)))));
-            arrayResult = allocateJSArray(resultLength, structure, indexingType, false, false);
+            arrayResult = allocateJSArray(resultLength, resultLength, structure, indexingType, false, false);
         }
 
         LBasicBlock loop = m_out.newBlock();
@@ -5114,9 +5114,11 @@
         
         if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
             unsigned numElements = m_node->numConstants();
-            
+            unsigned vectorLengthHint = m_node->vectorLengthHint();
+           
+            ASSERT(vectorLengthHint >= numElements);
             ArrayValues arrayValues =
-                allocateUninitializedContiguousJSArray(m_out.constInt32(numElements), structure);
+                allocateUninitializedContiguousJSArray(numElements, vectorLengthHint, structure);
             
             JSValue* data = ""
             for (unsigned index = 0; index < m_node->numConstants(); ++index) {
@@ -5155,7 +5157,7 @@
             IndexingType indexingType = m_node->indexingType();
             setJSValue(
                 allocateJSArray(
-                    publicLength, weakPointer(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), m_out.constInt32(indexingType)).array);
+                    publicLength, publicLength, weakPointer(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), m_out.constInt32(indexingType)).array);
             mutatorFence();
             return;
         }
@@ -11441,7 +11443,7 @@
         LValue butterfly;
     };
 
-    ArrayValues allocateJSArray(LValue publicLength, LValue structure, LValue indexingType, bool shouldInitializeElements = true, bool shouldLargeArraySizeCreateArrayStorage = true)
+    ArrayValues allocateJSArray(LValue publicLength, LValue vectorLength, LValue structure, LValue indexingType, bool shouldInitializeElements = true, bool shouldLargeArraySizeCreateArrayStorage = true)
     {
         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
         if (indexingType->hasInt32()) {
@@ -11460,6 +11462,18 @@
         LBasicBlock slowCase = m_out.newBlock();
         
         LBasicBlock lastNext = m_out.insertNewBlocksBefore(fastCase);
+
+        if (vectorLength->hasInt32() && structure->hasIntPtr()) {
+            unsigned vectorLengthConst = static_cast<unsigned>(vectorLength->asInt32());
+            if (vectorLengthConst <= MAX_STORAGE_VECTOR_LENGTH) {
+                vectorLength = m_out.constInt32(
+                    Butterfly::optimalContiguousVectorLength(
+                        bitwise_cast<Structure*>(structure->asIntPtr())->outOfLineCapacity(), vectorLengthConst));
+            }
+        } else {
+            // We don't compute the optimal vector length for new Array(blah) where blah is not
+            // statically known, since the compute effort of doing it here is probably not worth it.
+        }
         
         ValueFromBlock noButterfly = m_out.anchor(m_out.intPtrZero);
         
@@ -11472,22 +11486,6 @@
         m_out.branch(predicate, rarely(largeCase), usually(fastCase));
         
         m_out.appendTo(fastCase, largeCase);
-
-        LValue vectorLength = nullptr;
-        if (publicLength->hasInt32() && structure->hasIntPtr()) {
-            unsigned publicLengthConst = static_cast<unsigned>(publicLength->asInt32());
-            if (publicLengthConst <= MAX_STORAGE_VECTOR_LENGTH) {
-                vectorLength = m_out.constInt32(
-                    Butterfly::optimalContiguousVectorLength(
-                        bitwise_cast<Structure*>(structure->asIntPtr())->outOfLineCapacity(), publicLengthConst));
-            }
-        }
-        
-        if (!vectorLength) {
-            // We don't compute the optimal vector length for new Array(blah) where blah is not
-            // statically known, since the compute effort of doing it here is probably not worth it.
-            vectorLength = publicLength;
-        }
             
         LValue payloadSize =
             m_out.shl(m_out.zeroExt(vectorLength, pointerType()), m_out.constIntPtr(3));
@@ -11533,10 +11531,10 @@
         LValue slowResultValue = lazySlowPath(
             [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> {
                 return createLazyCallGenerator(vm,
-                    operationNewArrayWithSize, locations[0].directGPR(),
-                    locations[1].directGPR(), locations[2].directGPR(), locations[3].directGPR());
+                    operationNewArrayWithSizeAndHint, locations[0].directGPR(),
+                    locations[1].directGPR(), locations[2].directGPR(), locations[3].directGPR(), locations[4].directGPR());
             },
-            structureValue, publicLength, butterflyValue);
+            structureValue, publicLength, vectorLength, butterflyValue);
         ValueFromBlock slowResult = m_out.anchor(slowResultValue);
         ValueFromBlock slowButterfly = m_out.anchor(
             m_out.loadPtr(slowResultValue, m_heaps.JSObject_butterfly));
@@ -11548,14 +11546,25 @@
             m_out.phi(pointerType(), fastButterfly, slowButterfly));
     }
     
-    ArrayValues allocateUninitializedContiguousJSArray(LValue publicLength, RegisteredStructure structure)
+    ArrayValues allocateUninitializedContiguousJSArrayInternal(LValue publicLength, LValue vectorLength, RegisteredStructure structure)
     {
         bool shouldInitializeElements = false;
         bool shouldLargeArraySizeCreateArrayStorage = false;
         return allocateJSArray(
-            publicLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,
+            publicLength, vectorLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,
             shouldLargeArraySizeCreateArrayStorage);
     }
+
+    ArrayValues allocateUninitializedContiguousJSArray(LValue publicLength, RegisteredStructure structure)
+    {
+        return allocateUninitializedContiguousJSArrayInternal(publicLength, publicLength, structure);
+    }
+
+    ArrayValues allocateUninitializedContiguousJSArray(unsigned publicLength, unsigned vectorLength, RegisteredStructure structure)
+    {
+        ASSERT(vectorLength >= publicLength);
+        return allocateUninitializedContiguousJSArrayInternal(m_out.constInt32(publicLength), m_out.constInt32(vectorLength), structure);
+    }
     
     LValue ensureShadowChickenPacket()
     {

Modified: trunk/Source/_javascript_Core/runtime/ArrayConventions.h (222379 => 222380)


--- trunk/Source/_javascript_Core/runtime/ArrayConventions.h	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/runtime/ArrayConventions.h	2017-09-22 08:22:44 UTC (rev 222380)
@@ -77,6 +77,8 @@
 // for an array that was created with a sepcified length (e.g. a = new Array(123))
 #define BASE_CONTIGUOUS_VECTOR_LEN 3U
 #define BASE_CONTIGUOUS_VECTOR_LEN_EMPTY 5U
+#define BASE_CONTIGUOUS_VECTOR_LEN_MIN 3U
+#define BASE_CONTIGUOUS_VECTOR_LEN_MAX 25U
 #define BASE_ARRAY_STORAGE_VECTOR_LEN 4U
 
 // The upper bound to the size we'll grow a zero length array when the first element

Modified: trunk/Source/_javascript_Core/runtime/JSArray.h (222379 => 222380)


--- trunk/Source/_javascript_Core/runtime/JSArray.h	2017-09-22 06:36:20 UTC (rev 222379)
+++ trunk/Source/_javascript_Core/runtime/JSArray.h	2017-09-22 08:22:44 UTC (rev 222380)
@@ -54,6 +54,7 @@
 
 public:
     static JSArray* tryCreate(VM&, Structure*, unsigned initialLength = 0);
+    static JSArray* tryCreate(VM&, Structure*, unsigned initialLength, unsigned vectorLengthHint);
     static JSArray* create(VM&, Structure*, unsigned initialLength = 0);
     static JSArray* createWithButterfly(VM&, GCDeferralContext*, Structure*, Butterfly*);
 
@@ -215,8 +216,9 @@
 Butterfly* createArrayButterflyInDictionaryIndexingMode(
     VM&, JSCell* intendedOwner, unsigned initialLength);
 
-inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength)
+inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength, unsigned vectorLengthHint)
 {
+    ASSERT(vectorLengthHint >= initialLength);
     unsigned outOfLineStorage = structure->outOfLineCapacity();
 
     Butterfly* butterfly;
@@ -228,10 +230,10 @@
             || hasDouble(indexingType)
             || hasContiguous(indexingType));
 
-        if (UNLIKELY(initialLength > MAX_STORAGE_VECTOR_LENGTH))
+        if (UNLIKELY(vectorLengthHint > MAX_STORAGE_VECTOR_LENGTH))
             return nullptr;
 
-        unsigned vectorLength = Butterfly::optimalContiguousVectorLength(structure, initialLength);
+        unsigned vectorLength = Butterfly::optimalContiguousVectorLength(structure, vectorLengthHint);
         void* temp = vm.jsValueGigacageAuxiliarySpace.tryAllocate(nullptr, Butterfly::totalSize(0, outOfLineStorage, true, vectorLength * sizeof(EncodedJSValue)));
         if (!temp)
             return nullptr;
@@ -256,6 +258,11 @@
     return createWithButterfly(vm, nullptr, structure, butterfly);
 }
 
+inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength)
+{
+    return tryCreate(vm, structure, initialLength, initialLength);
+}
+
 inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength)
 {
     JSArray* result = JSArray::tryCreate(vm, structure, initialLength);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to