We should have a more concise way of determining when we're varargs calling a functio...
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 12 Nov 2016 02:58:11 +0000 (02:58 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 12 Nov 2016 02:58:11 +0000 (02:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=164258

Reviewed by Yusuke Suzuki.

JSTests:

* microbenchmarks/call-using-spread.js: Added.
(bar):
(foo):
* microbenchmarks/spread-large-array.js: Added.
(foo):
(arrays.push):
* microbenchmarks/spread-small-array.js: Added.
(foo):
* stress/spread-array-iterator-watchpoint-2.js: Added.
(foo):
(arrayIterator.next):
* stress/spread-array-iterator-watchpoint.js: Added.
(foo):
(Array.prototype.Symbol.iterator):
* stress/spread-non-array.js: Added.
(assert):
(foo):
(let.customIterator.Symbol.iterator):
(bar):

Source/JavaScriptCore:

This patch adds two new bytecodes and DFG nodes for the following code patterns:

```
foo(a, b, ...c)
let x = [a, b, ...c];
```

To do this, I've introduced two new bytecode operations (and their
corresponding DFG nodes):

op_spread and op_new_array_with_spread.

op_spread takes a single input and performs the ES6 iteration protocol on it.
It returns the result of doing the spread inside a new class I've
made called JSFixedArray. JSFixedArray is a cell with a single 'size'
field and a buffer of values allocated inline in the cell. Abstracting
the protocol into a single node is good because it will make IR analysis
in the future much simpler. For now, it's also good because it allows
us to create fast paths for array iteration (which is quite common).
This fast path allows us to emit really good code for array iteration
inside the DFG/FTL.

op_new_array_with_spread is a variable argument bytecode that also
has a bit vector associated with it. The bit vector indicates if
any particular argument is to be spread or not. Arguments that
are spread are known to be JSFixedArray because we must emit an
op_spread before op_new_array_with_spread consumes the value.
For example, for this array:
[a, b, ...c, d, ...e]
we will have this bit vector:
[0, 0, 1, 0, 1]

The reason I've chosen this IR is that it will make eliminating
a rest allocation for this type of code much easier:

```
function foo(...args) {
    return bar(a, b, ...args);
}
```

It will be easier to analyze the IR now that the operations
will be described at a high level.

This patch is an ~8% speedup on ES6SampleBench on my MBP.

* CMakeLists.txt:
* DerivedSources.make:
* JavaScriptCore.xcodeproj/project.pbxproj:
* builtins/IteratorHelpers.js: Added.
(performIteration):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecode/ObjectPropertyConditionSet.cpp:
(JSC::generateConditionForSelfEquivalence):
* bytecode/ObjectPropertyConditionSet.h:
* bytecode/TrackedReferences.cpp:
(JSC::TrackedReferences::check):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::bitVectors):
(JSC::UnlinkedCodeBlock::bitVector):
(JSC::UnlinkedCodeBlock::addBitVector):
(JSC::UnlinkedCodeBlock::shrinkToFit):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitNewArrayWithSpread):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ArrayNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addToGraph):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::watchHavingABadTime):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::isWatchingArrayIteratorProtocolWatchpoint):
* dfg/DFGNode.h:
(JSC::DFG::Node::bitVector):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileSpread):
(JSC::DFG::SpeculativeJIT::compileNewArrayWithSpread):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureRegistrationPhase.cpp:
(JSC::DFG::StructureRegistrationPhase::run):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSpread):
(JSC::FTL::DFG::LowerDFGToB3::compileSpread):
(JSC::FTL::DFG::LowerDFGToB3::allocateVariableSizedCell):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::emitAllocateVariableSizedCell):
(JSC::AssemblyHelpers::emitAllocateVariableSizedJSObject):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_new_array_with_spread):
(JSC::JIT::emit_op_spread):
* jit/JITOperations.h:
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LLIntSlowPaths.cpp:
* llint/LowLevelInterpreter.asm:
* runtime/ArrayIteratorAdaptiveWatchpoint.cpp: Added.
(JSC::ArrayIteratorAdaptiveWatchpoint::ArrayIteratorAdaptiveWatchpoint):
(JSC::ArrayIteratorAdaptiveWatchpoint::handleFire):
* runtime/ArrayIteratorAdaptiveWatchpoint.h: Added.
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/IteratorOperations.h:
(JSC::forEachInIterable):
* runtime/JSCInlines.h:
* runtime/JSFixedArray.cpp: Added.
(JSC::JSFixedArray::visitChildren):
* runtime/JSFixedArray.h: Added.
(JSC::JSFixedArray::createStructure):
(JSC::JSFixedArray::createFromArray):
(JSC::JSFixedArray::get):
(JSC::JSFixedArray::buffer):
(JSC::JSFixedArray::size):
(JSC::JSFixedArray::offsetOfSize):
(JSC::JSFixedArray::offsetOfData):
(JSC::JSFixedArray::create):
(JSC::JSFixedArray::JSFixedArray):
(JSC::JSFixedArray::allocationSize):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::JSGlobalObject):
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
(JSC::JSGlobalObject::objectPrototypeIsSane): Deleted.
(JSC::JSGlobalObject::arrayPrototypeChainIsSane): Deleted.
(JSC::JSGlobalObject::stringPrototypeChainIsSane): Deleted.
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::arrayIteratorProtocolWatchpoint):
(JSC::JSGlobalObject::iteratorProtocolFunction):
* runtime/JSGlobalObjectInlines.h: Added.
(JSC::JSGlobalObject::objectPrototypeIsSane):
(JSC::JSGlobalObject::arrayPrototypeChainIsSane):
(JSC::JSGlobalObject::stringPrototypeChainIsSane):
(JSC::JSGlobalObject::isArrayIteratorProtocolFastAndNonObservable):
* runtime/JSType.h:
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208637 268f45cc-cd09-0410-ab3c-d52691b4dbfc

65 files changed:
JSTests/ChangeLog
JSTests/microbenchmarks/call-using-spread.js [new file with mode: 0644]
JSTests/microbenchmarks/spread-large-array.js [new file with mode: 0644]
JSTests/microbenchmarks/spread-small-array.js [new file with mode: 0644]
JSTests/stress/spread-array-iterator-watchpoint-2.js [new file with mode: 0644]
JSTests/stress/spread-array-iterator-watchpoint.js [new file with mode: 0644]
JSTests/stress/spread-non-array.js [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/builtins/IteratorHelpers.js [new file with mode: 0644]
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp
Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.h
Source/JavaScriptCore/bytecode/TrackedReferences.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStructureRegistrationPhase.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/AssemblyHelpers.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/llint/LLIntData.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/IteratorOperations.h
Source/JavaScriptCore/runtime/JSCInlines.h
Source/JavaScriptCore/runtime/JSFixedArray.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSFixedArray.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSType.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h

index 1ae8b83..a20b84b 100644 (file)
@@ -1,3 +1,30 @@
+2016-11-11  Saam Barati  <sbarati@apple.com>
+
+        We should have a more concise way of determining when we're varargs calling a function using rest parameters
+        https://bugs.webkit.org/show_bug.cgi?id=164258
+
+        Reviewed by Yusuke Suzuki.
+
+        * microbenchmarks/call-using-spread.js: Added.
+        (bar):
+        (foo):
+        * microbenchmarks/spread-large-array.js: Added.
+        (foo):
+        (arrays.push):
+        * microbenchmarks/spread-small-array.js: Added.
+        (foo):
+        * stress/spread-array-iterator-watchpoint-2.js: Added.
+        (foo):
+        (arrayIterator.next):
+        * stress/spread-array-iterator-watchpoint.js: Added.
+        (foo):
+        (Array.prototype.Symbol.iterator):
+        * stress/spread-non-array.js: Added.
+        (assert):
+        (foo):
+        (let.customIterator.Symbol.iterator):
+        (bar):
+
 2016-11-11  Keith Miller  <keith_miller@apple.com>
 
         Relocate wasm tests and actually add them to the test runner
diff --git a/JSTests/microbenchmarks/call-using-spread.js b/JSTests/microbenchmarks/call-using-spread.js
new file mode 100644 (file)
index 0000000..659a344
--- /dev/null
@@ -0,0 +1,14 @@
+function bar(a, b, c, d, e, f) { }
+noInline(bar);
+function foo(a, b, ...args) {
+    return bar(a, b, ...args);
+}
+noInline(foo);
+
+let start = Date.now();
+for (let i = 0; i < 500000; i++) {
+    foo(i, i+1, i+2, i+3, i+4, i+5);
+}
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);
diff --git a/JSTests/microbenchmarks/spread-large-array.js b/JSTests/microbenchmarks/spread-large-array.js
new file mode 100644 (file)
index 0000000..d6efa52
--- /dev/null
@@ -0,0 +1,39 @@
+function foo(arg) {
+    return [...arg];
+}
+noInline(foo);
+
+let arrays = [ ];
+const size = 500;
+{
+    let arr = [];
+    for (let i = 0; i < size; i++) {
+        arr.push(i);
+    }
+    arrays.push(arr);
+}
+
+{
+    let arr = [];
+    for (let i = 0; i < size; i++) {
+        arr.push(i + 0.5);
+    }
+    arrays.push(arr);
+}
+
+{
+    let arr = [];
+    for (let i = 0; i < size; i++) {
+        arr.push({i: i});
+    }
+    arrays.push(arr);
+}
+
+let start = Date.now();
+for (let i = 0; i < 100000; i++) {
+    let array = arrays[i % arrays.length];
+    foo(array);
+}
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);
diff --git a/JSTests/microbenchmarks/spread-small-array.js b/JSTests/microbenchmarks/spread-small-array.js
new file mode 100644 (file)
index 0000000..a68ee6c
--- /dev/null
@@ -0,0 +1,19 @@
+function foo(arg) {
+    return [...arg];
+}
+noInline(foo);
+
+let arrays = [
+    [10, 20, 40],
+    [10.5, 20.5, 40.5],
+    [20, {}, 8],
+];
+
+let start = Date.now();
+for (let i = 0; i < 10000000; i++) {
+    let array = arrays[i % arrays.length];
+    foo(array);
+}
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);
diff --git a/JSTests/stress/spread-array-iterator-watchpoint-2.js b/JSTests/stress/spread-array-iterator-watchpoint-2.js
new file mode 100644 (file)
index 0000000..7dde534
--- /dev/null
@@ -0,0 +1,22 @@
+function foo(a) {
+    return [...a];
+}
+noInline(foo);
+
+let arr = [];
+for (let i = 0; i < 10000; i++) {
+    if (i % 100 === 0)
+        arr.push([], i);
+    foo(arr);
+}
+
+let calledIterator = false;
+let arrayIterator = [][Symbol.iterator]().__proto__;
+arrayIterator.next = function() {
+    calledIterator = true;
+    return {done: true};
+};
+
+let r = foo(arr);
+if (!calledIterator || r.length)
+    throw new Error("Bad result");
diff --git a/JSTests/stress/spread-array-iterator-watchpoint.js b/JSTests/stress/spread-array-iterator-watchpoint.js
new file mode 100644 (file)
index 0000000..ac77453
--- /dev/null
@@ -0,0 +1,25 @@
+function foo(a) {
+    return [...a];
+}
+noInline(foo);
+
+let arr = [];
+for (let i = 0; i < 10000; i++) {
+    if (i % 100 === 0)
+        arr.push([], i);
+    foo(arr);
+}
+
+let calledIterator = false;
+Array.prototype[Symbol.iterator] = function iterator() {
+    calledIterator = true;
+    return {
+        next() {
+            return {done: true};
+        }
+    };
+};
+
+foo(arr);
+if (!calledIterator)
+    throw new Error("Bad result");
diff --git a/JSTests/stress/spread-non-array.js b/JSTests/stress/spread-non-array.js
new file mode 100644 (file)
index 0000000..124789a
--- /dev/null
@@ -0,0 +1,62 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion.");
+}
+function foo(m) {
+    return [...m];
+}
+noInline(foo);
+
+let map = new Map;
+map.set(20, 30);
+map.set(40, 50);
+
+let called = 0;
+let customIterator = {
+    [Symbol.iterator]: function() {
+        called++;
+        let count = 0;
+        return {
+            next() {
+                called++;
+                count++;
+                if (count === 1)
+                    return {done: false, value: [20, 30]};
+                if (count === 2)
+                    return {done: false, value: [40, 50]};
+                return {done: true};
+            }
+        };
+    }
+};
+for (let i = 0; i < 10000; i++) {
+    for (let o of [customIterator, map]) {
+        let [[a, b], [c, d]] = foo(o);
+        assert(a === 20);
+        assert(b === 30);
+        assert(c === 40);
+        assert(d === 50);
+    }
+    assert(called === 4);
+    called = 0;
+}
+
+function bar(m) {
+    return [...m, ...m];
+}
+noInline(bar);
+for (let i = 0; i < 10000; i++) {
+    for (let o of [customIterator, map]) {
+        let [[a, b], [c, d], [e, f], [g, h]] = bar(o);
+        assert(a === 20);
+        assert(b === 30);
+        assert(c === 40);
+        assert(d === 50);
+        assert(e === 20);
+        assert(f === 30);
+        assert(g === 40);
+        assert(h === 50);
+    }
+    assert(called === 8);
+    called = 0;
+}
index 72dcc02..785e9d2 100644 (file)
@@ -650,6 +650,7 @@ set(JavaScriptCore_SOURCES
     runtime/ArrayBufferView.cpp
     runtime/ArrayConstructor.cpp
     runtime/ArrayConventions.cpp
+    runtime/ArrayIteratorAdaptiveWatchpoint.cpp
     runtime/ArrayIteratorPrototype.cpp
     runtime/ArrayPrototype.cpp
     runtime/AtomicsObject.cpp
@@ -743,6 +744,7 @@ set(JavaScriptCore_SOURCES
     runtime/JSDataViewPrototype.cpp
     runtime/JSDateMath.cpp
     runtime/JSEnvironmentRecord.cpp
+    runtime/JSFixedArray.cpp
     runtime/JSFunction.cpp
     runtime/JSGeneratorFunction.cpp
     runtime/JSGlobalLexicalEnvironment.cpp
@@ -1350,6 +1352,7 @@ set(JavaScriptCore_BUILTINS_SOURCES
     ${JAVASCRIPTCORE_DIR}/builtins/GlobalOperations.js
     ${JAVASCRIPTCORE_DIR}/builtins/InspectorInstrumentationObject.js
     ${JAVASCRIPTCORE_DIR}/builtins/InternalPromiseConstructor.js
+    ${JAVASCRIPTCORE_DIR}/builtins/IteratorHelpers.js
     ${JAVASCRIPTCORE_DIR}/builtins/IteratorPrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/MapPrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/ModuleLoaderPrototype.js
index 64811b1..3c7fad8 100644 (file)
@@ -1,3 +1,182 @@
+2016-11-11  Saam Barati  <sbarati@apple.com>
+
+        We should have a more concise way of determining when we're varargs calling a function using rest parameters
+        https://bugs.webkit.org/show_bug.cgi?id=164258
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch adds two new bytecodes and DFG nodes for the following code patterns:
+
+        ```
+        foo(a, b, ...c)
+        let x = [a, b, ...c];
+        ```
+
+        To do this, I've introduced two new bytecode operations (and their
+        corresponding DFG nodes):
+
+        op_spread and op_new_array_with_spread.
+
+        op_spread takes a single input and performs the ES6 iteration protocol on it.
+        It returns the result of doing the spread inside a new class I've
+        made called JSFixedArray. JSFixedArray is a cell with a single 'size'
+        field and a buffer of values allocated inline in the cell. Abstracting
+        the protocol into a single node is good because it will make IR analysis
+        in the future much simpler. For now, it's also good because it allows
+        us to create fast paths for array iteration (which is quite common).
+        This fast path allows us to emit really good code for array iteration
+        inside the DFG/FTL.
+
+        op_new_array_with_spread is a variable argument bytecode that also
+        has a bit vector associated with it. The bit vector indicates if
+        any particular argument is to be spread or not. Arguments that
+        are spread are known to be JSFixedArray because we must emit an
+        op_spread before op_new_array_with_spread consumes the value.
+        For example, for this array:
+        [a, b, ...c, d, ...e]
+        we will have this bit vector:
+        [0, 0, 1, 0, 1]
+
+        The reason I've chosen this IR is that it will make eliminating
+        a rest allocation for this type of code much easier:
+
+        ```
+        function foo(...args) {
+            return bar(a, b, ...args);
+        }
+        ```
+
+        It will be easier to analyze the IR now that the operations
+        will be described at a high level.
+
+        This patch is an ~8% speedup on ES6SampleBench on my MBP.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * builtins/IteratorHelpers.js: Added.
+        (performIteration):
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecode/ObjectPropertyConditionSet.cpp:
+        (JSC::generateConditionForSelfEquivalence):
+        * bytecode/ObjectPropertyConditionSet.h:
+        * bytecode/TrackedReferences.cpp:
+        (JSC::TrackedReferences::check):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::bitVectors):
+        (JSC::UnlinkedCodeBlock::bitVector):
+        (JSC::UnlinkedCodeBlock::addBitVector):
+        (JSC::UnlinkedCodeBlock::shrinkToFit):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitNewArrayWithSpread):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ArrayNode::emitBytecode):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addToGraph):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::watchHavingABadTime):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::isWatchingArrayIteratorProtocolWatchpoint):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::bitVector):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileSpread):
+        (JSC::DFG::SpeculativeJIT::compileNewArrayWithSpread):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStructureRegistrationPhase.cpp:
+        (JSC::DFG::StructureRegistrationPhase::run):
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSpread):
+        (JSC::FTL::DFG::LowerDFGToB3::compileSpread):
+        (JSC::FTL::DFG::LowerDFGToB3::allocateVariableSizedCell):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::emitAllocateVariableSizedCell):
+        (JSC::AssemblyHelpers::emitAllocateVariableSizedJSObject):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_new_array_with_spread):
+        (JSC::JIT::emit_op_spread):
+        * jit/JITOperations.h:
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LLIntSlowPaths.cpp:
+        * llint/LowLevelInterpreter.asm:
+        * runtime/ArrayIteratorAdaptiveWatchpoint.cpp: Added.
+        (JSC::ArrayIteratorAdaptiveWatchpoint::ArrayIteratorAdaptiveWatchpoint):
+        (JSC::ArrayIteratorAdaptiveWatchpoint::handleFire):
+        * runtime/ArrayIteratorAdaptiveWatchpoint.h: Added.
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        * runtime/IteratorOperations.h:
+        (JSC::forEachInIterable):
+        * runtime/JSCInlines.h:
+        * runtime/JSFixedArray.cpp: Added.
+        (JSC::JSFixedArray::visitChildren):
+        * runtime/JSFixedArray.h: Added.
+        (JSC::JSFixedArray::createStructure):
+        (JSC::JSFixedArray::createFromArray):
+        (JSC::JSFixedArray::get):
+        (JSC::JSFixedArray::buffer):
+        (JSC::JSFixedArray::size):
+        (JSC::JSFixedArray::offsetOfSize):
+        (JSC::JSFixedArray::offsetOfData):
+        (JSC::JSFixedArray::create):
+        (JSC::JSFixedArray::JSFixedArray):
+        (JSC::JSFixedArray::allocationSize):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::JSGlobalObject):
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        (JSC::JSGlobalObject::objectPrototypeIsSane): Deleted.
+        (JSC::JSGlobalObject::arrayPrototypeChainIsSane): Deleted.
+        (JSC::JSGlobalObject::stringPrototypeChainIsSane): Deleted.
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::arrayIteratorProtocolWatchpoint):
+        (JSC::JSGlobalObject::iteratorProtocolFunction):
+        * runtime/JSGlobalObjectInlines.h: Added.
+        (JSC::JSGlobalObject::objectPrototypeIsSane):
+        (JSC::JSGlobalObject::arrayPrototypeChainIsSane):
+        (JSC::JSGlobalObject::stringPrototypeChainIsSane):
+        (JSC::JSGlobalObject::isArrayIteratorProtocolFastAndNonObservable):
+        * runtime/JSType.h:
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+
 2016-11-11  Keith Miller  <keith_miller@apple.com>
 
         Move Wasm tests to JS
index b30c305..569cc1a 100644 (file)
@@ -99,6 +99,7 @@ JavaScriptCore_BUILTINS_SOURCES = \
     $(JavaScriptCore)/builtins/GlobalOperations.js \
     $(JavaScriptCore)/builtins/InspectorInstrumentationObject.js \
     $(JavaScriptCore)/builtins/InternalPromiseConstructor.js \
+    $(JavaScriptCore)/builtins/IteratorHelpers.js \
     $(JavaScriptCore)/builtins/IteratorPrototype.js \
     $(JavaScriptCore)/builtins/MapPrototype.js \
     $(JavaScriptCore)/builtins/ModuleLoaderPrototype.js \
index c73acc5..14423d3 100644 (file)
                52B310FF1975B4240080857C /* TypeLocationCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52B310FE1975B4240080857C /* TypeLocationCache.cpp */; };
                52B311011975B4670080857C /* TypeLocationCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B311001975B4670080857C /* TypeLocationCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
                52B717B51A0597E1007AF4F3 /* ControlFlowProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52B717B41A0597E1007AF4F3 /* ControlFlowProfiler.cpp */; };
+               52B74B4A1DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52B74B481DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.cpp */; };
+               52B74B4B1DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B74B491DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                52C0611F1AA51E1C00B4ADBA /* RuntimeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 52C0611D1AA51E1B00B4ADBA /* RuntimeType.h */; settings = {ATTRIBUTES = (Private, ); }; };
                52C952B719A289850069B386 /* TypeProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 52C952B619A289850069B386 /* TypeProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                52C952B919A28A1C0069B386 /* TypeProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52C952B819A28A1C0069B386 /* TypeProfiler.cpp */; };
                7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 796465681B952FF0003059EE /* GetPutInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                797E07A91B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */; };
                797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               798937781DCAB57300F8D4FB /* JSFixedArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 798937761DCAB57300F8D4FB /* JSFixedArray.cpp */; };
+               798937791DCAB57300F8D4FB /* JSFixedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 798937771DCAB57300F8D4FB /* JSFixedArray.h */; settings = {ATTRIBUTES = (Private, ); }; };
                799EF7C41C56ED96002B0534 /* B3PCToOriginMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79A0907F1D768465008B889B /* HashMapImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79A0907D1D768465008B889B /* HashMapImpl.cpp */; };
                79A090801D768465008B889B /* HashMapImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 79A0907E1D768465008B889B /* HashMapImpl.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79B00CBE1C6AB07E0088C65D /* ProxyObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79B00CBA1C6AB07E0088C65D /* ProxyObject.cpp */; settings = {COMPILER_FLAGS = "-fno-optimize-sibling-calls"; }; };
                79B00CBF1C6AB07E0088C65D /* ProxyObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 79B00CBB1C6AB07E0088C65D /* ProxyObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79B1788E1D399B8000B1A567 /* JITMathICForwards.h in Headers */ = {isa = PBXBuildFile; fileRef = 79A899FE1D38612E00D18C73 /* JITMathICForwards.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               79B819931DD25CF500DDC714 /* JSGlobalObjectInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 79B819921DD25CF500DDC714 /* JSGlobalObjectInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79C4B15D1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B15B1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp */; };
                79C4B15E1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 79C4B15C1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79CFC6F01C33B10000C768EA /* LLIntPCRanges.h in Headers */ = {isa = PBXBuildFile; fileRef = 79CFC6EF1C33B10000C768EA /* LLIntPCRanges.h */; settings = {ATTRIBUTES = (Private, ); }; };
                52B310FE1975B4240080857C /* TypeLocationCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLocationCache.cpp; sourceTree = "<group>"; };
                52B311001975B4670080857C /* TypeLocationCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeLocationCache.h; sourceTree = "<group>"; };
                52B717B41A0597E1007AF4F3 /* ControlFlowProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ControlFlowProfiler.cpp; sourceTree = "<group>"; };
+               52B74B481DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayIteratorAdaptiveWatchpoint.cpp; sourceTree = "<group>"; };
+               52B74B491DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayIteratorAdaptiveWatchpoint.h; sourceTree = "<group>"; };
                52C0611D1AA51E1B00B4ADBA /* RuntimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuntimeType.h; sourceTree = "<group>"; };
                52C952B619A289850069B386 /* TypeProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeProfiler.h; sourceTree = "<group>"; };
                52C952B819A28A1C0069B386 /* TypeProfiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeProfiler.cpp; sourceTree = "<group>"; };
                796465681B952FF0003059EE /* GetPutInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPutInfo.h; sourceTree = "<group>"; };
                797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalLexicalEnvironment.cpp; sourceTree = "<group>"; };
                797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalLexicalEnvironment.h; sourceTree = "<group>"; };
+               798937761DCAB57300F8D4FB /* JSFixedArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFixedArray.cpp; sourceTree = "<group>"; };
+               798937771DCAB57300F8D4FB /* JSFixedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFixedArray.h; sourceTree = "<group>"; };
                799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3PCToOriginMap.h; path = b3/B3PCToOriginMap.h; sourceTree = "<group>"; };
                79A0907D1D768465008B889B /* HashMapImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HashMapImpl.cpp; sourceTree = "<group>"; };
                79A0907E1D768465008B889B /* HashMapImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashMapImpl.h; sourceTree = "<group>"; };
                79B00CB91C6AB07E0088C65D /* ProxyConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProxyConstructor.h; sourceTree = "<group>"; };
                79B00CBA1C6AB07E0088C65D /* ProxyObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProxyObject.cpp; sourceTree = "<group>"; };
                79B00CBB1C6AB07E0088C65D /* ProxyObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProxyObject.h; sourceTree = "<group>"; };
+               79B819921DD25CF500DDC714 /* JSGlobalObjectInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObjectInlines.h; sourceTree = "<group>"; };
                79C4B15B1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLiveCatchVariablePreservationPhase.cpp; path = dfg/DFGLiveCatchVariablePreservationPhase.cpp; sourceTree = "<group>"; };
                79C4B15C1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLiveCatchVariablePreservationPhase.h; path = dfg/DFGLiveCatchVariablePreservationPhase.h; sourceTree = "<group>"; };
                79CFC6EF1C33B10000C768EA /* LLIntPCRanges.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntPCRanges.h; path = llint/LLIntPCRanges.h; sourceTree = "<group>"; };
                                BC7952070E15E8A800A898AB /* ArrayConstructor.h */,
                                0FB415831D78F98200DF8D09 /* ArrayConventions.cpp */,
                                0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */,
+                               52B74B481DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.cpp */,
+                               52B74B491DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.h */,
                                A7BDAEC217F4EA1400F6140C /* ArrayIteratorPrototype.cpp */,
                                A7BDAEC317F4EA1400F6140C /* ArrayIteratorPrototype.h */,
                                F692A84D0255597D01FF60F7 /* ArrayPrototype.cpp */,
                                BC22A39A0E16E14800AF21C8 /* JSEnvironmentRecord.cpp */,
                                14F252560D08DD8D004ECFFF /* JSEnvironmentRecord.h */,
                                A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */,
+                               798937761DCAB57300F8D4FB /* JSFixedArray.cpp */,
+                               798937771DCAB57300F8D4FB /* JSFixedArray.h */,
                                0F2B66C117B6B5AB00A7AE3F /* JSFloat32Array.h */,
                                0F2B66C217B6B5AB00A7AE3F /* JSFloat64Array.h */,
                                F692A85E0255597D01FF60F7 /* JSFunction.cpp */,
                                797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */,
                                14DE0D680D02431400AACCA2 /* JSGlobalObject.cpp */,
                                A8E894330CD0603F00367179 /* JSGlobalObject.h */,
+                               79B819921DD25CF500DDC714 /* JSGlobalObjectInlines.h */,
                                A59455901824744700CC3843 /* JSGlobalObjectDebuggable.cpp */,
                                A59455911824744700CC3843 /* JSGlobalObjectDebuggable.h */,
                                BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */,
                                0F2E892D16D02BAF009E4FD2 /* DFGMinifiedID.h in Headers */,
                                0F2BDC461522802000CD8910 /* DFGMinifiedNode.h in Headers */,
                                0F8F14361ADF090100ED792C /* DFGMovHintRemovalPhase.h in Headers */,
+                               52B74B4B1DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.h in Headers */,
                                AD2FCBEF1DB58DAD00B3E736 /* WebAssemblyCompileErrorPrototype.h in Headers */,
                                0FF2CD5C1B61A4F8004955A8 /* DFGMultiGetByOffsetData.h in Headers */,
                                A737810E1799EA2E00817533 /* DFGNaturalLoops.h in Headers */,
                                142D6F1213539A4100B02E86 /* MarkStack.h in Headers */,
                                0F2017891DCB942400EA5950 /* DFGNodeAbstractValuePair.h in Headers */,
                                8612E4CD152389EC00C836BE /* MatchResult.h in Headers */,
+                               79B819931DD25CF500DDC714 /* JSGlobalObjectInlines.h in Headers */,
                                4340A4851A9051AF00D73CCA /* MathCommon.h in Headers */,
                                BC18C43C0E16F5CD00B34460 /* MathObject.h in Headers */,
                                14AD91221DCA9FA40014F9FE /* UnlinkedGlobalCodeBlock.h in Headers */,
                                14AD91271DCA9FA40014F9FE /* UnlinkedFunctionExecutable.h in Headers */,
                                FE6491371D78F01D00A694D4 /* ExceptionScope.h in Headers */,
                                2AAAA31218BD49D100394CC8 /* StructureIDBlob.h in Headers */,
+                               798937791DCAB57300F8D4FB /* JSFixedArray.h in Headers */,
                                436E54531C468E7400B5AF73 /* B3LegalizeMemoryOffsets.h in Headers */,
                                2AF7382D18BBBF92008A5A37 /* StructureIDTable.h in Headers */,
                                0FD2C92416D01EE900C7803F /* StructureInlines.h in Headers */,
                                14469DE3107EC7E700650446 /* NumberObject.cpp in Sources */,
                                14469DE4107EC7E700650446 /* NumberPrototype.cpp in Sources */,
                                86F3EEBE168CDE930077B92A /* ObjCCallbackFunction.mm in Sources */,
+                               798937781DCAB57300F8D4FB /* JSFixedArray.cpp in Sources */,
                                14469DE5107EC7E700650446 /* ObjectConstructor.cpp in Sources */,
                                0FD3E4091B618B6600C80E1E /* ObjectPropertyCondition.cpp in Sources */,
                                0FD3E40B1B618B6600C80E1E /* ObjectPropertyConditionSet.cpp in Sources */,
                                0F190CAC189D82F6000AE5F0 /* ProfilerJettisonReason.cpp in Sources */,
                                0FF729B3166AD35C000F5BA3 /* ProfilerOrigin.cpp in Sources */,
                                0FF729B4166AD35C000F5BA3 /* ProfilerOriginStack.cpp in Sources */,
+                               52B74B4A1DCC04690034157D /* ArrayIteratorAdaptiveWatchpoint.cpp in Sources */,
                                AD2FCBE61DB58DAD00B3E736 /* JSWebAssemblyMemory.cpp in Sources */,
                                0F9D4C0C1C3E1C11006CD984 /* FTLExceptionTarget.cpp in Sources */,
                                0FB1058B1675483100F8AB6E /* ProfilerOSRExit.cpp in Sources */,
diff --git a/Source/JavaScriptCore/builtins/IteratorHelpers.js b/Source/JavaScriptCore/builtins/IteratorHelpers.js
new file mode 100644 (file)
index 0000000..f565d44
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+function performIteration(iterable)
+{
+    "use strict";
+    // This is performing a spread operation on the iterable passed in,
+    // and returning the result in an array.
+    // https://tc39.github.io/ecma262/#sec-runtime-semantics-arrayaccumulation
+
+    let result = [];
+
+    let iterator = iterable.@iteratorSymbol();
+    let item;
+    let index = 0;
+    while (true) {
+        item = iterator.next();
+        if (!@isObject(item))
+            @throwTypeError("Iterator result interface is not an object");
+        if (item.done)
+            return result;
+        @putByValDirect(result, index++, item.value);
+    }
+}
index 28467ea..fafded7 100644 (file)
@@ -16,6 +16,8 @@
             { "name" : "op_new_object", "length" : 4 },
             { "name" : "op_new_array", "length" : 5 },
             { "name" : "op_new_array_with_size", "length" : 4 },
+            { "name" : "op_new_array_with_spread", "length" : 5 },
+            { "name" : "op_spread", "length" : 3 },
             { "name" : "op_new_array_buffer", "length" : 5 },
             { "name" : "op_new_regexp", "length" : 3 },
             { "name" : "op_mov", "length" : 3 },
index 9907148..99b9394 100644 (file)
@@ -161,6 +161,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
         functor(codeBlock, instruction, opcodeID, instruction[5].u.operand);
         return;
     }
+    case op_spread:
     case op_get_property_enumerator:
     case op_get_enumerable_length:
     case op_new_func_exp:
@@ -277,6 +278,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
         functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
         return;
     }
+    case op_new_array_with_spread:
     case op_new_array:
     case op_strcat: {
         int base = instruction[2].u.operand;
@@ -384,6 +386,8 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_to_primitive:
     case op_create_this:
     case op_new_array:
+    case op_new_array_with_spread:
+    case op_spread:
     case op_new_array_buffer:
     case op_new_array_with_size:
     case op_new_regexp:
index 9e1d919..30ab028 100644 (file)
@@ -838,6 +838,30 @@ void CodeBlock::dumpBytecode(
             ++it; // Skip array allocation profile.
             break;
         }
+        case op_new_array_with_spread: {
+            int dst = (++it)->u.operand;
+            int argv = (++it)->u.operand;
+            int argc = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "new_array_with_spread");
+            out.printf("%s, %s, %d, ", registerName(dst).data(), registerName(argv).data(), argc);
+            unsigned bitVectorIndex = (++it)->u.unsignedValue;
+            const BitVector& bitVector = m_unlinkedCode->bitVector(bitVectorIndex);
+            out.print("BitVector:", bitVectorIndex, ":");
+            for (unsigned i = 0; i < static_cast<unsigned>(argc); i++) {
+                if (bitVector.get(i))
+                    out.print("1");
+                else
+                    out.print("0");
+            }
+            break;
+        }
+        case op_spread: {
+            int dst = (++it)->u.operand;
+            int arg = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "spread");
+            out.printf("%s, %s", registerName(dst).data(), registerName(arg).data());
+            break;
+        }
         case op_new_array_with_size: {
             int dst = (++it)->u.operand;
             int length = (++it)->u.operand;
index bb1ddd7..e2e4a8f 100644 (file)
@@ -421,5 +421,11 @@ ObjectPropertyConditionSet generateConditionsForPropertySetterMissConcurrently(
         }, Concurrent);
 }
 
+ObjectPropertyCondition generateConditionForSelfEquivalence(
+    VM& vm, JSCell* owner, JSObject* object, UniquedStringImpl* uid)
+{
+    return generateCondition(vm, owner, object, uid, PropertyCondition::Equivalence);
+}
+
 } // namespace JSC
 
index 15a3dd8..2b15965 100644 (file)
@@ -156,6 +156,9 @@ private:
     RefPtr<Data> m_data;
 };
 
+ObjectPropertyCondition generateConditionForSelfEquivalence(
+    VM&, JSCell* owner, JSObject* object, UniquedStringImpl* uid);
+
 ObjectPropertyConditionSet generateConditionsForPropertyMiss(
     VM&, JSCell* owner, ExecState*, Structure* headStructure, UniquedStringImpl* uid);
 ObjectPropertyConditionSet generateConditionsForPropertySetterMiss(
index d98fa97..ae213d5 100644 (file)
@@ -59,7 +59,7 @@ void TrackedReferences::check(JSCell* cell) const
     if (m_references.contains(cell))
         return;
     
-    dataLog("Found untracked reference: ", RawPointer(cell), "\n");
+    dataLog("Found untracked reference: ", JSValue(cell), "\n");
     dataLog("All tracked references: ", *this, "\n");
     RELEASE_ASSERT_NOT_REACHED();
 }
index 909ab81..225c9ae 100644 (file)
@@ -40,6 +40,7 @@
 #include "UnlinkedFunctionExecutable.h"
 #include "VariableEnvironment.h"
 #include "VirtualRegister.h"
+#include <wtf/BitVector.h>
 #include <wtf/TriState.h>
 #include <wtf/Vector.h>
 
@@ -171,6 +172,14 @@ public:
     const Identifier& identifier(int index) const { return m_identifiers[index]; }
     const Vector<Identifier>& identifiers() const { return m_identifiers; }
 
+    const Vector<BitVector>& bitVectors() const { return m_bitVectors; }
+    BitVector& bitVector(size_t i) { return m_bitVectors[i]; }
+    unsigned addBitVector(BitVector&& bitVector)
+    {
+        m_bitVectors.append(WTFMove(bitVector));
+        return m_bitVectors.size() - 1;
+    }
+
     unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other)
     {
         unsigned result = m_constantRegisters.size();
@@ -220,6 +229,7 @@ public:
     {
         m_jumpTargets.shrinkToFit();
         m_identifiers.shrinkToFit();
+        m_bitVectors.shrinkToFit();
         m_constantRegisters.shrinkToFit();
         m_constantsSourceCodeRepresentation.shrinkToFit();
         m_functionDecls.shrinkToFit();
@@ -441,6 +451,7 @@ private:
 
     // Constant Pools
     Vector<Identifier> m_identifiers;
+    Vector<BitVector> m_bitVectors;
     Vector<WriteBarrier<Unknown>> m_constantRegisters;
     Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
     typedef Vector<WriteBarrier<UnlinkedFunctionExecutable>> FunctionExpressionVector;
index 04e4cab..69b2539 100644 (file)
@@ -52,6 +52,7 @@
 #include "UnlinkedInstructionStream.h"
 #include "UnlinkedModuleProgramCodeBlock.h"
 #include "UnlinkedProgramCodeBlock.h"
+#include <wtf/BitVector.h>
 #include <wtf/CommaPrinter.h>
 #include <wtf/SmallPtrSet.h>
 #include <wtf/StdLibExtras.h>
@@ -3046,6 +3047,49 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
     return dst;
 }
 
+RegisterID* BytecodeGenerator::emitNewArrayWithSpread(RegisterID* dst, ElementNode* elements)
+{
+    BitVector bitVector;
+    Vector<RefPtr<RegisterID>, 16> argv;
+    for (ElementNode* node = elements; node; node = node->next()) {
+        bitVector.set(argv.size(), node->value()->isSpreadExpression());
+
+        argv.append(newTemporary());
+        // op_new_array_with_spread requires the initial values to be a sequential range of registers.
+        RELEASE_ASSERT(argv.size() == 1 || argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() - 1);
+    }
+
+    RELEASE_ASSERT(argv.size());
+
+    {
+        unsigned i = 0;
+        for (ElementNode* node = elements; node; node = node->next()) {
+            if (node->value()->isSpreadExpression()) {
+                ExpressionNode* expression = static_cast<SpreadExpressionNode*>(node->value())->expression();
+                RefPtr<RegisterID> tmp = newTemporary();
+                emitNode(tmp.get(), expression);
+
+                emitOpcode(op_spread);
+                instructions().append(argv[i].get()->index());
+                instructions().append(tmp.get()->index());
+            } else {
+                ExpressionNode* expression = node->value();
+                emitNode(argv[i].get(), expression);
+            }
+            i++;
+        }
+    }
+
+    unsigned bitVectorIndex = m_codeBlock->addBitVector(WTFMove(bitVector));
+    emitOpcode(op_new_array_with_spread);
+    instructions().append(dst->index());
+    instructions().append(argv[0]->index()); // argv
+    instructions().append(argv.size()); // argc
+    instructions().append(bitVectorIndex);
+
+    return dst;
+}
+
 RegisterID* BytecodeGenerator::emitNewArrayWithSize(RegisterID* dst, RegisterID* length)
 {
     emitOpcode(op_new_array_with_size);
index 6346118..721b396 100644 (file)
@@ -527,6 +527,7 @@ namespace JSC {
         void liftTDZCheckIfPossible(const Variable&);
         RegisterID* emitNewObject(RegisterID* dst);
         RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
+        RegisterID* emitNewArrayWithSpread(RegisterID* dst, ElementNode*);
         RegisterID* emitNewArrayWithSize(RegisterID* dst, RegisterID* length);
 
         RegisterID* emitNewFunction(RegisterID* dst, FunctionMetadataNode*);
index 65c86e8..d3595cf 100644 (file)
@@ -365,6 +365,21 @@ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     if (!firstPutElement && !m_elision)
         return generator.emitNewArray(generator.finalDestination(dst), m_element, length);
 
+    if (firstPutElement && firstPutElement->value()->isSpreadExpression()) {
+        bool hasElision = false;
+        for (ElementNode* node = m_element; node; node = node->next()) {
+            if (!!node->elision()) {
+                hasElision = true;
+                break;
+            }
+        }
+        if (!!m_elision)
+            hasElision = true;
+
+        if (!hasElision)
+            return generator.emitNewArrayWithSpread(generator.finalDestination(dst), m_element);
+    }
+
     RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element, length);
     ElementNode* n = firstPutElement;
     for (; n; n = n->next()) {
index 03f85bd..8c7e631 100644 (file)
@@ -1869,6 +1869,27 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             m_graph,
             m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
         break;
+
+    case NewArrayWithSpread:
+        if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
+            // We've compiled assuming we're not having a bad time, so to be consistent
+            // with StructureRegisterationPhase we must say we produce an original array
+            // allocation structure.
+            forNode(node).set(
+                m_graph,
+                m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous));
+        } else {
+            forNode(node).set(
+                m_graph,
+                m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
+        }
+
+        break;
+
+    case Spread:
+        forNode(node).set(
+            m_graph, m_graph.m_vm.fixedArrayStructure.get());
+        break;
         
     case NewArrayBuffer:
         forNode(node).set(
index de92452..1a941d1 100644 (file)
@@ -785,7 +785,7 @@ private:
         return addToGraph(result);
     }
     
-    Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2)
+    Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2 = OpInfo())
     {
         Node* result = m_graph.addNode(
             Node::VarArg, op, currentNodeOrigin(), info1, info2,
@@ -3830,6 +3830,27 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(Node::VarArg, NewArray, OpInfo(profile->selectIndexingType()), OpInfo(0)));
             NEXT_OPCODE(op_new_array);
         }
+
+        case op_new_array_with_spread: {
+            int startOperand = currentInstruction[2].u.operand;
+            int numOperands = currentInstruction[3].u.operand;
+            const BitVector& bitVector = m_inlineStackTop->m_profiledBlock->unlinkedCodeBlock()->bitVector(currentInstruction[4].u.unsignedValue);
+            for (int operandIdx = startOperand; operandIdx > startOperand - numOperands; --operandIdx)
+                addVarArgChild(get(VirtualRegister(operandIdx)));
+
+            BitVector* copy = m_graph.m_bitVectors.add(bitVector);
+            ASSERT(*copy == bitVector);
+
+            set(VirtualRegister(currentInstruction[1].u.operand),
+                addToGraph(Node::VarArg, NewArrayWithSpread, OpInfo(copy)));
+            NEXT_OPCODE(op_new_array_with_spread);
+        }
+
+        case op_spread: {
+            set(VirtualRegister(currentInstruction[1].u.operand),
+                addToGraph(Spread, get(VirtualRegister(currentInstruction[2].u.operand))));
+            NEXT_OPCODE(op_spread);
+        }
             
         case op_new_array_with_size: {
             int lengthOperand = currentInstruction[2].u.operand;
index 6023782..bfb7019 100644 (file)
@@ -198,6 +198,8 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_new_array:
     case op_new_array_with_size:
     case op_new_array_buffer:
+    case op_new_array_with_spread:
+    case op_spread:
     case op_strcat:
     case op_to_primitive:
     case op_throw:
index 0e4417b..e12dfa8 100644 (file)
@@ -1126,6 +1126,35 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         write(HeapObjectCount);
         return;
 
+    case NewArrayWithSpread: {
+        // This also reads from JSFixedArray's data store, but we don't have any way of describing that yet.
+        read(HeapObjectCount);
+        write(HeapObjectCount);
+        return;
+    }
+
+    case Spread: {
+        if (node->child1().useKind() == ArrayUse) {
+            // FIXME: We can probably CSE these together, but we need to construct the right rules
+            // to prove that nobody writes to child1() in between two Spreads: https://bugs.webkit.org/show_bug.cgi?id=164531
+            read(HeapObjectCount); 
+            read(JSCell_indexingType);
+            read(JSObject_butterfly);
+            read(Butterfly_publicLength);
+            read(IndexedDoubleProperties);
+            read(IndexedInt32Properties);
+            read(IndexedContiguousProperties);
+            read(IndexedArrayStorageProperties);
+
+            write(HeapObjectCount);
+            return;
+        }
+
+        read(World);
+        write(Heap);
+        return;
+    }
+
     case NewArray: {
         read(HeapObjectCount);
         write(HeapObjectCount);
index be6b1a4..9e853e3 100644 (file)
@@ -279,6 +279,8 @@ bool doesGC(Graph& graph, Node* node)
     case ArrayifyToStructure:
     case NewObject:
     case NewArray:
+    case NewArrayWithSpread:
+    case Spread:
     case NewArrayWithSize:
     case NewArrayBuffer:
     case NewRegexp:
index c3b72cd..cbf7b0e 100644 (file)
@@ -1050,6 +1050,45 @@ private:
             fixEdge<KnownStringUse>(node->child1());
             break;
         }
+
+        case NewArrayWithSpread: {
+            watchHavingABadTime(node);
+            
+            BitVector* bitVector = node->bitVector();
+            for (unsigned i = node->numChildren(); i--;) {
+                if (bitVector->get(i))
+                    fixEdge<KnownCellUse>(m_graph.m_varArgChildren[node->firstChild() + i]);
+                else
+                    fixEdge<UntypedUse>(m_graph.m_varArgChildren[node->firstChild() + i]);
+            }
+
+            break;
+        }
+
+        case Spread: {
+            // Note: We care about performing the protocol on our child's global object, not necessarily ours.
+            
+            watchHavingABadTime(node->child1().node());
+
+            JSGlobalObject* globalObject = m_graph.globalObjectFor(node->child1()->origin.semantic);
+            // When we go down the fast path, we don't consult the prototype chain, so we must prove
+            // that it doesn't contain any indexed properties, and that any holes will result in
+            // jsUndefined().
+            InlineWatchpointSet& objectPrototypeTransition = globalObject->objectPrototype()->structure()->transitionWatchpointSet();
+            InlineWatchpointSet& arrayPrototypeTransition = globalObject->arrayPrototype()->structure()->transitionWatchpointSet();
+            if (node->child1()->shouldSpeculateArray() 
+                && arrayPrototypeTransition.isStillValid() 
+                && objectPrototypeTransition.isStillValid() 
+                && globalObject->arrayPrototypeChainIsSane()
+                && m_graph.isWatchingArrayIteratorProtocolWatchpoint(node->child1().node())
+                && m_graph.isWatchingHavingABadTimeWatchpoint(node->child1().node())) {
+                m_graph.watchpoints().addLazily(objectPrototypeTransition);
+                m_graph.watchpoints().addLazily(arrayPrototypeTransition);
+                fixEdge<ArrayUse>(node->child1());
+            } else
+                fixEdge<CellUse>(node->child1());
+            break;
+        }
             
         case NewArray: {
             watchHavingABadTime(node);
@@ -1824,8 +1863,10 @@ private:
         // optimizing, the code just gets thrown out. Doing this at FixupPhase is just early enough, since
         // prior to this point nobody should have been doing optimizations based on the indexing type of
         // the allocation.
-        if (!globalObject->isHavingABadTime())
+        if (!globalObject->isHavingABadTime()) {
             m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
+            m_graph.freeze(globalObject);
+        }
     }
     
     template<UseKind useKind>
index 6417b85..d3047f3 100644 (file)
@@ -665,6 +665,26 @@ public:
         JSGlobalObject* globalObject = globalObjectFor(node->origin.semantic);
         return watchpoints().isWatched(globalObject->havingABadTimeWatchpoint());
     }
+
+    bool isWatchingArrayIteratorProtocolWatchpoint(Node* node)
+    {
+        JSGlobalObject* globalObject = globalObjectFor(node->origin.semantic);
+        InlineWatchpointSet& set = globalObject->arrayIteratorProtocolWatchpoint();
+        if (watchpoints().isWatched(set))
+            return true;
+
+        if (set.isStillValid()) {
+            // Since the global object owns this watchpoint, we make ourselves have a weak pointer to it.
+            // If the global object got deallocated, it wouldn't fire the watchpoint. It's unlikely the
+            // global object would get deallocated without this code ever getting thrown away, however,
+            // it's more sound logically to depend on the global object lifetime weakly.
+            freeze(globalObject);
+            watchpoints().addLazily(set);
+            return true;
+        }
+
+        return false;
+    }
     
     Profiler::Compilation* compilation() { return m_plan.compilation.get(); }
     
@@ -903,6 +923,7 @@ public:
     Bag<StackAccessData> m_stackAccessData;
     Bag<LazyJSValue> m_lazyJSValues;
     Bag<CallDOMGetterData> m_callDOMGetterData;
+    Bag<BitVector> m_bitVectors;
     Vector<InlineVariableData, 4> m_inlineVariableData;
     HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> m_bytecodeLiveness;
     HashMap<CodeBlock*, std::unique_ptr<BytecodeKills>> m_bytecodeKills;
index 6cdd160..1b21de9 100644 (file)
@@ -1061,6 +1061,12 @@ public:
         }
     }
 
+    BitVector* bitVector()
+    {
+        ASSERT(op() == NewArrayWithSpread);
+        return m_opInfo.as<BitVector*>();
+    }
+
     // Return the indexing type that an array allocation *wants* to use. It may end up using a different
     // type if we're having a bad time. You can determine the actual indexing type by asking the global
     // object:
index d433417..005af66 100644 (file)
@@ -290,6 +290,7 @@ namespace JSC { namespace DFG {
     /* Allocations. */\
     macro(NewObject, NodeResultJS) \
     macro(NewArray, NodeResultJS | NodeHasVarArgs) \
+    macro(NewArrayWithSpread, NodeResultJS | NodeHasVarArgs) \
     macro(NewArrayWithSize, NodeResultJS | NodeMustGenerate) \
     macro(NewArrayBuffer, NodeResultJS) \
     macro(NewTypedArray, NodeResultJS | NodeMustGenerate) \
@@ -298,6 +299,7 @@ namespace JSC { namespace DFG {
     macro(GetRestLength, NodeResultInt32) \
     macro(CreateRest, NodeResultJS | NodeMustGenerate) \
     \
+    macro(Spread, NodeResultJS | NodeMustGenerate) \
     /* Support for allocation sinking. */\
     macro(PhantomNewObject, NodeResultJS | NodeMustGenerate) \
     macro(PutHint, NodeMustGenerate) \
index e204d3e..dd24b24 100644 (file)
@@ -48,6 +48,7 @@
 #include "JIT.h"
 #include "JITExceptions.h"
 #include "JSCInlines.h"
+#include "JSFixedArray.h"
 #include "JSGenericTypedArrayViewConstructorInlines.h"
 #include "JSLexicalEnvironment.h"
 #include "JSMap.h"
@@ -1880,6 +1881,96 @@ JSCell* JIT_OPERATION operationNewObjectWithButterflyWithIndexingHeaderAndVector
     return result;
 }
 
+JSCell* JIT_OPERATION operationNewArrayWithSpreadSlow(ExecState* exec, void* buffer, uint32_t numItems)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    EncodedJSValue* values = static_cast<EncodedJSValue*>(buffer);
+    unsigned length = 0;
+    for (unsigned i = 0; i < numItems; i++) {
+        JSValue value = JSValue::decode(values[i]);
+        if (JSFixedArray* array = jsDynamicCast<JSFixedArray*>(value))
+            length += array->size();
+        else
+            ++length;
+    }
+
+
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
+
+    JSArray* result = JSArray::tryCreateUninitialized(vm, structure, length);
+    RETURN_IF_EXCEPTION(scope, nullptr);
+
+    unsigned index = 0;
+    for (unsigned i = 0; i < numItems; i++) {
+        JSValue value = JSValue::decode(values[i]);
+        if (JSFixedArray* array = jsDynamicCast<JSFixedArray*>(value)) {
+            // We are spreading.
+            for (unsigned i = 0; i < array->size(); i++) {
+                result->initializeIndex(vm, index, array->get(i));
+                ++index;
+            }
+        } else {
+            // We are not spreading.
+            result->initializeIndex(vm, index, value);
+            ++index;
+        }
+    }
+
+    return result;
+}
+
+JSCell* JIT_OPERATION operationSpreadGeneric(ExecState* exec, JSCell* iterable)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+    JSGlobalObject* globalObject = iterable->structure(vm)->globalObject();
+    if (!globalObject)
+        globalObject = exec->lexicalGlobalObject();
+
+    if (isJSArray(iterable) && globalObject->isArrayIteratorProtocolFastAndNonObservable()) {
+        JSArray* array = jsCast<JSArray*>(iterable);
+        return JSFixedArray::createFromArray(exec, vm, array);
+    }
+
+    // FIXME: we can probably make this path faster by having our caller JS code call directly into
+    // the iteration protocol builtin: https://bugs.webkit.org/show_bug.cgi?id=164520
+
+    JSArray* array;
+    {
+        JSFunction* iterationFunction = globalObject->iteratorProtocolFunction();
+        CallData callData;
+        CallType callType = JSC::getCallData(iterationFunction, callData);
+        ASSERT(callType != CallType::None);
+
+        MarkedArgumentBuffer arguments;
+        arguments.append(iterable);
+        JSValue arrayResult = call(exec, iterationFunction, callType, callData, jsNull(), arguments);
+        RETURN_IF_EXCEPTION(throwScope, nullptr);
+        array = jsCast<JSArray*>(arrayResult);
+    }
+
+    return JSFixedArray::createFromArray(exec, vm, array);
+}
+
+JSCell* JIT_OPERATION operationSpreadFastArray(ExecState* exec, JSCell* cell)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    ASSERT(isJSArray(cell));
+    JSArray* array = jsCast<JSArray*>(cell);
+    ASSERT(array->globalObject()->isArrayIteratorProtocolFastAndNonObservable());
+
+    return JSFixedArray::createFromArray(exec, vm, array);
+}
+
 void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState* exec) 
 {
     VM& vm = exec->vm();
index 9578cae..1d6d1c1 100644 (file)
@@ -188,6 +188,10 @@ void JIT_OPERATION operationLoadVarargs(ExecState*, int32_t firstElementDest, En
 
 int32_t JIT_OPERATION operationHasOwnProperty(ExecState*, JSObject*, EncodedJSValue);
 
+JSCell* JIT_OPERATION operationSpreadFastArray(ExecState*, JSCell*);
+JSCell* JIT_OPERATION operationSpreadGeneric(ExecState*, JSCell*);
+JSCell* JIT_OPERATION operationNewArrayWithSpreadSlow(ExecState*, void*, uint32_t);
+
 JSCell* JIT_OPERATION operationResolveScope(ExecState*, JSScope*, UniquedStringImpl*);
 EncodedJSValue JIT_OPERATION operationGetDynamicVar(ExecState*, JSObject* scope, UniquedStringImpl*, unsigned);
 void JIT_OPERATION operationPutDynamicVar(ExecState*, JSObject* scope, EncodedJSValue, UniquedStringImpl*, unsigned);
index dc13a1f..0907b9f 100644 (file)
@@ -859,6 +859,7 @@ private:
             break;
         }
             
+        case NewArrayWithSpread:
         case NewArray:
         case NewArrayWithSize:
         case CreateRest:
@@ -866,6 +867,10 @@ private:
             setPrediction(SpecArray);
             break;
         }
+
+        case Spread:
+            setPrediction(SpecCellOther);
+            break;
             
         case NewTypedArray: {
             setPrediction(speculationFromTypedArrayType(m_currentNode->typedArrayType()));
index 9a8444a..065e665 100644 (file)
@@ -263,6 +263,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case NewArray:
     case NewArrayWithSize:
     case NewArrayBuffer:
+    case NewArrayWithSpread:
+    case Spread:
     case NewRegexp:
     case ProfileType:
     case ProfileControlFlow:
index b887f32..d308b98 100644 (file)
@@ -52,6 +52,7 @@
 #include "JITSubGenerator.h"
 #include "JSCInlines.h"
 #include "JSEnvironmentRecord.h"
+#include "JSFixedArray.h"
 #include "JSGeneratorFunction.h"
 #include "JSLexicalEnvironment.h"
 #include "LinkBuffer.h"
@@ -59,6 +60,7 @@
 #include "ScopedArguments.h"
 #include "ScratchRegisterAllocator.h"
 #include "WriteBarrierBuffer.h"
+#include <wtf/BitVector.h>
 #include <wtf/Box.h>
 #include <wtf/MathExtras.h>
 
@@ -6884,6 +6886,247 @@ void SpeculativeJIT::compileCreateRest(Node* node)
     cellResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileSpread(Node* node)
+{
+    ASSERT(node->op() == Spread);
+
+    SpeculateCellOperand operand(this, node->child1());
+    GPRReg argument = operand.gpr();
+
+    if (node->child1().useKind() == ArrayUse) {
+        // Note: we only speculate on ArrayUse when we've set up the necessary watchpoints
+        // to prove that the iteration protocol is non-observable.
+        speculateArray(node->child1(), argument);
+
+#if USE(JSVALUE64)
+        GPRTemporary result(this);
+        GPRTemporary scratch1(this);
+        GPRTemporary scratch2(this);
+        GPRTemporary length(this);
+        FPRTemporary doubleRegister(this);
+
+        GPRReg resultGPR = result.gpr();
+        GPRReg scratch1GPR = scratch1.gpr();
+        GPRReg scratch2GPR = scratch2.gpr();
+        GPRReg lengthGPR = length.gpr();
+        FPRReg doubleFPR = doubleRegister.fpr();
+
+        MacroAssembler::JumpList slowPath;
+
+        m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeOffset()), scratch1GPR);
+        m_jit.and32(TrustedImm32(IndexingShapeMask), scratch1GPR);
+        m_jit.sub32(TrustedImm32(Int32Shape), scratch1GPR);
+
+        slowPath.append(m_jit.branch32(MacroAssembler::Above, scratch1GPR, TrustedImm32(ContiguousShape - Int32Shape)));
+
+        m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), lengthGPR);
+        m_jit.load32(MacroAssembler::Address(lengthGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
+        static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
+        m_jit.move(lengthGPR, scratch1GPR);
+        m_jit.lshift32(TrustedImm32(3), scratch1GPR);
+        m_jit.add32(TrustedImm32(JSFixedArray::offsetOfData()), scratch1GPR);
+
+        m_jit.emitAllocateVariableSizedCell<JSFixedArray>(resultGPR, TrustedImmPtr(m_jit.graph().m_vm.fixedArrayStructure.get()), scratch1GPR, scratch1GPR, scratch2GPR, slowPath);
+        m_jit.store32(lengthGPR, MacroAssembler::Address(resultGPR, JSFixedArray::offsetOfSize()));
+
+        m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), scratch1GPR);
+
+        MacroAssembler::JumpList done;
+
+        m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeOffset()), scratch2GPR);
+        m_jit.and32(TrustedImm32(IndexingShapeMask), scratch2GPR);
+        auto isDoubleArray = m_jit.branch32(MacroAssembler::Equal, scratch2GPR, TrustedImm32(DoubleShape));
+
+        {
+            done.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
+            auto loopStart = m_jit.label();
+            m_jit.sub32(TrustedImm32(1), lengthGPR);
+            m_jit.load64(MacroAssembler::BaseIndex(scratch1GPR, lengthGPR, MacroAssembler::TimesEight), scratch2GPR);
+            auto notEmpty = m_jit.branchTest64(MacroAssembler::NonZero, scratch2GPR);
+            m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
+            notEmpty.link(&m_jit);
+            m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
+            m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
+            done.append(m_jit.jump());
+        }
+
+        isDoubleArray.link(&m_jit);
+        {
+
+            done.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
+            auto loopStart = m_jit.label();
+            m_jit.sub32(TrustedImm32(1), lengthGPR);
+            m_jit.loadDouble(MacroAssembler::BaseIndex(scratch1GPR, lengthGPR, MacroAssembler::TimesEight), doubleFPR);
+            auto notEmpty = m_jit.branchDouble(JITCompiler::DoubleEqual, doubleFPR, doubleFPR);
+            m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
+            auto doStore = m_jit.jump();
+            notEmpty.link(&m_jit);
+            m_jit.boxDouble(doubleFPR, scratch2GPR);
+            doStore.link(&m_jit);
+            m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
+            m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
+            done.append(m_jit.jump());
+        }
+
+        slowPath.link(&m_jit);
+        addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationSpreadFastArray, resultGPR, argument));
+
+        done.link(&m_jit);
+        cellResult(resultGPR, node);
+#else
+        flushRegisters();
+
+        GPRFlushedCallResult result(this);
+        GPRReg resultGPR = result.gpr();
+        callOperation(operationSpreadFastArray, resultGPR, argument);
+        m_jit.exceptionCheck();
+        cellResult(resultGPR, node);
+#endif // USE(JSVALUE64)
+    } else {
+        flushRegisters();
+
+        GPRFlushedCallResult result(this);
+        GPRReg resultGPR = result.gpr();
+        callOperation(operationSpreadGeneric, resultGPR, argument);
+        m_jit.exceptionCheck();
+        cellResult(resultGPR, node);
+    }
+}
+
+void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
+{
+    ASSERT(node->op() == NewArrayWithSpread);
+
+#if USE(JSVALUE64)
+    if (m_jit.graph().isWatchingHavingABadTimeWatchpoint(node)) {
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+
+        BitVector* bitVector = node->bitVector();
+        {
+            unsigned startLength = 0;
+            for (unsigned i = 0; i < node->numChildren(); ++i) {
+                if (!bitVector->get(i))
+                    ++startLength;
+            }
+
+            GPRTemporary length(this);
+            GPRReg lengthGPR = length.gpr();
+            m_jit.move(TrustedImm32(startLength), lengthGPR);
+
+            for (unsigned i = 0; i < node->numChildren(); ++i) {
+                if (bitVector->get(i)) {
+                    Edge use = m_jit.graph().varArgChild(node, i);
+                    SpeculateCellOperand fixedArray(this, use);
+                    GPRReg fixedArrayGPR = fixedArray.gpr();
+                    m_jit.add32(MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), lengthGPR);
+                }
+            }
+
+
+            bool shouldAllowForArrayStorageStructureForLargeArrays = false;
+            ASSERT(m_jit.graph().globalObjectFor(node->origin.semantic)->restParameterStructure()->indexingType() == ArrayWithContiguous);
+            compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), resultGPR, lengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
+        }
+
+        GPRTemporary index(this);
+        GPRReg indexGPR = index.gpr();
+
+        GPRTemporary storage(this);
+        GPRReg storageGPR = storage.gpr();
+
+        m_jit.move(TrustedImm32(0), indexGPR);
+        m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), storageGPR);
+
+        for (unsigned i = 0; i < node->numChildren(); ++i) {
+            Edge use = m_jit.graph().varArgChild(node, i);
+            if (bitVector->get(i)) {
+                SpeculateCellOperand fixedArray(this, use);
+                GPRReg fixedArrayGPR = fixedArray.gpr();
+
+                GPRTemporary fixedIndex(this);
+                GPRReg fixedIndexGPR = fixedIndex.gpr();
+
+                GPRTemporary item(this);
+                GPRReg itemGPR = item.gpr();
+
+                GPRTemporary fixedLength(this);
+                GPRReg fixedLengthGPR = fixedLength.gpr();
+
+                m_jit.load32(MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), fixedLengthGPR);
+                m_jit.move(TrustedImm32(0), fixedIndexGPR);
+                auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, fixedIndexGPR, fixedLengthGPR);
+                auto loopStart = m_jit.label();
+                m_jit.load64(
+                    MacroAssembler::BaseIndex(fixedArrayGPR, fixedIndexGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()),
+                    itemGPR);
+
+                m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
+                m_jit.addPtr(TrustedImm32(1), fixedIndexGPR);
+                m_jit.addPtr(TrustedImm32(1), indexGPR);
+                m_jit.branchPtr(MacroAssembler::Below, fixedIndexGPR, fixedLengthGPR).linkTo(loopStart, &m_jit);
+
+                done.link(&m_jit);
+            } else {
+                JSValueOperand item(this, use);
+                GPRReg itemGPR = item.gpr();
+                m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
+                m_jit.addPtr(TrustedImm32(1), indexGPR);
+            }
+        }
+
+        cellResult(resultGPR, node);
+        return;
+    }
+#endif // USE(JSVALUE64)
+
+    ASSERT(node->numChildren());
+    size_t scratchSize = sizeof(EncodedJSValue) * node->numChildren();
+    ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
+    EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
+
+    BitVector* bitVector = node->bitVector();
+    for (unsigned i = 0; i < node->numChildren(); ++i) {
+        Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + i];
+        if (bitVector->get(i)) {
+            SpeculateCellOperand fixedArray(this, use);
+            GPRReg arrayGPR = fixedArray.gpr();
+#if USE(JSVALUE64)
+            m_jit.store64(arrayGPR, &buffer[i]);
+#else
+            char* pointer = static_cast<char*>(static_cast<void*>(&buffer[i]));
+            m_jit.store32(arrayGPR, pointer + PayloadOffset);
+            m_jit.store32(TrustedImm32(JSValue::CellTag), pointer + TagOffset);
+#endif
+        } else {
+            JSValueOperand input(this, use);
+            JSValueRegs inputRegs = input.jsValueRegs();
+            m_jit.storeValue(inputRegs, &buffer[i]);
+        }
+    }
+
+    {
+        GPRTemporary scratch(this);
+        m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+        m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(scratch.gpr()));
+    }
+
+    flushRegisters();
+
+    GPRFlushedCallResult result(this);
+    GPRReg resultGPR = result.gpr();
+
+    callOperation(operationNewArrayWithSpreadSlow, resultGPR, buffer, node->numChildren());
+    m_jit.exceptionCheck();
+    {
+        GPRTemporary scratch(this);
+        m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+        m_jit.storePtr(TrustedImmPtr(0), MacroAssembler::Address(scratch.gpr()));
+    }
+
+    cellResult(resultGPR, node);
+}
+
 void SpeculativeJIT::compileGetRestLength(Node* node)
 {
     ASSERT(node->op() == GetRestLength);
index 18c2880..c8c9ef3 100644 (file)
@@ -960,6 +960,11 @@ public:
         m_jit.setupArgumentsWithExecState(old, TrustedImmPtr(size));
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(C_JITOperation_EPUi operation, GPRReg result, void* arg1, uint32_t arg2)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(arg1), TrustedImm32(arg2));
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(P_JITOperation_ES operation, GPRReg result, size_t size)
     {
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(size));
@@ -2671,6 +2676,8 @@ public:
     void compileCreateScopedArguments(Node*);
     void compileCreateClonedArguments(Node*);
     void compileCreateRest(Node*);
+    void compileSpread(Node*);
+    void compileNewArrayWithSpread(Node*);
     void compileGetRestLength(Node*);
     void compileNotifyWrite(Node*);
     bool compileRegExpExec(Node*);
index a5d24b3..a4e7c10 100644 (file)
@@ -3939,6 +3939,16 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case NewArrayWithSpread: {
+        compileNewArrayWithSpread(node);
+        break;
+    }
+
+    case Spread: {
+        compileSpread(node);
+        break;
+    }
+
     case NewArrayWithSize: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
         if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
index 8d765af..c12143a 100644 (file)
@@ -3920,6 +3920,16 @@ void SpeculativeJIT::compile(Node* node)
         cellResult(result.gpr(), node, UseChildrenCalledExplicitly);
         break;
     }
+
+    case NewArrayWithSpread: {
+        compileNewArrayWithSpread(node);
+        break;
+    }
+
+    case Spread: {
+        compileSpread(node);
+        break;
+    }
         
     case NewArrayWithSize: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
index 86b50dd..bed19f5 100644 (file)
@@ -119,6 +119,22 @@ public:
                     break;
                 }
 
+                case NewArrayWithSpread: {
+                    JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
+                    if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
+                        // We've compiled assuming we're not having a bad time, so to be consistent
+                        // with AI we must say we produce an original array allocation structure.
+                        registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous));
+                    } else
+                        registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
+                    break;
+                }
+
+                case Spread: {
+                    registerStructure(m_graph.m_vm.fixedArrayStructure.get());
+                    break;
+                }
+
                 case CreateRest: {
                     if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
                         JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
index fe6b1c6..bc25ec0 100644 (file)
@@ -32,6 +32,7 @@
 #include "FTLAbstractHeap.h"
 #include "HasOwnPropertyCache.h"
 #include "IndexingType.h"
+#include "JSFixedArray.h"
 #include "JSMap.h"
 #include "JSSet.h"
 #include "Symbol.h"
@@ -113,6 +114,7 @@ namespace JSC { namespace FTL {
     macro(HashMapBucket_value, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()) \
     macro(HashMapBucket_key, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()) \
     macro(Symbol_symbolImpl, Symbol::offsetOfSymbolImpl()) \
+    macro(JSFixedArray_size, JSFixedArray::offsetOfSize()) \
 
 #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \
     macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \
@@ -133,6 +135,7 @@ namespace JSC { namespace FTL {
     macro(structureTable, 0, sizeof(Structure*)) \
     macro(variables, 0, sizeof(Register)) \
     macro(HasOwnPropertyCache, 0, sizeof(HasOwnPropertyCache::Entry)) \
+    macro(JSFixedArray_buffer, JSFixedArray::offsetOfData(), sizeof(EncodedJSValue)) \
     
 #define FOR_EACH_NUMBERED_ABSTRACT_HEAP(macro) \
     macro(properties)
index d05a9f5..bce38a6 100644 (file)
@@ -71,6 +71,8 @@ inline CapabilityLevel canCompile(Node* node)
     case GetButterfly:
     case NewObject:
     case NewArray:
+    case NewArrayWithSpread:
+    case Spread:
     case NewArrayBuffer:
     case NewTypedArray:
     case GetByOffset:
index 60e04a0..fd8a90b 100644 (file)
@@ -727,6 +727,12 @@ private:
         case NewArray:
             compileNewArray();
             break;
+        case NewArrayWithSpread:
+            compileNewArrayWithSpread();
+            break;
+        case Spread:
+            compileSpread();
+            break;
         case NewArrayBuffer:
             compileNewArrayBuffer();
             break;
@@ -4296,6 +4302,195 @@ private:
         
         setJSValue(result);
     }
+
+    void compileNewArrayWithSpread()
+    {
+        if (m_graph.isWatchingHavingABadTimeWatchpoint(m_node)) {
+            unsigned startLength = 0;
+            BitVector* bitVector = m_node->bitVector();
+            for (unsigned i = 0; i < m_node->numChildren(); ++i) {
+                if (!bitVector->get(i))
+                    ++startLength;
+            }
+
+            LValue length = m_out.constInt32(startLength);
+
+            for (unsigned i = 0; i < m_node->numChildren(); ++i) {
+                if (bitVector->get(i)) {
+                    Edge use = m_graph.varArgChild(m_node, i);
+                    LValue fixedArray = lowCell(use);
+                    length = m_out.add(length, m_out.load32(fixedArray, m_heaps.JSFixedArray_size));
+                }
+            }
+
+            Structure* structure = m_graph.globalObjectFor(m_node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous);
+            ArrayValues arrayValues = allocateUninitializedContiguousJSArray(length, structure);
+            LValue result = arrayValues.array;
+            LValue storage = arrayValues.butterfly;
+            LValue index = m_out.constIntPtr(0);
+
+            for (unsigned i = 0; i < m_node->numChildren(); ++i) {
+                Edge use = m_graph.varArgChild(m_node, i);
+                if (bitVector->get(i)) {
+                    LBasicBlock loopStart = m_out.newBlock();
+                    LBasicBlock continuation = m_out.newBlock();
+
+                    LValue fixedArray = lowCell(use);
+
+                    ValueFromBlock fixedIndexStart = m_out.anchor(m_out.constIntPtr(0));
+                    ValueFromBlock arrayIndexStart = m_out.anchor(index);
+                    ValueFromBlock arrayIndexStartForFinish = m_out.anchor(index);
+
+                    LValue fixedArraySize = m_out.zeroExtPtr(m_out.load32(fixedArray, m_heaps.JSFixedArray_size));
+
+                    m_out.branch(
+                        m_out.isZero64(fixedArraySize),
+                        unsure(continuation), unsure(loopStart));
+
+                    LBasicBlock lastNext = m_out.appendTo(loopStart, continuation);
+
+                    LValue arrayIndex = m_out.phi(pointerType(), arrayIndexStart);
+                    LValue fixedArrayIndex = m_out.phi(pointerType(), fixedIndexStart);
+
+                    LValue item = m_out.load64(m_out.baseIndex(m_heaps.JSFixedArray_buffer, fixedArray, fixedArrayIndex));
+                    m_out.store64(item, m_out.baseIndex(m_heaps.indexedContiguousProperties, storage, arrayIndex));
+
+                    LValue nextArrayIndex = m_out.add(arrayIndex, m_out.constIntPtr(1));
+                    LValue nextFixedArrayIndex = m_out.add(fixedArrayIndex, m_out.constIntPtr(1));
+                    ValueFromBlock arrayIndexLoopForFinish = m_out.anchor(nextArrayIndex);
+
+                    m_out.addIncomingToPhi(fixedArrayIndex, m_out.anchor(nextFixedArrayIndex));
+                    m_out.addIncomingToPhi(arrayIndex, m_out.anchor(nextArrayIndex));
+
+                    m_out.branch(
+                        m_out.below(nextFixedArrayIndex, fixedArraySize),
+                        unsure(loopStart), unsure(continuation));
+
+                    m_out.appendTo(continuation, lastNext);
+                    index = m_out.phi(pointerType(), arrayIndexStartForFinish, arrayIndexLoopForFinish);
+                } else {
+                    IndexedAbstractHeap& heap = m_heaps.indexedContiguousProperties;
+                    LValue item = lowJSValue(use);
+                    m_out.store64(item, m_out.baseIndex(heap, storage, index));
+                    index = m_out.add(index, m_out.constIntPtr(1));
+                }
+            }
+
+            setJSValue(result);
+            return;
+        }
+
+        ASSERT(m_node->numChildren());
+        size_t scratchSize = sizeof(EncodedJSValue) * m_node->numChildren();
+        ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
+        EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
+        BitVector* bitVector = m_node->bitVector();
+        for (unsigned i = 0; i < m_node->numChildren(); ++i) {
+            Edge use = m_graph.m_varArgChildren[m_node->firstChild() + i];
+            LValue value;
+            if (bitVector->get(i))
+                value = lowCell(use);
+            else
+                value = lowJSValue(use);
+            m_out.store64(value, m_out.absolute(&buffer[i]));
+        }
+
+        m_out.storePtr(m_out.constIntPtr(scratchSize), m_out.absolute(scratchBuffer->activeLengthPtr()));
+        LValue result = vmCall(Int64, m_out.operation(operationNewArrayWithSpreadSlow), m_callFrame, m_out.constIntPtr(buffer), m_out.constInt32(m_node->numChildren()));
+        m_out.storePtr(m_out.constIntPtr(0), m_out.absolute(scratchBuffer->activeLengthPtr()));
+
+        setJSValue(result);
+    }
+
+    void compileSpread()
+    {
+        LValue argument = lowCell(m_node->child1());
+
+        LValue result;
+        if (m_node->child1().useKind() == ArrayUse) {
+            speculateArray(m_node->child1());
+
+            LBasicBlock preLoop = m_out.newBlock();
+            LBasicBlock loopSelection = m_out.newBlock();
+            LBasicBlock contiguousLoopStart = m_out.newBlock();
+            LBasicBlock doubleLoopStart = m_out.newBlock();
+            LBasicBlock slowPath = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
+
+            LValue indexingShape = m_out.load8ZeroExt32(argument, m_heaps.JSCell_indexingType);
+            indexingShape = m_out.bitAnd(indexingShape, m_out.constInt32(IndexingShapeMask));
+            LValue isOKIndexingType = m_out.belowOrEqual(
+                m_out.sub(indexingShape, m_out.constInt32(Int32Shape)),
+                m_out.constInt32(ContiguousShape - Int32Shape));
+
+            m_out.branch(isOKIndexingType, unsure(preLoop), unsure(slowPath));
+            LBasicBlock lastNext = m_out.appendTo(preLoop, loopSelection);
+
+            LValue butterfly = m_out.loadPtr(argument, m_heaps.JSObject_butterfly);
+            LValue length = m_out.load32NonNegative(butterfly, m_heaps.Butterfly_publicLength);
+            static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "Assumed in the code below.");
+            LValue size = m_out.add(
+                m_out.shl(m_out.zeroExtPtr(length), m_out.constInt32(3)),
+                m_out.constIntPtr(JSFixedArray::offsetOfData()));
+
+            LValue fastAllocation = allocateVariableSizedCell<JSFixedArray>(size, m_graph.m_vm.fixedArrayStructure.get(), slowPath);
+            ValueFromBlock fastResult = m_out.anchor(fastAllocation);
+            m_out.store32(length, fastAllocation, m_heaps.JSFixedArray_size);
+
+            ValueFromBlock startIndexForContiguous = m_out.anchor(m_out.constIntPtr(0));
+            ValueFromBlock startIndexForDouble = m_out.anchor(m_out.constIntPtr(0));
+
+            m_out.branch(m_out.isZero32(length), unsure(continuation), unsure(loopSelection));
+
+            m_out.appendTo(loopSelection, contiguousLoopStart);
+            m_out.branch(m_out.equal(indexingShape, m_out.constInt32(DoubleShape)),
+                unsure(doubleLoopStart), unsure(contiguousLoopStart));
+
+            {
+                m_out.appendTo(contiguousLoopStart, doubleLoopStart);
+                LValue index = m_out.phi(pointerType(), startIndexForContiguous);
+
+                TypedPointer loadSite = m_out.baseIndex(m_heaps.root, butterfly, index, ScaleEight); // We read TOP here since we can be reading either int32 or contiguous properties.
+                LValue value = m_out.load64(loadSite);
+                value = m_out.select(m_out.isZero64(value), m_out.constInt64(JSValue::encode(jsUndefined())), value);
+                m_out.store64(value, m_out.baseIndex(m_heaps.JSFixedArray_buffer, fastAllocation, index));
+
+                LValue nextIndex = m_out.add(index, m_out.constIntPtr(1));
+                m_out.addIncomingToPhi(index, m_out.anchor(nextIndex));
+
+                m_out.branch(m_out.below(nextIndex, m_out.zeroExtPtr(length)),
+                    unsure(contiguousLoopStart), unsure(continuation));
+            }
+
+            {
+                m_out.appendTo(doubleLoopStart, slowPath);
+                LValue index = m_out.phi(pointerType(), startIndexForDouble);
+
+                LValue value = m_out.loadDouble(m_out.baseIndex(m_heaps.indexedDoubleProperties, butterfly, index));
+                LValue isNaN = m_out.doubleNotEqualOrUnordered(value, value);
+                LValue holeResult = m_out.constInt64(JSValue::encode(jsUndefined()));
+                LValue normalResult = boxDouble(value);
+                value = m_out.select(isNaN, holeResult, normalResult);
+                m_out.store64(value, m_out.baseIndex(m_heaps.JSFixedArray_buffer, fastAllocation, index));
+
+                LValue nextIndex = m_out.add(index, m_out.constIntPtr(1));
+                m_out.addIncomingToPhi(index, m_out.anchor(nextIndex));
+
+                m_out.branch(m_out.below(nextIndex, m_out.zeroExtPtr(length)),
+                    unsure(doubleLoopStart), unsure(continuation));
+            }
+
+            m_out.appendTo(slowPath, continuation);
+            ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, m_out.operation(operationSpreadFastArray), m_callFrame, argument));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            result = m_out.phi(Int64, fastResult, slowResult);
+        } else
+            result = vmCall(Int64, m_out.operation(operationSpreadGeneric), m_callFrame, argument);
+
+        setJSValue(result);
+    }
     
     void compileNewArrayBuffer()
     {
@@ -9741,6 +9936,15 @@ private:
             vm().heap.subspaceForObjectOfType<ClassType>(), size, slowPath);
         return allocateObject(allocator, structure, butterfly, slowPath);
     }
+
+    template<typename ClassType>
+    LValue allocateVariableSizedCell(
+        LValue size, Structure* structure, LBasicBlock slowPath)
+    {
+        LValue allocator = allocatorForSize(
+            vm().heap.subspaceForObjectOfType<ClassType>(), size, slowPath);
+        return allocateCell(allocator, structure, slowPath);
+    }
     
     LValue allocateObject(Structure* structure)
     {
index 94d8d3f..9672a2b 100644 (file)
@@ -1567,11 +1567,17 @@ public:
     }
     
     template<typename ClassType, typename StructureType>
-    void emitAllocateVariableSizedJSObject(GPRReg resultGPR, StructureType structure, GPRReg allocationSize, GPRReg scratchGPR1, GPRReg scratchGPR2, JumpList& slowPath)
+    void emitAllocateVariableSizedCell(GPRReg resultGPR, StructureType structure, GPRReg allocationSize, GPRReg scratchGPR1, GPRReg scratchGPR2, JumpList& slowPath)
     {
         MarkedSpace::Subspace& subspace = vm()->heap.template subspaceForObjectOfType<ClassType>();
         emitAllocateVariableSized(resultGPR, subspace, allocationSize, scratchGPR1, scratchGPR2, slowPath);
         emitStoreStructureWithTypeInfo(structure, resultGPR, scratchGPR2);
+    }
+
+    template<typename ClassType, typename StructureType>
+    void emitAllocateVariableSizedJSObject(GPRReg resultGPR, StructureType structure, GPRReg allocationSize, GPRReg scratchGPR1, GPRReg scratchGPR2, JumpList& slowPath)
+    {
+        emitAllocateVariableSizedCell<ClassType>(resultGPR, structure, allocationSize, scratchGPR1, scratchGPR2, slowPath);
         storePtr(TrustedImmPtr(0), Address(resultGPR, JSObject::butterflyOffset()));
     }
 
index 143927a..f4c5f29 100644 (file)
@@ -296,6 +296,8 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_new_array)
         DEFINE_OP(op_new_array_with_size)
         DEFINE_OP(op_new_array_buffer)
+        DEFINE_OP(op_new_array_with_spread)
+        DEFINE_OP(op_spread)
         DEFINE_OP(op_new_func)
         DEFINE_OP(op_new_func_exp)
         DEFINE_OP(op_new_generator_func)
index 6b656bc..e6aa023 100644 (file)
@@ -541,6 +541,8 @@ namespace JSC {
         void emit_op_new_array(Instruction*);
         void emit_op_new_array_with_size(Instruction*);
         void emit_op_new_array_buffer(Instruction*);
+        void emit_op_new_array_with_spread(Instruction*);
+        void emit_op_spread(Instruction*);
         void emit_op_new_func(Instruction*);
         void emit_op_new_func_exp(Instruction*);
         void emit_op_new_generator_func(Instruction*);
index a3bd888..f32f02a 100644 (file)
@@ -1074,6 +1074,18 @@ void JIT::emit_op_new_array_buffer(Instruction* currentInstruction)
     callOperation(operationNewArrayBufferWithProfile, dst, currentInstruction[4].u.arrayAllocationProfile, values, size);
 }
 
+void JIT::emit_op_new_array_with_spread(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_new_array_with_spread);
+    slowPathCall.call();
+}
+
+void JIT::emit_op_spread(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_spread);
+    slowPathCall.call();
+}
+
 #if USE(JSVALUE64)
 void JIT::emit_op_has_structure_property(Instruction* currentInstruction)
 {
index af10e97..590b3c5 100644 (file)
@@ -174,6 +174,7 @@ typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EZZ)(ExecState*, int32_t,
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EZSymtabJ)(ExecState*, int32_t, SymbolTable*, EncodedJSValue);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EOIUi)(ExecState*, JSObject*, UniquedStringImpl*, uint32_t);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJI)(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
+typedef JSCell* (JIT_OPERATION *C_JITOperation_EPUi)(ExecState*, void*, uint32_t);
 typedef JSCell* (JIT_OPERATION *C_JITOperation_E)(ExecState*);
 typedef JSCell* (JIT_OPERATION *C_JITOperation_EZ)(ExecState*, int32_t);
 typedef JSCell* (JIT_OPERATION *C_JITOperation_EC)(ExecState*, JSCell*);
index 3a2113a..579d2bb 100644 (file)
@@ -156,21 +156,21 @@ void Data::performAssertions(VM& vm)
     
     STATIC_ASSERT(StringType == 6);
     STATIC_ASSERT(SymbolType == 7);
-    STATIC_ASSERT(ObjectType == 20);
-    STATIC_ASSERT(FinalObjectType == 21);
-    STATIC_ASSERT(JSFunctionType == 23);
-    STATIC_ASSERT(ArrayType == 31);
-    STATIC_ASSERT(DerivedArrayType == 32);
-    STATIC_ASSERT(ProxyObjectType == 50);
-    STATIC_ASSERT(Int8ArrayType == 33);
-    STATIC_ASSERT(Int16ArrayType == 34);
-    STATIC_ASSERT(Int32ArrayType == 35);
-    STATIC_ASSERT(Uint8ArrayType == 36);
-    STATIC_ASSERT(Uint8ClampedArrayType == 37);
-    STATIC_ASSERT(Uint16ArrayType == 38);
-    STATIC_ASSERT(Uint32ArrayType == 39);
-    STATIC_ASSERT(Float32ArrayType == 40);
-    STATIC_ASSERT(Float64ArrayType == 41);
+    STATIC_ASSERT(ObjectType == 21);
+    STATIC_ASSERT(FinalObjectType == 22);
+    STATIC_ASSERT(JSFunctionType == 24);
+    STATIC_ASSERT(ArrayType == 32);
+    STATIC_ASSERT(DerivedArrayType == 33);
+    STATIC_ASSERT(ProxyObjectType == 51);
+    STATIC_ASSERT(Int8ArrayType == 34);
+    STATIC_ASSERT(Int16ArrayType == 35);
+    STATIC_ASSERT(Int32ArrayType == 36);
+    STATIC_ASSERT(Uint8ArrayType == 37);
+    STATIC_ASSERT(Uint8ClampedArrayType == 38);
+    STATIC_ASSERT(Uint16ArrayType == 39);
+    STATIC_ASSERT(Uint32ArrayType == 40);
+    STATIC_ASSERT(Float32ArrayType == 41);
+    STATIC_ASSERT(Float64ArrayType == 42);
     STATIC_ASSERT(MasqueradesAsUndefined == 1);
     STATIC_ASSERT(ImplementsDefaultHasInstance == 2);
     STATIC_ASSERT(FirstConstantRegisterIndex == 0x40000000);
index a06225e..68ae154 100644 (file)
 #include "GetterSetter.h"
 #include "HostCallReturnValue.h"
 #include "Interpreter.h"
+#include "IteratorOperations.h"
 #include "JIT.h"
 #include "JITExceptions.h"
 #include "JITWorklist.h"
 #include "JSAsyncFunction.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
+#include "JSFixedArray.h"
 #include "JSGeneratorFunction.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSLexicalEnvironment.h"
index 6445a47..f40f038 100644 (file)
@@ -345,24 +345,24 @@ const SlowPutArrayStorageShape = 30
 # Type constants.
 const StringType = 6
 const SymbolType = 7
-const ObjectType = 20
-const FinalObjectType = 21
-const JSFunctionType = 23
-const ArrayType = 31
-const DerivedArrayType = 32
-const ProxyObjectType = 50
+const ObjectType = 21
+const FinalObjectType = 22
+const JSFunctionType = 24
+const ArrayType = 32
+const DerivedArrayType = 33
+const ProxyObjectType = 51
 
 # The typed array types need to be numbered in a particular order because of the manually written
 # switch statement in get_by_val and put_by_val.
-const Int8ArrayType = 33
-const Int16ArrayType = 34
-const Int32ArrayType = 35
-const Uint8ArrayType = 36
-const Uint8ClampedArrayType = 37
-const Uint16ArrayType = 38
-const Uint32ArrayType = 39
-const Float32ArrayType = 40
-const Float64ArrayType = 41
+const Int8ArrayType = 34
+const Int16ArrayType = 35
+const Int32ArrayType = 36
+const Uint8ArrayType = 37
+const Uint8ClampedArrayType = 38
+const Uint16ArrayType = 39
+const Uint32ArrayType = 40
+const Float32ArrayType = 41
+const Float64ArrayType = 42
 
 const FirstArrayType = Int8ArrayType
 const LastArrayType = Float64ArrayType
@@ -1333,6 +1333,18 @@ _llint_op_new_array:
     dispatch(5)
 
 
+_llint_op_new_array_with_spread:
+    traceExecution()
+    callOpcodeSlowPath(_slow_path_new_array_with_spread)
+    dispatch(5)
+
+
+_llint_op_spread:
+    traceExecution()
+    callOpcodeSlowPath(_slow_path_spread)
+    dispatch(3)
+
+
 _llint_op_new_array_with_size:
     traceExecution()
     callOpcodeSlowPath(_llint_slow_path_new_array_with_size)
diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.cpp b/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.cpp
new file mode 100644 (file)
index 0000000..1fc8a7a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "ArrayIteratorAdaptiveWatchpoint.h"
+
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+ArrayIteratorAdaptiveWatchpoint::ArrayIteratorAdaptiveWatchpoint(const ObjectPropertyCondition& condition, JSGlobalObject* globalObject)
+    : Base(condition)
+    , m_globalObject(globalObject)
+{
+    RELEASE_ASSERT(m_globalObject->arrayIteratorProtocolWatchpoint().stateOnJSThread() == IsWatched);
+}
+
+void ArrayIteratorAdaptiveWatchpoint::handleFire(const FireDetail&)
+{
+    m_globalObject->arrayIteratorProtocolWatchpoint().fireAll(m_globalObject->vm(), StringFireDetail("Array iterator protocol changed."));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.h b/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.h
new file mode 100644 (file)
index 0000000..a45cce2
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "AdaptiveInferredPropertyValueWatchpointBase.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+
+class ArrayIteratorAdaptiveWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase {
+public:
+    typedef AdaptiveInferredPropertyValueWatchpointBase Base;
+    ArrayIteratorAdaptiveWatchpoint(const ObjectPropertyCondition&, JSGlobalObject*);
+
+private:
+    void handleFire(const FireDetail&) override;
+
+    JSGlobalObject* m_globalObject;
+};
+
+} // namespace JSC
index 9f64da0..4806a30 100644 (file)
 #include "GetterSetter.h"
 #include "HostCallReturnValue.h"
 #include "Interpreter.h"
+#include "IteratorOperations.h"
 #include "JIT.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
+#include "JSFixedArray.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSLexicalEnvironment.h"
 #include "JSPropertyNameEnumerator.h"
@@ -976,4 +978,83 @@ SLOW_PATH_DECL(slow_path_throw_static_error)
     THROW(createError(exec, errorType, errorMessage));
 }
 
+SLOW_PATH_DECL(slow_path_new_array_with_spread)
+{
+    BEGIN();
+    int numItems = pc[3].u.operand;
+    ASSERT(numItems >= 0);
+    const BitVector& bitVector = exec->codeBlock()->unlinkedCodeBlock()->bitVector(pc[4].u.unsignedValue);
+
+    JSValue* values = bitwise_cast<JSValue*>(&OP(2));
+
+    unsigned arraySize = 0;
+    for (int i = 0; i < numItems; i++) {
+        if (bitVector.get(i)) {
+            JSValue value = values[-i];
+            JSFixedArray* array = jsCast<JSFixedArray*>(value);
+            arraySize += array->size();
+        } else
+            arraySize += 1;
+    }
+
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
+
+    JSArray* result = JSArray::tryCreateUninitialized(vm, structure, arraySize);
+    CHECK_EXCEPTION();
+
+    unsigned index = 0;
+    for (int i = 0; i < numItems; i++) {
+        JSValue value = values[-i];
+        if (bitVector.get(i)) {
+            // We are spreading.
+            JSFixedArray* array = jsCast<JSFixedArray*>(value);
+            for (unsigned i = 0; i < array->size(); i++) {
+                RELEASE_ASSERT(array->get(i));
+                result->initializeIndex(vm, index, array->get(i));
+                ++index;
+            }
+        } else {
+            // We are not spreading.
+            result->initializeIndex(vm, index, value);
+            ++index;
+        }
+    }
+
+    RETURN(result);
+}
+
+SLOW_PATH_DECL(slow_path_spread)
+{
+    BEGIN();
+
+    JSValue iterable = OP_C(2).jsValue();
+
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+
+    if (iterable.isCell() && isJSArray(iterable.asCell()) && globalObject->isArrayIteratorProtocolFastAndNonObservable()) {
+        // JSFixedArray::createFromArray does not consult the prototype chain,
+        // so we must be sure that not consulting the prototype chain would
+        // produce the same value during iteration.
+        JSArray* array = jsCast<JSArray*>(iterable);
+        RETURN(JSFixedArray::createFromArray(exec, vm, array));
+    }
+
+    JSArray* array;
+    {
+        JSFunction* iterationFunction = globalObject->iteratorProtocolFunction();
+        CallData callData;
+        CallType callType = JSC::getCallData(iterationFunction, callData);
+        ASSERT(callType != CallType::None);
+
+        MarkedArgumentBuffer arguments;
+        arguments.append(iterable);
+        JSValue arrayResult = call(exec, iterationFunction, callType, callData, jsNull(), arguments);
+        CHECK_EXCEPTION();
+        array = jsCast<JSArray*>(arrayResult);
+    }
+
+    RETURN(JSFixedArray::createFromArray(exec, vm, array));
+}
+
 } // namespace JSC
index 934017c..9eed6f1 100644 (file)
@@ -260,5 +260,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_with_this);
 SLOW_PATH_HIDDEN_DECL(slow_path_define_data_property);
 SLOW_PATH_HIDDEN_DECL(slow_path_define_accessor_property);
 SLOW_PATH_HIDDEN_DECL(slow_path_throw_static_error);
+SLOW_PATH_HIDDEN_DECL(slow_path_new_array_with_spread);
+SLOW_PATH_HIDDEN_DECL(slow_path_spread);
 
 } // namespace JSC
index 614ad79..7ac9a02 100644 (file)
@@ -45,24 +45,24 @@ Structure* createIteratorResultObjectStructure(VM&, JSGlobalObject&);
 JS_EXPORT_PRIVATE JSValue iteratorForIterable(ExecState*, JSValue iterable);
 
 template <typename CallBackType>
-void forEachInIterable(ExecState* state, JSValue iterable, const CallBackType& callback)
+void forEachInIterable(ExecState* exec, JSValue iterable, const CallBackType& callback)
 {
-    auto& vm = state->vm();
+    auto& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    JSValue iterator = iteratorForIterable(state, iterable);
+    JSValue iterator = iteratorForIterable(exec, iterable);
     RETURN_IF_EXCEPTION(scope, void());
     while (true) {
-        JSValue next = iteratorStep(state, iterator);
+        JSValue next = iteratorStep(exec, iterator);
         if (next.isFalse() || UNLIKELY(scope.exception()))
             return;
 
-        JSValue nextValue = iteratorValue(state, next);
+        JSValue nextValue = iteratorValue(exec, next);
         RETURN_IF_EXCEPTION(scope, void());
 
-        callback(vm, state, nextValue);
+        callback(vm, exec, nextValue);
         if (UNLIKELY(scope.exception())) {
-            iteratorClose(state, iterator);
+            iteratorClose(exec, iterator);
             return;
         }
     }
index a0104bb..cb3db3d 100644 (file)
@@ -43,6 +43,7 @@
 #include "JSArrayBufferViewInlines.h"
 #include "JSCJSValueInlines.h"
 #include "JSFunctionInlines.h"
+#include "JSGlobalObjectInlines.h"
 #include "JSObjectInlines.h"
 #include "JSProxy.h"
 #include "JSString.h"
diff --git a/Source/JavaScriptCore/runtime/JSFixedArray.cpp b/Source/JavaScriptCore/runtime/JSFixedArray.cpp
new file mode 100644 (file)
index 0000000..15d3e23
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "JSFixedArray.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSFixedArray::s_info = { "JSFixedArray", nullptr, nullptr, CREATE_METHOD_TABLE(JSFixedArray) };
+
+void JSFixedArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    JSFixedArray* thisObject = jsCast<JSFixedArray*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    Base::visitChildren(thisObject, visitor);
+    visitor.appendValuesHidden(thisObject->buffer(), thisObject->size());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSFixedArray.h b/Source/JavaScriptCore/runtime/JSFixedArray.h
new file mode 100644 (file)
index 0000000..cdb1ff1
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "JSGlobalObject.h"
+#include "JSObject.h"
+
+namespace JSC {
+
+class JSFixedArray : public JSCell {
+    typedef JSCell Base;
+
+public:
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+    DECLARE_INFO;
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSFixedArrayType, StructureFlags), info());
+    }
+
+    ALWAYS_INLINE static JSFixedArray* createFromArray(ExecState* exec, VM& vm, JSArray* array)
+    {
+        IndexingType indexingType = array->indexingType() & IndexingShapeMask;
+        unsigned length = array->length();
+        JSFixedArray* result = JSFixedArray::create(vm, vm.fixedArrayStructure.get(), length);
+
+        if (!length)
+            return result;
+
+        if (indexingType == ContiguousShape || indexingType == Int32Shape) {
+            for (unsigned i = 0; i < length; i++) {
+                JSValue value = array->butterfly()->contiguous()[i].get();
+                value = !!value ? value : jsUndefined();
+                result->buffer()[i].set(vm, result, value);
+            }
+            return result;
+        }
+
+        if (indexingType == DoubleShape) {
+            for (unsigned i = 0; i < length; i++) {
+                double d = array->butterfly()->contiguousDouble()[i];
+                JSValue value = std::isnan(d) ? jsUndefined() : JSValue(JSValue::EncodeAsDouble, d);
+                result->buffer()[i].set(vm, result, value);
+            }
+            return result;
+        }
+
+
+        auto throwScope = DECLARE_THROW_SCOPE(vm);
+        for (unsigned i = 0; i < length; i++) {
+            JSValue value = array->getDirectIndex(exec, i);
+            if (!value) {
+                // When we see a hole, we assume that it's safe to assume the get would have returned undefined.
+                // We may still call into this function when !globalObject->isArrayIteratorProtocolFastAndNonObservable(),
+                // however, if we do that, we ensure we're calling in with an array with all self properties between
+                // [0, length).
+                ASSERT(array->globalObject()->isArrayIteratorProtocolFastAndNonObservable());
+                value = jsUndefined();
+            }
+            RETURN_IF_EXCEPTION(throwScope, nullptr);
+            result->buffer()[i].set(vm, result, value);
+        }
+        return result;
+    }
+
+    ALWAYS_INLINE JSValue get(unsigned index)
+    {
+        ASSERT(index < m_size);
+        return buffer()[index].get();
+    }
+
+    ALWAYS_INLINE WriteBarrier<Unknown>* buffer() { return bitwise_cast<WriteBarrier<Unknown>*>(bitwise_cast<char*>(this) + offsetOfData()); }
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    unsigned size() const { return m_size; }
+
+    static size_t offsetOfSize() { return OBJECT_OFFSETOF(JSFixedArray, m_size); }
+
+    static size_t offsetOfData()
+    {
+        return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSFixedArray));
+    }
+
+private:
+    unsigned m_size;
+
+    ALWAYS_INLINE static JSFixedArray* create(VM& vm, Structure* structure, unsigned size)
+    {
+        JSFixedArray* result = new (NotNull, allocateCell<JSFixedArray>(vm.heap, allocationSize(size))) JSFixedArray(vm, structure, size);
+        result->finishCreation(vm);
+        return result;
+    }
+
+
+    JSFixedArray(VM& vm, Structure* structure, unsigned size)
+        : Base(vm, structure)
+        , m_size(size)
+    {
+        for (unsigned i = 0; i < m_size; i++)
+            buffer()[i].setStartingValue(JSValue());
+    }
+
+
+    static size_t allocationSize(unsigned numItems)
+    {
+        return offsetOfData() + numItems * sizeof(WriteBarrier<Unknown>);
+    }
+};
+
+} // namespace JSC
index e9c9876..8aa6c11 100644 (file)
@@ -31,6 +31,7 @@
 #include "JSGlobalObject.h"
 
 #include "ArrayConstructor.h"
+#include "ArrayIteratorAdaptiveWatchpoint.h"
 #include "ArrayIteratorPrototype.h"
 #include "ArrayPrototype.h"
 #include "AtomicsObject.h"
@@ -77,6 +78,7 @@
 #include "JSDataViewPrototype.h"
 #include "JSDollarVM.h"
 #include "JSDollarVMPrototype.h"
+#include "JSFixedArray.h"
 #include "JSFunction.h"
 #include "JSGeneratorFunction.h"
 #include "JSGenericTypedArrayViewConstructorInlines.h"
 #include "NumberPrototype.h"
 #include "ObjCCallbackFunction.h"
 #include "ObjectConstructor.h"
+#include "ObjectPropertyConditionSet.h"
 #include "ObjectPrototype.h"
 #include "ParserError.h"
 #include "ProxyConstructor.h"
@@ -313,6 +316,7 @@ JSGlobalObject::JSGlobalObject(VM& vm, Structure* structure, const GlobalObjectM
     , m_havingABadTimeWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
     , 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_templateRegistry(vm)
     , m_evalEnabled(true)
     , m_runtimeFlags()
@@ -411,6 +415,12 @@ void JSGlobalObject::init(VM& vm)
         [] (const Initializer<JSFunction>& init) {
             init.set(JSFunction::createBuiltinFunction(init.vm, promiseOperationsInitializePromiseCodeGenerator(init.vm), init.owner));
         });
+
+    m_iteratorProtocolFunction.initLater(
+        [] (const Initializer<JSFunction>& init) {
+            init.set(JSFunction::createBuiltinFunction(init.vm, iteratorHelpersPerformIterationCodeGenerator(init.vm), init.owner));
+        });
+
     m_newPromiseCapabilityFunction.set(vm, this, JSFunction::createBuiltinFunction(vm, promiseOperationsNewPromiseCapabilityCodeGenerator(vm), this));
     m_functionProtoHasInstanceSymbolFunction.set(vm, this, hasInstanceSymbolFunction);
     m_throwTypeErrorGetterSetter.initLater(
@@ -754,7 +764,6 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
     JSObject* arrayIteratorPrototype = ArrayIteratorPrototype::create(vm, this, ArrayIteratorPrototype::createStructure(vm, this, m_iteratorPrototype.get()));
     createArrayIteratorPrivateFunction->putDirect(vm, vm.propertyNames->prototype, arrayIteratorPrototype);
 
-
     GlobalPropertyInfo staticGlobals[] = {
 #define INIT_PRIVATE_GLOBAL(name, code) GlobalPropertyInfo(vm.propertyNames->builtinNames().name ## PrivateName(), name ## PrivateFunction, DontEnum | DontDelete | ReadOnly),
         JSC_FOREACH_BUILTIN_FUNCTION_PRIVATE_GLOBAL_NAME(INIT_PRIVATE_GLOBAL)
@@ -886,6 +895,44 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
     }
 #endif // ENABLE(WEBASSEMBLY)
 
+    {
+        ExecState* exec = globalExec();
+        auto scope = DECLARE_THROW_SCOPE(vm);
+
+        auto setupAdaptiveWatchpoint = [&] (JSObject* base, const Identifier& ident) -> ObjectPropertyCondition {
+            // Performing these gets should not throw.
+            PropertySlot slot(base, PropertySlot::InternalMethodType::Get);
+            bool result = base->getOwnPropertySlot(base, exec, ident, slot);
+            ASSERT_UNUSED(result, result);
+            ASSERT_UNUSED(scope, !scope.exception());
+            RELEASE_ASSERT(slot.isCacheableValue());
+            JSValue functionValue = slot.getValue(exec, ident);
+            ASSERT_UNUSED(scope, !scope.exception());
+            ASSERT(jsDynamicCast<JSFunction*>(functionValue));
+
+            ObjectPropertyCondition condition = generateConditionForSelfEquivalence(m_vm, nullptr, base, ident.impl());
+            RELEASE_ASSERT(condition.requiredValue() == functionValue);
+
+            bool isWatchable = condition.isWatchable(PropertyCondition::EnsureWatchability);
+            RELEASE_ASSERT(isWatchable); // We allow this to install the necessary watchpoints.
+
+            return condition;
+        };
+
+        {
+            ObjectPropertyCondition condition = setupAdaptiveWatchpoint(arrayIteratorPrototype, m_vm.propertyNames->next);
+            m_arrayIteratorPrototypeNext = std::make_unique<ArrayIteratorAdaptiveWatchpoint>(condition, this);
+            m_arrayIteratorPrototypeNext->install();
+        }
+
+        {
+            ArrayPrototype* arrayPrototype = this->arrayPrototype();
+            ObjectPropertyCondition condition = setupAdaptiveWatchpoint(arrayPrototype, m_vm.propertyNames->iteratorSymbol);
+            m_arrayPrototypeSymbolIteratorWatchpoint = std::make_unique<ArrayIteratorAdaptiveWatchpoint>(condition, this);
+            m_arrayPrototypeSymbolIteratorWatchpoint->install();
+        }
+    }
+
     resetPrototype(vm, getPrototypeDirect());
 }
 
@@ -1073,26 +1120,6 @@ void JSGlobalObject::haveABadTime(VM& vm)
     }
 }
 
-bool JSGlobalObject::objectPrototypeIsSane()
-{
-    return !hasIndexedProperties(m_objectPrototype->indexingType())
-        && m_objectPrototype->getPrototypeDirect().isNull();
-}
-
-bool JSGlobalObject::arrayPrototypeChainIsSane()
-{
-    return !hasIndexedProperties(m_arrayPrototype->indexingType())
-        && m_arrayPrototype->getPrototypeDirect() == m_objectPrototype.get()
-        && objectPrototypeIsSane();
-}
-
-bool JSGlobalObject::stringPrototypeChainIsSane()
-{
-    return !hasIndexedProperties(m_stringPrototype->indexingType())
-        && m_stringPrototype->getPrototypeDirect() == m_objectPrototype.get()
-        && objectPrototypeIsSane();
-}
-
 // Set prototype, and also insert the object prototype at the end of the chain.
 void JSGlobalObject::resetPrototype(VM& vm, JSValue prototype)
 {
@@ -1142,6 +1169,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     thisObject->m_arrayProtoToStringFunction.visit(visitor);
     thisObject->m_arrayProtoValuesFunction.visit(visitor);
     thisObject->m_initializePromiseFunction.visit(visitor);
+    thisObject->m_iteratorProtocolFunction.visit(visitor);
     visitor.append(&thisObject->m_newPromiseCapabilityFunction);
     visitor.append(&thisObject->m_functionProtoHasInstanceSymbolFunction);
     thisObject->m_throwTypeErrorGetterSetter.visit(visitor);
index 324bffb..6b1bff8 100644 (file)
@@ -54,9 +54,9 @@ class JSGlobalObjectInspectorController;
 }
 
 namespace JSC {
-
 class ArrayConstructor;
 class ArrayPrototype;
+class ArrayIteratorAdaptiveWatchpoint;
 class AsyncFunctionPrototype;
 class BooleanPrototype;
 class ConsoleClient;
@@ -259,6 +259,7 @@ public:
     LazyProperty<JSGlobalObject, JSFunction> m_arrayProtoToStringFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_arrayProtoValuesFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_initializePromiseFunction;
+    LazyProperty<JSGlobalObject, JSFunction> m_iteratorProtocolFunction;
     WriteBarrier<JSFunction> m_newPromiseCapabilityFunction;
     WriteBarrier<JSFunction> m_functionProtoHasInstanceSymbolFunction;
     LazyProperty<JSGlobalObject, GetterSetter> m_throwTypeErrorGetterSetter;
@@ -395,6 +396,15 @@ public:
 
     WeakRandom m_weakRandom;
 
+    InlineWatchpointSet& arrayIteratorProtocolWatchpoint() { return m_arrayIteratorProtocolWatchpoint; }
+    // If this hasn't been invalidated, it means the array iterator protocol
+    // is not observable to user code yet.
+    InlineWatchpointSet m_arrayIteratorProtocolWatchpoint;
+    std::unique_ptr<ArrayIteratorAdaptiveWatchpoint> m_arrayPrototypeSymbolIteratorWatchpoint;
+    std::unique_ptr<ArrayIteratorAdaptiveWatchpoint> m_arrayIteratorPrototypeNext;
+
+    bool isArrayIteratorProtocolFastAndNonObservable();
+
     TemplateRegistry m_templateRegistry;
 
     bool m_evalEnabled;
@@ -513,6 +523,7 @@ public:
     JSFunction* arrayProtoToStringFunction() const { return m_arrayProtoToStringFunction.get(this); }
     JSFunction* arrayProtoValuesFunction() const { return m_arrayProtoValuesFunction.get(this); }
     JSFunction* initializePromiseFunction() const { return m_initializePromiseFunction.get(this); }
+    JSFunction* iteratorProtocolFunction() const { return m_iteratorProtocolFunction.get(this); }
     JSFunction* newPromiseCapabilityFunction() const { return m_newPromiseCapabilityFunction.get(); }
     JSFunction* functionProtoHasInstanceSymbolFunction() const { return m_functionProtoHasInstanceSymbolFunction.get(); }
     JSObject* regExpProtoExecFunction() const { return m_regExpProtoExec.get(); }
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h b/Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h
new file mode 100644 (file)
index 0000000..7e334eb
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#include "JSGlobalObject.h"
+
+#include "ArrayPrototype.h"
+#include "ObjectPrototype.h"
+
+namespace JSC {
+
+ALWAYS_INLINE bool JSGlobalObject::objectPrototypeIsSane()
+{
+    return !hasIndexedProperties(m_objectPrototype->indexingType())
+        && m_objectPrototype->getPrototypeDirect().isNull();
+}
+
+ALWAYS_INLINE bool JSGlobalObject::arrayPrototypeChainIsSane()
+{
+    return !hasIndexedProperties(m_arrayPrototype->indexingType())
+        && m_arrayPrototype->getPrototypeDirect() == m_objectPrototype.get()
+        && objectPrototypeIsSane();
+}
+
+ALWAYS_INLINE bool JSGlobalObject::stringPrototypeChainIsSane()
+{
+    return !hasIndexedProperties(m_stringPrototype->indexingType())
+        && m_stringPrototype->getPrototypeDirect() == m_objectPrototype.get()
+        && objectPrototypeIsSane();
+}
+
+
+ALWAYS_INLINE bool JSGlobalObject::isArrayIteratorProtocolFastAndNonObservable()
+{
+    // We're fast if we don't have any indexed properties on the prototype.
+    // We're non-observable if the iteration protocol hasn't changed.
+    //
+    // Note: it only makes sense to call this from the main thread. If you're
+    // trying to prove this behavior on the compiler thread, you'll want to
+    // carefully set up watchpoints to have correct ordering while JS code is
+    // executing concurrently.
+
+    return arrayIteratorProtocolWatchpoint().isStillValid() && !isHavingABadTime() && arrayPrototypeChainIsSane();
+}
+
+} // namespace JSC
index f8bb7af..05202f3 100644 (file)
@@ -49,6 +49,8 @@ enum JSType : uint8_t {
     UnlinkedEvalCodeBlockType,
     UnlinkedFunctionCodeBlockType,
 
+    JSFixedArrayType,
+
     // The ObjectType value must come before any JSType that is a subclass of JSObject.
     ObjectType,
     FinalObjectType,
index 7a2f0f2..34e8b95 100644 (file)
@@ -63,6 +63,7 @@
 #include "JSAPIValueWrapper.h"
 #include "JSArray.h"
 #include "JSCInlines.h"
+#include "JSFixedArray.h"
 #include "JSFunction.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSInternalPromiseDeferred.h"
@@ -233,6 +234,7 @@ VM::VM(VMType vmType, HeapType heapType)
     regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
     symbolStructure.set(*this, Symbol::createStructure(*this, 0, jsNull()));
     symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull()));
+    fixedArrayStructure.set(*this, JSFixedArray::createStructure(*this, 0, jsNull()));
     structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
     sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull()));
     templateRegistryKeyStructure.set(*this, JSTemplateRegistryKey::createStructure(*this, 0, jsNull()));
index e14b885..28a9b63 100644 (file)
@@ -314,6 +314,7 @@ public:
     Strong<Structure> regExpStructure;
     Strong<Structure> symbolStructure;
     Strong<Structure> symbolTableStructure;
+    Strong<Structure> fixedArrayStructure;
     Strong<Structure> structureChainStructure;
     Strong<Structure> sparseArrayValueMapStructure;
     Strong<Structure> templateRegistryKeyStructure;