Changeset 222563 in webkit


Ignore:
Timestamp:
Sep 27, 2017 11:37:41 AM (7 years ago)
Author:
Yusuke Suzuki
Message:

[DFG] Support ArrayPush with multiple args
https://bugs.webkit.org/show_bug.cgi?id=175823

Reviewed by Saam Barati.

JSTests:

  • microbenchmarks/array-push-0.js: Added.

(arrayPush0):

  • microbenchmarks/array-push-1.js: Added.

(arrayPush1):

  • microbenchmarks/array-push-2.js: Added.

(arrayPush2):

  • microbenchmarks/array-push-3.js: Added.

(arrayPush3):

  • stress/array-push-multiple-contiguous.js: Added.

(shouldBe):
(test):

  • stress/array-push-multiple-double-nan.js: Added.

(shouldBe):
(test):

  • stress/array-push-multiple-double.js: Added.

(shouldBe):
(test):

  • stress/array-push-multiple-int32.js: Added.

(shouldBe):
(test):

  • stress/array-push-multiple-many-contiguous.js: Added.

(shouldBe):
(test):

  • stress/array-push-multiple-many-double.js: Added.

(shouldBe):
(test):

  • stress/array-push-multiple-many-int32.js: Added.

(shouldBe):
(test):

  • stress/array-push-multiple-many-storage.js: Added.

(shouldBe):
(test):

  • stress/array-push-multiple-storage.js: Added.

(shouldBe):
(test):

Source/JavaScriptCore:

This patch implements ArrayPush(with multiple arguments) in DFG and FTL. Previously, they are not handled
by ArrayPush. Then they go to generic direct call to Array#push and it does in slow path. This patch
extends ArrayPush to push multiple arguments in a bulk push manner.

The problem of ArrayPush is that we need to perform ArrayPush atomically: If OSR exit occurs in the middle
of ArrayPush, we incorrectly push pushed elements twice. Once we start pushing values, we should not exit.
But we do not want to iterate elements twice, once for type checks and once for actually pushing it. It
could move elements between registers and memory back and forth.

This patch achieves the above goal by separating type checks from ArrayPush. When starting ArrayPush, type
checks for elements are already done by separately emitted Check nodes.

We also add JSArray::pushInline for DFG operations just calling JSArray::push. And we also use it in
arrayProtoFuncPush's fast path.

This patch significantly improves performance of push(multiple args).

baseline patched

Microbenchmarks:

array-push-0 461.8455+-28.9995 151.3438+-6.5653 definitely 3.0516x faster
array-push-1 133.8845+-7.0349 ? 136.1775+-5.8327 ? might be 1.0171x slower
array-push-2 675.6555+-13.4645 145.8747+-6.4621 definitely 4.6318x faster
array-push-3 849.5284+-15.2540 253.4421+-9.1249 definitely 3.3520x faster

baseline patched

SixSpeed:

spread-literal.es5 90.3482+-6.6514 24.8123+-2.3304 definitely 3.6413x faster

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleIntrinsicCall):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileArrayPush):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGStoreBarrierInsertionPhase.cpp:
  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileArrayPush):

  • jit/JITOperations.h:
  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncPush):

  • runtime/JSArray.cpp:

(JSC::JSArray::push):

  • runtime/JSArray.h:
  • runtime/JSArrayInlines.h:

(JSC::JSArray::pushInline):

Location:
trunk
Files:
13 added
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r222523 r222563  
     12017-09-25  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DFG] Support ArrayPush with multiple args
     4        https://bugs.webkit.org/show_bug.cgi?id=175823
     5
     6        Reviewed by Saam Barati.
     7
     8        * microbenchmarks/array-push-0.js: Added.
     9        (arrayPush0):
     10        * microbenchmarks/array-push-1.js: Added.
     11        (arrayPush1):
     12        * microbenchmarks/array-push-2.js: Added.
     13        (arrayPush2):
     14        * microbenchmarks/array-push-3.js: Added.
     15        (arrayPush3):
     16        * stress/array-push-multiple-contiguous.js: Added.
     17        (shouldBe):
     18        (test):
     19        * stress/array-push-multiple-double-nan.js: Added.
     20        (shouldBe):
     21        (test):
     22        * stress/array-push-multiple-double.js: Added.
     23        (shouldBe):
     24        (test):
     25        * stress/array-push-multiple-int32.js: Added.
     26        (shouldBe):
     27        (test):
     28        * stress/array-push-multiple-many-contiguous.js: Added.
     29        (shouldBe):
     30        (test):
     31        * stress/array-push-multiple-many-double.js: Added.
     32        (shouldBe):
     33        (test):
     34        * stress/array-push-multiple-many-int32.js: Added.
     35        (shouldBe):
     36        (test):
     37        * stress/array-push-multiple-many-storage.js: Added.
     38        (shouldBe):
     39        (test):
     40        * stress/array-push-multiple-storage.js: Added.
     41        (shouldBe):
     42        (test):
     43
    1442017-09-26  Commit Queue  <commit-queue@webkit.org>
    245
  • trunk/Source/JavaScriptCore/ChangeLog

    r222560 r222563  
     12017-09-25  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DFG] Support ArrayPush with multiple args
     4        https://bugs.webkit.org/show_bug.cgi?id=175823
     5
     6        Reviewed by Saam Barati.
     7
     8        This patch implements ArrayPush(with multiple arguments) in DFG and FTL. Previously, they are not handled
     9        by ArrayPush. Then they go to generic direct call to Array#push and it does in slow path. This patch
     10        extends ArrayPush to push multiple arguments in a bulk push manner.
     11
     12        The problem of ArrayPush is that we need to perform ArrayPush atomically: If OSR exit occurs in the middle
     13        of ArrayPush, we incorrectly push pushed elements twice. Once we start pushing values, we should not exit.
     14        But we do not want to iterate elements twice, once for type checks and once for actually pushing it. It
     15        could move elements between registers and memory back and forth.
     16
     17        This patch achieves the above goal by separating type checks from ArrayPush. When starting ArrayPush, type
     18        checks for elements are already done by separately emitted Check nodes.
     19
     20        We also add JSArray::pushInline for DFG operations just calling JSArray::push. And we also use it in
     21        arrayProtoFuncPush's fast path.
     22
     23        This patch significantly improves performance of `push(multiple args)`.
     24
     25                                            baseline                  patched
     26            Microbenchmarks:
     27                array-push-0            461.8455+-28.9995    ^    151.3438+-6.5653        ^ definitely 3.0516x faster
     28                array-push-1            133.8845+-7.0349     ?    136.1775+-5.8327        ? might be 1.0171x slower
     29                array-push-2            675.6555+-13.4645    ^    145.8747+-6.4621        ^ definitely 4.6318x faster
     30                array-push-3            849.5284+-15.2540    ^    253.4421+-9.1249        ^ definitely 3.3520x faster
     31
     32                                            baseline                  patched
     33            SixSpeed:
     34                spread-literal.es5       90.3482+-6.6514     ^     24.8123+-2.3304        ^ definitely 3.6413x faster
     35
     36        * dfg/DFGByteCodeParser.cpp:
     37        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     38        * dfg/DFGFixupPhase.cpp:
     39        (JSC::DFG::FixupPhase::fixupNode):
     40        * dfg/DFGNodeType.h:
     41        * dfg/DFGOperations.cpp:
     42        * dfg/DFGOperations.h:
     43        * dfg/DFGSpeculativeJIT.cpp:
     44        (JSC::DFG::SpeculativeJIT::compileArrayPush):
     45        * dfg/DFGSpeculativeJIT.h:
     46        (JSC::DFG::SpeculativeJIT::callOperation):
     47        * dfg/DFGSpeculativeJIT32_64.cpp:
     48        (JSC::DFG::SpeculativeJIT::compile):
     49        * dfg/DFGSpeculativeJIT64.cpp:
     50        (JSC::DFG::SpeculativeJIT::compile):
     51        * dfg/DFGStoreBarrierInsertionPhase.cpp:
     52        * ftl/FTLLowerDFGToB3.cpp:
     53        (JSC::FTL::DFG::LowerDFGToB3::compileArrayPush):
     54        * jit/JITOperations.h:
     55        * runtime/ArrayPrototype.cpp:
     56        (JSC::arrayProtoFuncPush):
     57        * runtime/JSArray.cpp:
     58        (JSC::JSArray::push):
     59        * runtime/JSArray.h:
     60        * runtime/JSArrayInlines.h:
     61        (JSC::JSArray::pushInline):
     62
    1632017-09-26  Joseph Pecoraro  <pecoraro@apple.com>
    264
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r222523 r222563  
    23352335       
    23362336    case ArrayPushIntrinsic: {
    2337         if (argumentCountIncludingThis != 2)
     2337        if (static_cast<unsigned>(argumentCountIncludingThis) >= MIN_SPARSE_ARRAY_INDEX)
    23382338            return false;
    23392339       
     
    23472347        case Array::ArrayStorage: {
    23482348            insertChecks();
    2349             Node* arrayPush = addToGraph(ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
     2349
     2350            addVarArgChild(nullptr); // For storage.
     2351            for (int i = 0; i < argumentCountIncludingThis; ++i)
     2352                addVarArgChild(get(virtualRegisterForArgument(i, registerOffset)));
     2353            Node* arrayPush = addToGraph(Node::VarArg, ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction));
    23502354            set(VirtualRegister(resultOperand), arrayPush);
    23512355           
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r222523 r222563  
    10101010            // array-related - so if refine() turned this into a "Generic" ArrayPush then
    10111011            // that would break things.
    1012             node->setArrayMode(
    1013                 node->arrayMode().refine(
    1014                     m_graph, node,
    1015                     node->child1()->prediction() & SpecCell,
    1016                     SpecInt32Only,
    1017                     node->child2()->prediction()));
    1018             blessArrayOperation(node->child1(), Edge(), node->child3());
    1019             fixEdge<KnownCellUse>(node->child1());
    1020            
    1021             switch (node->arrayMode().type()) {
    1022             case Array::Int32:
    1023                 fixEdge<Int32Use>(node->child2());
    1024                 break;
    1025             case Array::Double:
    1026                 fixEdge<DoubleRepRealUse>(node->child2());
    1027                 break;
    1028             case Array::Contiguous:
    1029             case Array::ArrayStorage:
    1030                 speculateForBarrier(node->child2());
    1031                 break;
    1032             default:
    1033                 break;
     1012            Edge& storageEdge = m_graph.varArgChild(node, 0);
     1013            Edge& arrayEdge = m_graph.varArgChild(node, 1);
     1014            unsigned elementOffset = 2;
     1015            unsigned elementCount = node->numChildren() - elementOffset;
     1016            for (unsigned i = 0; i < elementCount; ++i) {
     1017                Edge& element = m_graph.varArgChild(node, i + elementOffset);
     1018                node->setArrayMode(
     1019                    node->arrayMode().refine(
     1020                        m_graph, node,
     1021                        arrayEdge->prediction() & SpecCell,
     1022                        SpecInt32Only,
     1023                        element->prediction()));
     1024            }
     1025            blessArrayOperation(arrayEdge, Edge(), storageEdge);
     1026            fixEdge<KnownCellUse>(arrayEdge);
     1027
     1028            // Convert `array.push()` to GetArrayLength.
     1029            ASSERT(node->arrayMode().supportsSelfLength());
     1030            if (!elementCount) {
     1031                node->setOpAndDefaultFlags(GetArrayLength);
     1032                node->child1() = arrayEdge;
     1033                node->child2() = storageEdge;
     1034                fixEdge<KnownCellUse>(node->child1());
     1035                break;
     1036            }
     1037
     1038            // We do not want to perform osr exit and retry for ArrayPush. We insert Check with appropriate type,
     1039            // and ArrayPush uses the edge as known typed edge. Therefore, ArrayPush do not need to perform type checks.
     1040            for (unsigned i = 0; i < elementCount; ++i) {
     1041                Edge& element = m_graph.varArgChild(node, i + elementOffset);
     1042                switch (node->arrayMode().type()) {
     1043                case Array::Int32:
     1044                    insertCheck<Int32Use>(element.node());
     1045                    fixEdge<KnownInt32Use>(element);
     1046                    break;
     1047                case Array::Double:
     1048                    insertCheck<DoubleRepRealUse>(element.node());
     1049                    fixEdge<DoubleRepUse>(element);
     1050                    break;
     1051                case Array::Contiguous:
     1052                case Array::ArrayStorage:
     1053                    speculateForBarrier(element);
     1054                    break;
     1055                default:
     1056                    RELEASE_ASSERT_NOT_REACHED();
     1057                }
     1058                ASSERT(shouldNotHaveTypeCheck(element.useKind()));
    10341059            }
    10351060            break;
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r222523 r222563  
    266266    \
    267267    /* Optimizations for array mutation. */\
    268     macro(ArrayPush, NodeResultJS | NodeMustGenerate) \
     268    macro(ArrayPush, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
    269269    macro(ArrayPop, NodeResultJS | NodeMustGenerate) \
    270270    macro(ArraySlice, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r222473 r222563  
    870870    NativeCallFrameTracer tracer(vm, exec);
    871871   
    872     array->push(exec, JSValue::decode(encodedValue));
     872    array->pushInline(exec, JSValue::decode(encodedValue));
    873873    return JSValue::encode(jsNumber(array->length()));
    874874}
     
    879879    NativeCallFrameTracer tracer(vm, exec);
    880880   
    881     array->push(exec, JSValue(JSValue::EncodeAsDouble, value));
     881    array->pushInline(exec, JSValue(JSValue::EncodeAsDouble, value));
     882    return JSValue::encode(jsNumber(array->length()));
     883}
     884
     885EncodedJSValue JIT_OPERATION operationArrayPushMultiple(ExecState* exec, JSArray* array, void* buffer, int32_t elementCount)
     886{
     887    VM& vm = exec->vm();
     888    NativeCallFrameTracer tracer(&vm, exec);
     889    auto scope = DECLARE_THROW_SCOPE(vm);
     890
     891    // We assume that multiple JSArray::push calls with ArrayWithInt32/ArrayWithContiguous do not cause JS traps.
     892    // If it can cause any JS interactions, we can call the caller JS function of this function and overwrite the
     893    // content of ScratchBuffer. If the IndexingType is now ArrayWithInt32/ArrayWithContiguous, we can ensure
     894    // that there is no indexed accessors in this object and its prototype chain.
     895    //
     896    // ArrayWithArrayStorage is also OK. It can have indexed accessors. But if you define an indexed accessor, the array's length
     897    // becomes larger than that index. So Array#push never overlaps with this accessor. So accessors are never called unless
     898    // the IndexingType is ArrayWithSlowPutArrayStorage which could have an indexed accessor in a prototype chain.
     899    RELEASE_ASSERT(!shouldUseSlowPut(array->indexingType()));
     900
     901    EncodedJSValue* values = static_cast<EncodedJSValue*>(buffer);
     902    for (int32_t i = 0; i < elementCount; ++i) {
     903        array->pushInline(exec, JSValue::decode(values[i]));
     904        RETURN_IF_EXCEPTION(scope, encodedJSValue());
     905    }
     906    return JSValue::encode(jsNumber(array->length()));
     907}
     908
     909EncodedJSValue JIT_OPERATION operationArrayPushDoubleMultiple(ExecState* exec, JSArray* array, void* buffer, int32_t elementCount)
     910{
     911    VM& vm = exec->vm();
     912    NativeCallFrameTracer tracer(&vm, exec);
     913    auto scope = DECLARE_THROW_SCOPE(vm);
     914
     915    // We assume that multiple JSArray::push calls with ArrayWithDouble do not cause JS traps.
     916    // If it can cause any JS interactions, we can call the caller JS function of this function and overwrite the
     917    // content of ScratchBuffer. If the IndexingType is now ArrayWithDouble, we can ensure
     918    // that there is no indexed accessors in this object and its prototype chain.
     919    ASSERT(array->indexingType() == ArrayWithDouble);
     920
     921    double* values = static_cast<double*>(buffer);
     922    for (int32_t i = 0; i < elementCount; ++i) {
     923        array->pushInline(exec, JSValue(JSValue::EncodeAsDouble, values[i]));
     924        RETURN_IF_EXCEPTION(scope, encodedJSValue());
     925    }
    882926    return JSValue::encode(jsNumber(array->length()));
    883927}
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r222384 r222563  
    137137void JIT_OPERATION operationDefineAccessorPropertySymbol(ExecState*, JSObject*, Symbol*, JSObject*, JSObject*, int32_t) WTF_INTERNAL;
    138138EncodedJSValue JIT_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL;
     139EncodedJSValue JIT_OPERATION operationArrayPushMultiple(ExecState*, JSArray*, void* buffer, int32_t elementCount) WTF_INTERNAL;
    139140EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState*, double value, JSArray*) WTF_INTERNAL;
     141EncodedJSValue JIT_OPERATION operationArrayPushDoubleMultiple(ExecState*, JSArray*, void* buffer, int32_t elementCount) WTF_INTERNAL;
    140142EncodedJSValue JIT_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
    141143EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState*, JSArray*) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r222523 r222563  
    78677867}
    78687868
     7869void SpeculativeJIT::compileArrayPush(Node* node)
     7870{
     7871    ASSERT(node->arrayMode().isJSArray());
     7872
     7873    Edge& storageEdge = m_jit.graph().varArgChild(node, 0);
     7874    Edge& arrayEdge = m_jit.graph().varArgChild(node, 1);
     7875
     7876    SpeculateCellOperand base(this, arrayEdge);
     7877    GPRTemporary storageLength(this);
     7878
     7879    GPRReg baseGPR = base.gpr();
     7880    GPRReg storageLengthGPR = storageLength.gpr();
     7881
     7882    StorageOperand storage(this, storageEdge);
     7883    GPRReg storageGPR = storage.gpr();
     7884    unsigned elementOffset = 2;
     7885    unsigned elementCount = node->numChildren() - elementOffset;
     7886
     7887#if USE(JSVALUE32_64)
     7888    GPRTemporary tag(this);
     7889    GPRReg tagGPR = tag.gpr();
     7890    JSValueRegs resultRegs { tagGPR, storageLengthGPR };
     7891#else
     7892    JSValueRegs resultRegs { storageLengthGPR };
     7893#endif
     7894
     7895    auto getStorageBufferAddress = [&] (GPRReg storageGPR, GPRReg indexGPR, int32_t offset, GPRReg bufferGPR) {
     7896#if USE(JSVALUE32_64)
     7897        static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
     7898        m_jit.move(indexGPR, bufferGPR);
     7899        m_jit.lshift32(TrustedImm32(3), bufferGPR);
     7900        m_jit.add32(storageGPR, bufferGPR);
     7901        if (offset)
     7902            m_jit.add32(TrustedImm32(offset), bufferGPR);
     7903#else
     7904        m_jit.getEffectiveAddress64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, offset), bufferGPR);
     7905#endif
     7906    };
     7907
     7908    switch (node->arrayMode().type()) {
     7909    case Array::Int32:
     7910    case Array::Contiguous: {
     7911        if (elementCount == 1) {
     7912            Edge& element = m_jit.graph().varArgChild(node, elementOffset);
     7913            JSValueOperand value(this, element, ManualOperandSpeculation);
     7914            JSValueRegs valueRegs = value.jsValueRegs();
     7915
     7916            if (node->arrayMode().type() == Array::Int32)
     7917                RELEASE_ASSERT(!needsTypeCheck(element, SpecInt32Only));
     7918
     7919            m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
     7920            MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
     7921            m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
     7922            m_jit.add32(TrustedImm32(1), storageLengthGPR);
     7923            m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
     7924            m_jit.boxInt32(storageLengthGPR, resultRegs);
     7925
     7926            addSlowPathGenerator(
     7927                slowPathCall(slowPath, this, operationArrayPush, resultRegs, valueRegs, baseGPR));
     7928
     7929            jsValueResult(resultRegs, node);
     7930            return;
     7931        }
     7932
     7933        GPRTemporary buffer(this);
     7934        GPRReg bufferGPR = buffer.gpr();
     7935
     7936        m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
     7937        m_jit.move(storageLengthGPR, bufferGPR);
     7938        m_jit.add32(TrustedImm32(elementCount), bufferGPR);
     7939        MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
     7940
     7941        m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
     7942        getStorageBufferAddress(storageGPR, storageLengthGPR, 0, bufferGPR);
     7943        m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
     7944        m_jit.boxInt32(storageLengthGPR, resultRegs);
     7945        auto storageDone = m_jit.jump();
     7946
     7947        slowPath.link(&m_jit);
     7948
     7949        size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
     7950        ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
     7951        m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
     7952        m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
     7953        m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
     7954
     7955        storageDone.link(&m_jit);
     7956        for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
     7957            Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
     7958            JSValueOperand value(this, element, ManualOperandSpeculation);
     7959            JSValueRegs valueRegs = value.jsValueRegs();
     7960
     7961            if (node->arrayMode().type() == Array::Int32)
     7962                RELEASE_ASSERT(!needsTypeCheck(element, SpecInt32Only));
     7963
     7964            m_jit.storeValue(valueRegs, MacroAssembler::Address(bufferGPR, sizeof(EncodedJSValue) * elementIndex));
     7965            value.use();
     7966        }
     7967
     7968        MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
     7969
     7970        addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationArrayPushMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
     7971
     7972        m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
     7973        m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
     7974
     7975        base.use();
     7976        storage.use();
     7977
     7978        fastPath.link(&m_jit);
     7979        jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
     7980        return;
     7981    }
     7982
     7983    case Array::Double: {
     7984        if (elementCount == 1) {
     7985            Edge& element = m_jit.graph().varArgChild(node, elementOffset);
     7986            SpeculateDoubleOperand value(this, element);
     7987            FPRReg valueFPR = value.fpr();
     7988
     7989            RELEASE_ASSERT(!needsTypeCheck(element, SpecDoubleReal));
     7990
     7991            m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
     7992            MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
     7993            m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
     7994            m_jit.add32(TrustedImm32(1), storageLengthGPR);
     7995            m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
     7996            m_jit.boxInt32(storageLengthGPR, resultRegs);
     7997
     7998            addSlowPathGenerator(
     7999                slowPathCall(slowPath, this, operationArrayPushDouble, resultRegs, valueFPR, baseGPR));
     8000
     8001            jsValueResult(resultRegs, node);
     8002            return;
     8003        }
     8004
     8005        GPRTemporary buffer(this);
     8006        GPRReg bufferGPR = buffer.gpr();
     8007
     8008        m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
     8009        m_jit.move(storageLengthGPR, bufferGPR);
     8010        m_jit.add32(TrustedImm32(elementCount), bufferGPR);
     8011        MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
     8012
     8013        m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
     8014        getStorageBufferAddress(storageGPR, storageLengthGPR, 0, bufferGPR);
     8015        m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
     8016        m_jit.boxInt32(storageLengthGPR, resultRegs);
     8017        auto storageDone = m_jit.jump();
     8018
     8019        slowPath.link(&m_jit);
     8020
     8021        size_t scratchSize = sizeof(double) * elementCount;
     8022        ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
     8023        m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
     8024        m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
     8025        m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
     8026
     8027        storageDone.link(&m_jit);
     8028        for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
     8029            Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
     8030            SpeculateDoubleOperand value(this, element);
     8031            FPRReg valueFPR = value.fpr();
     8032
     8033            RELEASE_ASSERT(!needsTypeCheck(element, SpecDoubleReal));
     8034
     8035            m_jit.storeDouble(valueFPR, MacroAssembler::Address(bufferGPR, sizeof(double) * elementIndex));
     8036            value.use();
     8037        }
     8038
     8039        MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
     8040
     8041        addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationArrayPushDoubleMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
     8042
     8043        m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
     8044        m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
     8045
     8046        base.use();
     8047        storage.use();
     8048
     8049        fastPath.link(&m_jit);
     8050        jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
     8051        return;
     8052    }
     8053
     8054    case Array::ArrayStorage: {
     8055        // This ensures that the result of ArrayPush is Int32 in AI.
     8056        int32_t largestPositiveInt32Length = 0x7fffffff - elementCount;
     8057        if (elementCount == 1) {
     8058            Edge& element = m_jit.graph().varArgChild(node, elementOffset);
     8059            JSValueOperand value(this, element);
     8060            JSValueRegs valueRegs = value.jsValueRegs();
     8061
     8062            m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
     8063
     8064            // Refuse to handle bizarre lengths.
     8065            speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(largestPositiveInt32Length)));
     8066
     8067            MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
     8068
     8069            m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
     8070
     8071            m_jit.add32(TrustedImm32(1), storageLengthGPR);
     8072            m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
     8073            m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
     8074            m_jit.boxInt32(storageLengthGPR, resultRegs);
     8075
     8076            addSlowPathGenerator(
     8077                slowPathCall(slowPath, this, operationArrayPush, resultRegs, valueRegs, baseGPR));
     8078
     8079            jsValueResult(resultRegs, node);
     8080            return;
     8081        }
     8082
     8083        GPRTemporary buffer(this);
     8084        GPRReg bufferGPR = buffer.gpr();
     8085
     8086        m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
     8087
     8088        // Refuse to handle bizarre lengths.
     8089        speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(largestPositiveInt32Length)));
     8090
     8091        m_jit.move(storageLengthGPR, bufferGPR);
     8092        m_jit.add32(TrustedImm32(elementCount), bufferGPR);
     8093        MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
     8094
     8095        m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
     8096        getStorageBufferAddress(storageGPR, storageLengthGPR, ArrayStorage::vectorOffset(), bufferGPR);
     8097        m_jit.add32(TrustedImm32(elementCount), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
     8098        m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
     8099        m_jit.boxInt32(storageLengthGPR, resultRegs);
     8100        auto storageDone = m_jit.jump();
     8101
     8102        slowPath.link(&m_jit);
     8103
     8104        size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
     8105        ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
     8106        m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
     8107        m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
     8108        m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
     8109
     8110        storageDone.link(&m_jit);
     8111        for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
     8112            Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
     8113            JSValueOperand value(this, element);
     8114            JSValueRegs valueRegs = value.jsValueRegs();
     8115
     8116            m_jit.storeValue(valueRegs, MacroAssembler::Address(bufferGPR, sizeof(EncodedJSValue) * elementIndex));
     8117            value.use();
     8118        }
     8119
     8120        MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
     8121
     8122        addSlowPathGenerator(
     8123            slowPathCall(m_jit.jump(), this, operationArrayPushMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
     8124
     8125        m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
     8126        m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
     8127
     8128        base.use();
     8129        storage.use();
     8130
     8131        fastPath.link(&m_jit);
     8132        jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
     8133        return;
     8134    }
     8135
     8136    default:
     8137        RELEASE_ASSERT_NOT_REACHED();
     8138    }
     8139}
     8140
    78698141void SpeculativeJIT::compileNotifyWrite(Node* node)
    78708142{
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r222523 r222563  
    16141614        return appendCallSetResult(operation, result);
    16151615    }
    1616     JITCompiler::Call callOperation(J_JITOperation_EJA operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     1616    JITCompiler::Call callOperation(J_JITOperation_EJA operation, JSValueRegs result, JSValueRegs arg1, GPRReg arg2)
     1617    {
     1618        m_jit.setupArgumentsWithExecState(arg1.gpr(), arg2);
     1619        return appendCallSetResult(operation, result.payloadGPR());
     1620    }
     1621    JITCompiler::Call callOperation(J_JITOperation_EJA operation, GPRReg result, JSValueRegs arg1, GPRReg arg2)
     1622    {
     1623        m_jit.setupArgumentsWithExecState(arg1.gpr(), arg2);
     1624        return appendCallSetResult(operation, result);
     1625    }
     1626    JITCompiler::Call callOperation(J_JITOperation_EP operation, GPRReg result, GPRReg arg1)
     1627    {
     1628        m_jit.setupArgumentsWithExecState(arg1);
     1629        return appendCallSetResult(operation, result);
     1630    }
     1631    JITCompiler::Call callOperation(J_JITOperation_EZ operation, GPRReg result, GPRReg arg1)
     1632    {
     1633        m_jit.setupArgumentsWithExecState(arg1);
     1634        return appendCallSetResult(operation, result);
     1635    }
     1636    JITCompiler::Call callOperation(J_JITOperation_EZ operation, GPRReg result, int32_t arg1)
     1637    {
     1638        m_jit.setupArgumentsWithExecState(TrustedImm32(arg1));
     1639        return appendCallSetResult(operation, result);
     1640    }
     1641    JITCompiler::Call callOperation(J_JITOperation_EZZ operation, GPRReg result, int32_t arg1, GPRReg arg2)
     1642    {
     1643        m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2);
     1644        return appendCallSetResult(operation, result);
     1645    }
     1646    JITCompiler::Call callOperation(P_JITOperation_EQZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    16171647    {
    16181648        m_jit.setupArgumentsWithExecState(arg1, arg2);
    16191649        return appendCallSetResult(operation, result);
    16201650    }
    1621     JITCompiler::Call callOperation(J_JITOperation_EP operation, GPRReg result, GPRReg arg1)
     1651    JITCompiler::Call callOperation(P_JITOperation_EQZ operation, GPRReg result, GPRReg arg1, TrustedImm32 arg2)
     1652    {
     1653        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1654        return appendCallSetResult(operation, result);
     1655    }
     1656
     1657    JITCompiler::Call callOperation(J_JITOperation_EZIcfZ operation, GPRReg result, int32_t arg1, InlineCallFrame* inlineCallFrame, GPRReg arg2)
     1658    {
     1659        m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), TrustedImmPtr(inlineCallFrame), arg2);
     1660        return appendCallSetResult(operation, result);
     1661    }
     1662
     1663    JITCompiler::Call callOperation(P_JITOperation_EJS operation, GPRReg result, GPRReg value, size_t index)
     1664    {
     1665        m_jit.setupArgumentsWithExecState(value, TrustedImmPtr(index));
     1666        return appendCallSetResult(operation, result);
     1667    }
     1668
     1669    JITCompiler::Call callOperation(P_JITOperation_EStJ operation, GPRReg result, RegisteredStructure structure, GPRReg arg2)
     1670    {
     1671        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2);
     1672        return appendCallSetResult(operation, result);
     1673    }
     1674
     1675    JITCompiler::Call callOperation(C_JITOperation_EGJ operation, GPRReg result, JSGlobalObject* globalObject, GPRReg arg1)
     1676    {
     1677        m_jit.setupArgumentsWithExecState(TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), arg1);
     1678        return appendCallSetResult(operation, result);
     1679    }
     1680
     1681    JITCompiler::Call callOperation(C_JITOperation_EGJ operation, GPRReg result, JSGlobalObject* globalObject, JSValueRegs arg1)
     1682    {
     1683        return callOperation(operation, result, globalObject, arg1.gpr());
     1684    }
     1685
     1686    JITCompiler::Call callOperation(C_JITOperation_EJ operation, GPRReg result, GPRReg arg1)
    16221687    {
    16231688        m_jit.setupArgumentsWithExecState(arg1);
    16241689        return appendCallSetResult(operation, result);
    16251690    }
    1626     JITCompiler::Call callOperation(J_JITOperation_EZ operation, GPRReg result, GPRReg arg1)
     1691    JITCompiler::Call callOperation(C_JITOperation_EJ operation, GPRReg result, JSValueRegs arg1)
     1692    {
     1693        m_jit.setupArgumentsWithExecState(arg1.gpr());
     1694        return appendCallSetResult(operation, result);
     1695    }
     1696    JITCompiler::Call callOperation(C_JITOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     1697    {
     1698        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1699        return appendCallSetResult(operation, result);
     1700    }
     1701    JITCompiler::Call callOperation(C_JITOperation_EJJC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1702    {
     1703        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     1704        return appendCallSetResult(operation, result);
     1705    }
     1706    JITCompiler::Call callOperation(C_JITOperation_EJJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1707    {
     1708        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     1709        return appendCallSetResult(operation, result);
     1710    }
     1711    JITCompiler::Call callOperation(C_JITOperation_EJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     1712    {
     1713        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1714        return appendCallSetResult(operation, result);
     1715    }
     1716    JITCompiler::Call callOperation(C_JITOperation_EJZC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1717    {
     1718        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     1719        return appendCallSetResult(operation, result);
     1720    }
     1721    JITCompiler::Call callOperation(S_JITOperation_J operation, GPRReg result, GPRReg arg1)
     1722    {
     1723        m_jit.setupArguments(arg1);
     1724        return appendCallSetResult(operation, result);
     1725    }
     1726    JITCompiler::Call callOperation(S_JITOperation_EJ operation, GPRReg result, GPRReg arg1)
    16271727    {
    16281728        m_jit.setupArgumentsWithExecState(arg1);
    16291729        return appendCallSetResult(operation, result);
    16301730    }
    1631     JITCompiler::Call callOperation(J_JITOperation_EZ operation, GPRReg result, int32_t arg1)
    1632     {
    1633         m_jit.setupArgumentsWithExecState(TrustedImm32(arg1));
    1634         return appendCallSetResult(operation, result);
    1635     }
    1636     JITCompiler::Call callOperation(J_JITOperation_EZZ operation, GPRReg result, int32_t arg1, GPRReg arg2)
    1637     {
    1638         m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2);
    1639         return appendCallSetResult(operation, result);
    1640     }
    1641     JITCompiler::Call callOperation(P_JITOperation_EQZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     1731    JITCompiler::Call callOperation(S_JITOperation_EJ operation, GPRReg result, JSValueRegs arg1)
     1732    {
     1733        return callOperation(operation, result, arg1.gpr());
     1734    }
     1735    JITCompiler::Call callOperation(J_JITOperation_EJ operation, JSValueRegs result, JSValueRegs arg1)
     1736    {
     1737        return callOperation(operation, result.payloadGPR(), arg1.payloadGPR());
     1738    }
     1739    JITCompiler::Call callOperation(J_JITOperation_EJ operation, GPRReg result, JSValueRegs arg1)
     1740    {
     1741        return callOperation(operation, result, arg1.payloadGPR());
     1742    }
     1743    JITCompiler::Call callOperation(J_JITOperation_EJ operation, GPRReg result, GPRReg arg1)
     1744    {
     1745        m_jit.setupArgumentsWithExecState(arg1);
     1746        return appendCallSetResult(operation, result);
     1747    }
     1748    JITCompiler::Call callOperation(S_JITOperation_EJI operation, GPRReg result, GPRReg arg1, UniquedStringImpl* uid)
     1749    {
     1750        m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(uid));
     1751        return appendCallSetResult(operation, result);
     1752    }
     1753    JITCompiler::Call callOperation(S_JITOperation_EJI operation, GPRReg result, JSValueRegs arg1, UniquedStringImpl* uid)
     1754    {
     1755        return callOperation(operation, result, arg1.gpr(), uid);
     1756    }
     1757    JITCompiler::Call callOperation(S_JITOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    16421758    {
    16431759        m_jit.setupArgumentsWithExecState(arg1, arg2);
    16441760        return appendCallSetResult(operation, result);
    16451761    }
    1646     JITCompiler::Call callOperation(P_JITOperation_EQZ operation, GPRReg result, GPRReg arg1, TrustedImm32 arg2)
     1762    JITCompiler::Call callOperation(S_JITOperation_EJJ operation, GPRReg result,  JSValueRegs arg1, JSValueRegs arg2)
     1763    {
     1764        return callOperation(operation, result, arg1.gpr(), arg2.gpr());
     1765    }
     1766    JITCompiler::Call callOperation(S_JITOperation_EGJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1767    {
     1768        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     1769        return appendCallSetResult(operation, result);
     1770    }
     1771    JITCompiler::Call callOperation(S_JITOperation_EGReoJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1772    {
     1773        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     1774        return appendCallSetResult(operation, result);
     1775    }
     1776    JITCompiler::Call callOperation(S_JITOperation_EGReoJss operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1777    {
     1778        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     1779        return appendCallSetResult(operation, result);
     1780    }
     1781
     1782    JITCompiler::Call callOperation(J_JITOperation_EPP operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    16471783    {
    16481784        m_jit.setupArgumentsWithExecState(arg1, arg2);
    16491785        return appendCallSetResult(operation, result);
    16501786    }
    1651 
    1652     JITCompiler::Call callOperation(J_JITOperation_EZIcfZ operation, GPRReg result, int32_t arg1, InlineCallFrame* inlineCallFrame, GPRReg arg2)
    1653     {
    1654         m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), TrustedImmPtr(inlineCallFrame), arg2);
    1655         return appendCallSetResult(operation, result);
    1656     }
    1657 
    1658     JITCompiler::Call callOperation(P_JITOperation_EJS operation, GPRReg result, GPRReg value, size_t index)
    1659     {
    1660         m_jit.setupArgumentsWithExecState(value, TrustedImmPtr(index));
    1661         return appendCallSetResult(operation, result);
    1662     }
    1663 
    1664     JITCompiler::Call callOperation(P_JITOperation_EStJ operation, GPRReg result, RegisteredStructure structure, GPRReg arg2)
    1665     {
    1666         m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2);
    1667         return appendCallSetResult(operation, result);
    1668     }
    1669 
    1670     JITCompiler::Call callOperation(C_JITOperation_EGJ operation, GPRReg result, JSGlobalObject* globalObject, GPRReg arg1)
    1671     {
    1672         m_jit.setupArgumentsWithExecState(TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), arg1);
    1673         return appendCallSetResult(operation, result);
    1674     }
    1675 
    1676     JITCompiler::Call callOperation(C_JITOperation_EGJ operation, GPRReg result, JSGlobalObject* globalObject, JSValueRegs arg1)
    1677     {
    1678         return callOperation(operation, result, globalObject, arg1.gpr());
    1679     }
    1680 
    1681     JITCompiler::Call callOperation(C_JITOperation_EJ operation, GPRReg result, GPRReg arg1)
    1682     {
    1683         m_jit.setupArgumentsWithExecState(arg1);
    1684         return appendCallSetResult(operation, result);
    1685     }
    1686     JITCompiler::Call callOperation(C_JITOperation_EJ operation, GPRReg result, JSValueRegs arg1)
    1687     {
    1688         m_jit.setupArgumentsWithExecState(arg1.gpr());
    1689         return appendCallSetResult(operation, result);
    1690     }
    1691     JITCompiler::Call callOperation(C_JITOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     1787    JITCompiler::Call callOperation(J_JITOperation_EPPP operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1788    {
     1789        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     1790        return appendCallSetResult(operation, result);
     1791    }
     1792    JITCompiler::Call callOperation(J_JITOperation_EGP operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    16921793    {
    16931794        m_jit.setupArgumentsWithExecState(arg1, arg2);
    16941795        return appendCallSetResult(operation, result);
    16951796    }
    1696     JITCompiler::Call callOperation(C_JITOperation_EJJC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1797    JITCompiler::Call callOperation(J_JITOperation_EAPZ operation, JSValueRegs result, GPRReg arg1, GPRReg arg2, TrustedImm32 arg3)
    16971798    {
    16981799        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    1699         return appendCallSetResult(operation, result);
    1700     }
    1701     JITCompiler::Call callOperation(C_JITOperation_EJJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     1800        return appendCallSetResult(operation, result.payloadGPR());
     1801    }
     1802    JITCompiler::Call callOperation(J_JITOperation_EAPZ operation, GPRReg result, GPRReg arg1, GPRReg arg2, TrustedImm32 arg3)
    17021803    {
    17031804        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    1704         return appendCallSetResult(operation, result);
    1705     }
    1706     JITCompiler::Call callOperation(C_JITOperation_EJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    1707     {
    1708         m_jit.setupArgumentsWithExecState(arg1, arg2);
    1709         return appendCallSetResult(operation, result);
    1710     }
    1711     JITCompiler::Call callOperation(C_JITOperation_EJZC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
    1712     {
    1713         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    1714         return appendCallSetResult(operation, result);
    1715     }
    1716     JITCompiler::Call callOperation(S_JITOperation_J operation, GPRReg result, GPRReg arg1)
    1717     {
    1718         m_jit.setupArguments(arg1);
    1719         return appendCallSetResult(operation, result);
    1720     }
    1721     JITCompiler::Call callOperation(S_JITOperation_EJ operation, GPRReg result, GPRReg arg1)
    1722     {
    1723         m_jit.setupArgumentsWithExecState(arg1);
    1724         return appendCallSetResult(operation, result);
    1725     }
    1726     JITCompiler::Call callOperation(S_JITOperation_EJ operation, GPRReg result, JSValueRegs arg1)
    1727     {
    1728         return callOperation(operation, result, arg1.gpr());
    1729     }
    1730     JITCompiler::Call callOperation(J_JITOperation_EJ operation, JSValueRegs result, JSValueRegs arg1)
    1731     {
    1732         return callOperation(operation, result.payloadGPR(), arg1.payloadGPR());
    1733     }
    1734     JITCompiler::Call callOperation(J_JITOperation_EJ operation, GPRReg result, JSValueRegs arg1)
    1735     {
    1736         return callOperation(operation, result, arg1.payloadGPR());
    1737     }
    1738     JITCompiler::Call callOperation(J_JITOperation_EJ operation, GPRReg result, GPRReg arg1)
    1739     {
    1740         m_jit.setupArgumentsWithExecState(arg1);
    1741         return appendCallSetResult(operation, result);
    1742     }
    1743     JITCompiler::Call callOperation(S_JITOperation_EJI operation, GPRReg result, GPRReg arg1, UniquedStringImpl* uid)
    1744     {
    1745         m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(uid));
    1746         return appendCallSetResult(operation, result);
    1747     }
    1748     JITCompiler::Call callOperation(S_JITOperation_EJI operation, GPRReg result, JSValueRegs arg1, UniquedStringImpl* uid)
    1749     {
    1750         return callOperation(operation, result, arg1.gpr(), uid);
    1751     }
    1752     JITCompiler::Call callOperation(S_JITOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    1753     {
    1754         m_jit.setupArgumentsWithExecState(arg1, arg2);
    1755         return appendCallSetResult(operation, result);
    1756     }
    1757     JITCompiler::Call callOperation(S_JITOperation_EJJ operation, GPRReg result,  JSValueRegs arg1, JSValueRegs arg2)
    1758     {
    1759         return callOperation(operation, result, arg1.gpr(), arg2.gpr());
    1760     }
    1761     JITCompiler::Call callOperation(S_JITOperation_EGJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
    1762     {
    1763         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    1764         return appendCallSetResult(operation, result);
    1765     }
    1766     JITCompiler::Call callOperation(S_JITOperation_EGReoJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
    1767     {
    1768         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    1769         return appendCallSetResult(operation, result);
    1770     }
    1771     JITCompiler::Call callOperation(S_JITOperation_EGReoJss operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
    1772     {
    1773         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    1774         return appendCallSetResult(operation, result);
    1775     }
    1776 
    1777     JITCompiler::Call callOperation(J_JITOperation_EPP operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    1778     {
    1779         m_jit.setupArgumentsWithExecState(arg1, arg2);
    1780         return appendCallSetResult(operation, result);
    1781     }
    1782     JITCompiler::Call callOperation(J_JITOperation_EPPP operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
    1783     {
    1784         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    1785         return appendCallSetResult(operation, result);
    1786     }
    1787     JITCompiler::Call callOperation(J_JITOperation_EGP operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    1788     {
    1789         m_jit.setupArgumentsWithExecState(arg1, arg2);
    17901805        return appendCallSetResult(operation, result);
    17911806    }
     
    21132128    {
    21142129        m_jit.setupArgumentsWithExecState(arg1, arg2);
     2130        return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
     2131    }
     2132    JITCompiler::Call callOperation(J_JITOperation_EAPZ operation, JSValueRegs result, GPRReg arg1, GPRReg arg2, TrustedImm32 arg3)
     2133    {
     2134        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    21152135        return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
    21162136    }
     
    29282948    void compileArraySlice(Node*);
    29292949    void compileArrayIndexOf(Node*);
     2950    void compileArrayPush(Node*);
    29302951    void compileNotifyWrite(Node*);
    29312952    bool compileRegExpExec(Node*);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r222523 r222563  
    33773377       
    33783378    case ArrayPush: {
    3379         ASSERT(node->arrayMode().isJSArray());
    3380        
    3381         SpeculateCellOperand base(this, node->child1());
    3382         GPRTemporary storageLength(this);
    3383        
    3384         GPRReg baseGPR = base.gpr();
    3385         GPRReg storageLengthGPR = storageLength.gpr();
    3386        
    3387         StorageOperand storage(this, node->child3());
    3388         GPRReg storageGPR = storage.gpr();
    3389        
    3390         switch (node->arrayMode().type()) {
    3391         case Array::Int32: {
    3392             SpeculateInt32Operand value(this, node->child2());
    3393             GPRReg valuePayloadGPR = value.gpr();
    3394            
    3395             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
    3396             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
    3397             m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
    3398             m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
    3399             m_jit.add32(TrustedImm32(1), storageLengthGPR);
    3400             m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
    3401             m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
    3402            
    3403             addSlowPathGenerator(
    3404                 slowPathCall(
    3405                     slowPath, this, operationArrayPush,
    3406                     JSValueRegs(storageGPR, storageLengthGPR),
    3407                     TrustedImm32(JSValue::Int32Tag), valuePayloadGPR, baseGPR));
    3408        
    3409             jsValueResult(storageGPR, storageLengthGPR, node);
    3410             break;
    3411         }
    3412            
    3413         case Array::Contiguous: {
    3414             JSValueOperand value(this, node->child2());
    3415             GPRReg valueTagGPR = value.tagGPR();
    3416             GPRReg valuePayloadGPR = value.payloadGPR();
    3417 
    3418             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
    3419             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
    3420             m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
    3421             m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
    3422             m_jit.add32(TrustedImm32(1), storageLengthGPR);
    3423             m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
    3424             m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
    3425            
    3426             addSlowPathGenerator(
    3427                 slowPathCall(
    3428                     slowPath, this, operationArrayPush,
    3429                     JSValueRegs(storageGPR, storageLengthGPR),
    3430                     JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
    3431        
    3432             jsValueResult(storageGPR, storageLengthGPR, node);
    3433             break;
    3434         }
    3435            
    3436         case Array::Double: {
    3437             SpeculateDoubleOperand value(this, node->child2());
    3438             FPRReg valueFPR = value.fpr();
    3439 
    3440             DFG_TYPE_CHECK(
    3441                 JSValueRegs(), node->child2(), SpecDoubleReal,
    3442                 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
    3443            
    3444             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
    3445             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
    3446             m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
    3447             m_jit.add32(TrustedImm32(1), storageLengthGPR);
    3448             m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
    3449             m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
    3450            
    3451             addSlowPathGenerator(
    3452                 slowPathCall(
    3453                     slowPath, this, operationArrayPushDouble,
    3454                     JSValueRegs(storageGPR, storageLengthGPR),
    3455                     valueFPR, baseGPR));
    3456        
    3457             jsValueResult(storageGPR, storageLengthGPR, node);
    3458             break;
    3459         }
    3460            
    3461         case Array::ArrayStorage: {
    3462             JSValueOperand value(this, node->child2());
    3463             GPRReg valueTagGPR = value.tagGPR();
    3464             GPRReg valuePayloadGPR = value.payloadGPR();
    3465 
    3466             m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
    3467        
    3468             // Refuse to handle bizarre lengths.
    3469             speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
    3470        
    3471             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
    3472        
    3473             m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
    3474             m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
    3475        
    3476             m_jit.add32(TrustedImm32(1), storageLengthGPR);
    3477             m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
    3478             m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
    3479             m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
    3480        
    3481             addSlowPathGenerator(slowPathCall(slowPath, this, operationArrayPush, JSValueRegs(storageGPR, storageLengthGPR),
    3482                 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
    3483        
    3484             jsValueResult(storageGPR, storageLengthGPR, node);
    3485             break;
    3486         }
    3487            
    3488         default:
    3489             CRASH();
    3490             break;
    3491         }
     3379        compileArrayPush(node);
    34923380        break;
    34933381    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r222523 r222563  
    36563656       
    36573657    case ArrayPush: {
    3658         ASSERT(node->arrayMode().isJSArray());
    3659        
    3660         SpeculateCellOperand base(this, node->child1());
    3661         GPRTemporary storageLength(this);
    3662        
    3663         GPRReg baseGPR = base.gpr();
    3664         GPRReg storageLengthGPR = storageLength.gpr();
    3665        
    3666         StorageOperand storage(this, node->child3());
    3667         GPRReg storageGPR = storage.gpr();
    3668 
    3669         switch (node->arrayMode().type()) {
    3670         case Array::Int32:
    3671         case Array::Contiguous: {
    3672             JSValueOperand value(this, node->child2(), ManualOperandSpeculation);
    3673             GPRReg valueGPR = value.gpr();
    3674 
    3675             if (node->arrayMode().type() == Array::Int32) {
    3676                 DFG_TYPE_CHECK(
    3677                     JSValueRegs(valueGPR), node->child2(), SpecInt32Only,
    3678                     m_jit.branch64(
    3679                         MacroAssembler::Below, valueGPR, GPRInfo::tagTypeNumberRegister));
    3680             }
    3681 
    3682             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
    3683             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
    3684             m_jit.store64(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
    3685             m_jit.add32(TrustedImm32(1), storageLengthGPR);
    3686             m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
    3687             m_jit.or64(GPRInfo::tagTypeNumberRegister, storageLengthGPR);
    3688            
    3689             addSlowPathGenerator(
    3690                 slowPathCall(
    3691                     slowPath, this, operationArrayPush, storageLengthGPR,
    3692                     valueGPR, baseGPR));
    3693        
    3694             jsValueResult(storageLengthGPR, node);
    3695             break;
    3696         }
    3697            
    3698         case Array::Double: {
    3699             SpeculateDoubleOperand value(this, node->child2());
    3700             FPRReg valueFPR = value.fpr();
    3701 
    3702             DFG_TYPE_CHECK(
    3703                 JSValueRegs(), node->child2(), SpecDoubleReal,
    3704                 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
    3705            
    3706             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
    3707             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
    3708             m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
    3709             m_jit.add32(TrustedImm32(1), storageLengthGPR);
    3710             m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
    3711             m_jit.or64(GPRInfo::tagTypeNumberRegister, storageLengthGPR);
    3712            
    3713             addSlowPathGenerator(
    3714                 slowPathCall(
    3715                     slowPath, this, operationArrayPushDouble, storageLengthGPR,
    3716                     valueFPR, baseGPR));
    3717        
    3718             jsValueResult(storageLengthGPR, node);
    3719             break;
    3720         }
    3721            
    3722         case Array::ArrayStorage: {
    3723             JSValueOperand value(this, node->child2());
    3724             GPRReg valueGPR = value.gpr();
    3725 
    3726             m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
    3727        
    3728             // Refuse to handle bizarre lengths.
    3729             speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
    3730        
    3731             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
    3732        
    3733             m_jit.store64(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
    3734        
    3735             m_jit.add32(TrustedImm32(1), storageLengthGPR);
    3736             m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
    3737             m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
    3738             m_jit.or64(GPRInfo::tagTypeNumberRegister, storageLengthGPR);
    3739        
    3740             addSlowPathGenerator(
    3741                 slowPathCall(
    3742                     slowPath, this, operationArrayPush, NoResult, storageLengthGPR,
    3743                     valueGPR, baseGPR));
    3744        
    3745             jsValueResult(storageLengthGPR, node);
    3746             break;
    3747         }
    3748            
    3749         default:
    3750             CRASH();
    3751             break;
    3752         }
     3658        compileArrayPush(node);
    37533659        break;
    37543660    }
  • trunk/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp

    r221954 r222563  
    251251                switch (m_node->arrayMode().type()) {
    252252                case Array::Contiguous:
    253                 case Array::ArrayStorage:
    254                     considerBarrier(m_node->child1(), m_node->child2());
     253                case Array::ArrayStorage: {
     254                    unsigned elementOffset = 2;
     255                    unsigned elementCount = m_node->numChildren() - elementOffset;
     256                    Edge& arrayEdge = m_graph.varArgChild(m_node, 1);
     257                    for (unsigned i = 0; i < elementCount; ++i) {
     258                        Edge& element = m_graph.varArgChild(m_node, i + elementOffset);
     259                        considerBarrier(arrayEdge, element);
     260                    }
    255261                    break;
     262                }
    256263                default:
    257264                    break;
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r222523 r222563  
    40834083    void compileArrayPush()
    40844084    {
    4085         LValue base = lowCell(m_node->child1());
    4086         LValue storage = lowStorage(m_node->child3());
    4087        
     4085        LValue base = lowCell(m_graph.varArgChild(m_node, 1));
     4086        LValue storage = lowStorage(m_graph.varArgChild(m_node, 0));
     4087        unsigned elementOffset = 2;
     4088        unsigned elementCount = m_node->numChildren() - elementOffset;
     4089
    40884090        switch (m_node->arrayMode().type()) {
    40894091        case Array::Int32:
    40904092        case Array::Contiguous:
    40914093        case Array::Double: {
    4092             LValue value;
    4093             Output::StoreType storeType;
    4094            
    4095             if (m_node->arrayMode().type() != Array::Double) {
    4096                 value = lowJSValue(m_node->child2(), ManualOperandSpeculation);
    4097                 if (m_node->arrayMode().type() == Array::Int32) {
    4098                     FTL_TYPE_CHECK(
    4099                         jsValueValue(value), m_node->child2(), SpecInt32Only, isNotInt32(value));
     4094            IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
     4095
     4096            if (elementCount == 1) {
     4097                LValue value;
     4098                Output::StoreType storeType;
     4099               
     4100                Edge& element = m_graph.varArgChild(m_node, elementOffset);
     4101                if (m_node->arrayMode().type() != Array::Double) {
     4102                    value = lowJSValue(element, ManualOperandSpeculation);
     4103                    if (m_node->arrayMode().type() == Array::Int32)
     4104                        RELEASE_ASSERT(!m_interpreter.needsTypeCheck(element, SpecInt32Only));
     4105                    storeType = Output::Store64;
     4106                } else {
     4107                    value = lowDouble(element);
     4108                    RELEASE_ASSERT(!m_interpreter.needsTypeCheck(element, SpecDoubleReal));
     4109                    storeType = Output::StoreDouble;
    41004110                }
    4101                 storeType = Output::Store64;
    4102             } else {
    4103                 value = lowDouble(m_node->child2());
    4104                 FTL_TYPE_CHECK(
    4105                     doubleValue(value), m_node->child2(), SpecDoubleReal,
    4106                     m_out.doubleNotEqualOrUnordered(value, value));
    4107                 storeType = Output::StoreDouble;
     4111
     4112                LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
     4113               
     4114                LBasicBlock fastPath = m_out.newBlock();
     4115                LBasicBlock slowPath = m_out.newBlock();
     4116                LBasicBlock continuation = m_out.newBlock();
     4117               
     4118                m_out.branch(
     4119                    m_out.aboveOrEqual(
     4120                        prevLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength)),
     4121                    unsure(slowPath), unsure(fastPath));
     4122               
     4123                LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
     4124                m_out.store(
     4125                    value, m_out.baseIndex(heap, storage, m_out.zeroExtPtr(prevLength)), storeType);
     4126                LValue newLength = m_out.add(prevLength, m_out.int32One);
     4127                m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
     4128               
     4129                ValueFromBlock fastResult = m_out.anchor(boxInt32(newLength));
     4130                m_out.jump(continuation);
     4131               
     4132                m_out.appendTo(slowPath, continuation);
     4133                LValue operation;
     4134                if (m_node->arrayMode().type() != Array::Double)
     4135                    operation = m_out.operation(operationArrayPush);
     4136                else
     4137                    operation = m_out.operation(operationArrayPushDouble);
     4138                ValueFromBlock slowResult = m_out.anchor(
     4139                    vmCall(Int64, operation, m_callFrame, value, base));
     4140                m_out.jump(continuation);
     4141               
     4142                m_out.appendTo(continuation, lastNext);
     4143                setJSValue(m_out.phi(Int64, fastResult, slowResult));
     4144                return;
    41084145            }
    4109            
    4110             IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
    41114146
    41124147            LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
    4113            
     4148            LValue newLength = m_out.add(prevLength, m_out.constInt32(elementCount));
     4149
    41144150            LBasicBlock fastPath = m_out.newBlock();
    41154151            LBasicBlock slowPath = m_out.newBlock();
     4152            LBasicBlock setup = m_out.newBlock();
     4153            LBasicBlock slowCallPath = m_out.newBlock();
    41164154            LBasicBlock continuation = m_out.newBlock();
    4117            
    4118             m_out.branch(
    4119                 m_out.aboveOrEqual(
    4120                     prevLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength)),
    4121                 unsure(slowPath), unsure(fastPath));
    4122            
     4155
     4156            LValue beyondVectorLength = m_out.above(newLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength));
     4157
     4158            m_out.branch(beyondVectorLength, unsure(slowPath), unsure(fastPath));
     4159
    41234160            LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
    4124             m_out.store(
    4125                 value, m_out.baseIndex(heap, storage, m_out.zeroExtPtr(prevLength)), storeType);
    4126             LValue newLength = m_out.add(prevLength, m_out.int32One);
    41274161            m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
    4128            
     4162            ValueFromBlock fastBufferResult = m_out.anchor(m_out.baseIndex(storage, m_out.zeroExtPtr(prevLength), ScaleEight));
     4163            m_out.jump(setup);
     4164
     4165            m_out.appendTo(slowPath, setup);
     4166            size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
     4167            static_assert(sizeof(EncodedJSValue) == sizeof(double), "");
     4168            ASSERT(scratchSize);
     4169            ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
     4170            m_out.storePtr(m_out.constIntPtr(scratchSize), m_out.absolute(scratchBuffer->addressOfActiveLength()));
     4171            ValueFromBlock slowBufferResult = m_out.anchor(m_out.constIntPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
     4172            m_out.jump(setup);
     4173
     4174            m_out.appendTo(setup, slowCallPath);
     4175            LValue buffer = m_out.phi(pointerType(), fastBufferResult, slowBufferResult);
     4176            for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
     4177                Edge& element = m_graph.varArgChild(m_node, elementIndex + elementOffset);
     4178
     4179                LValue value;
     4180                Output::StoreType storeType;
     4181                if (m_node->arrayMode().type() != Array::Double) {
     4182                    value = lowJSValue(element, ManualOperandSpeculation);
     4183                    if (m_node->arrayMode().type() == Array::Int32)
     4184                        RELEASE_ASSERT(!m_interpreter.needsTypeCheck(element, SpecInt32Only));
     4185                    storeType = Output::Store64;
     4186                } else {
     4187                    value = lowDouble(element);
     4188                    RELEASE_ASSERT(!m_interpreter.needsTypeCheck(element, SpecDoubleReal));
     4189                    storeType = Output::StoreDouble;
     4190                }
     4191
     4192                m_out.store(value, m_out.baseIndex(heap, buffer, m_out.constInt32(elementIndex), jsNumber(elementIndex)), storeType);
     4193            }
    41294194            ValueFromBlock fastResult = m_out.anchor(boxInt32(newLength));
    4130             m_out.jump(continuation);
    4131            
    4132             m_out.appendTo(slowPath, continuation);
     4195
     4196            m_out.branch(beyondVectorLength, unsure(slowCallPath), unsure(continuation));
     4197
     4198            m_out.appendTo(slowCallPath, continuation);
    41334199            LValue operation;
    41344200            if (m_node->arrayMode().type() != Array::Double)
    4135                 operation = m_out.operation(operationArrayPush);
     4201                operation = m_out.operation(operationArrayPushMultiple);
    41364202            else
    4137                 operation = m_out.operation(operationArrayPushDouble);
    4138             ValueFromBlock slowResult = m_out.anchor(
    4139                 vmCall(Int64, operation, m_callFrame, value, base));
     4203                operation = m_out.operation(operationArrayPushDoubleMultiple);
     4204            ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, operation, m_callFrame, base, buffer, m_out.constInt32(elementCount)));
     4205            m_out.storePtr(m_out.constIntPtr(0), m_out.absolute(scratchBuffer->addressOfActiveLength()));
    41404206            m_out.jump(continuation);
    4141            
     4207
    41424208            m_out.appendTo(continuation, lastNext);
    41434209            setJSValue(m_out.phi(Int64, fastResult, slowResult));
    41444210            return;
    41454211        }
    4146            
     4212
    41474213        default:
    41484214            DFG_CRASH(m_graph, m_node, "Bad array type");
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r222009 r222563  
    142142typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJC)(ExecState*, EncodedJSValue, JSCell*);
    143143typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
     144typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EAPZ)(ExecState*, JSArray*, void*, int32_t);
    144145typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJArp)(ExecState*, EncodedJSValue, ArithProfile*);
    145146typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJI)(ExecState*, EncodedJSValue, UniquedStringImpl*);
  • trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp

    r222473 r222563  
    765765    JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
    766766
    767     if (isJSArray(thisValue) && exec->argumentCount() == 1) {
     767    if (LIKELY(isJSArray(thisValue) && exec->argumentCount() == 1)) {
    768768        JSArray* array = asArray(thisValue);
    769769        scope.release();
    770         array->push(exec, exec->uncheckedArgument(0));
     770        array->pushInline(exec, exec->uncheckedArgument(0));
    771771        return JSValue::encode(jsNumber(array->length()));
    772772    }
  • trunk/Source/JavaScriptCore/runtime/JSArray.cpp

    r222473 r222563  
    4141namespace JSC {
    4242
    43 static const char* const LengthExceededTheMaximumArrayLengthError = "Length exceeded the maximum array length";
     43const char* const LengthExceededTheMaximumArrayLengthError = "Length exceeded the maximum array length";
    4444
    4545STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSArray);
     
    726726//  - we always are writing beyond the current array bounds, so it is always necessary to update m_length & m_numValuesInVector.
    727727//  - pushing to an array of length 2^32-1 stores the property, but throws a range error.
    728 void JSArray::push(ExecState* exec, JSValue value)
    729 {
    730     VM& vm = exec->vm();
    731     auto scope = DECLARE_THROW_SCOPE(vm);
    732 
    733     Butterfly* butterfly = m_butterfly.getMayBeNull();
    734    
    735     switch (indexingType()) {
    736     case ArrayClass: {
    737         createInitialUndecided(vm, 0);
    738         FALLTHROUGH;
    739     }
    740        
    741     case ArrayWithUndecided: {
    742         convertUndecidedForValue(vm, value);
    743         scope.release();
    744         push(exec, value);
    745         return;
    746     }
    747        
    748     case ArrayWithInt32: {
    749         if (!value.isInt32()) {
    750             convertInt32ForValue(vm, value);
    751             scope.release();
    752             push(exec, value);
    753             return;
    754         }
    755 
    756         unsigned length = butterfly->publicLength();
    757         ASSERT(length <= butterfly->vectorLength());
    758         if (length < butterfly->vectorLength()) {
    759             butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
    760             butterfly->setPublicLength(length + 1);
    761             return;
    762         }
    763        
    764         if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
    765             methodTable(vm)->putByIndex(this, exec, length, value, true);
    766             if (!scope.exception())
    767                 throwException(exec, scope, createRangeError(exec, ASCIILiteral(LengthExceededTheMaximumArrayLengthError)));
    768             return;
    769         }
    770 
    771         scope.release();
    772         putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, length, value);
    773         return;
    774     }
    775 
    776     case ArrayWithContiguous: {
    777         unsigned length = butterfly->publicLength();
    778         ASSERT(length <= butterfly->vectorLength());
    779         if (length < butterfly->vectorLength()) {
    780             butterfly->contiguous()[length].set(vm, this, value);
    781             butterfly->setPublicLength(length + 1);
    782             return;
    783         }
    784        
    785         if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
    786             methodTable(vm)->putByIndex(this, exec, length, value, true);
    787             if (!scope.exception())
    788                 throwException(exec, scope, createRangeError(exec, ASCIILiteral(LengthExceededTheMaximumArrayLengthError)));
    789             return;
    790         }
    791 
    792         scope.release();
    793         putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, length, value);
    794         return;
    795     }
    796        
    797     case ArrayWithDouble: {
    798         if (!value.isNumber()) {
    799             convertDoubleToContiguous(vm);
    800             scope.release();
    801             push(exec, value);
    802             return;
    803         }
    804         double valueAsDouble = value.asNumber();
    805         if (valueAsDouble != valueAsDouble) {
    806             convertDoubleToContiguous(vm);
    807             scope.release();
    808             push(exec, value);
    809             return;
    810         }
    811 
    812         unsigned length = butterfly->publicLength();
    813         ASSERT(length <= butterfly->vectorLength());
    814         if (length < butterfly->vectorLength()) {
    815             butterfly->contiguousDouble()[length] = valueAsDouble;
    816             butterfly->setPublicLength(length + 1);
    817             return;
    818         }
    819        
    820         if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
    821             methodTable(vm)->putByIndex(this, exec, length, value, true);
    822             if (!scope.exception())
    823                 throwException(exec, scope, createRangeError(exec, ASCIILiteral(LengthExceededTheMaximumArrayLengthError)));
    824             return;
    825         }
    826 
    827         scope.release();
    828         putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, length, value);
    829         return;
    830     }
    831        
    832     case ArrayWithSlowPutArrayStorage: {
    833         unsigned oldLength = length();
    834         bool putResult = false;
    835         if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true, putResult)) {
    836             if (!scope.exception() && oldLength < 0xFFFFFFFFu) {
    837                 scope.release();
    838                 setLength(exec, oldLength + 1, true);
    839             }
    840             return;
    841         }
    842         FALLTHROUGH;
    843     }
    844        
    845     case ArrayWithArrayStorage: {
    846         ArrayStorage* storage = butterfly->arrayStorage();
    847 
    848         // Fast case - push within vector, always update m_length & m_numValuesInVector.
    849         unsigned length = storage->length();
    850         if (length < storage->vectorLength()) {
    851             storage->m_vector[length].set(vm, this, value);
    852             storage->setLength(length + 1);
    853             ++storage->m_numValuesInVector;
    854             return;
    855         }
    856 
    857         // Pushing to an array of invalid length (2^31-1) stores the property, but throws a range error.
    858         if (UNLIKELY(storage->length() > MAX_ARRAY_INDEX)) {
    859             methodTable(vm)->putByIndex(this, exec, storage->length(), value, true);
    860             // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
    861             if (!scope.exception())
    862                 throwException(exec, scope, createRangeError(exec, ASCIILiteral(LengthExceededTheMaximumArrayLengthError)));
    863             return;
    864         }
    865 
    866         // Handled the same as putIndex.
    867         scope.release();
    868         putByIndexBeyondVectorLengthWithArrayStorage(exec, storage->length(), value, true, storage);
    869         return;
    870     }
    871        
    872     default:
    873         RELEASE_ASSERT_NOT_REACHED();
    874     }
     728NEVER_INLINE void JSArray::push(ExecState* exec, JSValue value)
     729{
     730    pushInline(exec, value);
    875731}
    876732
  • trunk/Source/JavaScriptCore/runtime/JSArray.h

    r222384 r222563  
    3232class LLIntOffsetsExtractor;
    3333
     34extern const char* const LengthExceededTheMaximumArrayLengthError;
     35
    3436class JSArray : public JSNonFinalObject {
    3537    friend class LLIntOffsetsExtractor;
     
    9193    JS_EXPORT_PRIVATE bool setLength(ExecState*, unsigned, bool throwException = false);
    9294
     95    void pushInline(ExecState*, JSValue);
    9396    JS_EXPORT_PRIVATE void push(ExecState*, JSValue);
    9497    JS_EXPORT_PRIVATE JSValue pop(ExecState*);
  • trunk/Source/JavaScriptCore/runtime/JSArrayInlines.h

    r218449 r222563  
    8181}
    8282
     83ALWAYS_INLINE void JSArray::pushInline(ExecState* exec, JSValue value)
     84{
     85    VM& vm = exec->vm();
     86    auto scope = DECLARE_THROW_SCOPE(vm);
     87
     88    Butterfly* butterfly = m_butterfly.getMayBeNull();
     89
     90    switch (indexingType()) {
     91    case ArrayClass: {
     92        createInitialUndecided(vm, 0);
     93        FALLTHROUGH;
     94    }
     95
     96    case ArrayWithUndecided: {
     97        convertUndecidedForValue(vm, value);
     98        scope.release();
     99        push(exec, value);
     100        return;
     101    }
     102
     103    case ArrayWithInt32: {
     104        if (!value.isInt32()) {
     105            convertInt32ForValue(vm, value);
     106            scope.release();
     107            push(exec, value);
     108            return;
     109        }
     110
     111        unsigned length = butterfly->publicLength();
     112        ASSERT(length <= butterfly->vectorLength());
     113        if (length < butterfly->vectorLength()) {
     114            butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
     115            butterfly->setPublicLength(length + 1);
     116            return;
     117        }
     118
     119        if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
     120            methodTable(vm)->putByIndex(this, exec, length, value, true);
     121            if (!scope.exception())
     122                throwException(exec, scope, createRangeError(exec, ASCIILiteral(LengthExceededTheMaximumArrayLengthError)));
     123            return;
     124        }
     125
     126        scope.release();
     127        putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, length, value);
     128        return;
     129    }
     130
     131    case ArrayWithContiguous: {
     132        unsigned length = butterfly->publicLength();
     133        ASSERT(length <= butterfly->vectorLength());
     134        if (length < butterfly->vectorLength()) {
     135            butterfly->contiguous()[length].set(vm, this, value);
     136            butterfly->setPublicLength(length + 1);
     137            return;
     138        }
     139
     140        if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
     141            methodTable(vm)->putByIndex(this, exec, length, value, true);
     142            if (!scope.exception())
     143                throwException(exec, scope, createRangeError(exec, ASCIILiteral(LengthExceededTheMaximumArrayLengthError)));
     144            return;
     145        }
     146
     147        scope.release();
     148        putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, length, value);
     149        return;
     150    }
     151
     152    case ArrayWithDouble: {
     153        if (!value.isNumber()) {
     154            convertDoubleToContiguous(vm);
     155            scope.release();
     156            push(exec, value);
     157            return;
     158        }
     159        double valueAsDouble = value.asNumber();
     160        if (valueAsDouble != valueAsDouble) {
     161            convertDoubleToContiguous(vm);
     162            scope.release();
     163            push(exec, value);
     164            return;
     165        }
     166
     167        unsigned length = butterfly->publicLength();
     168        ASSERT(length <= butterfly->vectorLength());
     169        if (length < butterfly->vectorLength()) {
     170            butterfly->contiguousDouble()[length] = valueAsDouble;
     171            butterfly->setPublicLength(length + 1);
     172            return;
     173        }
     174
     175        if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
     176            methodTable(vm)->putByIndex(this, exec, length, value, true);
     177            if (!scope.exception())
     178                throwException(exec, scope, createRangeError(exec, ASCIILiteral(LengthExceededTheMaximumArrayLengthError)));
     179            return;
     180        }
     181
     182        scope.release();
     183        putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, length, value);
     184        return;
     185    }
     186
     187    case ArrayWithSlowPutArrayStorage: {
     188        unsigned oldLength = length();
     189        bool putResult = false;
     190        if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true, putResult)) {
     191            if (!scope.exception() && oldLength < 0xFFFFFFFFu) {
     192                scope.release();
     193                setLength(exec, oldLength + 1, true);
     194            }
     195            return;
     196        }
     197        FALLTHROUGH;
     198    }
     199
     200    case ArrayWithArrayStorage: {
     201        ArrayStorage* storage = butterfly->arrayStorage();
     202
     203        // Fast case - push within vector, always update m_length & m_numValuesInVector.
     204        unsigned length = storage->length();
     205        if (length < storage->vectorLength()) {
     206            storage->m_vector[length].set(vm, this, value);
     207            storage->setLength(length + 1);
     208            ++storage->m_numValuesInVector;
     209            return;
     210        }
     211
     212        // Pushing to an array of invalid length (2^31-1) stores the property, but throws a range error.
     213        if (UNLIKELY(storage->length() > MAX_ARRAY_INDEX)) {
     214            methodTable(vm)->putByIndex(this, exec, storage->length(), value, true);
     215            // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
     216            if (!scope.exception())
     217                throwException(exec, scope, createRangeError(exec, ASCIILiteral(LengthExceededTheMaximumArrayLengthError)));
     218            return;
     219        }
     220
     221        // Handled the same as putIndex.
     222        scope.release();
     223        putByIndexBeyondVectorLengthWithArrayStorage(exec, storage->length(), value, true, storage);
     224        return;
     225    }
     226
     227    default:
     228        RELEASE_ASSERT_NOT_REACHED();
     229    }
     230}
     231
    83232} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.