Title: [210865] branches/safari-603-branch
Revision
210865
Author
matthew_han...@apple.com
Date
2017-01-18 12:42:19 -0800 (Wed, 18 Jan 2017)

Log Message

Merge r210695. rdar://problem/29913445

Modified Paths

Added Paths

Diff

Modified: branches/safari-603-branch/JSTests/ChangeLog (210864 => 210865)


--- branches/safari-603-branch/JSTests/ChangeLog	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/JSTests/ChangeLog	2017-01-18 20:42:19 UTC (rev 210865)
@@ -1,5 +1,45 @@
 2017-01-18  Matthew Hanson  <matthew_han...@apple.com>
 
+        Merge r210695. rdar://problem/29913445
+
+    2017-01-12  Saam Barati  <sbar...@apple.com>
+
+            Add a slice intrinsic to the DFG/FTL
+            https://bugs.webkit.org/show_bug.cgi?id=166707
+            <rdar://problem/29913445>
+
+            Reviewed by Filip Pizlo.
+
+            * stress/array-slice-intrinsic.js: Added.
+            (assert):
+            (shallowEq):
+            (runTest1):
+            (runTest2):
+            * stress/array-slice-jettison-on-constructor-change.js: Added.
+            (assert):
+            (runTest1):
+            (runTest2):
+            (addRandomProperties):
+            (runTests):
+            * stress/array-slice-osr-exit-2.js: Added.
+            (assert):
+            (Foo):
+            (shallowEq):
+            (runTest1):
+            (runTest2):
+            (addRandomProperties):
+            (runTests):
+            * stress/array-slice-osr-exit.js: Added.
+            (assert):
+            (Foo):
+            (shallowEq):
+            (runTest1):
+            (runTest2):
+            (addRandomProperties):
+            (runTests):
+
+2017-01-18  Matthew Hanson  <matthew_han...@apple.com>
+
         Merge r210837. rdar://problem/29432371
 
     2017-01-17  Michael Saboff  <msab...@apple.com>

Added: branches/safari-603-branch/JSTests/stress/array-slice-intrinsic.js (0 => 210865)


--- branches/safari-603-branch/JSTests/stress/array-slice-intrinsic.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/stress/array-slice-intrinsic.js	2017-01-18 20:42:19 UTC (rev 210865)
@@ -0,0 +1,49 @@
+function assert(b, ...m) {
+    if (!b)
+        throw new Error("Bad: ", ...m);
+}
+noInline(assert);
+
+function shallowEq(a, b) {
+    assert(a.length === b.length, a, b);
+    for (let i = 0; i < a.length; i++)
+        assert(a[i] === b[i], a, b);
+}
+noInline(shallowEq);
+
+let tests = [
+    [[1,2,3,4,5], [1,2,3,4,5], 0, 5],
+    [[1,2,3,4,5], [1,2,3,4,5], 0],
+    [[1,2,3,4,5], [4], -2, -1],
+    [[1,2,3,4,5], [5], -1],
+    [[1,2,3,4,5], [5], -1, 5],
+    [[1,2,3,4,5], [], -10, -20],
+    [[1,2,3,4,5], [], -20, -10],
+    [[1,2,3,4,5], [], 6, 4],
+    [[1,2,3,4,5], [], 3, 2],
+    [[1,2,3,4,5], [4,5], 3, 10],
+    [[1,2,3,4,5], [3,4,5], 2, 10],
+    [[1,2,3,4,5], [1,2,3,4,5], -10, 10],
+    [[1,2,3,4,5], [1,2,3,4,5], -5, 10],
+    [[1,2,3,4,5], [2,3,4,5], -4, 10],
+];
+
+function runTest1(a, b) {
+    return a.slice(b);
+}
+noInline(runTest1);
+
+function runTest2(a, b, c) {
+    return a.slice(b, c);
+}
+noInline(runTest2);
+
+for (let i = 0; i < 10000; i++) {
+    for (let [input, output, ...args] of tests) {
+        assert(args.length === 1 || args.length === 2);
+        if (args.length === 1)
+            shallowEq(runTest1(input, args[0]), output);
+        else
+            shallowEq(runTest2(input, args[0], args[1]), output);
+    }
+}

Added: branches/safari-603-branch/JSTests/stress/array-slice-jettison-on-constructor-change.js (0 => 210865)


--- branches/safari-603-branch/JSTests/stress/array-slice-jettison-on-constructor-change.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/stress/array-slice-jettison-on-constructor-change.js	2017-01-18 20:42:19 UTC (rev 210865)
@@ -0,0 +1,72 @@
+function assert(b, ...m) {
+    if (!b)
+        throw new Error("Bad: ", ...m)
+}
+noInline(assert);
+
+let shouldBeNewConstructor = false;
+const newConstructor = {};
+
+function shallowEq(a, b) {
+    assert(a.length === b.length, a, b);
+    if (shouldBeNewConstructor)
+        assert(b.constructor === newConstructor);
+    for (let i = 0; i < a.length; i++)
+        assert(a[i] === b[i], a, b);
+}
+noInline(shallowEq);
+
+let tests = [
+    [[1,2,3,4,5], [1,2,3,4,5], 0, 5],
+    [[1,2,3,4,5], [1,2,3,4,5], 0],
+    [[1,2,3,4,5], [4], -2, -1],
+    [[1,2,3,4,5], [5], -1],
+    [[1,2,3,4,5], [5], -1, 5],
+    [[1,2,3,4,5], [], -10, -20],
+    [[1,2,3,4,5], [], -20, -10],
+    [[1,2,3,4,5], [], 6, 4],
+    [[1,2,3,4,5], [], 3, 2],
+    [[1,2,3,4,5], [4,5], 3, 10],
+    [[1,2,3,4,5], [3,4,5], 2, 10],
+    [[1,2,3,4,5], [1,2,3,4,5], -10, 10],
+    [[1,2,3,4,5], [1,2,3,4,5], -5, 10],
+    [[1,2,3,4,5], [2,3,4,5], -4, 10],
+];
+
+function runTest1(a, b) {
+    let result = a.slice(b);
+    return result;
+}
+noInline(runTest1);
+
+function runTest2(a, b, c) {
+    let result = a.slice(b, c);
+    return result;
+}
+noInline(runTest2);
+
+function addRandomProperties(input) {
+    for (let i = 0; i < 4; i++) {
+        input["prop" + i + ((Math.random() * 100000) | 0)] = i;
+    }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+    for (let i = 0; i < 10000; i++) {
+        for (let [input, output, ...args] of tests) {
+            addRandomProperties(input);
+            assert(args.length === 1 || args.length === 2);
+            if (args.length === 1)
+                shallowEq(runTest1(input, args[0]), output);
+            else
+                shallowEq(runTest2(input, args[0], args[1]), output);
+        }
+    }
+}
+
+runTests();
+
+Array.prototype.constructor = newConstructor;
+shouldBeNewConstructor = true;
+runTests();

Added: branches/safari-603-branch/JSTests/stress/array-slice-osr-exit-2.js (0 => 210865)


--- branches/safari-603-branch/JSTests/stress/array-slice-osr-exit-2.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/stress/array-slice-osr-exit-2.js	2017-01-18 20:42:19 UTC (rev 210865)
@@ -0,0 +1,76 @@
+function assert(b, ...m) {
+    if (!b)
+        throw new Error("Bad: ", ...m)
+}
+noInline(assert);
+
+class Foo extends Array {
+    constructor(...args) {
+        super(...args);
+    }
+};
+function shallowEq(a, b) {
+    assert(a.length === b.length, a, b);
+    for (let i = 0; i < a.length; i++)
+        assert(a[i] === b[i], a, b);
+}
+noInline(shallowEq);
+
+let tests = [
+    [[1,2,3,4,5], [1,2,3,4,5], 0, 5],
+    [[1,2,3,4,5], [1,2,3,4,5], 0],
+    [[1,2,3,4,5], [4], -2, -1],
+    [[1,2,3,4,5], [5], -1],
+    [[1,2,3,4,5], [5], -1, 5],
+    [[1,2,3,4,5], [], -10, -20],
+    [[1,2,3,4,5], [], -20, -10],
+    [[1,2,3,4,5], [], 6, 4],
+    [[1,2,3,4,5], [], 3, 2],
+    [[1,2,3,4,5], [4,5], 3, 10],
+    [[1,2,3,4,5], [3,4,5], 2, 10],
+    [[1,2,3,4,5], [1,2,3,4,5], -10, 10],
+    [[1,2,3,4,5], [1,2,3,4,5], -5, 10],
+    [[1,2,3,4,5], [2,3,4,5], -4, 10],
+];
+
+function runTest1(a, b) {
+    let result = a.slice(b);
+    assert(a instanceof Foo === result instanceof Foo);
+    return result;
+}
+noInline(runTest1);
+
+function runTest2(a, b, c) {
+    let result = a.slice(b, c);
+    assert(a instanceof Foo === result instanceof Foo);
+    return result;
+}
+noInline(runTest2);
+
+function addRandomProperties(input) {
+    for (let i = 0; i < 4; i++) {
+        input["prop" + i + ((Math.random() * 100000) | 0)] = i;
+    }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+    for (let i = 0; i < 10000; i++) {
+        for (let [input, output, ...args] of tests) {
+            addRandomProperties(input);
+            assert(args.length === 1 || args.length === 2);
+            if (args.length === 1)
+                shallowEq(runTest1(input, args[0]), output);
+            else
+                shallowEq(runTest2(input, args[0], args[1]), output);
+        }
+    }
+}
+
+runTests();
+
+tests.push([new Foo(1,2,3,4,5), [1,2,3,4,5], -10, 10]);
+tests.push([new Foo(1,2,3,4,5), [1,2,3,4,5], -5, 10]);
+tests.push([new Foo(1,2,3,4,5), [2,3,4,5], -4, 10]);
+tests.push([new Foo(1,2,3,4,5), [2,3,4,5], -4]);
+runTests();

Added: branches/safari-603-branch/JSTests/stress/array-slice-osr-exit.js (0 => 210865)


--- branches/safari-603-branch/JSTests/stress/array-slice-osr-exit.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/stress/array-slice-osr-exit.js	2017-01-18 20:42:19 UTC (rev 210865)
@@ -0,0 +1,74 @@
+function assert(b, ...m) {
+    if (!b)
+        throw new Error("Bad: ", ...m)
+}
+noInline(assert);
+
+class Foo extends Array {
+    constructor(...args) {
+        super(...args);
+    }
+};
+function shallowEq(a, b) {
+    assert(a.length === b.length, a, b);
+    for (let i = 0; i < a.length; i++)
+        assert(a[i] === b[i], a, b);
+}
+noInline(shallowEq);
+
+let tests = [
+    [[1,2,3,4,5], [1,2,3,4,5], 0, 5],
+    [[1,2,3,4,5], [1,2,3,4,5], 0],
+    [[1,2,3,4,5], [4], -2, -1],
+    [[1,2,3,4,5], [5], -1],
+    [[1,2,3,4,5], [5], -1, 5],
+    [[1,2,3,4,5], [], -10, -20],
+    [[1,2,3,4,5], [], -20, -10],
+    [[1,2,3,4,5], [], 6, 4],
+    [[1,2,3,4,5], [], 3, 2],
+    [[1,2,3,4,5], [4,5], 3, 10],
+    [[1,2,3,4,5], [3,4,5], 2, 10],
+    [[1,2,3,4,5], [1,2,3,4,5], -10, 10],
+    [[1,2,3,4,5], [1,2,3,4,5], -5, 10],
+    [[1,2,3,4,5], [2,3,4,5], -4, 10],
+];
+tests.push([new Foo(1,2,3,4,5), [1,2,3,4,5], -10, 10]);
+tests.push([new Foo(1,2,3,4,5), [1,2,3,4,5], -5, 10]);
+tests.push([new Foo(1,2,3,4,5), [2,3,4,5], -4, 10]);
+tests.push([new Foo(1,2,3,4,5), [2,3,4,5], -4]);
+
+function runTest1(a, b) {
+    let result = a.slice(b);
+    assert(a instanceof Foo === result instanceof Foo);
+    return result;
+}
+noInline(runTest1);
+
+function runTest2(a, b, c) {
+    let result = a.slice(b, c);
+    assert(a instanceof Foo === result instanceof Foo);
+    return result;
+}
+noInline(runTest2);
+
+function addRandomProperties(input) {
+    for (let i = 0; i < 4; i++) {
+        input["prop" + i + ((Math.random() * 100000) | 0)] = i;
+    }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+    for (let i = 0; i < 10000; i++) {
+        for (let [input, output, ...args] of tests) {
+            addRandomProperties(input);
+            assert(args.length === 1 || args.length === 2);
+            if (args.length === 1)
+                shallowEq(runTest1(input, args[0]), output);
+            else
+                shallowEq(runTest2(input, args[0], args[1]), output);
+        }
+    }
+}
+
+runTests();

Modified: branches/safari-603-branch/Source/_javascript_Core/ChangeLog (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/ChangeLog	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/ChangeLog	2017-01-18 20:42:19 UTC (rev 210865)
@@ -1,5 +1,111 @@
 2017-01-18  Matthew Hanson  <matthew_han...@apple.com>
 
+        Merge r210695. rdar://problem/29913445
+
+    2017-01-12  Saam Barati  <sbar...@apple.com>
+
+            Add a slice intrinsic to the DFG/FTL
+            https://bugs.webkit.org/show_bug.cgi?id=166707
+            <rdar://problem/29913445>
+
+            Reviewed by Filip Pizlo.
+
+            The gist of this patch is to inline Array.prototype.slice
+            into the DFG/FTL. The implementation in the DFG-backend
+            and FTLLowerDFGToB3 is just a straight forward implementation
+            of what the C function is doing. The more interesting bits
+            of this patch are setting up the proper watchpoints and conditions
+            in the executing code to prove that its safe to skip all of the
+            observable JS actions that Array.prototype.slice normally does.
+
+            We perform the following proofs:
+            1. Array.prototype.constructor has not changed (via a watchpoint).
+            2. That Array.prototype.constructor[Symbol.species] has not changed (via a watchpoint).
+            3. The global object is not having a bad time.
+            4. The array that is being sliced has an original array structure.
+            5. Array.prototype/Object.prototype have not transitioned.
+
+            Conditions 1, 2, and 3 are strictly required.
+
+            4 is ensuring a couple things:
+            1. That a "constructor" property hasn't been added to the array
+            we're slicing since we're supposed to perform a Get(array, "constructor").
+            2. That we're not slicing an instance of a subclass of Array.
+
+            We could relax 4.1 in the future if we find other ways to test if
+            the incoming array hasn't changed the "constructor" property. We
+            would probably use TryGetById to do this.
+
+            I'm seeing a 5% speedup on crypto-pbkdf2 and often a 1% speedup on
+            the total benchmark (the results are sometimes noisy).
+
+            * dfg/DFGAbstractInterpreterInlines.h:
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+            * dfg/DFGByteCodeParser.cpp:
+            (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+            * dfg/DFGCallArrayAllocatorSlowPathGenerator.h:
+            (JSC::DFG::CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator::CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator):
+            * dfg/DFGClobberize.h:
+            (JSC::DFG::clobberize):
+            * dfg/DFGDoesGC.cpp:
+            (JSC::DFG::doesGC):
+            * dfg/DFGFixupPhase.cpp:
+            (JSC::DFG::FixupPhase::fixupNode):
+            * dfg/DFGNodeType.h:
+            * dfg/DFGPredictionPropagationPhase.cpp:
+            * dfg/DFGSafeToExecute.h:
+            (JSC::DFG::safeToExecute):
+            * dfg/DFGSpeculativeJIT.cpp:
+            (JSC::DFG::SpeculativeJIT::compileArraySlice):
+            (JSC::DFG::SpeculativeJIT::emitAllocateButterfly):
+            * dfg/DFGSpeculativeJIT.h:
+            * dfg/DFGSpeculativeJIT32_64.cpp:
+            (JSC::DFG::SpeculativeJIT::compile):
+            (JSC::DFG::SpeculativeJIT::emitInitializeButterfly):
+            (JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
+            * dfg/DFGSpeculativeJIT64.cpp:
+            (JSC::DFG::SpeculativeJIT::compile):
+            (JSC::DFG::SpeculativeJIT::emitInitializeButterfly):
+            (JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
+            * ftl/FTLAbstractHeapRepository.h:
+            * ftl/FTLCapabilities.cpp:
+            (JSC::FTL::canCompile):
+            * ftl/FTLLowerDFGToB3.cpp:
+            (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+            (JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
+            (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSize):
+            (JSC::FTL::DFG::LowerDFGToB3::compileMaterializeNewObject):
+            (JSC::FTL::DFG::LowerDFGToB3::initializeArrayElements):
+            (JSC::FTL::DFG::LowerDFGToB3::storeStructure):
+            (JSC::FTL::DFG::LowerDFGToB3::allocateCell):
+            (JSC::FTL::DFG::LowerDFGToB3::allocateObject):
+            (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray):
+            (JSC::FTL::DFG::LowerDFGToB3::allocateUninitializedContiguousJSArray):
+            * jit/AssemblyHelpers.cpp:
+            (JSC::AssemblyHelpers::emitLoadStructure):
+            * runtime/ArrayPrototype.cpp:
+            (JSC::ArrayPrototype::finishCreation):
+            (JSC::speciesWatchpointIsValid):
+            (JSC::speciesConstructArray):
+            (JSC::arrayProtoFuncSlice):
+            (JSC::arrayProtoPrivateFuncConcatMemcpy):
+            (JSC::ArrayPrototype::initializeSpeciesWatchpoint):
+            (JSC::ArrayPrototypeAdaptiveInferredPropertyWatchpoint::handleFire):
+            (JSC::speciesWatchpointsValid): Deleted.
+            (JSC::ArrayPrototype::attemptToInitializeSpeciesWatchpoint): Deleted.
+            * runtime/ArrayPrototype.h:
+            (JSC::ArrayPrototype::speciesWatchpointStatus): Deleted.
+            (): Deleted.
+            * runtime/Intrinsic.h:
+            * runtime/JSGlobalObject.cpp:
+            (JSC::JSGlobalObject::JSGlobalObject):
+            (JSC::JSGlobalObject::init):
+            * runtime/JSGlobalObject.h:
+            (JSC::JSGlobalObject::arraySpeciesWatchpoint):
+            * runtime/Structure.h:
+
+2017-01-18  Matthew Hanson  <matthew_han...@apple.com>
+
         Merge r210837. rdar://problem/29432371
 
     2017-01-17  Michael Saboff  <msab...@apple.com>

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -1650,6 +1650,20 @@
         clobberWorld(node->origin.semantic, clobberLimit);
         forNode(node).setType(SpecBytecodeNumber);
         break;
+
+    case ArraySlice: {
+        JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
+
+        // FIXME: We could do better here if we prove that the
+        // incoming value has only a single structure.
+        StructureSet structureSet;
+        structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32));
+        structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous));
+        structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble));
+
+        forNode(node).set(m_graph, structureSet);
+        break;
+    }
             
     case ArrayPop:
         clobberWorld(node->origin.semantic, clobberLimit);

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -2246,6 +2246,94 @@
             return false;
         }
     }
+
+    case ArraySliceIntrinsic: {
+#if USE(JSVALUE32_64)
+        if (isX86()) {
+            // There aren't enough registers for this to be done easily.
+            return false;
+        }
+#endif
+        if (argumentCountIncludingThis < 2)
+            return false;
+
+        if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
+            || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache))
+            return false;
+
+        ArrayMode arrayMode = getArrayMode(m_currentInstruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile);
+        if (!arrayMode.isJSArray())
+            return false;
+
+        if (arrayMode.arrayClass() != Array::OriginalArray)
+            return false;
+
+        switch (arrayMode.type()) {
+        case Array::Double:
+        case Array::Int32:
+        case Array::Contiguous: {
+            JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic);
+
+            InlineWatchpointSet& objectPrototypeTransition = globalObject->objectPrototype()->structure()->transitionWatchpointSet();
+            InlineWatchpointSet& arrayPrototypeTransition = globalObject->arrayPrototype()->structure()->transitionWatchpointSet();
+
+            // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole.
+            if (globalObject->arraySpeciesWatchpoint().isStillValid()
+                && globalObject->havingABadTimeWatchpoint()->isStillValid()
+                && arrayPrototypeTransition.isStillValid()
+                && objectPrototypeTransition.isStillValid()
+                && globalObject->arrayPrototypeChainIsSane()) {
+
+                m_graph.watchpoints().addLazily(globalObject->arraySpeciesWatchpoint());
+                m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
+                m_graph.watchpoints().addLazily(arrayPrototypeTransition);
+                m_graph.watchpoints().addLazily(objectPrototypeTransition);
+
+                insertChecks();
+
+                Node* array = get(virtualRegisterForArgument(0, registerOffset));
+                // We do a few things here to prove that we aren't skipping doing side-effects in an observable way:
+                // 1. We ensure that the "constructor" property hasn't been changed (because the observable
+                // effects of slice require that we perform a Get(array, "constructor") and we can skip
+                // that if we're an original array structure. (We can relax this in the future by using
+                // TryGetById and CheckCell).
+                //
+                // 2. We check that the array we're calling slice on has the same global object as the lexical
+                // global object that this code is running in. This requirement is necessary because we setup the
+                // watchpoints above on the lexical global object. This means that code that calls slice on
+                // arrays produced by other global objects won't get this optimization. We could relax this
+                // requirement in the future by checking that the watchpoint hasn't fired at runtime in the code
+                // we generate instead of registering it as a watchpoint that would invalidate the compilation.
+                //
+                // 3. By proving we're an original array structure, we guarantee that the incoming array
+                // isn't a subclass of Array.
+
+                StructureSet structureSet;
+                structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32));
+                structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous));
+                structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble));
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), array);
+
+                addVarArgChild(array);
+                addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Start index.
+                if (argumentCountIncludingThis >= 3)
+                    addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // End index.
+                addVarArgChild(addToGraph(GetButterfly, array));
+
+                Node* arraySlice = addToGraph(Node::VarArg, ArraySlice, OpInfo(), OpInfo());
+                set(VirtualRegister(resultOperand), arraySlice);
+                return true;
+            }
+
+            return false;
+        }
+        default:
+            return false;
+        }
+
+        RELEASE_ASSERT_NOT_REACHED();
+        return false;
+    }
         
     case ArrayPopIntrinsic: {
         if (argumentCountIncludingThis != 1)

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGCallArrayAllocatorSlowPathGenerator.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGCallArrayAllocatorSlowPathGenerator.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGCallArrayAllocatorSlowPathGenerator.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -124,6 +124,45 @@
     Vector<SilentRegisterSavePlan, 2> m_plans;
 };
 
+class CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator : public JumpingSlowPathGenerator<MacroAssembler::JumpList> {
+public:
+    CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator(
+        MacroAssembler::JumpList from, SpeculativeJIT* jit, P_JITOperation_EStZB function,
+        GPRReg resultGPR, GPRReg structureGPR, GPRReg sizeGPR, GPRReg storageGPR, GPRReg scratchGPR)
+        : JumpingSlowPathGenerator<MacroAssembler::JumpList>(from, jit)
+        , m_function(function)
+        , m_resultGPR(resultGPR)
+        , m_structureGPR(structureGPR)
+        , m_sizeGPR(sizeGPR)
+        , m_storageGPR(storageGPR)
+        , m_scratchGPR(scratchGPR)
+    {
+        jit->silentSpillAllRegistersImpl(false, m_plans, resultGPR, m_scratchGPR);
+    }
+
+protected:
+    void generateInternal(SpeculativeJIT* jit) override
+    {
+        linkFrom(jit);
+        for (unsigned i = 0; i < m_plans.size(); ++i)
+            jit->silentSpill(m_plans[i]);
+        jit->callOperation(m_function, m_resultGPR, m_structureGPR, m_sizeGPR, m_storageGPR);
+        for (unsigned i = m_plans.size(); i--;)
+            jit->silentFill(m_plans[i], m_scratchGPR);
+        jit->m_jit.exceptionCheck();
+        jumpTo(jit);
+    }
+    
+private:
+    P_JITOperation_EStZB m_function;
+    GPRReg m_resultGPR;
+    GPRReg m_structureGPR;
+    GPRReg m_sizeGPR;
+    GPRReg m_storageGPR;
+    GPRReg m_scratchGPR;
+    Vector<SilentRegisterSavePlan, 2> m_plans;
+};
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGClobberize.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGClobberize.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGClobberize.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -503,6 +503,19 @@
         read(MiscFields);
         def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
         return;
+
+    case ArraySlice:
+        read(MiscFields);
+        read(JSCell_indexingType);
+        read(JSCell_structureID);
+        read(JSObject_butterfly);
+        read(Butterfly_publicLength);
+        read(IndexedDoubleProperties);
+        read(IndexedInt32Properties);
+        read(IndexedContiguousProperties);
+        read(HeapObjectCount);
+        write(HeapObjectCount);
+        return;
         
     case GetById:
     case GetByIdFlush:

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGDoesGC.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -309,6 +309,7 @@
     case ToLowerCase:
     case CallDOMGetter:
     case CallDOM:
+    case ArraySlice:
         return true;
         
     case MultiPutByOffset:

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -931,6 +931,14 @@
             fixEdge<KnownCellUse>(node->child1());
             break;
         }
+
+        case ArraySlice: {
+            fixEdge<KnownCellUse>(m_graph.varArgChild(node, 0));
+            fixEdge<Int32Use>(m_graph.varArgChild(node, 1));
+            if (node->numChildren() == 4)
+                fixEdge<Int32Use>(m_graph.varArgChild(node, 2));
+            break;
+        }
             
         case RegExpExec:
         case RegExpTest: {

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGNodeType.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGNodeType.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGNodeType.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -248,6 +248,7 @@
     /* Optimizations for array mutation. */\
     macro(ArrayPush, NodeResultJS | NodeMustGenerate) \
     macro(ArrayPop, NodeResultJS | NodeMustGenerate) \
+    macro(ArraySlice, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
     \
     /* Optimizations for regular _expression_ matching. */\
     macro(RegExpExec, NodeResultJS | NodeMustGenerate) \

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -860,6 +860,7 @@
             break;
         }
             
+        case ArraySlice:
         case NewArrayWithSpread:
         case NewArray:
         case NewArrayWithSize:

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSafeToExecute.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -382,6 +382,13 @@
     case IsNonEmptyMapBucket:
         return true;
 
+    case ArraySlice: {
+        // You could plausibly move this code around as long as you proved the
+        // incoming array base structure is an original array at the hoisted location.
+        // Instead of doing that extra work, we just conservatively return false.
+        return false;
+    }
+
     case BottomValue:
         // If in doubt, assume that this isn't safe to execute, just because we have no way of
         // compiling this node.

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -7169,6 +7169,182 @@
     int32Result(resultGPR, node);
 }
 
+void SpeculativeJIT::compileArraySlice(Node* node)
+{
+    ASSERT(node->op() == ArraySlice);
+
+    JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
+
+    GPRTemporary temp(this);
+    StorageOperand storage(this, node->numChildren() == 3 ? m_jit.graph().varArgChild(node, 2) : m_jit.graph().varArgChild(node, 3));
+    GPRTemporary result(this);
+    
+    GPRReg storageGPR = storage.gpr();
+    GPRReg resultGPR = result.gpr();
+    GPRReg tempGPR = temp.gpr();
+
+    auto populateIndex = [&] (unsigned childIndex, GPRReg length, GPRReg result) {
+        SpeculateInt32Operand index(this, m_jit.graph().varArgChild(node, childIndex));
+        GPRReg indexGPR = index.gpr();
+        MacroAssembler::JumpList done;
+        auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR, TrustedImm32(0));
+        m_jit.move(length, result);
+        done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR, result));
+        m_jit.move(TrustedImm32(0), result);
+        done.append(m_jit.jump());
+
+        isPositive.link(&m_jit);
+        m_jit.move(indexGPR, result);
+        done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
+        m_jit.move(length, result);
+
+        done.link(&m_jit);
+    };
+
+    {
+        GPRTemporary tempLength(this);
+        GPRReg lengthGPR = tempLength.gpr();
+        m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
+
+        if (node->numChildren() == 4)
+            populateIndex(2, lengthGPR, tempGPR);
+        else
+            m_jit.move(lengthGPR, tempGPR);
+
+        GPRTemporary tempStartIndex(this);
+        GPRReg startGPR = tempStartIndex.gpr();
+        populateIndex(1, lengthGPR, startGPR);
+
+        auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
+        m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
+        auto done = m_jit.jump();
+
+        tooBig.link(&m_jit);
+        m_jit.move(TrustedImm32(0), tempGPR);
+        done.link(&m_jit);
+    }
+
+
+    GPRTemporary temp3(this);
+    GPRReg tempValue = temp3.gpr();
+    {
+        SpeculateCellOperand cell(this, m_jit.graph().varArgChild(node, 0));
+        m_jit.load8(MacroAssembler::Address(cell.gpr(), JSCell::indexingTypeAndMiscOffset()), tempValue);
+        m_jit.and32(TrustedImm32(AllArrayTypesAndHistory), tempValue);
+    }
+
+    {
+#if USE(JSVALUE64)
+        GPRTemporary emptyValue(this);
+        JSValueRegs emptyValueRegs = JSValueRegs(emptyValue.gpr());
+#else
+        GPRTemporary emptyValuePayload(this);
+        GPRTemporary emptyValueTag(this);
+        JSValueRegs emptyValueRegs(emptyValueTag.gpr(), emptyValuePayload.gpr());
+#endif
+
+        GPRTemporary storage(this);
+        GPRReg storageResultGPR = storage.gpr();
+
+        GPRReg sizeGPR = tempGPR; 
+
+        CCallHelpers::JumpList done;
+
+        auto emitMoveEmptyValue = [&] (JSValue v) {
+#if USE(JSVALUE64)
+            m_jit.move(TrustedImm64(JSValue::encode(v)), emptyValueRegs.gpr());
+#else
+            m_jit.move(TrustedImm32(v.tag()), emptyValueRegs.tagGPR());
+            m_jit.move(TrustedImm32(v.payload()), emptyValueRegs.payloadGPR());
+#endif
+        };
+
+        auto isContiguous = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithContiguous));
+        auto isInt32 = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithInt32));
+        // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure
+        // to ensure the incoming array is one to be one of the original array structures
+        // with one of the following indexing shapes: Int32, Contiguous, Double. Therefore,
+        // we're a double array here.
+        m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble)), tempValue);
+        emitMoveEmptyValue(jsNaN());
+        done.append(m_jit.jump());
+
+        isContiguous.link(&m_jit);
+        m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous)), tempValue);
+        emitMoveEmptyValue(JSValue());
+        done.append(m_jit.jump());
+
+        isInt32.link(&m_jit);
+        m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32)), tempValue);
+        emitMoveEmptyValue(JSValue());
+
+        done.link(&m_jit);
+
+        {
+            GPRTemporary scratch(this);
+            GPRTemporary scratch2(this);
+            GPRReg scratchGPR = scratch.gpr();
+            GPRReg scratch2GPR = scratch2.gpr();
+
+            MacroAssembler::JumpList slowCases;
+            m_jit.move(TrustedImmPtr(0), storageResultGPR);
+
+            emitAllocateButterfly(storageResultGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
+            emitInitializeButterfly(storageResultGPR, sizeGPR, emptyValueRegs, scratchGPR);
+            emitAllocateJSObject<JSArray>(resultGPR, tempValue, storageResultGPR, scratchGPR, scratch2GPR, slowCases);
+            m_jit.mutatorFence();
+
+            addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator>(
+                slowCases, this, operationNewArrayWithSize, resultGPR, tempValue, sizeGPR, storageResultGPR, scratchGPR));
+        }
+    }
+
+    GPRTemporary temp4(this);
+    GPRReg loadIndex = temp4.gpr();
+
+    m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
+    if (node->numChildren() == 4)
+        populateIndex(2, tempValue, tempGPR);
+    else
+        m_jit.move(tempValue, tempGPR);
+    populateIndex(1, tempValue, loadIndex);
+
+    GPRTemporary temp5(this);
+    GPRReg storeIndex = temp5.gpr();
+    m_jit.move(TrustedImmPtr(0), storeIndex);
+
+    GPRTemporary temp2(this);
+    GPRReg resultButterfly = temp2.gpr();
+
+    m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), resultButterfly);
+    m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
+    m_jit.zeroExtend32ToPtr(loadIndex, loadIndex);
+    auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, loadIndex, tempGPR);
+
+    auto loop = m_jit.label();
+#if USE(JSVALUE64)
+    m_jit.load64(
+        MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight), tempValue);
+    m_jit.store64(
+        tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight));
+#else
+    m_jit.load32(
+        MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, PayloadOffset), tempValue);
+    m_jit.store32(
+        tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, PayloadOffset));
+    m_jit.load32(
+        MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, TagOffset), tempValue);
+    m_jit.store32(
+        tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, TagOffset));
+#endif // USE(JSVALUE64)
+    m_jit.addPtr(TrustedImm32(1), loadIndex);
+    m_jit.addPtr(TrustedImm32(1), storeIndex);
+    m_jit.branchPtr(MacroAssembler::Below, loadIndex, tempGPR).linkTo(loop, &m_jit);
+
+    done.link(&m_jit);
+    cellResult(resultGPR, node);
+}
+
 void SpeculativeJIT::compileNotifyWrite(Node* node)
 {
     WatchpointSet* set = node->watchpointSet();
@@ -9381,6 +9557,21 @@
     noResult(node, UseChildrenCalledExplicitly);
 }
 
+void SpeculativeJIT::emitAllocateButterfly(GPRReg storageResultGPR, GPRReg sizeGPR, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, MacroAssembler::JumpList& slowCases)
+{
+    RELEASE_ASSERT(RegisterSet(storageResultGPR, sizeGPR, scratch1, scratch2, scratch3).numberOfSetGPRs() == 5);
+    ASSERT((1 << 3) == sizeof(JSValue));
+    m_jit.zeroExtend32ToPtr(sizeGPR, scratch1);
+    m_jit.lshift32(TrustedImm32(3), scratch1);
+    m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratch1, scratch2);
+    m_jit.emitAllocateVariableSized(
+        storageResultGPR, m_jit.vm()->heap.subspaceForAuxiliaryData(), scratch2, scratch1, scratch3, slowCases);
+    m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageResultGPR);
+
+    m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfPublicLength()));
+    m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfVectorLength()));
+}
+
 } } // namespace JSC::DFG
 
 #endif

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -743,6 +743,8 @@
 
     void emitCall(Node*);
 
+    void emitAllocateButterfly(GPRReg storageGPR, GPRReg sizeGPR, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, MacroAssembler::JumpList& slowCases);
+    void emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR);
     void compileAllocateNewArrayWithSize(JSGlobalObject*, GPRReg resultGPR, GPRReg sizeGPR, IndexingType, bool shouldConvertLargeSizeToArrayStorage = true);
     
     // Called once a node has completed code generation but prior to setting
@@ -2680,6 +2682,7 @@
     void compileSpread(Node*);
     void compileNewArrayWithSpread(Node*);
     void compileGetRestLength(Node*);
+    void compileArraySlice(Node*);
     void compileNotifyWrite(Node*);
     bool compileRegExpExec(Node*);
     void compileIsObjectOrNull(Node*);

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -3550,6 +3550,11 @@
         break;
     }
 
+    case ArraySlice: {
+        compileArraySlice(node);
+        break;
+    }
+
     case DFG::Jump: {
         jump(node->targetBlock());
         noResult(node);
@@ -5666,6 +5671,18 @@
     doubleResult(result.fpr(), node);
 }
 
+void SpeculativeJIT::emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR)
+{
+    m_jit.move(sizeGPR, scratchGPR);
+    MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
+    MacroAssembler::Label loop = m_jit.label();
+    m_jit.sub32(TrustedImm32(1), scratchGPR);
+    m_jit.store32(emptyValueRegs.tagGPR(), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+    m_jit.store32(emptyValueRegs.payloadGPR(), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+    m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
+    done.link(&m_jit);
+}
+
 void SpeculativeJIT::compileAllocateNewArrayWithSize(JSGlobalObject* globalObject, GPRReg resultGPR, GPRReg sizeGPR, IndexingType indexingType, bool shouldConvertLargeSizeToArrayStorage)
 {
     GPRTemporary storage(this);
@@ -5681,34 +5698,21 @@
     MacroAssembler::JumpList slowCases;
     if (shouldConvertLargeSizeToArrayStorage)
         slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
-            
-    ASSERT((1 << 3) == sizeof(JSValue));
-    m_jit.move(sizeGPR, scratchGPR);
-    m_jit.lshift32(TrustedImm32(3), scratchGPR);
-    m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratchGPR, resultGPR);
-    m_jit.emitAllocateVariableSized(
-        storageGPR, m_jit.vm()->heap.subspaceForAuxiliaryData(), resultGPR, scratchGPR,
-        scratch2GPR, slowCases);
-    m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageGPR);
 
-    m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
-    m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
-            
+    // We can use result as a scratch for this.
+    emitAllocateButterfly(storageGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
+
     JSValue hole;
     if (hasDouble(indexingType))
         hole = JSValue(JSValue::EncodeAsDouble, PNaN);
     else
         hole = JSValue();
+    JSValueRegs emptyValueRegs(scratchGPR, scratch2GPR);
+    m_jit.move(TrustedImm32(hole.tag()), emptyValueRegs.tagGPR());
+    m_jit.move(TrustedImm32(hole.payload()), emptyValueRegs.payloadGPR());
+    // We can use result as a scratch for this.
+    emitInitializeButterfly(storageGPR, sizeGPR, emptyValueRegs, resultGPR);
             
-    m_jit.move(sizeGPR, scratchGPR);
-    MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
-    MacroAssembler::Label loop = m_jit.label();
-    m_jit.sub32(TrustedImm32(1), scratchGPR);
-    m_jit.store32(TrustedImm32(hole.u.asBits.tag), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
-    m_jit.store32(TrustedImm32(hole.u.asBits.payload), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-    m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
-    done.link(&m_jit);
-    
     Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType);
     emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
             

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -3462,6 +3462,11 @@
         }
         break;
     }
+
+    case ArraySlice: {
+        compileArraySlice(node);
+        break;
+    }
         
     case ArrayPop: {
         ASSERT(node->arrayMode().isJSArray());
@@ -5939,6 +5944,17 @@
     doubleResult(result.fpr(), node);
 }
 
+void SpeculativeJIT::emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR)
+{
+    m_jit.zeroExtend32ToPtr(sizeGPR, scratchGPR);
+    MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
+    MacroAssembler::Label loop = m_jit.label();
+    m_jit.sub32(TrustedImm32(1), scratchGPR);
+    m_jit.store64(emptyValueRegs.gpr(), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight));
+    m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
+    done.link(&m_jit);
+}
+
 void SpeculativeJIT::compileAllocateNewArrayWithSize(JSGlobalObject* globalObject, GPRReg resultGPR, GPRReg sizeGPR, IndexingType indexingType, bool shouldConvertLargeSizeToArrayStorage)
 {
     GPRTemporary storage(this);
@@ -5955,30 +5971,15 @@
     if (shouldConvertLargeSizeToArrayStorage)
         slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
             
-    ASSERT((1 << 3) == sizeof(JSValue));
-    m_jit.move(sizeGPR, scratchGPR);
-    m_jit.lshift32(TrustedImm32(3), scratchGPR);
-    m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratchGPR, resultGPR);
-    m_jit.emitAllocateVariableSized(
-        storageGPR, m_jit.vm()->heap.subspaceForAuxiliaryData(), resultGPR, scratchGPR,
-        scratch2GPR, slowCases);
-    m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageGPR);
+    // We can use resultGPR as a scratch right now.
+    emitAllocateButterfly(storageGPR, sizeGPR, resultGPR, scratchGPR, scratch2GPR, slowCases);
 
-    m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
-    m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
-            
     if (hasDouble(indexingType))
         m_jit.move(TrustedImm64(bitwise_cast<int64_t>(PNaN)), scratchGPR);
     else
         m_jit.move(TrustedImm64(JSValue::encode(JSValue())), scratchGPR);
-    m_jit.move(sizeGPR, scratch2GPR);
-    MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratch2GPR);
-    MacroAssembler::Label loop = m_jit.label();
-    m_jit.sub32(TrustedImm32(1), scratch2GPR);
-    m_jit.store64(scratchGPR, MacroAssembler::BaseIndex(storageGPR, scratch2GPR, MacroAssembler::TimesEight));
-    m_jit.branchTest32(MacroAssembler::NonZero, scratch2GPR).linkTo(loop, &m_jit);
-    done.link(&m_jit);
-    
+    emitInitializeButterfly(storageGPR, sizeGPR, JSValueRegs(scratchGPR), scratch2GPR);
+
     Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType);
     
     emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);

Modified: branches/safari-603-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -107,6 +107,8 @@
     macro(Structure_globalObject, Structure::globalObjectOffset()) \
     macro(Structure_prototype, Structure::prototypeOffset()) \
     macro(Structure_structureID, Structure::structureIDOffset()) \
+    macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \
+    macro(Structure_indexingTypeIncludingHistory, Structure::indexingTypeIncludingHistoryOffset()) \
     macro(JSMap_hashMapImpl, JSMap::offsetOfHashMapImpl()) \
     macro(JSSet_hashMapImpl, JSSet::offsetOfHashMapImpl()) \
     macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \

Modified: branches/safari-603-branch/Source/_javascript_Core/ftl/FTLCapabilities.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -282,6 +282,7 @@
     case CheckDOM:
     case CallDOM:
     case CallDOMGetter:
+    case ArraySlice:
         // These are OK.
         break;
 

Modified: branches/safari-603-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -706,6 +706,9 @@
         case ArrayPop:
             compileArrayPop();
             break;
+        case ArraySlice:
+            compileArraySlice();
+            break;
         case CreateActivation:
             compileCreateActivation();
             break;
@@ -3860,6 +3863,75 @@
             return;
         }
     }
+
+    void compileArraySlice()
+    {
+        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+
+        LValue sourceStorage = lowStorage(m_node->numChildren() == 3 ? m_graph.varArgChild(m_node, 2) : m_graph.varArgChild(m_node, 3));
+        LValue inputLength = m_out.load32(sourceStorage, m_heaps.Butterfly_publicLength);
+
+        LValue endBoundary;
+        if (m_node->numChildren() == 3)
+            endBoundary = m_out.load32(sourceStorage, m_heaps.Butterfly_publicLength);
+        else {
+            endBoundary = lowInt32(m_graph.varArgChild(m_node, 2));
+            endBoundary = m_out.select(m_out.greaterThanOrEqual(endBoundary, m_out.constInt32(0)),
+                m_out.select(m_out.above(endBoundary, inputLength), inputLength, endBoundary),
+                m_out.select(m_out.lessThan(m_out.add(inputLength, endBoundary), m_out.constInt32(0)), m_out.constInt32(0), m_out.add(inputLength, endBoundary)));
+        }
+
+        LValue startIndex = lowInt32(m_graph.varArgChild(m_node, 1));
+        startIndex = m_out.select(m_out.greaterThanOrEqual(startIndex, m_out.constInt32(0)),
+            m_out.select(m_out.above(startIndex, inputLength), inputLength, startIndex),
+            m_out.select(m_out.lessThan(m_out.add(inputLength, startIndex), m_out.constInt32(0)), m_out.constInt32(0), m_out.add(inputLength, startIndex)));
+
+        LValue resultLength = m_out.select(m_out.below(startIndex, endBoundary),
+            m_out.sub(endBoundary, startIndex),
+            m_out.constInt32(0));
+
+        ArrayValues arrayResult;
+        {
+            LValue indexingType = m_out.load8ZeroExt32(lowCell(m_graph.varArgChild(m_node, 0)), m_heaps.JSCell_indexingTypeAndMisc);
+            indexingType = m_out.bitAnd(indexingType, m_out.constInt32(AllArrayTypesAndHistory));
+            // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure
+            // to ensure the incoming array is one to be one of the original array structures
+            // with one of the following indexing shapes: Int32, Contiguous, Double.
+            LValue structure = m_out.select(
+                m_out.equal(indexingType, m_out.constInt32(ArrayWithInt32)),
+                m_out.constIntPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32)),
+                m_out.select(m_out.equal(indexingType, m_out.constInt32(ArrayWithContiguous)),
+                    m_out.constIntPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous)),
+                    m_out.constIntPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble))));
+            arrayResult = allocateJSArray(resultLength, structure, indexingType, false, false);
+        }
+
+        LBasicBlock loop = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        resultLength = m_out.zeroExtPtr(resultLength);
+        ValueFromBlock startLoadIndex = m_out.anchor(m_out.zeroExtPtr(startIndex));
+        ValueFromBlock startStoreIndex = m_out.anchor(m_out.constIntPtr(0));
+
+        m_out.branch(
+            m_out.below(m_out.constIntPtr(0), resultLength), unsure(loop), unsure(continuation));
+
+        LBasicBlock lastNext = m_out.appendTo(loop, continuation);
+        LValue storeIndex = m_out.phi(pointerType(), startStoreIndex);
+        LValue loadIndex = m_out.phi(pointerType(), startLoadIndex);
+        LValue value = m_out.load64(m_out.baseIndex(m_heaps.root, sourceStorage, loadIndex, ScaleEight));
+        m_out.store64(value, m_out.baseIndex(m_heaps.root, arrayResult.butterfly, storeIndex, ScaleEight));
+        LValue nextStoreIndex = m_out.add(storeIndex, m_out.constIntPtr(1));
+        m_out.addIncomingToPhi(storeIndex, m_out.anchor(nextStoreIndex));
+        m_out.addIncomingToPhi(loadIndex, m_out.anchor(m_out.add(loadIndex, m_out.constIntPtr(1))));
+        m_out.branch(
+            m_out.below(nextStoreIndex, resultLength), unsure(loop), unsure(continuation));
+
+        m_out.appendTo(continuation, lastNext);
+
+        mutatorFence();
+        setJSValue(arrayResult.array);
+    }
     
     void compileArrayPop()
     {
@@ -4626,11 +4698,10 @@
             m_node->indexingType());
         
         if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
+            IndexingType indexingType = m_node->indexingType();
             setJSValue(
                 allocateJSArray(
-                    publicLength,
-                    globalObject->arrayStructureForIndexingTypeDuringAllocation(
-                        m_node->indexingType())).array);
+                    publicLength, m_out.constIntPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), m_out.constInt32(indexingType)).array);
             mutatorFence();
             return;
         }
@@ -8665,7 +8736,7 @@
 
                 m_out.store32(publicLength, butterfly, m_heaps.Butterfly_publicLength);
 
-                initializeArrayElements(structure->indexingType(), m_out.int32Zero, vectorLength, butterfly);
+                initializeArrayElements(m_out.constInt32(structure->indexingType()), m_out.int32Zero, vectorLength, butterfly);
 
                 HashMap<int32_t, LValue, DefaultHash<int32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<int32_t>> indexMap;
                 Vector<int32_t> indices;
@@ -9421,26 +9492,35 @@
         return result;
     }
 
-    void initializeArrayElements(IndexingType indexingType, LValue begin, LValue end, LValue butterfly)
+    void initializeArrayElements(LValue indexingType, LValue begin, LValue end, LValue butterfly)
     {
-        if (hasUndecided(indexingType))
-            return;
         
         if (begin == end)
             return;
         
-        IndexedAbstractHeap* heap = m_heaps.forIndexingType(indexingType);
-        DFG_ASSERT(m_graph, m_node, heap);
-        
-        LValue hole;
-        if (hasDouble(indexingType))
-            hole = m_out.constInt64(bitwise_cast<int64_t>(PNaN));
-        else
-            hole = m_out.constInt64(JSValue::encode(JSValue()));
-        
-        splatWords(butterfly, begin, end, hole, heap->atAnyIndex());
+        if (indexingType->hasInt32()) {
+            IndexingType rawIndexingType = static_cast<IndexingType>(indexingType->asInt32());
+            if (hasUndecided(rawIndexingType))
+                return;
+            IndexedAbstractHeap* heap = m_heaps.forIndexingType(rawIndexingType);
+            DFG_ASSERT(m_graph, m_node, heap);
+            
+            LValue hole;
+            if (hasDouble(rawIndexingType))
+                hole = m_out.constInt64(bitwise_cast<int64_t>(PNaN));
+            else
+                hole = m_out.constInt64(JSValue::encode(JSValue()));
+            
+            splatWords(butterfly, begin, end, hole, heap->atAnyIndex());
+        } else {
+            LValue hole = m_out.select(
+                m_out.equal(m_out.bitAnd(indexingType, m_out.constInt32(IndexingShapeMask)), m_out.constInt32(DoubleShape)),
+                m_out.constInt64(bitwise_cast<int64_t>(PNaN)),
+                m_out.constInt64(JSValue::encode(JSValue())));
+            splatWords(butterfly, begin, end, hole, m_heaps.root);
+        }
     }
-    
+
     void splatWords(LValue base, LValue begin, LValue end, LValue value, const AbstractHeap& heap)
     {
         const uint64_t unrollingLimit = 10;
@@ -10392,37 +10472,69 @@
             object, m_heaps.JSCell_usefulBytes);
     }
 
-    LValue allocateCell(LValue allocator, Structure* structure, LBasicBlock slowPath)
+    void storeStructure(LValue object, LValue structure)
     {
+        if (structure->hasIntPtr()) {
+            storeStructure(object, bitwise_cast<Structure*>(structure->asIntPtr()));
+            return;
+        }
+
+        LValue id = m_out.load32(structure, m_heaps.Structure_structureID);
+        m_out.store32(id, object, m_heaps.JSCell_structureID);
+
+        LValue blob = m_out.load32(structure, m_heaps.Structure_indexingTypeIncludingHistory);
+        m_out.store32(blob, object, m_heaps.JSCell_usefulBytes);
+    }
+
+    template <typename StructureType>
+    LValue allocateCell(LValue allocator, StructureType structure, LBasicBlock slowPath)
+    {
         LValue result = allocateHeapCell(allocator, slowPath);
         storeStructure(result, structure);
         return result;
     }
 
-    LValue allocateObject(
-        LValue allocator, Structure* structure, LValue butterfly, LBasicBlock slowPath)
+    LValue allocateObject(LValue allocator, Structure* structure, LValue butterfly, LBasicBlock slowPath)
     {
+        return allocateObject(allocator, m_out.constIntPtr(structure), butterfly, slowPath);
+    }
+
+    LValue allocateObject(LValue allocator, LValue structure, LValue butterfly, LBasicBlock slowPath)
+    {
         LValue result = allocateCell(allocator, structure, slowPath);
-        splatWords(
-            result,
-            m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
-            m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8 + structure->inlineCapacity()),
-            m_out.int64Zero,
-            m_heaps.properties.atAnyNumber());
+        if (structure->hasIntPtr()) {
+            splatWords(
+                result,
+                m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
+                m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8 + bitwise_cast<Structure*>(structure->asIntPtr())->inlineCapacity()),
+                m_out.int64Zero,
+                m_heaps.properties.atAnyNumber());
+        } else {
+            LValue end = m_out.add(
+                m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
+                m_out.load8ZeroExt32(structure, m_heaps.Structure_inlineCapacity));
+            splatWords(
+                result,
+                m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
+                end,
+                m_out.int64Zero,
+                m_heaps.properties.atAnyNumber());
+        }
+        
         m_out.storePtr(butterfly, result, m_heaps.JSObject_butterfly);
         return result;
     }
     
-    template<typename ClassType>
+    template<typename ClassType, typename StructureType>
     LValue allocateObject(
-        size_t size, Structure* structure, LValue butterfly, LBasicBlock slowPath)
+        size_t size, StructureType structure, LValue butterfly, LBasicBlock slowPath)
     {
         MarkedAllocator* allocator = vm().heap.allocatorForObjectOfType<ClassType>(size);
         return allocateObject(m_out.constIntPtr(allocator), structure, butterfly, slowPath);
     }
     
-    template<typename ClassType>
-    LValue allocateObject(Structure* structure, LValue butterfly, LBasicBlock slowPath)
+    template<typename ClassType, typename StructureType>
+    LValue allocateObject(StructureType structure, LValue butterfly, LBasicBlock slowPath)
     {
         return allocateObject<ClassType>(
             ClassType::allocationSize(0), structure, butterfly, slowPath);
@@ -10545,15 +10657,17 @@
         LValue butterfly;
     };
 
-    ArrayValues allocateJSArray(LValue publicLength, Structure* structure, bool shouldInitializeElements = true, bool shouldLargeArraySizeCreateArrayStorage = true)
+    ArrayValues allocateJSArray(LValue publicLength, LValue structure, LValue indexingType, bool shouldInitializeElements = true, bool shouldLargeArraySizeCreateArrayStorage = true)
     {
         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
-        IndexingType indexingType = structure->indexingType();
-        ASSERT(
-            hasUndecided(indexingType)
-            || hasInt32(indexingType)
-            || hasDouble(indexingType)
-            || hasContiguous(indexingType));
+        if (indexingType->hasInt32()) {
+            IndexingType type = static_cast<IndexingType>(indexingType->asInt32());
+            ASSERT_UNUSED(type,
+                hasUndecided(type)
+                || hasInt32(type)
+                || hasDouble(type)
+                || hasContiguous(type));
+        }
 
         LBasicBlock fastCase = m_out.newBlock();
         LBasicBlock largeCase = m_out.newBlock();
@@ -10576,12 +10690,12 @@
         m_out.appendTo(fastCase, largeCase);
 
         LValue vectorLength = nullptr;
-        if (publicLength->hasInt32()) {
+        if (publicLength->hasInt32() && structure->hasIntPtr()) {
             unsigned publicLengthConst = static_cast<unsigned>(publicLength->asInt32());
             if (publicLengthConst <= MAX_STORAGE_VECTOR_LENGTH) {
                 vectorLength = m_out.constInt32(
                     Butterfly::optimalContiguousVectorLength(
-                        structure->outOfLineCapacity(), publicLengthConst));
+                        bitwise_cast<Structure*>(structure->asIntPtr())->outOfLineCapacity(), publicLengthConst));
             }
         }
         
@@ -10614,7 +10728,7 @@
         ValueFromBlock haveButterfly = m_out.anchor(butterfly);
         
         LValue object = allocateObject<JSArray>(structure, butterfly, failCase);
-            
+
         ValueFromBlock fastResult = m_out.anchor(object);
         ValueFromBlock fastButterfly = m_out.anchor(butterfly);
         m_out.jump(continuation);
@@ -10626,7 +10740,7 @@
         m_out.jump(slowCase);
         
         m_out.appendTo(failCase, slowCase);
-        ValueFromBlock failStructure = m_out.anchor(m_out.constIntPtr(structure));
+        ValueFromBlock failStructure = m_out.anchor(structure);
         m_out.jump(slowCase);
         
         m_out.appendTo(slowCase, continuation);
@@ -10656,7 +10770,7 @@
         bool shouldInitializeElements = false;
         bool shouldLargeArraySizeCreateArrayStorage = false;
         return allocateJSArray(
-            publicLength, structure, shouldInitializeElements,
+            publicLength, m_out.constIntPtr(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,
             shouldLargeArraySizeCreateArrayStorage);
     }
     

Modified: branches/safari-603-branch/Source/_javascript_Core/jit/AssemblyHelpers.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/jit/AssemblyHelpers.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/jit/AssemblyHelpers.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -447,6 +447,7 @@
 void AssemblyHelpers::emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch)
 {
 #if USE(JSVALUE64)
+    ASSERT(dest != scratch);
     load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
     loadPtr(vm()->heap.structureIDTable().base(), scratch);
     loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);

Modified: branches/safari-603-branch/Source/_javascript_Core/runtime/ArrayPrototype.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -98,7 +98,7 @@
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("reverse", arrayProtoFuncReverse, DontEnum, 0);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().shiftPublicName(), arrayProtoFuncShift, DontEnum, 0);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().shiftPrivateName(), arrayProtoFuncShift, DontEnum | DontDelete | ReadOnly, 0);
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, arrayProtoFuncSlice, DontEnum, 2);
+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, arrayProtoFuncSlice, DontEnum, 2, ArraySliceIntrinsic);
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("sort", arrayPrototypeSortCodeGenerator, DontEnum);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("splice", arrayProtoFuncSplice, DontEnum, 2);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("unshift", arrayProtoFuncUnShift, DontEnum, 1);
@@ -191,21 +191,12 @@
         throwTypeError(exec, scope, ASCIILiteral(ReadonlyPropertyWriteError));
 }
 
-inline bool speciesWatchpointsValid(ExecState* exec, JSObject* thisObject)
+inline bool speciesWatchpointIsValid(JSObject* thisObject)
 {
-    VM& vm = exec->vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
     ArrayPrototype* arrayPrototype = thisObject->globalObject()->arrayPrototype();
-    ArrayPrototype::SpeciesWatchpointStatus status = arrayPrototype->speciesWatchpointStatus();
-    if (UNLIKELY(status == ArrayPrototype::SpeciesWatchpointStatus::Uninitialized)) {
-        status = arrayPrototype->attemptToInitializeSpeciesWatchpoint(exec);
-        RETURN_IF_EXCEPTION(scope, false);
-    }
-    ASSERT(status != ArrayPrototype::SpeciesWatchpointStatus::Uninitialized);
     return !thisObject->hasCustomProperties()
         && arrayPrototype == thisObject->getPrototypeDirect()
-        && status == ArrayPrototype::SpeciesWatchpointStatus::Initialized;
+        && arrayPrototype->globalObject()->arraySpeciesWatchpoint().isStillValid();
 }
 
 enum class SpeciesConstructResult {
@@ -230,8 +221,7 @@
     if (LIKELY(thisIsArray)) {
         // Fast path in the normal case where the user has not set an own constructor and the Array.prototype.constructor is normal.
         // We need prototype check for subclasses of Array, which are Array objects but have a different prototype by default.
-        bool isValid = speciesWatchpointsValid(exec, thisObject);
-        RETURN_IF_EXCEPTION(scope, exceptionResult());
+        bool isValid = speciesWatchpointIsValid(thisObject);
         if (LIKELY(isValid))
             return std::make_pair(SpeciesConstructResult::FastPath, nullptr);
 
@@ -920,29 +910,29 @@
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
 {
-    // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
+    // https://tc39.github.io/ecma262/#sec-array.prototype.slice
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
     JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
     ASSERT(!!scope.exception() == !thisObj);
     if (UNLIKELY(!thisObj))
-        return encodedJSValue();
+        return { };
     unsigned length = getLength(exec, thisObj);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    RETURN_IF_EXCEPTION(scope, { });
 
     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    RETURN_IF_EXCEPTION(scope, { });
     unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    RETURN_IF_EXCEPTION(scope, { });
 
     std::pair<SpeciesConstructResult, JSObject*> speciesResult = speciesConstructArray(exec, thisObj, end - begin);
     // We can only get an exception if we call some user function.
     ASSERT(!!scope.exception() == (speciesResult.first == SpeciesConstructResult::Exception));
     if (UNLIKELY(speciesResult.first == SpeciesConstructResult::Exception))
-        return encodedJSValue();
+        return { };
 
     bool okToDoFastPath = speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == getLength(exec, thisObj);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    RETURN_IF_EXCEPTION(scope, { });
     if (LIKELY(okToDoFastPath)) {
         if (JSArray* result = asArray(thisObj)->fastSlice(*exec, begin, end - begin))
             return JSValue::encode(result);
@@ -953,16 +943,16 @@
         result = speciesResult.second;
     else {
         result = constructEmptyArray(exec, nullptr, end - begin);
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        RETURN_IF_EXCEPTION(scope, { });
     }
 
     unsigned n = 0;
     for (unsigned k = begin; k < end; k++, n++) {
         JSValue v = getProperty(exec, thisObj, k);
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        RETURN_IF_EXCEPTION(scope, { });
         if (v) {
             result->putDirectIndex(exec, n, v, 0, PutDirectIndexShouldThrow);
-            RETURN_IF_EXCEPTION(scope, encodedJSValue());
+            RETURN_IF_EXCEPTION(scope, { });
         }
     }
     scope.release();
@@ -1249,8 +1239,7 @@
         return JSValue::encode(jsNull());
 
     // We need to check the species constructor here since checking it in the JS wrapper is too expensive for the non-optimizing tiers.
-    bool isValid = speciesWatchpointsValid(exec, firstArray);
-    ASSERT(!scope.exception() || !isValid);
+    bool isValid = speciesWatchpointIsValid(firstArray);
     if (UNLIKELY(!isValid))
         return JSValue::encode(jsNull());
 
@@ -1342,15 +1331,18 @@
     ArrayPrototype* m_arrayPrototype;
 };
 
-ArrayPrototype::SpeciesWatchpointStatus ArrayPrototype::attemptToInitializeSpeciesWatchpoint(ExecState* exec)
+void ArrayPrototype::initializeSpeciesWatchpoint(ExecState* exec)
 {
-    ASSERT(m_speciesWatchpointStatus == SpeciesWatchpointStatus::Uninitialized);
+    VM& vm = exec->vm();
 
-    VM& vm = exec->vm();
+    RELEASE_ASSERT(!m_constructorWatchpoint);
+    RELEASE_ASSERT(!m_constructorSpeciesWatchpoint);
+
     auto scope = DECLARE_THROW_SCOPE(vm);
+    UNUSED_PARAM(scope);
 
     if (verbose)
-        dataLog("Attempting to initialize Array species watchpoints for Array.prototype: ", pointerDump(this), " with structure: ", pointerDump(this->structure()), "\nand Array: ", pointerDump(this->globalObject()->arrayConstructor()), " with structure: ", pointerDump(this->globalObject()->arrayConstructor()->structure()), "\n");
+        dataLog("Initializing Array species watchpoints for Array.prototype: ", pointerDump(this), " with structure: ", pointerDump(this->structure()), "\nand Array: ", pointerDump(this->globalObject()->arrayConstructor()), " with structure: ", pointerDump(this->globalObject()->arrayConstructor()->structure()), "\n");
     // First we need to make sure that the Array.prototype.constructor property points to Array
     // and that Array[Symbol.species] is the primordial GetterSetter.
 
@@ -1364,12 +1356,11 @@
     ArrayConstructor* arrayConstructor = globalObject->arrayConstructor();
 
     PropertySlot constructorSlot(this, PropertySlot::InternalMethodType::VMInquiry);
-    JSValue(this).get(exec, vm.propertyNames->constructor, constructorSlot);
-    if (UNLIKELY(scope.exception())
-        || constructorSlot.slotBase() != this
-        || !constructorSlot.isCacheableValue()
-        || constructorSlot.getValue(exec, vm.propertyNames->constructor) != arrayConstructor)
-        return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Fired;
+    this->getOwnPropertySlot(this, exec, vm.propertyNames->constructor, constructorSlot);
+    ASSERT(!scope.exception());
+    ASSERT(constructorSlot.slotBase() == this);
+    ASSERT(constructorSlot.isCacheableValue());
+    RELEASE_ASSERT(constructorSlot.getValue(exec, vm.propertyNames->constructor) == arrayConstructor);
 
     Structure* constructorStructure = arrayConstructor->structure(vm);
     if (constructorStructure->isDictionary())
@@ -1376,12 +1367,11 @@
         constructorStructure = constructorStructure->flattenDictionaryStructure(vm, arrayConstructor);
 
     PropertySlot speciesSlot(arrayConstructor, PropertySlot::InternalMethodType::VMInquiry);
-    JSValue(arrayConstructor).get(exec, vm.propertyNames->speciesSymbol, speciesSlot);
-    if (UNLIKELY(scope.exception())
-        || speciesSlot.slotBase() != arrayConstructor
-        || !speciesSlot.isCacheableGetter()
-        || speciesSlot.getterSetter() != globalObject->speciesGetterSetter())
-        return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Fired;
+    arrayConstructor->getOwnPropertySlot(arrayConstructor, exec, vm.propertyNames->speciesSymbol, speciesSlot);
+    ASSERT(!scope.exception());
+    ASSERT(speciesSlot.slotBase() == arrayConstructor);
+    ASSERT(speciesSlot.isCacheableGetter());
+    RELEASE_ASSERT(speciesSlot.getterSetter() == globalObject->speciesGetterSetter());
 
     // Now we need to setup the watchpoints to make sure these conditions remain valid.
     prototypeStructure->startWatchingPropertyForReplacements(vm, constructorSlot.cachedOffset());
@@ -1390,8 +1380,8 @@
     ObjectPropertyCondition constructorCondition = ObjectPropertyCondition::equivalence(vm, this, this, vm.propertyNames->constructor.impl(), arrayConstructor);
     ObjectPropertyCondition speciesCondition = ObjectPropertyCondition::equivalence(vm, this, arrayConstructor, vm.propertyNames->speciesSymbol.impl(), globalObject->speciesGetterSetter());
 
-    if (!constructorCondition.isWatchable() || !speciesCondition.isWatchable())
-        return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Fired;
+    RELEASE_ASSERT(constructorCondition.isWatchable());
+    RELEASE_ASSERT(speciesCondition.isWatchable());
 
     m_constructorWatchpoint = std::make_unique<ArrayPrototypeAdaptiveInferredPropertyWatchpoint>(constructorCondition, this);
     m_constructorWatchpoint->install();
@@ -1398,8 +1388,6 @@
 
     m_constructorSpeciesWatchpoint = std::make_unique<ArrayPrototypeAdaptiveInferredPropertyWatchpoint>(speciesCondition, this);
     m_constructorSpeciesWatchpoint->install();
-
-    return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Initialized;
 }
 
 ArrayPrototypeAdaptiveInferredPropertyWatchpoint::ArrayPrototypeAdaptiveInferredPropertyWatchpoint(const ObjectPropertyCondition& key, ArrayPrototype* prototype)
@@ -1418,7 +1406,8 @@
     if (verbose)
         WTF::dataLog(stringDetail, "\n");
 
-    m_arrayPrototype->m_speciesWatchpointStatus = ArrayPrototype::SpeciesWatchpointStatus::Fired;
+    JSGlobalObject* globalObject = m_arrayPrototype->globalObject();
+    globalObject->arraySpeciesWatchpoint().fireAll(globalObject->vm(), stringDetail);
 }
 
 } // namespace JSC

Modified: branches/safari-603-branch/Source/_javascript_Core/runtime/ArrayPrototype.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/runtime/ArrayPrototype.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/runtime/ArrayPrototype.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -49,8 +49,7 @@
         return Structure::create(vm, globalObject, prototype, TypeInfo(DerivedArrayType, StructureFlags), info(), ArrayClass);
     }
 
-    SpeciesWatchpointStatus speciesWatchpointStatus() const { return m_speciesWatchpointStatus; }
-    SpeciesWatchpointStatus attemptToInitializeSpeciesWatchpoint(ExecState*);
+    void initializeSpeciesWatchpoint(ExecState*);
 
     static const bool needsDestruction = false;
     // We don't need destruction since we use a finalizer.
@@ -64,7 +63,6 @@
     friend ArrayPrototypeAdaptiveInferredPropertyWatchpoint;
     std::unique_ptr<ArrayPrototypeAdaptiveInferredPropertyWatchpoint> m_constructorWatchpoint;
     std::unique_ptr<ArrayPrototypeAdaptiveInferredPropertyWatchpoint> m_constructorSpeciesWatchpoint;
-    SpeciesWatchpointStatus m_speciesWatchpointStatus { SpeciesWatchpointStatus::Uninitialized };
 };
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*);

Modified: branches/safari-603-branch/Source/_javascript_Core/runtime/Intrinsic.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/runtime/Intrinsic.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/runtime/Intrinsic.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -40,6 +40,7 @@
     TanIntrinsic,
     ArrayPushIntrinsic,
     ArrayPopIntrinsic,
+    ArraySliceIntrinsic,
     CharCodeAtIntrinsic,
     CharAtIntrinsic,
     FromCharCodeIntrinsic,

Modified: branches/safari-603-branch/Source/_javascript_Core/runtime/JSGlobalObject.cpp (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-01-18 20:42:19 UTC (rev 210865)
@@ -331,6 +331,7 @@
     , m_varInjectionWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
     , m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
     , m_arrayIteratorProtocolWatchpoint(IsWatched)
+    , m_arraySpeciesWatchpoint(IsWatched)
     , m_templateRegistry(vm)
     , m_evalEnabled(true)
     , m_runtimeFlags()
@@ -943,6 +944,8 @@
             m_arrayPrototypeSymbolIteratorWatchpoint = std::make_unique<ArrayIteratorAdaptiveWatchpoint>(condition, this);
             m_arrayPrototypeSymbolIteratorWatchpoint->install();
         }
+
+        this->arrayPrototype()->initializeSpeciesWatchpoint(exec);
     }
 
     resetPrototype(vm, getPrototypeDirect());

Modified: branches/safari-603-branch/Source/_javascript_Core/runtime/JSGlobalObject.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/runtime/JSGlobalObject.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/runtime/JSGlobalObject.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -398,9 +398,11 @@
     WeakRandom m_weakRandom;
 
     InlineWatchpointSet& arrayIteratorProtocolWatchpoint() { return m_arrayIteratorProtocolWatchpoint; }
+    InlineWatchpointSet& arraySpeciesWatchpoint() { return m_arraySpeciesWatchpoint; }
     // If this hasn't been invalidated, it means the array iterator protocol
     // is not observable to user code yet.
     InlineWatchpointSet m_arrayIteratorProtocolWatchpoint;
+    InlineWatchpointSet m_arraySpeciesWatchpoint;
     std::unique_ptr<ArrayIteratorAdaptiveWatchpoint> m_arrayPrototypeSymbolIteratorWatchpoint;
     std::unique_ptr<ArrayIteratorAdaptiveWatchpoint> m_arrayIteratorPrototypeNext;
 

Modified: branches/safari-603-branch/Source/_javascript_Core/runtime/Structure.h (210864 => 210865)


--- branches/safari-603-branch/Source/_javascript_Core/runtime/Structure.h	2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/_javascript_Core/runtime/Structure.h	2017-01-18 20:42:19 UTC (rev 210865)
@@ -464,6 +464,11 @@
         return OBJECT_OFFSETOF(Structure, m_propertyTableUnsafe);
     }
 
+    static ptrdiff_t inlineCapacityOffset()
+    {
+        return OBJECT_OFFSETOF(Structure, m_inlineCapacity);
+    }
+
     static Structure* createStructure(VM&);
         
     bool transitionWatchpointSetHasBeenInvalidated() const
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to