Speculatively change iteration protocall to use the same next function
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Sep 2017 02:08:04 +0000 (02:08 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Sep 2017 02:08:04 +0000 (02:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175653

Reviewed by Saam Barati.

JSTests:

Change test to match the new iteration behavior.

* stress/spread-optimized-properly.js:

Source/JavaScriptCore:

This patch speculatively makes a change to the iteration protocall to fetch the next
property immediately after calling the Symbol.iterator function. This is, in theory,
a breaking change, so we will see if this breaks things (most likely it won't as this
is a relatively subtle point).

See: https://github.com/tc39/ecma262/issues/976

* builtins/IteratorHelpers.js:
(performIteration):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitEnumeration):
(JSC::BytecodeGenerator::emitIteratorNext):
(JSC::BytecodeGenerator::emitIteratorNextWithValue):
(JSC::BytecodeGenerator::emitDelegateYield):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ArrayPatternNode::bindValue const):
* inspector/JSInjectedScriptHost.cpp:
(Inspector::JSInjectedScriptHost::iteratorEntries):
* runtime/IteratorOperations.cpp:
(JSC::iteratorNext):
(JSC::iteratorStep):
(JSC::iteratorClose):
(JSC::iteratorForIterable):
* runtime/IteratorOperations.h:
(JSC::forEachInIterable):
* runtime/JSGenericTypedArrayViewConstructorInlines.h:
(JSC::constructGenericTypedArrayViewFromIterator):
(JSC::constructGenericTypedArrayViewWithArguments):

LayoutTests:

Change test to match the new iteration behavior.

* js/sequence-iterator-protocol-2-expected.txt:
* js/sequence-iterator-protocol-2.html:

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

15 files changed:
JSTests/ChangeLog
JSTests/stress/spread-optimized-properly.js
JSTests/test262.yaml
LayoutTests/ChangeLog
LayoutTests/js/sequence-iterator-protocol-2-expected.txt
LayoutTests/js/sequence-iterator-protocol-2.html
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/IteratorHelpers.js
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
Source/JavaScriptCore/runtime/IteratorOperations.cpp
Source/JavaScriptCore/runtime/IteratorOperations.h
Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h

index 1f01f8e..6402b6a 100644 (file)
@@ -1,3 +1,14 @@
+2017-09-22  Keith Miller  <keith_miller@apple.com>
+
+        Speculatively change iteration protocall to use the same next function
+        https://bugs.webkit.org/show_bug.cgi?id=175653
+
+        Reviewed by Saam Barati.
+
+        Change test to match the new iteration behavior.
+
+        * stress/spread-optimized-properly.js:
+
 2017-09-22  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [DFG][FTL] Profile array vector length for array allocation
index 120fe9e..3c8566d 100644 (file)
@@ -149,7 +149,7 @@ test(function() {
         assert(t.length === 3);
         assert(t[0] === 1);
         assert(t[1] === 2);
-        assert(t[2] === 4);
+        assert(t[2] === 3);
         iterProto.next = oldNext;
     }
 });
index f4b0517..c57c190 100644 (file)
 - path: test262/test/language/expressions/async-generator/named-yield-spread-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/compareArray.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/async-generator/named-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/async-generator/named-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/async-generator/named-yield-star-async-return.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/async-generator/named-yield-star-async-return.js
 - path: test262/test/language/expressions/async-generator/yield-spread-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/compareArray.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/async-generator/yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/async-generator/yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/async-generator/yield-star-async-return.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/async-generator/yield-star-async-return.js
 - path: test262/test/language/expressions/class/async-gen-method-static-yield-spread-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/compareArray.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/class/async-gen-method-static-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/class/async-gen-method-static-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/class/async-gen-method-static-yield-star-async-return.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/class/async-gen-method-static-yield-star-async-return.js
 - path: test262/test/language/expressions/class/async-gen-method-yield-spread-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/compareArray.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/class/async-gen-method-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/class/async-gen-method-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/class/async-gen-method-yield-star-async-return.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/class/async-gen-method-yield-star-async-return.js
 - path: test262/test/language/expressions/object/method-definition/async-gen-yield-spread-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/compareArray.js", "../../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/object/method-definition/async-gen-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:async]
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/object/method-definition/async-gen-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:strict, :async]
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/expressions/object/method-definition/async-gen-yield-star-async-return.js
   cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/expressions/object/method-definition/async-gen-yield-star-async-return.js
 - path: test262/test/language/statements/async-generator/yield-spread-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/compareArray.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/statements/async-generator/yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/statements/async-generator/yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/statements/async-generator/yield-star-async-return.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/statements/async-generator/yield-star-async-return.js
 - path: test262/test/language/statements/class/async-gen-method-static-yield-spread-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/compareArray.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/statements/class/async-gen-method-static-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/statements/class/async-gen-method-static-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/statements/class/async-gen-method-static-yield-star-async-return.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/statements/class/async-gen-method-static-yield-star-async-return.js
 - path: test262/test/language/statements/class/async-gen-method-yield-spread-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/compareArray.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/statements/class/async-gen-method-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/statements/class/async-gen-method-yield-star-async-next.js
-  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+  cmd: runTest262 :fail, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/statements/class/async-gen-method-yield-star-async-return.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
 - path: test262/test/language/statements/class/async-gen-method-yield-star-async-return.js
index bf70167..8cfd5a5 100644 (file)
@@ -1,3 +1,15 @@
+2017-09-22  Keith Miller  <keith_miller@apple.com>
+
+        Speculatively change iteration protocall to use the same next function
+        https://bugs.webkit.org/show_bug.cgi?id=175653
+
+        Reviewed by Saam Barati.
+
+        Change test to match the new iteration behavior.
+
+        * js/sequence-iterator-protocol-2-expected.txt:
+        * js/sequence-iterator-protocol-2.html:
+
 2017-09-22  Ryan Haddad  <ryanhaddad@apple.com>
 
         WebRTC test gardening for iOS.
index a99e588..e5484d7 100644 (file)
@@ -2,9 +2,9 @@ CONSOLE MESSAGE: line 28: Using an array but with objects with valueOf()
 CONSOLE MESSAGE: line 29: 1,2,3,1,2,3
 CONSOLE MESSAGE: line 33: 1,2,3,1,2,3
 CONSOLE MESSAGE: line 38: callCount: 3
-CONSOLE MESSAGE: line 66: 1,2,4,1,2,4
-CONSOLE MESSAGE: line 71: 1,2,4,1,2,4
-CONSOLE MESSAGE: line 75: callCount: 2
+CONSOLE MESSAGE: line 66: 1,2,3,1,2,3
+CONSOLE MESSAGE: line 71: 1,2,3,1,2,3
+CONSOLE MESSAGE: line 75: callCount: 0
 PASS successfullyParsed is true
 
 TEST COMPLETE
index ee243a9..357e2ed 100644 (file)
             log(`${b}`);
 
             iterProto.next = oldNext;
-            ctx.setLineDash([1,2,4]);
+            ctx.setLineDash([1,2,3]);
             a = ctx.getLineDash();
             log(a);
             if (a.toString() !== b.toString())
                 throw new Error("Bad result. They should be equal.");
 
             log(`callCount: ${callCount}`);
-            if (callCount !== 2)
-                throw new Error("Bad result. callCount should be 2.");
+            if (callCount !== 0)
+                throw new Error("Bad result. callCount should be 0.");
 
         </script>
 
index 9d15871..64deeca 100644 (file)
@@ -1,3 +1,40 @@
+2017-09-22  Keith Miller  <keith_miller@apple.com>
+
+        Speculatively change iteration protocall to use the same next function
+        https://bugs.webkit.org/show_bug.cgi?id=175653
+
+        Reviewed by Saam Barati.
+
+        This patch speculatively makes a change to the iteration protocall to fetch the next
+        property immediately after calling the Symbol.iterator function. This is, in theory,
+        a breaking change, so we will see if this breaks things (most likely it won't as this
+        is a relatively subtle point).
+
+        See: https://github.com/tc39/ecma262/issues/976
+
+        * builtins/IteratorHelpers.js:
+        (performIteration):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitEnumeration):
+        (JSC::BytecodeGenerator::emitIteratorNext):
+        (JSC::BytecodeGenerator::emitIteratorNextWithValue):
+        (JSC::BytecodeGenerator::emitDelegateYield):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ArrayPatternNode::bindValue const):
+        * inspector/JSInjectedScriptHost.cpp:
+        (Inspector::JSInjectedScriptHost::iteratorEntries):
+        * runtime/IteratorOperations.cpp:
+        (JSC::iteratorNext):
+        (JSC::iteratorStep):
+        (JSC::iteratorClose):
+        (JSC::iteratorForIterable):
+        * runtime/IteratorOperations.h:
+        (JSC::forEachInIterable):
+        * runtime/JSGenericTypedArrayViewConstructorInlines.h:
+        (JSC::constructGenericTypedArrayViewFromIterator):
+        (JSC::constructGenericTypedArrayViewWithArguments):
+
 2017-09-22  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         [Win64] Crashes in Yarr JIT compiled code
index f565d44..1ac9f91 100644 (file)
@@ -33,10 +33,11 @@ function performIteration(iterable)
     let result = [];
 
     let iterator = iterable.@iteratorSymbol();
+    let next = iterator.next;
     let item;
     let index = 0;
     while (true) {
-        item = iterator.next();
+        item = next.@call(iterator);
         if (!@isObject(item))
             @throwTypeError("Iterator result interface is not an object");
         if (item.done)
index 5c70347..6160639 100644 (file)
@@ -4315,8 +4315,8 @@ void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, Expressio
 
     RefPtr<RegisterID> subject = newTemporary();
     emitNode(subject.get(), subjectNode);
-
     RefPtr<RegisterID> iterator = isForAwait ? emitGetAsyncIterator(subject.get(), node) : emitGetIterator(subject.get(), node);
+    RefPtr<RegisterID> nextMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().next);
 
     Ref<Label> loopDone = newLabel();
     Ref<Label> tryStartLabel = newLabel();
@@ -4422,7 +4422,7 @@ void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, Expressio
         }
 
         {
-            emitIteratorNext(value.get(), iterator.get(), node, isForAwait ? EmitAwait::Yes : EmitAwait::No);
+            emitIteratorNext(value.get(), nextMethod.get(), iterator.get(), node, isForAwait ? EmitAwait::Yes : EmitAwait::No);
 
             emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), loopDone.get());
             emitGetById(value.get(), value.get(), propertyNames().value);
@@ -4587,13 +4587,12 @@ RegisterID* BytecodeGenerator::emitIsEmpty(RegisterID* dst, RegisterID* src)
     return dst;
 }
     
-RegisterID* BytecodeGenerator::emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node, EmitAwait doEmitAwait)
+RegisterID* BytecodeGenerator::emitIteratorNext(RegisterID* dst, RegisterID* nextMethod, RegisterID* iterator, const ThrowableExpressionData* node, EmitAwait doEmitAwait)
 {
     {
-        RefPtr<RegisterID> next = emitGetById(newTemporary(), iterator, propertyNames().next);
         CallArguments nextArguments(*this, nullptr);
         emitMove(nextArguments.thisRegister(), iterator);
-        emitCall(dst, next.get(), NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
+        emitCall(dst, nextMethod, NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
 
         if (doEmitAwait == EmitAwait::Yes)
             emitAwait(dst);
@@ -4607,14 +4606,13 @@ RegisterID* BytecodeGenerator::emitIteratorNext(RegisterID* dst, RegisterID* ite
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitIteratorNextWithValue(RegisterID* dst, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node)
+RegisterID* BytecodeGenerator::emitIteratorNextWithValue(RegisterID* dst, RegisterID* nextMethod, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node)
 {
     {
-        RefPtr<RegisterID> next = emitGetById(newTemporary(), iterator, propertyNames().next);
         CallArguments nextArguments(*this, nullptr, 1);
         emitMove(nextArguments.thisRegister(), iterator);
         emitMove(nextArguments.argumentRegister(0), value);
-        emitCall(dst, next.get(), NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
+        emitCall(dst, nextMethod, NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
     }
 
     return dst;
@@ -4916,8 +4914,7 @@ RegisterID* BytecodeGenerator::emitGetAsyncIterator(RegisterID* argument, Throwa
     emitJump(asyncIteratorFound.get());
     emitLabel(asyncIteratorNotFound.get());
 
-    RefPtr<RegisterID> commonIterator = emitGetById(newTemporary(), argument, propertyNames().iteratorSymbol);
-    emitCallIterator(commonIterator.get(), argument, node);
+    RefPtr<RegisterID> commonIterator = emitGetIterator(argument, node);
     emitMove(iterator.get(), commonIterator.get());
 
     auto varCreateAsyncFromSyncIterator = variable(propertyNames().builtinNames().createAsyncFromSyncIteratorPrivateName());
@@ -4947,6 +4944,7 @@ RegisterID* BytecodeGenerator::emitDelegateYield(RegisterID* argument, Throwable
     RefPtr<RegisterID> value = newTemporary();
     {
         RefPtr<RegisterID> iterator = parseMode() == SourceParseMode::AsyncGeneratorBodyMode ? emitGetAsyncIterator(argument, node) : emitGetIterator(argument, node);
+        RefPtr<RegisterID> nextMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().next);
 
         Ref<Label> loopDone = newLabel();
         {
@@ -5044,7 +5042,7 @@ RegisterID* BytecodeGenerator::emitDelegateYield(RegisterID* argument, Throwable
             }
 
             emitLabel(nextElement.get());
-            emitIteratorNextWithValue(value.get(), iterator.get(), value.get(), node);
+            emitIteratorNextWithValue(value.get(), nextMethod.get(), iterator.get(), value.get(), node);
 
             emitLabel(branchOnResult.get());
 
index 47674d7..89ef1bd 100644 (file)
@@ -780,8 +780,8 @@ namespace JSC {
         RegisterID* emitIsDerivedArray(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, DerivedArrayType); }
         void emitRequireObjectCoercible(RegisterID* value, const String& error);
 
-        RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node, JSC::EmitAwait = JSC::EmitAwait::No);
-        RegisterID* emitIteratorNextWithValue(RegisterID* dst, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node);
+        RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* nextMethod, RegisterID* iterator, const ThrowableExpressionData* node, JSC::EmitAwait = JSC::EmitAwait::No);
+        RegisterID* emitIteratorNextWithValue(RegisterID* dst, RegisterID* nextMethod, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node);
         void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node, EmitAwait = EmitAwait::No);
 
         RegisterID* emitRestParameter(RegisterID* result, unsigned numParametersToSkip);
index 0dbfeb4..e4883a1 100644 (file)
@@ -3944,6 +3944,7 @@ void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs)
         generator.emitMove(args.thisRegister(), rhs);
         generator.emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No);
     }
+    RefPtr<RegisterID> nextMethod = generator.emitGetById(generator.newTemporary(), iterator.get(), generator.propertyNames().next);
 
     if (m_targetPatterns.isEmpty()) {
         generator.emitIteratorClose(iterator.get(), this);
@@ -3962,7 +3963,7 @@ void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs)
                 generator.emitJumpIfTrue(done.get(), iterationSkipped.get());
 
             RefPtr<RegisterID> value = generator.newTemporary();
-            generator.emitIteratorNext(value.get(), iterator.get(), this);
+            generator.emitIteratorNext(value.get(), nextMethod.get(), iterator.get(), this);
             generator.emitGetById(done.get(), value.get(), generator.propertyNames().done);
             generator.emitJumpIfTrue(done.get(), iterationSkipped.get());
             generator.emitGetById(value.get(), value.get(), generator.propertyNames().value);
@@ -3998,7 +3999,7 @@ void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs)
             generator.emitLabel(loopStart.get());
 
             RefPtr<RegisterID> value = generator.newTemporary();
-            generator.emitIteratorNext(value.get(), iterator.get(), this);
+            generator.emitIteratorNext(value.get(), nextMethod.get(), iterator.get(), this);
             generator.emitGetById(done.get(), value.get(), generator.propertyNames().done);
             generator.emitJumpIfTrue(done.get(), iterationDone.get());
             generator.emitGetById(value.get(), value.get(), generator.propertyNames().value);
index 11b384f..adf7c6c 100644 (file)
@@ -586,6 +586,8 @@ JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec)
     if (!iterator)
         return jsUndefined();
 
+    IterationRecord iterationRecord = { iterator, iterator.get(exec, vm.propertyNames->next) };
+
     unsigned numberToFetch = 5;
     JSValue numberToFetchArg = exec->argument(1);
     double fetchDouble = numberToFetchArg.toInteger(exec);
@@ -597,7 +599,7 @@ JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec)
     RETURN_IF_EXCEPTION(scope, { });
 
     for (unsigned i = 0; i < numberToFetch; ++i) {
-        JSValue next = iteratorStep(exec, iterator);
+        JSValue next = iteratorStep(exec, iterationRecord);
         if (UNLIKELY(scope.exception()) || next.isFalse())
             break;
 
@@ -609,7 +611,7 @@ JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec)
         array->putDirectIndex(exec, i, entry);
         if (UNLIKELY(scope.exception())) {
             scope.release();
-            iteratorClose(exec, iterator);
+            iteratorClose(exec, iterationRecord);
             break;
         }
     }
index 3cb2404..e10fae5 100644 (file)
@@ -36,13 +36,13 @@ using namespace WTF;
 
 namespace JSC {
 
-JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value)
+JSValue iteratorNext(ExecState* exec, IterationRecord iterationRecord, JSValue argument)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    JSValue nextFunction = iterator.get(exec, vm.propertyNames->next);
-    RETURN_IF_EXCEPTION(scope, JSValue());
+    JSValue iterator = iterationRecord.iterator;
+    JSValue nextFunction = iterationRecord.nextMethod;
 
     CallData nextFunctionCallData;
     CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData);
@@ -50,8 +50,8 @@ JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value)
         return throwTypeError(exec, scope);
 
     MarkedArgumentBuffer nextFunctionArguments;
-    if (!value.isEmpty())
-        nextFunctionArguments.append(value);
+    if (!argument.isEmpty())
+        nextFunctionArguments.append(argument);
     JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments);
     RETURN_IF_EXCEPTION(scope, JSValue());
 
@@ -61,11 +61,6 @@ JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value)
     return result;
 }
 
-JSValue iteratorNext(ExecState* exec, JSValue iterator)
-{
-    return iteratorNext(exec, iterator, JSValue());
-}
-
 JSValue iteratorValue(ExecState* exec, JSValue iterResult)
 {
     return iterResult.get(exec, exec->vm().propertyNames->value);
@@ -77,12 +72,12 @@ bool iteratorComplete(ExecState* exec, JSValue iterResult)
     return done.toBoolean(exec);
 }
 
-JSValue iteratorStep(ExecState* exec, JSValue iterator)
+JSValue iteratorStep(ExecState* exec, IterationRecord iterationRecord)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    JSValue result = iteratorNext(exec, iterator);
+    JSValue result = iteratorNext(exec, iterationRecord);
     RETURN_IF_EXCEPTION(scope, JSValue());
     bool done = iteratorComplete(exec, result);
     RETURN_IF_EXCEPTION(scope, JSValue());
@@ -91,7 +86,7 @@ JSValue iteratorStep(ExecState* exec, JSValue iterator)
     return result;
 }
 
-void iteratorClose(ExecState* exec, JSValue iterator)
+void iteratorClose(ExecState* exec, IterationRecord iterationRecord)
 {
     VM& vm = exec->vm();
     auto throwScope = DECLARE_THROW_SCOPE(vm);
@@ -102,7 +97,7 @@ void iteratorClose(ExecState* exec, JSValue iterator)
         exception = catchScope.exception();
         catchScope.clearException();
     }
-    JSValue returnFunction = iterator.get(exec, vm.propertyNames->returnKeyword);
+    JSValue returnFunction = iterationRecord.iterator.get(exec, vm.propertyNames->returnKeyword);
     RETURN_IF_EXCEPTION(throwScope, void());
 
     if (returnFunction.isUndefined()) {
@@ -122,7 +117,7 @@ void iteratorClose(ExecState* exec, JSValue iterator)
     }
 
     MarkedArgumentBuffer returnFunctionArguments;
-    JSValue innerResult = call(exec, returnFunction, returnFunctionCallType, returnFunctionCallData, iterator, returnFunctionArguments);
+    JSValue innerResult = call(exec, returnFunction, returnFunctionCallType, returnFunctionCallData, iterationRecord.iterator, returnFunctionArguments);
 
     if (exception) {
         throwException(exec, throwScope, exception);
@@ -190,7 +185,7 @@ JSValue iteratorMethod(ExecState& state, JSObject* object)
     return method;
 }
 
-JSValue iteratorForIterable(ExecState& state, JSObject* object, JSValue iteratorMethod)
+IterationRecord iteratorForIterable(ExecState& state, JSObject* object, JSValue iteratorMethod)
 {
     VM& vm = state.vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -211,34 +206,40 @@ JSValue iteratorForIterable(ExecState& state, JSObject* object, JSValue iterator
         return { };
     }
 
-    return iterator;
+    JSValue nextMethod = iterator.getObject()->get(&state, vm.propertyNames->next);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    return { iterator, nextMethod };
 }
 
-JSValue iteratorForIterable(ExecState* state, JSValue iterable)
+IterationRecord iteratorForIterable(ExecState* state, JSValue iterable)
 {
     VM& vm = state->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
     
     JSValue iteratorFunction = iterable.get(state, vm.propertyNames->iteratorSymbol);
-    RETURN_IF_EXCEPTION(scope, JSValue());
+    RETURN_IF_EXCEPTION(scope, { });
     
     CallData iteratorFunctionCallData;
     CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
     if (iteratorFunctionCallType == CallType::None) {
         throwTypeError(state, scope);
-        return JSValue();
+        return { };
     }
 
     ArgList iteratorFunctionArguments;
     JSValue iterator = call(state, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
-    RETURN_IF_EXCEPTION(scope, JSValue());
+    RETURN_IF_EXCEPTION(scope, { });
 
     if (!iterator.isObject()) {
         throwTypeError(state, scope);
-        return JSValue();
+        return { };
     }
 
-    return iterator;
+    JSValue nextMethod = iterator.getObject()->get(state, vm.propertyNames->next);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    return { iterator, nextMethod };
 }
 
 } // namespace JSC
index 00a6273..592c914 100644 (file)
 
 namespace JSC {
 
-JSValue iteratorNext(ExecState*, JSValue iterator, JSValue);
-JSValue iteratorNext(ExecState*, JSValue iterator);
-JS_EXPORT_PRIVATE JSValue iteratorValue(ExecState*, JSValue iterator);
-bool iteratorComplete(ExecState*, JSValue iterator);
-JS_EXPORT_PRIVATE JSValue iteratorStep(ExecState*, JSValue iterator);
-JS_EXPORT_PRIVATE void iteratorClose(ExecState*, JSValue iterator);
+struct IterationRecord {
+    JSValue iterator;
+    JSValue nextMethod;
+};
+
+JSValue iteratorNext(ExecState*, IterationRecord, JSValue argument = JSValue());
+JS_EXPORT_PRIVATE JSValue iteratorValue(ExecState*, JSValue iterResult);
+bool iteratorComplete(ExecState*, JSValue iterResult);
+JS_EXPORT_PRIVATE JSValue iteratorStep(ExecState*, IterationRecord);
+JS_EXPORT_PRIVATE void iteratorClose(ExecState*, IterationRecord);
 JS_EXPORT_PRIVATE JSObject* createIteratorResultObject(ExecState*, JSValue, bool done);
 
 Structure* createIteratorResultObjectStructure(VM&, JSGlobalObject&);
 
 JS_EXPORT_PRIVATE JSValue iteratorMethod(ExecState&, JSObject*);
-JS_EXPORT_PRIVATE JSValue iteratorForIterable(ExecState&, JSObject*, JSValue iteratorMethod);
+JS_EXPORT_PRIVATE IterationRecord iteratorForIterable(ExecState&, JSObject*, JSValue iteratorMethod);
+JS_EXPORT_PRIVATE IterationRecord iteratorForIterable(ExecState*, JSValue iterable);
 
 JS_EXPORT_PRIVATE JSValue iteratorMethod(ExecState&, JSObject*);
 JS_EXPORT_PRIVATE bool hasIteratorMethod(ExecState&, JSValue);
 
-JS_EXPORT_PRIVATE JSValue iteratorForIterable(ExecState*, JSValue iterable);
-
 template<typename CallBackType>
 void forEachInIterable(ExecState* exec, JSValue iterable, const CallBackType& callback)
 {
     auto& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    JSValue iterator = iteratorForIterable(exec, iterable);
+    IterationRecord iterationRecord = iteratorForIterable(exec, iterable);
     RETURN_IF_EXCEPTION(scope, void());
     while (true) {
-        JSValue next = iteratorStep(exec, iterator);
+        JSValue next = iteratorStep(exec, iterationRecord);
         if (UNLIKELY(scope.exception()) || next.isFalse())
             return;
 
@@ -69,7 +72,7 @@ void forEachInIterable(ExecState* exec, JSValue iterable, const CallBackType& ca
         callback(vm, exec, nextValue);
         if (UNLIKELY(scope.exception())) {
             scope.release();
-            iteratorClose(exec, iterator);
+            iteratorClose(exec, iterationRecord);
             return;
         }
     }
@@ -81,10 +84,10 @@ void forEachInIterable(ExecState& state, JSObject* iterable, JSValue iteratorMet
     auto& vm = state.vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    auto iterator = iteratorForIterable(state, iterable, iteratorMethod);
+    auto iterationRecord = iteratorForIterable(state, iterable, iteratorMethod);
     RETURN_IF_EXCEPTION(scope, void());
     while (true) {
-        JSValue next = iteratorStep(&state, iterator);
+        JSValue next = iteratorStep(&state, iterationRecord);
         if (UNLIKELY(scope.exception()) || next.isFalse())
             return;
 
@@ -94,7 +97,7 @@ void forEachInIterable(ExecState& state, JSObject* iterable, JSValue iteratorMet
         callback(vm, state, nextValue);
         if (UNLIKELY(scope.exception())) {
             scope.release();
-            iteratorClose(&state, iterator);
+            iteratorClose(&state, iterationRecord);
             return;
         }
     }
index 8c40792..c6165fb 100644 (file)
@@ -77,27 +77,16 @@ Structure* JSGenericTypedArrayViewConstructor<ViewClass>::createStructure(
 }
 
 template<typename ViewClass>
-inline JSObject* constructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSValue iterator)
+inline JSObject* constructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSObject* iterable, JSValue iteratorMethod)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    if (!iterator.isObject())
-        return throwTypeError(exec, scope, ASCIILiteral("Symbol.Iterator for the first argument did not return an object."));
-
     MarkedArgumentBuffer storage;
-    while (true) {
-        JSValue next = iteratorStep(exec, iterator);
-        RETURN_IF_EXCEPTION(scope, nullptr);
-
-        if (next.isFalse())
-            break;
-
-        JSValue nextItem = iteratorValue(exec, next);
-        RETURN_IF_EXCEPTION(scope, nullptr);
-
-        storage.append(nextItem);
-    }
+    forEachInIterable(*exec, iterable, iteratorMethod, [&] (VM&, ExecState&, JSValue value) {
+        storage.append(value);
+    });
+    RETURN_IF_EXCEPTION(scope, nullptr);
 
     ViewClass* result = ViewClass::createUninitialized(exec, structure, storage.size());
     EXCEPTION_ASSERT(!!scope.exception() == !result);
@@ -172,17 +161,7 @@ inline JSObject* constructGenericTypedArrayViewWithArguments(ExecState* exec, St
                     || lengthSlot.isAccessor() || lengthSlot.isCustom() || lengthSlot.isTaintedByOpaqueObject()
                     || hasAnyArrayStorage(object->indexingType()))) {
 
-                    CallData callData;
-                    CallType callType = getCallData(iteratorFunc, callData);
-                    if (callType == CallType::None)
-                        return throwTypeError(exec, scope, ASCIILiteral("Symbol.Iterator for the first argument cannot be called."));
-
-                    ArgList arguments;
-                    JSValue iterator = call(exec, iteratorFunc, callType, callData, object, arguments);
-                    RETURN_IF_EXCEPTION(scope, nullptr);
-
-                    scope.release();
-                    return constructGenericTypedArrayViewFromIterator<ViewClass>(exec, structure, iterator);
+                    return constructGenericTypedArrayViewFromIterator<ViewClass>(exec, structure, object, iteratorFunc);
             }
 
             if (lengthSlot.isUnset())