Changeset 218084 in webkit


Ignore:
Timestamp:
Jun 11, 2017 8:58:23 PM (7 years ago)
Author:
Yusuke Suzuki
Message:

[DFG] Add ArrayIndexOf intrinsic
https://bugs.webkit.org/show_bug.cgi?id=172421

Reviewed by Saam Barati.

JSTests:

  • stress/array-indexof-array-prototype-change.js: Added.

(shouldBe):
(indexOfInt32):

  • stress/array-indexof-have-a-bad-time-getter.js: Added.

(shouldBe):
(indexOfInt32):

  • stress/array-indexof-have-a-bad-time.js: Added.

(shouldBe):
(indexOfInt32):

  • stress/array-indexof-hole-with-prototype.js: Added.

(shouldBe):
(indexOf):

  • stress/array-indexof-hole.js: Added.

(shouldBe):
(indexOf):

  • stress/array-indexof-index.js: Added.

(shouldBe):
(indexOfInt32):
(indexOfDouble):
(indexOfString):
(indexOfObject):
(indexOfValue):

  • stress/array-indexof-negative-index.js: Added.

(shouldBe):
(indexOfInt32):
(indexOfDouble):
(indexOfString):
(indexOfObject):
(indexOfValue):

  • stress/array-indexof-non-int32-start-index.js: Added.

(shouldBe):
(indexOf):
(object.valueOf):

  • stress/array-indexof-object-prototype-change.js: Added.

(shouldBe):
(indexOfInt32):

  • stress/array-indexof-object.js: Added.

(shouldBe):
(indexOf):

  • stress/array-indexof-original-array.js: Added.

(shouldBe):
(indexOfInt32):

  • stress/array-indexof-string.js: Added.

(shouldBe):
(indexOf):

  • stress/array-indexof-structure-change-convert.js: Added.

(shouldBe):
(indexOf):

  • stress/array-indexof-structure-change.js: Added.

(shouldBe):
(indexOf):

  • stress/array-indexof.js: Added.

(shouldBe):
(indexOf):

Source/JavaScriptCore:

This patch introduces ArrayIndexOfInstrinsic for DFG and FTL optimizations.
We emit array check and go fast path if the array is Array::Int32, Array::Double
or Array::Continugous. In addition, for Array::Int32 and Array::Double case,
we have inlined fast paths.

With updated ARES-6 Babylon,

Before

firstIteration: 45.76 +- 3.87 ms
averageWorstCase: 24.41 +- 2.17 ms
steadyState: 8.01 +- 0.22 ms

After

firstIteration: 45.64 +- 4.23 ms
averageWorstCase: 23.03 +- 3.34 ms
steadyState: 7.33 +- 0.34 ms

In SixSpeed.

baseline patched

map-set-lookup.es5 734.4701+-10.4383 102.0968+-2.6357 definitely 7.1939x faster
map-set.es5 41.1396+-1.0558 33.1916+-0.7986 definitely 1.2395x faster
map-set-object.es5 62.8317+-1.2518 45.6944+-0.8369 definitely 1.3750x faster

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasArrayMode):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileArrayIndexOf):
(JSC::DFG::SpeculativeJIT::speculateObject):

  • dfg/DFGSpeculativeJIT.h:

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

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileArrayIndexOf):

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

(JSC::ArrayPrototype::finishCreation):

  • runtime/Intrinsic.cpp:

(JSC::intrinsicName):

  • runtime/Intrinsic.h:
Location:
trunk
Files:
15 added
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r218082 r218084  
     12017-06-09  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DFG] Add ArrayIndexOf intrinsic
     4        https://bugs.webkit.org/show_bug.cgi?id=172421
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/array-indexof-array-prototype-change.js: Added.
     9        (shouldBe):
     10        (indexOfInt32):
     11        * stress/array-indexof-have-a-bad-time-getter.js: Added.
     12        (shouldBe):
     13        (indexOfInt32):
     14        * stress/array-indexof-have-a-bad-time.js: Added.
     15        (shouldBe):
     16        (indexOfInt32):
     17        * stress/array-indexof-hole-with-prototype.js: Added.
     18        (shouldBe):
     19        (indexOf):
     20        * stress/array-indexof-hole.js: Added.
     21        (shouldBe):
     22        (indexOf):
     23        * stress/array-indexof-index.js: Added.
     24        (shouldBe):
     25        (indexOfInt32):
     26        (indexOfDouble):
     27        (indexOfString):
     28        (indexOfObject):
     29        (indexOfValue):
     30        * stress/array-indexof-negative-index.js: Added.
     31        (shouldBe):
     32        (indexOfInt32):
     33        (indexOfDouble):
     34        (indexOfString):
     35        (indexOfObject):
     36        (indexOfValue):
     37        * stress/array-indexof-non-int32-start-index.js: Added.
     38        (shouldBe):
     39        (indexOf):
     40        (object.valueOf):
     41        * stress/array-indexof-object-prototype-change.js: Added.
     42        (shouldBe):
     43        (indexOfInt32):
     44        * stress/array-indexof-object.js: Added.
     45        (shouldBe):
     46        (indexOf):
     47        * stress/array-indexof-original-array.js: Added.
     48        (shouldBe):
     49        (indexOfInt32):
     50        * stress/array-indexof-string.js: Added.
     51        (shouldBe):
     52        (indexOf):
     53        * stress/array-indexof-structure-change-convert.js: Added.
     54        (shouldBe):
     55        (indexOf):
     56        * stress/array-indexof-structure-change.js: Added.
     57        (shouldBe):
     58        (indexOf):
     59        * stress/array-indexof.js: Added.
     60        (shouldBe):
     61        (indexOf):
     62
    1632017-06-11  Keith Miller  <keith_miller@apple.com>
    264
  • trunk/Source/JavaScriptCore/ChangeLog

    r218082 r218084  
     12017-06-09  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DFG] Add ArrayIndexOf intrinsic
     4        https://bugs.webkit.org/show_bug.cgi?id=172421
     5
     6        Reviewed by Saam Barati.
     7
     8        This patch introduces ArrayIndexOfInstrinsic for DFG and FTL optimizations.
     9        We emit array check and go fast path if the array is Array::Int32, Array::Double
     10        or Array::Continugous. In addition, for Array::Int32 and Array::Double case,
     11        we have inlined fast paths.
     12
     13        With updated ARES-6 Babylon,
     14
     15        Before
     16            firstIteration:     45.76 +- 3.87 ms
     17            averageWorstCase:   24.41 +- 2.17 ms
     18            steadyState:        8.01 +- 0.22 ms
     19        After
     20            firstIteration:     45.64 +- 4.23 ms
     21            averageWorstCase:   23.03 +- 3.34 ms
     22            steadyState:        7.33 +- 0.34 ms
     23
     24        In SixSpeed.
     25                                         baseline                  patched
     26
     27            map-set-lookup.es5      734.4701+-10.4383    ^    102.0968+-2.6357        ^ definitely 7.1939x faster
     28            map-set.es5              41.1396+-1.0558     ^     33.1916+-0.7986        ^ definitely 1.2395x faster
     29            map-set-object.es5       62.8317+-1.2518     ^     45.6944+-0.8369        ^ definitely 1.3750x faster
     30
     31        * dfg/DFGAbstractInterpreterInlines.h:
     32        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     33        * dfg/DFGByteCodeParser.cpp:
     34        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     35        * dfg/DFGClobberize.h:
     36        (JSC::DFG::clobberize):
     37        * dfg/DFGDoesGC.cpp:
     38        (JSC::DFG::doesGC):
     39        * dfg/DFGFixupPhase.cpp:
     40        (JSC::DFG::FixupPhase::fixupNode):
     41        * dfg/DFGNode.h:
     42        (JSC::DFG::Node::hasArrayMode):
     43        * dfg/DFGNodeType.h:
     44        * dfg/DFGOperations.cpp:
     45        * dfg/DFGOperations.h:
     46        * dfg/DFGPredictionPropagationPhase.cpp:
     47        * dfg/DFGSafeToExecute.h:
     48        (JSC::DFG::safeToExecute):
     49        * dfg/DFGSpeculativeJIT.cpp:
     50        (JSC::DFG::SpeculativeJIT::compileArrayIndexOf):
     51        (JSC::DFG::SpeculativeJIT::speculateObject):
     52        * dfg/DFGSpeculativeJIT.h:
     53        (JSC::DFG::SpeculativeJIT::callOperation):
     54        * dfg/DFGSpeculativeJIT32_64.cpp:
     55        (JSC::DFG::SpeculativeJIT::compile):
     56        * dfg/DFGSpeculativeJIT64.cpp:
     57        (JSC::DFG::SpeculativeJIT::compile):
     58        (JSC::DFG::SpeculativeJIT::speculateInt32):
     59        * ftl/FTLCapabilities.cpp:
     60        (JSC::FTL::canCompile):
     61        * ftl/FTLLowerDFGToB3.cpp:
     62        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     63        (JSC::FTL::DFG::LowerDFGToB3::compileArrayIndexOf):
     64        * jit/JITOperations.h:
     65        * runtime/ArrayPrototype.cpp:
     66        (JSC::ArrayPrototype::finishCreation):
     67        * runtime/Intrinsic.cpp:
     68        (JSC::intrinsicName):
     69        * runtime/Intrinsic.h:
     70
    1712017-06-11  Keith Miller  <keith_miller@apple.com>
    272
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r217523 r218084  
    17071707
    17081708        forNode(node).set(m_graph, structureSet);
     1709        break;
     1710    }
     1711
     1712    case ArrayIndexOf: {
     1713        forNode(node).setType(SpecInt32Only);
    17091714        break;
    17101715    }
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r217840 r218084  
    23242324
    23252325            // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole.
     2326            // https://bugs.webkit.org/show_bug.cgi?id=173171
    23262327            if (globalObject->arraySpeciesWatchpoint().state() == IsWatched
    23272328                && globalObject->havingABadTimeWatchpoint()->isStillValid()
     
    23792380        RELEASE_ASSERT_NOT_REACHED();
    23802381        return false;
     2382    }
     2383
     2384    case ArrayIndexOfIntrinsic: {
     2385        if (argumentCountIncludingThis < 2)
     2386            return false;
     2387
     2388        if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)
     2389            || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
     2390            || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)
     2391            || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
     2392            return false;
     2393
     2394        ArrayMode arrayMode = getArrayMode(m_currentInstruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile);
     2395        if (!arrayMode.isJSArray())
     2396            return false;
     2397
     2398        if (arrayMode.arrayClass() != Array::OriginalArray)
     2399            return false;
     2400
     2401        // We do not want to convert arrays into one type just to perform indexOf.
     2402        if (arrayMode.doesConversion())
     2403            return false;
     2404
     2405        switch (arrayMode.type()) {
     2406        case Array::Double:
     2407        case Array::Int32:
     2408        case Array::Contiguous: {
     2409            JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic);
     2410
     2411            InlineWatchpointSet& objectPrototypeTransition = globalObject->objectPrototype()->structure()->transitionWatchpointSet();
     2412            InlineWatchpointSet& arrayPrototypeTransition = globalObject->arrayPrototype()->structure()->transitionWatchpointSet();
     2413
     2414            // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole.
     2415            // https://bugs.webkit.org/show_bug.cgi?id=173171
     2416            if (globalObject->havingABadTimeWatchpoint()->isStillValid()
     2417                && arrayPrototypeTransition.isStillValid()
     2418                && objectPrototypeTransition.isStillValid()
     2419                && globalObject->arrayPrototypeChainIsSane()) {
     2420
     2421                m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
     2422                m_graph.watchpoints().addLazily(arrayPrototypeTransition);
     2423                m_graph.watchpoints().addLazily(objectPrototypeTransition);
     2424
     2425                insertChecks();
     2426
     2427                Node* array = get(virtualRegisterForArgument(0, registerOffset));
     2428                addVarArgChild(array);
     2429                addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Search element.
     2430                if (argumentCountIncludingThis >= 3)
     2431                    addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // Start index.
     2432                addVarArgChild(nullptr);
     2433
     2434                Node* node = addToGraph(Node::VarArg, ArrayIndexOf, OpInfo(arrayMode.asWord()), OpInfo());
     2435                set(VirtualRegister(resultOperand), node);
     2436                return true;
     2437            }
     2438
     2439            return false;
     2440        }
     2441        default:
     2442            return false;
     2443        }
     2444
     2445        RELEASE_ASSERT_NOT_REACHED();
     2446        return false;
     2447
    23812448    }
    23822449       
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r217523 r218084  
    539539        write(HeapObjectCount);
    540540        return;
     541
     542    case ArrayIndexOf: {
     543        // FIXME: Should support a CSE rule.
     544        // https://bugs.webkit.org/show_bug.cgi?id=173173
     545        read(MiscFields);
     546        read(JSCell_indexingType);
     547        read(JSCell_structureID);
     548        read(JSObject_butterfly);
     549        read(Butterfly_publicLength);
     550        switch (node->arrayMode().type()) {
     551        case Array::Double:
     552            read(IndexedDoubleProperties);
     553            return;
     554        case Array::Int32:
     555            read(IndexedInt32Properties);
     556            return;
     557        case Array::Contiguous:
     558            read(IndexedContiguousProperties);
     559            return;
     560        default:
     561            RELEASE_ASSERT_NOT_REACHED();
     562            return;
     563        }
     564        return;
     565    }
    541566       
    542567    case GetById:
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r217202 r218084  
    321321    case CallDOM:
    322322    case ArraySlice:
     323    case ArrayIndexOf:
    323324    case ParseInt: // We might resolve a rope even though we don't clobber anything.
    324325        return true;
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r217523 r218084  
    10211021            if (node->numChildren() == 4)
    10221022                fixEdge<Int32Use>(m_graph.varArgChild(node, 2));
     1023            break;
     1024        }
     1025
     1026        case ArrayIndexOf: {
     1027            Edge& array = m_graph.varArgChild(node, 0);
     1028            Edge& storage = m_graph.varArgChild(node, node->numChildren() == 3 ? 2 : 3);
     1029            blessArrayOperation(array, Edge(), storage);
     1030            ASSERT_WITH_MESSAGE(storage.node(), "blessArrayOperation for ArrayIndexOf must set Butterfly for storage edge.");
     1031
     1032            fixEdge<KnownCellUse>(array);
     1033            if (node->numChildren() == 4)
     1034                fixEdge<Int32Use>(m_graph.varArgChild(node, 2));
     1035
     1036            Edge& searchElement = m_graph.varArgChild(node, 1);
     1037            // FIXME: We have a chance to constant-fold this node to -1 by
     1038            // emitting non number edge filters.
     1039            // https://bugs.webkit.org/show_bug.cgi?id=173176
     1040            switch (node->arrayMode().type()) {
     1041            case Array::Double: {
     1042                if (searchElement->shouldSpeculateNumber())
     1043                    fixEdge<DoubleRepUse>(searchElement);
     1044                break;
     1045            }
     1046            case Array::Int32: {
     1047                if (searchElement->shouldSpeculateInt32())
     1048                    fixEdge<Int32Use>(searchElement);
     1049                break;
     1050            }
     1051            case Array::Contiguous: {
     1052                if (searchElement->shouldSpeculateString())
     1053                    fixEdge<StringUse>(searchElement);
     1054                else if (searchElement->shouldSpeculateObject())
     1055                    fixEdge<ObjectUse>(searchElement);
     1056                break;
     1057            }
     1058            default:
     1059                RELEASE_ASSERT_NOT_REACHED();
     1060                break;
     1061            }
    10231062            break;
    10241063        }
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r217523 r218084  
    18191819        case ArrayPush:
    18201820        case ArrayPop:
     1821        case ArrayIndexOf:
    18211822        case HasIndexedProperty:
    18221823        case AtomicsAdd:
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r217202 r218084  
    263263    macro(ArrayPop, NodeResultJS | NodeMustGenerate) \
    264264    macro(ArraySlice, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
     265    macro(ArrayIndexOf, NodeResultInt32 | NodeHasVarArgs) \
    265266    \
    266267    /* Optimizations for regular expression matching. */\
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r217202 r218084  
    19061906}
    19071907
     1908int32_t JIT_OPERATION operationArrayIndexOfString(ExecState* exec, Butterfly* butterfly, JSString* searchElement, int32_t index)
     1909{
     1910    VM& vm = exec->vm();
     1911    NativeCallFrameTracer tracer(&vm, exec);
     1912    auto scope = DECLARE_THROW_SCOPE(vm);
     1913
     1914    int32_t length = butterfly->publicLength();
     1915    auto data = butterfly->contiguous().data();
     1916    for (; index < length; ++index) {
     1917        JSValue value = data[index].get();
     1918        if (!value || !value.isString())
     1919            continue;
     1920        auto* string = asString(value);
     1921        if (string == searchElement)
     1922            return index;
     1923        if (string->equal(exec, searchElement))
     1924            return index;
     1925        RETURN_IF_EXCEPTION(scope, { });
     1926    }
     1927    return -1;
     1928}
     1929
     1930int32_t JIT_OPERATION operationArrayIndexOfValueInt32OrContiguous(ExecState* exec, Butterfly* butterfly, EncodedJSValue encodedValue, int32_t index)
     1931{
     1932    VM& vm = exec->vm();
     1933    NativeCallFrameTracer tracer(&vm, exec);
     1934    auto scope = DECLARE_THROW_SCOPE(vm);
     1935
     1936    JSValue searchElement = JSValue::decode(encodedValue);
     1937
     1938    int32_t length = butterfly->publicLength();
     1939    auto data = butterfly->contiguous().data();
     1940    for (; index < length; ++index) {
     1941        JSValue value = data[index].get();
     1942        if (!value)
     1943            continue;
     1944        if (JSValue::strictEqual(exec, searchElement, value))
     1945            return index;
     1946        RETURN_IF_EXCEPTION(scope, { });
     1947    }
     1948    return -1;
     1949}
     1950
     1951int32_t JIT_OPERATION operationArrayIndexOfValueDouble(ExecState* exec, Butterfly* butterfly, EncodedJSValue encodedValue, int32_t index)
     1952{
     1953    VM& vm = exec->vm();
     1954    NativeCallFrameTracer tracer(&vm, exec);
     1955
     1956    JSValue searchElement = JSValue::decode(encodedValue);
     1957
     1958    if (!searchElement.isNumber())
     1959        return -1;
     1960    double number = searchElement.asNumber();
     1961
     1962    int32_t length = butterfly->publicLength();
     1963    const double* data = butterfly->contiguousDouble().data();
     1964    for (; index < length; ++index) {
     1965        // This comparison ignores NaN.
     1966        if (data[index] == number)
     1967            return index;
     1968    }
     1969    return -1;
     1970}
     1971
    19081972void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum)
    19091973{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r217202 r218084  
    206206int32_t JIT_OPERATION operationHasOwnProperty(ExecState*, JSObject*, EncodedJSValue);
    207207
     208int32_t JIT_OPERATION operationArrayIndexOfString(ExecState*, Butterfly*, JSString*, int32_t);
     209int32_t JIT_OPERATION operationArrayIndexOfValue(ExecState*, Butterfly*, EncodedJSValue, int32_t);
     210int32_t JIT_OPERATION operationArrayIndexOfValueDouble(ExecState*, Butterfly*, EncodedJSValue, int32_t);
     211int32_t JIT_OPERATION operationArrayIndexOfValueInt32OrContiguous(ExecState*, Butterfly*, EncodedJSValue, int32_t);
     212
    208213JSCell* JIT_OPERATION operationSpreadFastArray(ExecState*, JSCell*);
    209214JSCell* JIT_OPERATION operationSpreadGeneric(ExecState*, JSCell*);
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r217202 r218084  
    763763            break;
    764764
    765         case GetRestLength: {
     765        case GetRestLength:
     766        case ArrayIndexOf: {
    766767            setPrediction(SpecInt32Only);
    767768            break;
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r217202 r218084  
    393393        return true;
    394394
    395     case ArraySlice: {
     395    case ArraySlice:
     396    case ArrayIndexOf: {
    396397        // You could plausibly move this code around as long as you proved the
    397398        // incoming array base structure is an original array at the hoisted location.
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r217523 r218084  
    74437443}
    74447444
     7445void SpeculativeJIT::compileArrayIndexOf(Node* node)
     7446{
     7447    ASSERT(node->op() == ArrayIndexOf);
     7448
     7449    StorageOperand storage(this, m_jit.graph().varArgChild(node, node->numChildren() == 3 ? 2 : 3));
     7450    GPRTemporary index(this);
     7451    GPRTemporary tempLength(this);
     7452
     7453    GPRReg storageGPR = storage.gpr();
     7454    GPRReg indexGPR = index.gpr();
     7455    GPRReg lengthGPR = tempLength.gpr();
     7456
     7457    m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
     7458
     7459    if (node->numChildren() == 4) {
     7460        SpeculateInt32Operand startIndex(this, m_jit.graph().varArgChild(node, 2));
     7461        GPRReg startIndexGPR = startIndex.gpr();
     7462        MacroAssembler::JumpList done;
     7463        auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, startIndexGPR, TrustedImm32(0));
     7464        m_jit.move(lengthGPR, indexGPR);
     7465        done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, startIndexGPR, indexGPR));
     7466        m_jit.move(TrustedImm32(0), indexGPR);
     7467        done.append(m_jit.jump());
     7468
     7469        isPositive.link(&m_jit);
     7470        m_jit.move(startIndexGPR, indexGPR);
     7471        done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, indexGPR, lengthGPR));
     7472        m_jit.move(lengthGPR, indexGPR);
     7473
     7474        done.link(&m_jit);
     7475    } else
     7476        m_jit.move(TrustedImm32(0), indexGPR);
     7477
     7478    Edge& searchElementEdge = m_jit.graph().varArgChild(node, 1);
     7479    switch (searchElementEdge.useKind()) {
     7480    case Int32Use:
     7481    case ObjectUse: {
     7482        auto emitLoop = [&] (auto emitCompare) {
     7483            m_jit.zeroExtend32ToPtr(lengthGPR, lengthGPR);
     7484            m_jit.zeroExtend32ToPtr(indexGPR, indexGPR);
     7485
     7486            auto loop = m_jit.label();
     7487            auto notFound = m_jit.branch32(CCallHelpers::Equal, indexGPR, lengthGPR);
     7488
     7489            auto found = emitCompare();
     7490
     7491            m_jit.add32(TrustedImm32(1), indexGPR);
     7492            m_jit.jump().linkTo(loop, &m_jit);
     7493
     7494            notFound.link(&m_jit);
     7495            m_jit.move(TrustedImm32(-1), indexGPR);
     7496            found.link(&m_jit);
     7497            int32Result(indexGPR, node);
     7498        };
     7499
     7500#if USE(JSVALUE32_64)
     7501        GPRTemporary temp(this);
     7502        GPRReg tempGPR = temp.gpr();
     7503#endif
     7504
     7505        if (searchElementEdge.useKind() == Int32Use) {
     7506            ASSERT(node->arrayMode().type() == Array::Int32);
     7507#if USE(JSVALUE64)
     7508            JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation);
     7509            JSValueRegs searchElementRegs = searchElement.jsValueRegs();
     7510            speculateInt32(searchElementEdge, searchElementRegs);
     7511            GPRReg searchElementGPR = searchElementRegs.payloadGPR();
     7512#else
     7513            SpeculateInt32Operand searchElement(this, searchElementEdge);
     7514            GPRReg searchElementGPR = searchElement.gpr();
     7515#endif
     7516            emitLoop([&] () {
     7517#if USE(JSVALUE64)
     7518                auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
     7519#else
     7520                auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::Int32Tag));
     7521                m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
     7522                auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
     7523                skip.link(&m_jit);
     7524#endif
     7525                return found;
     7526            });
     7527        } else {
     7528            ASSERT(node->arrayMode().type() == Array::Contiguous);
     7529            SpeculateCellOperand searchElement(this, searchElementEdge);
     7530            GPRReg searchElementGPR = searchElement.gpr();
     7531            speculateObject(searchElementEdge, searchElementGPR);
     7532
     7533            emitLoop([&] () {
     7534#if USE(JSVALUE64)
     7535                auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
     7536#else
     7537                auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::CellTag));
     7538                m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
     7539                auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
     7540                skip.link(&m_jit);
     7541#endif
     7542                return found;
     7543            });
     7544        }
     7545        break;
     7546    }
     7547
     7548    case DoubleRepUse: {
     7549        ASSERT(node->arrayMode().type() == Array::Double);
     7550        SpeculateDoubleOperand searchElement(this, searchElementEdge);
     7551        FPRTemporary tempDouble(this);
     7552
     7553        FPRReg searchElementFPR = searchElement.fpr();
     7554        FPRReg tempFPR = tempDouble.fpr();
     7555
     7556        m_jit.zeroExtend32ToPtr(lengthGPR, lengthGPR);
     7557        m_jit.zeroExtend32ToPtr(indexGPR, indexGPR);
     7558
     7559        auto loop = m_jit.label();
     7560        auto notFound = m_jit.branch32(CCallHelpers::Equal, indexGPR, lengthGPR);
     7561        m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), tempFPR);
     7562        auto found = m_jit.branchDouble(CCallHelpers::DoubleEqual, tempFPR, searchElementFPR);
     7563        m_jit.add32(TrustedImm32(1), indexGPR);
     7564        m_jit.jump().linkTo(loop, &m_jit);
     7565
     7566        notFound.link(&m_jit);
     7567        m_jit.move(TrustedImm32(-1), indexGPR);
     7568        found.link(&m_jit);
     7569        int32Result(indexGPR, node);
     7570        break;
     7571    }
     7572
     7573    case StringUse: {
     7574        ASSERT(node->arrayMode().type() == Array::Contiguous);
     7575        SpeculateCellOperand searchElement(this, searchElementEdge);
     7576
     7577        GPRReg searchElementGPR = searchElement.gpr();
     7578
     7579        speculateString(searchElementEdge, searchElementGPR);
     7580
     7581        flushRegisters();
     7582
     7583        callOperation(operationArrayIndexOfString, lengthGPR, storageGPR, searchElementGPR, indexGPR);
     7584        m_jit.exceptionCheck();
     7585
     7586        int32Result(lengthGPR, node);
     7587        break;
     7588    }
     7589
     7590    case UntypedUse: {
     7591        JSValueOperand searchElement(this, searchElementEdge);
     7592
     7593        JSValueRegs searchElementRegs = searchElement.jsValueRegs();
     7594
     7595        flushRegisters();
     7596        switch (node->arrayMode().type()) {
     7597        case Array::Double:
     7598            callOperation(operationArrayIndexOfValueDouble, lengthGPR, storageGPR, searchElementRegs, indexGPR);
     7599            break;
     7600        case Array::Int32:
     7601        case Array::Contiguous:
     7602            callOperation(operationArrayIndexOfValueInt32OrContiguous, lengthGPR, storageGPR, searchElementRegs, indexGPR);
     7603            break;
     7604        default:
     7605            RELEASE_ASSERT_NOT_REACHED();
     7606            break;
     7607        }
     7608        m_jit.exceptionCheck();
     7609
     7610        int32Result(lengthGPR, node);
     7611        break;
     7612    }
     7613
     7614    default:
     7615        RELEASE_ASSERT_NOT_REACHED();
     7616        break;
     7617    }
     7618}
     7619
    74457620void SpeculativeJIT::compileNotifyWrite(Node* node)
    74467621{
     
    84298604}
    84308605
     8606void SpeculativeJIT::speculateObject(Edge edge, GPRReg cell)
     8607{
     8608    DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, SpecObject, m_jit.branchIfNotObject(cell));
     8609}
     8610
    84318611void SpeculativeJIT::speculateObject(Edge edge)
    84328612{
     
    84358615   
    84368616    SpeculateCellOperand operand(this, edge);
    8437     GPRReg gpr = operand.gpr();
    8438     DFG_TYPE_CHECK(
    8439         JSValueSource::unboxedCell(gpr), edge, SpecObject, m_jit.branchIfNotObject(gpr));
     8617    speculateObject(edge, operand.gpr());
    84408618}
    84418619
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r217202 r218084  
    10071007        return appendCallSetResult(operation, result);
    10081008    }
     1009    JITCompiler::Call callOperation(Z_JITOperation_EBJssZ operation, GPRReg result, GPRReg butterfly, GPRReg string, GPRReg index)
     1010    {
     1011        m_jit.setupArgumentsWithExecState(butterfly, string, index);
     1012        return appendCallSetResult(operation, result);
     1013    }
    10091014    JITCompiler::Call callOperation(P_JITOperation_ESt operation, GPRReg result, RegisteredStructure structure)
    10101015    {
     
    18861891    {
    18871892        m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2));
     1893        return appendCallSetResult(operation, result);
     1894    }
     1895    JITCompiler::Call callOperation(Z_JITOperation_EBJZ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2, GPRReg arg3)
     1896    {
     1897        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg3);
    18881898        return appendCallSetResult(operation, result);
    18891899    }
     
    24192429    {
    24202430        m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1.payloadGPR(), arg1.tagGPR(), TrustedImm32(arg2));
     2431        return appendCallSetResult(operation, result);
     2432    }
     2433    JITCompiler::Call callOperation(Z_JITOperation_EBJZ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2, GPRReg arg3)
     2434    {
     2435        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR(), arg3);
    24212436        return appendCallSetResult(operation, result);
    24222437    }
     
    28302845    void compileGetRestLength(Node*);
    28312846    void compileArraySlice(Node*);
     2847    void compileArrayIndexOf(Node*);
    28322848    void compileNotifyWrite(Node*);
    28332849    bool compileRegExpExec(Node*);
     
    29502966    void convertAnyInt(Edge, GPRReg resultGPR);
    29512967    void speculateAnyInt(Edge);
     2968    void speculateInt32(Edge, JSValueRegs);
    29522969    void speculateDoubleRepAnyInt(Edge);
    29532970#endif // USE(JSVALUE64)
     
    29582975    void speculateCell(Edge);
    29592976    void speculateCellOrOther(Edge);
     2977    void speculateObject(Edge, GPRReg cell);
    29602978    void speculateObject(Edge);
    29612979    void speculateArray(Edge, GPRReg cell);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r217202 r218084  
    35843584    }
    35853585
     3586    case ArrayIndexOf: {
     3587        compileArrayIndexOf(node);
     3588        break;
     3589    }
     3590
    35863591    case DFG::Jump: {
    35873592        jump(node->targetBlock());
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r217896 r218084  
    37203720    case ArraySlice: {
    37213721        compileArraySlice(node);
     3722        break;
     3723    }
     3724
     3725    case ArrayIndexOf: {
     3726        compileArrayIndexOf(node);
    37223727        break;
    37233728    }
     
    61696174}
    61706175
     6176void SpeculativeJIT::speculateInt32(Edge edge, JSValueRegs regs)
     6177{
     6178    DFG_TYPE_CHECK(regs, edge, SpecInt32Only, m_jit.branchIfNotInt32(regs));
     6179}
     6180
    61716181void SpeculativeJIT::speculateDoubleRepAnyInt(Edge edge)
    61726182{
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r217202 r218084  
    283283    case CallDOMGetter:
    284284    case ArraySlice:
     285    case ArrayIndexOf:
    285286    case ParseInt:
    286287    case AtomicsAdd:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r217995 r218084  
    727727            compileArraySlice();
    728728            break;
     729        case ArrayIndexOf:
     730            compileArrayIndexOf();
     731            break;
    729732        case CreateActivation:
    730733            compileCreateActivation();
     
    40514054        setJSValue(arrayResult.array);
    40524055    }
     4056
     4057    void compileArrayIndexOf()
     4058    {
     4059        LValue storage = lowStorage(m_node->numChildren() == 3 ? m_graph.varArgChild(m_node, 2) : m_graph.varArgChild(m_node, 3));
     4060        LValue length = m_out.load32(storage, m_heaps.Butterfly_publicLength);
     4061
     4062        LValue startIndex;
     4063        if (m_node->numChildren() == 4) {
     4064            startIndex = lowInt32(m_graph.varArgChild(m_node, 2));
     4065            startIndex = m_out.select(m_out.greaterThanOrEqual(startIndex, m_out.int32Zero),
     4066                m_out.select(m_out.above(startIndex, length), length, startIndex),
     4067                m_out.select(m_out.lessThan(m_out.add(length, startIndex), m_out.int32Zero), m_out.int32Zero, m_out.add(length, startIndex)));
     4068        } else
     4069            startIndex = m_out.int32Zero;
     4070
     4071        Edge& searchElementEdge = m_graph.varArgChild(m_node, 1);
     4072        switch (searchElementEdge.useKind()) {
     4073        case Int32Use:
     4074        case ObjectUse:
     4075        case DoubleRepUse: {
     4076            LBasicBlock loopHeader = m_out.newBlock();
     4077            LBasicBlock loopBody = m_out.newBlock();
     4078            LBasicBlock loopNext = m_out.newBlock();
     4079            LBasicBlock notFound = m_out.newBlock();
     4080            LBasicBlock continuation = m_out.newBlock();
     4081
     4082            LValue searchElement;
     4083            if (searchElementEdge.useKind() == Int32Use) {
     4084                ASSERT(m_node->arrayMode().type() == Array::Int32);
     4085                speculate(searchElementEdge);
     4086                searchElement = lowJSValue(searchElementEdge, ManualOperandSpeculation);
     4087            } else if (searchElementEdge.useKind() == ObjectUse) {
     4088                ASSERT(m_node->arrayMode().type() == Array::Contiguous);
     4089                searchElement = lowObject(searchElementEdge);
     4090            } else {
     4091                ASSERT(m_node->arrayMode().type() == Array::Double);
     4092                searchElement = lowDouble(searchElementEdge);
     4093            }
     4094
     4095            startIndex = m_out.zeroExtPtr(startIndex);
     4096            length = m_out.zeroExtPtr(length);
     4097
     4098            ValueFromBlock initialStartIndex = m_out.anchor(startIndex);
     4099            m_out.jump(loopHeader);
     4100
     4101            LBasicBlock lastNext = m_out.appendTo(loopHeader, loopBody);
     4102            LValue index = m_out.phi(pointerType(), initialStartIndex);
     4103            m_out.branch(m_out.notEqual(index, length), unsure(loopBody), unsure(notFound));
     4104
     4105            m_out.appendTo(loopBody, loopNext);
     4106            ValueFromBlock foundResult = m_out.anchor(index);
     4107            if (searchElementEdge.useKind() == Int32Use) {
     4108                // Empty value is ignored because of TagTypeNumber.
     4109                LValue value = m_out.load64(m_out.baseIndex(m_heaps.indexedInt32Properties, storage, index));
     4110                m_out.branch(m_out.equal(value, searchElement), unsure(continuation), unsure(loopNext));
     4111            } else if (searchElementEdge.useKind() == ObjectUse) {
     4112                // Empty value never matches against object pointers.
     4113                LValue value = m_out.load64(m_out.baseIndex(m_heaps.indexedContiguousProperties, storage, index));
     4114                m_out.branch(m_out.equal(value, searchElement), unsure(continuation), unsure(loopNext));
     4115            } else {
     4116                // Empty value is ignored because of NaN.
     4117                LValue value = m_out.loadDouble(m_out.baseIndex(m_heaps.indexedDoubleProperties, storage, index));
     4118                m_out.branch(m_out.doubleEqual(value, searchElement), unsure(continuation), unsure(loopNext));
     4119            }
     4120
     4121            m_out.appendTo(loopNext, notFound);
     4122            LValue nextIndex = m_out.add(index, m_out.intPtrOne);
     4123            m_out.addIncomingToPhi(index, m_out.anchor(nextIndex));
     4124            m_out.jump(loopHeader);
     4125
     4126            m_out.appendTo(notFound, continuation);
     4127            ValueFromBlock notFoundResult = m_out.anchor(m_out.constIntPtr(-1));
     4128            m_out.jump(continuation);
     4129
     4130            m_out.appendTo(continuation, lastNext);
     4131            setInt32(m_out.castToInt32(m_out.phi(pointerType(), notFoundResult, foundResult)));
     4132            break;
     4133        }
     4134
     4135        case StringUse:
     4136            ASSERT(m_node->arrayMode().type() == Array::Contiguous);
     4137            setInt32(vmCall(Int32, m_out.operation(operationArrayIndexOfString), m_callFrame, storage, lowString(searchElementEdge), startIndex));
     4138            break;
     4139
     4140        case UntypedUse:
     4141            switch (m_node->arrayMode().type()) {
     4142            case Array::Double:
     4143                setInt32(vmCall(Int32, m_out.operation(operationArrayIndexOfValueDouble), m_callFrame, storage, lowJSValue(searchElementEdge), startIndex));
     4144                break;
     4145            case Array::Int32:
     4146            case Array::Contiguous:
     4147                setInt32(vmCall(Int32, m_out.operation(operationArrayIndexOfValueInt32OrContiguous), m_callFrame, storage, lowJSValue(searchElementEdge), startIndex));
     4148                break;
     4149            default:
     4150                RELEASE_ASSERT_NOT_REACHED();
     4151                break;
     4152            }
     4153            break;
     4154
     4155        default:
     4156            RELEASE_ASSERT_NOT_REACHED();
     4157            break;
     4158        }
     4159    }
     4160
    40534161   
    40544162    void compileArrayPop()
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r217202 r218084  
    234234typedef int32_t (JIT_OPERATION *Z_JITOperation_EOI)(ExecState*, JSObject*, UniquedStringImpl*);
    235235typedef int32_t (JIT_OPERATION *Z_JITOperation_EOJ)(ExecState*, JSObject*, EncodedJSValue);
     236typedef int32_t (JIT_OPERATION *Z_JITOperation_EBJssZ)(ExecState*, Butterfly*, JSString*, int32_t);
     237typedef int32_t (JIT_OPERATION *Z_JITOperation_EBJZ)(ExecState*, Butterfly*, EncodedJSValue, int32_t);
    236238typedef size_t (JIT_OPERATION *S_JITOperation_EO)(ExecState*, JSObject*);
    237239typedef size_t (JIT_OPERATION *S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
  • trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp

    r217149 r218084  
    106106    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("forEach", arrayPrototypeForEachCodeGenerator, DontEnum);
    107107    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("some", arrayPrototypeSomeCodeGenerator, DontEnum);
    108     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", arrayProtoFuncIndexOf, DontEnum, 1);
     108    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("indexOf", arrayProtoFuncIndexOf, DontEnum, 1, ArrayIndexOfIntrinsic);
    109109    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", arrayProtoFuncLastIndexOf, DontEnum, 1);
    110110    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("filter", arrayPrototypeFilterCodeGenerator, DontEnum);
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp

    r217050 r218084  
    7272    case TanhIntrinsic:
    7373        return "TanhIntrinsic";
     74    case ArrayIndexOfIntrinsic:
     75        return "ArrayIndexOfIntrinsic";
    7476    case ArrayPushIntrinsic:
    7577        return "ArrayPushIntrinsic";
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r217050 r218084  
    5252    ArrayPopIntrinsic,
    5353    ArraySliceIntrinsic,
     54    ArrayIndexOfIntrinsic,
    5455    CharCodeAtIntrinsic,
    5556    CharAtIntrinsic,
Note: See TracChangeset for help on using the changeset viewer.