Bug 1021835 - Part 2: Do not convert iterable[@@iterator]() value to object in ForOfIterator::init. r=till
authorTooru Fujisawa <arai_a@mac.com>
Sun, 13 Nov 2016 00:40:29 +0900
changeset 349030 9b186ff95a5ef9ff00237fa72b19a0aa2d620a6d
parent 349029 d27d2fec192e62ec05267147c60769b6379bf2e4
child 349031 953d2b8f17036a81990d82eac213622191019b8e
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1021835
milestone52.0a1
Bug 1021835 - Part 2: Do not convert iterable[@@iterator]() value to object in ForOfIterator::init. r=till
js/src/tests/ecma_6/Promise/iterator-primitive.js
js/src/tests/ecma_7/AsyncFunctions/shell.js
js/src/tests/shell.js
js/src/vm/ForOfIterator.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Promise/iterator-primitive.js
@@ -0,0 +1,26 @@
+var BUGNUMBER = 1021835;
+var summary = "Returning non-object from @@iterator should throw";
+
+print(BUGNUMBER + ": " + summary);
+
+let primitives = [
+    1,
+    true,
+    undefined,
+    null,
+    "foo",
+    Symbol.iterator
+];
+
+for (let primitive of primitives) {
+    let arg = {
+        [Symbol.iterator]() {
+            return primitive;
+        }
+    };
+    assertEventuallyThrows(Promise.all(arg), TypeError);
+    assertEventuallyThrows(Promise.race(arg), TypeError);
+}
+
+if (typeof reportCompare === "function")
+  reportCompare(0, 0);
--- a/js/src/tests/ecma_7/AsyncFunctions/shell.js
+++ b/js/src/tests/ecma_7/AsyncFunctions/shell.js
@@ -1,26 +0,0 @@
-(function(global) {
-  function getPromiseResult(promise) {
-    var result, error, caught = false;
-    promise.then(r => { result = r; },
-                 e => { caught = true; error = e; });
-    drainJobQueue();
-    if (caught)
-      throw error;
-    return result;
-  }
-
-  function assertEventuallyEq(promise, expected) {
-    assertEq(getPromiseResult(promise), expected);
-  }
-  global.assertEventuallyEq = assertEventuallyEq;
-
-  function assertEventuallyThrows(promise, expectedErrorType) {
-    assertThrowsInstanceOf(() => getPromiseResult(promise), expectedErrorType);
-  };
-  global.assertEventuallyThrows = assertEventuallyThrows;
-
-  function assertEventuallyDeepEq(promise, expected) {
-    assertDeepEq(getPromiseResult(promise), expected);
-  };
-  global.assertEventuallyDeepEq = assertEventuallyDeepEq;
-})(this);
--- a/js/src/tests/shell.js
+++ b/js/src/tests/shell.js
@@ -319,16 +319,42 @@
   function OptLevel(i) {
     i = Number(i);
     var cx = GetContext();
     cx.setOptimizationLevel(i);
   }
   global.OptLevel = OptLevel;
 })(this);
 
+(function(global) {
+  function getPromiseResult(promise) {
+    var result, error, caught = false;
+    promise.then(r => { result = r; },
+                 e => { caught = true; error = e; });
+    drainJobQueue();
+    if (caught)
+      throw error;
+    return result;
+  }
+
+  function assertEventuallyEq(promise, expected) {
+    assertEq(getPromiseResult(promise), expected);
+  }
+  global.assertEventuallyEq = assertEventuallyEq;
+
+  function assertEventuallyThrows(promise, expectedErrorType) {
+    assertThrowsInstanceOf(() => getPromiseResult(promise), expectedErrorType);
+  };
+  global.assertEventuallyThrows = assertEventuallyThrows;
+
+  function assertEventuallyDeepEq(promise, expected) {
+    assertDeepEq(getPromiseResult(promise), expected);
+  };
+  global.assertEventuallyDeepEq = assertEventuallyDeepEq;
+})(this);
 
 var STATUS = "STATUS: ";
 
 var gDelayTestDriverEnd = false;
 
 var gTestcases = new Array();
 var gTc = gTestcases.length;
 var summary = '';
--- a/js/src/vm/ForOfIterator.cpp
+++ b/js/src/vm/ForOfIterator.cpp
@@ -69,20 +69,20 @@ ForOfIterator::init(HandleValue iterable
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes.get());
         return false;
     }
 
     RootedValue res(cx);
     if (!js::Call(cx, callee, iterable, &res))
         return false;
 
-    iterator = ToObject(cx, res);
-    if (!iterator)
-        return false;
+    if (!res.isObject())
+        return ThrowCheckIsObject(cx, CheckIsObjectKind::GetIterator);
 
+    iterator = &res.toObject();
     return true;
 }
 
 inline bool
 ForOfIterator::nextFromOptimizedArray(MutableHandleValue vp, bool* done)
 {
     MOZ_ASSERT(index != NOT_ARRAY);