Changeset 222380 in webkit for trunk/Source/JavaScriptCore


Ignore:
Timestamp:
Sep 22, 2017, 1:22:44 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):

Location:
trunk/Source/JavaScriptCore
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r222356 r222380  
     12017-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
    1742017-09-21  Joseph Pecoraro  <[email protected]>
    275
  • trunk/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp

    r219187 r222380  
    3131namespace JSC {
    3232
    33 void ArrayAllocationProfile::updateIndexingType()
     33void ArrayAllocationProfile::updateProfile()
    3434{
    3535    // This is awkwardly racy but totally sound even when executed concurrently. The
     
    5050    if (!lastArray)
    5151        return;
    52     if (LIKELY(Options::useArrayAllocationProfiling()))
     52    if (LIKELY(Options::useArrayAllocationProfiling())) {
    5353        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;
    5557}
    5658
  • trunk/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h

    r206525 r222380  
    3333class ArrayAllocationProfile {
    3434public:
    35     ArrayAllocationProfile()
    36         : m_currentIndexingType(ArrayWithUndecided)
    37         , m_lastArray(0)
    38     {
    39     }
    40    
    4135    IndexingType selectIndexingType()
    4236    {
    4337        JSArray* lastArray = m_lastArray;
    4438        if (lastArray && UNLIKELY(lastArray->indexingType() != m_currentIndexingType))
    45             updateIndexingType();
     39            updateProfile();
    4640        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;
    4750    }
    4851   
     
    5356    }
    5457   
    55     JS_EXPORT_PRIVATE void updateIndexingType();
     58    JS_EXPORT_PRIVATE void updateProfile();
    5659   
    5760    static IndexingType selectIndexingTypeFor(ArrayAllocationProfile* profile)
     
    7174private:
    7275   
    73     IndexingType m_currentIndexingType;
    74     JSArray* m_lastArray;
     76    IndexingType m_currentIndexingType { ArrayWithUndecided };
     77    unsigned m_largestSeenVectorLength { 0 };
     78    JSArray* m_lastArray { nullptr };
    7579};
    7680
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r222009 r222380  
    25692569    // Don't count these either, for similar reasons.
    25702570    for (unsigned i = m_arrayAllocationProfiles.size(); i--;)
    2571         m_arrayAllocationProfiles[i].updateIndexingType();
     2571        m_arrayAllocationProfiles[i].updateProfile();
    25722572}
    25732573
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r222115 r222380  
    44004400            data.numConstants = numConstants;
    44014401            data.indexingType = profile->selectIndexingType();
     4402            data.vectorLengthHint = std::max<unsigned>(profile->vectorLengthHint(), numConstants);
    44024403
    44034404            // If this statement has never executed, we'll have the wrong indexing type in the profile.
     
    44094410            }
    44104411           
    4411             m_graph.m_newArrayBufferData.append(data);
     4412            m_graph.m_newArrayBufferData.append(WTFMove(data));
    44124413            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewArrayBuffer, OpInfo(&m_graph.m_newArrayBufferData.last())));
    44134414            NEXT_OPCODE(op_new_array_buffer);
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r222066 r222380  
    322322            out.print(anotherComma, pointerDumpInContext(freeze(m_codeBlock->constantBuffer(node->startConstant())[i]), context));
    323323        out.print("]");
     324        out.print(comma, "vectorLengthHint = ", node->vectorLengthHint());
    324325    }
    325326    if (node->hasLazyJSValue())
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r222143 r222380  
    100100    unsigned startConstant;
    101101    unsigned numConstants;
     102    unsigned vectorLengthHint;
    102103    IndexingType indexingType;
    103104};
     
    11151116    {
    11161117        return newArrayBufferData()->numConstants;
     1118    }
     1119
     1120    unsigned vectorLengthHint()
     1121    {
     1122        return newArrayBufferData()->vectorLengthHint;
    11171123    }
    11181124   
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r222009 r222380  
    13121312}
    13131313
     1314char* 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
    13141333char* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size)
    13151334{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r222009 r222380  
    8282char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
    8383char* JIT_OPERATION operationNewArrayWithSize(ExecState*, Structure*, int32_t, Butterfly*) WTF_INTERNAL;
     84char* JIT_OPERATION operationNewArrayWithSizeAndHint(ExecState*, Structure*, int32_t, int32_t, Butterfly*) WTF_INTERNAL;
    8485char* JIT_OPERATION operationNewInt8ArrayWithSize(ExecState*, Structure*, int32_t, char*) WTF_INTERNAL;
    8586char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r222143 r222380  
    42394239        if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingType)) {
    42404240            unsigned numElements = node->numConstants();
     4241            unsigned vectorLengthHint = node->vectorLengthHint();
     4242            ASSERT(vectorLengthHint >= numElements);
    42414243           
    42424244            GPRTemporary result(this);
     
    42464248            GPRReg storageGPR = storage.gpr();
    42474249
    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);
    42494251           
    42504252            DFG_ASSERT(m_jit.graph(), node, indexingType & IsArray);
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r222143 r222380  
    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        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        }
    1146311477       
    1146411478        ValueFromBlock noButterfly = m_out.anchor(m_out.intPtrZero);
     
    1147311487       
    1147411488        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         }
    1149111489           
    1149211490        LValue payloadSize =
     
    1153411532            [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> {
    1153511533                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());
    1153811536            },
    11539             structureValue, publicLength, butterflyValue);
     11537            structureValue, publicLength, vectorLength, butterflyValue);
    1154011538        ValueFromBlock slowResult = m_out.anchor(slowResultValue);
    1154111539        ValueFromBlock slowButterfly = m_out.anchor(
     
    1154911547    }
    1155011548   
    11551     ArrayValues allocateUninitializedContiguousJSArray(LValue publicLength, RegisteredStructure structure)
     11549    ArrayValues allocateUninitializedContiguousJSArrayInternal(LValue publicLength, LValue vectorLength, RegisteredStructure structure)
    1155211550    {
    1155311551        bool shouldInitializeElements = false;
    1155411552        bool shouldLargeArraySizeCreateArrayStorage = false;
    1155511553        return allocateJSArray(
    11556             publicLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,
     11554            publicLength, vectorLength, weakStructure(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,
    1155711555            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);
    1155811567    }
    1155911568   
  • trunk/Source/JavaScriptCore/runtime/ArrayConventions.h

    r218794 r222380  
    7878#define BASE_CONTIGUOUS_VECTOR_LEN 3U
    7979#define BASE_CONTIGUOUS_VECTOR_LEN_EMPTY 5U
     80#define BASE_CONTIGUOUS_VECTOR_LEN_MIN 3U
     81#define BASE_CONTIGUOUS_VECTOR_LEN_MAX 25U
    8082#define BASE_ARRAY_STORAGE_VECTOR_LEN 4U
    8183
  • trunk/Source/JavaScriptCore/runtime/JSArray.h

    r221822 r222380  
    5555public:
    5656    static JSArray* tryCreate(VM&, Structure*, unsigned initialLength = 0);
     57    static JSArray* tryCreate(VM&, Structure*, unsigned initialLength, unsigned vectorLengthHint);
    5758    static JSArray* create(VM&, Structure*, unsigned initialLength = 0);
    5859    static JSArray* createWithButterfly(VM&, GCDeferralContext*, Structure*, Butterfly*);
     
    216217    VM&, JSCell* intendedOwner, unsigned initialLength);
    217218
    218 inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength)
    219 {
     219inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength, unsigned vectorLengthHint)
     220{
     221    ASSERT(vectorLengthHint >= initialLength);
    220222    unsigned outOfLineStorage = structure->outOfLineCapacity();
    221223
     
    229231            || hasContiguous(indexingType));
    230232
    231         if (UNLIKELY(initialLength > MAX_STORAGE_VECTOR_LENGTH))
     233        if (UNLIKELY(vectorLengthHint > MAX_STORAGE_VECTOR_LENGTH))
    232234            return nullptr;
    233235
    234         unsigned vectorLength = Butterfly::optimalContiguousVectorLength(structure, initialLength);
     236        unsigned vectorLength = Butterfly::optimalContiguousVectorLength(structure, vectorLengthHint);
    235237        void* temp = vm.jsValueGigacageAuxiliarySpace.tryAllocate(nullptr, Butterfly::totalSize(0, outOfLineStorage, true, vectorLength * sizeof(EncodedJSValue)));
    236238        if (!temp)
     
    257259}
    258260
     261inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength)
     262{
     263    return tryCreate(vm, structure, initialLength, initialLength);
     264}
     265
    259266inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength)
    260267{
Note: See TracChangeset for help on using the changeset viewer.