Commit 1f2e5973 authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

Don't take iterable path in ArrayFrom if items[@@iterator] is null

BUG=v8:3833
LOG=N
R=arv@chromium.org

Review URL: https://codereview.chromium.org/856303002

Cr-Commit-Position: refs/heads/master@{#26314}
parent f7dc15fe
...@@ -142,7 +142,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) { ...@@ -142,7 +142,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
} }
} }
var iterable = ToIterable(items); var iterable = GetMethod(items, symbolIterator);
var k; var k;
var result; var result;
var mappedValue; var mappedValue;
...@@ -151,23 +151,40 @@ function ArrayFrom(arrayLike, mapfn, receiver) { ...@@ -151,23 +151,40 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
if (!IS_UNDEFINED(iterable)) { if (!IS_UNDEFINED(iterable)) {
result = %IsConstructor(this) ? new this() : []; result = %IsConstructor(this) ? new this() : [];
var iterator = GetIterator(items, iterable);
k = 0; k = 0;
for (nextValue of items) { while (true) {
if (mapping) mappedValue = %_CallFunction(receiver, nextValue, k, mapfn); var next = iterator.next();
else mappedValue = nextValue;
if (!IS_OBJECT(next)) {
throw MakeTypeError("iterator_result_not_an_object", [next]);
}
if (next.done) {
result.length = k;
return result;
}
nextValue = next.value;
if (mapping) {
mappedValue = %_CallFunction(receiver, nextValue, k, mapfn);
} else {
mappedValue = nextValue;
}
%AddElement(result, k++, mappedValue, NONE); %AddElement(result, k++, mappedValue, NONE);
} }
result.length = k;
return result;
} else { } else {
var len = ToLength(items.length); var len = ToLength(items.length);
result = %IsConstructor(this) ? new this(len) : new $Array(len); result = %IsConstructor(this) ? new this(len) : new $Array(len);
for (k = 0; k < len; ++k) { for (k = 0; k < len; ++k) {
nextValue = items[k]; nextValue = items[k];
if (mapping) mappedValue = %_CallFunction(receiver, nextValue, k, mapfn); if (mapping) {
else mappedValue = nextValue; mappedValue = %_CallFunction(receiver, nextValue, k, mapfn);
} else {
mappedValue = nextValue;
}
%AddElement(result, k, mappedValue, NONE); %AddElement(result, k, mappedValue, NONE);
} }
......
...@@ -654,6 +654,15 @@ function Delete(obj, p, should_throw) { ...@@ -654,6 +654,15 @@ function Delete(obj, p, should_throw) {
} }
// ES6, draft 12-24-14, section 7.3.8
function GetMethod(obj, p) {
var func = obj[p];
if (IS_NULL_OR_UNDEFINED(func)) return UNDEFINED;
if (IS_SPEC_FUNCTION(func)) return func;
throw MakeTypeError('called_non_callable', [typeof func]);
}
// Harmony proxies. // Harmony proxies.
function DefineProxyProperty(obj, p, attributes, should_throw) { function DefineProxyProperty(obj, p, attributes, should_throw) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies. // TODO(rossberg): adjust once there is a story for symbols vs proxies.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-arrays --harmony-generators // Flags: --harmony-arrays
(function() { (function() {
assertEquals(1, Array.from.length); assertEquals(1, Array.from.length);
...@@ -91,21 +91,48 @@ function testArrayFrom(thisArg, constructor) { ...@@ -91,21 +91,48 @@ function testArrayFrom(thisArg, constructor) {
return x.toUpperCase(); return x.toUpperCase();
}), ['T', 'E', 'S', 'T'], constructor); }), ['T', 'E', 'S', 'T'], constructor);
this.thisArg = thisArg; assertThrows(function() { Array.from.call(thisArg, null); }, TypeError);
assertThrows('Array.from.call(thisArg, null)', TypeError); assertThrows(function() { Array.from.call(thisArg, undefined); }, TypeError);
assertThrows('Array.from.call(thisArg, undefined)', TypeError); assertThrows(function() { Array.from.call(thisArg, [], null); }, TypeError);
assertThrows('Array.from.call(thisArg, [], null)', TypeError); assertThrows(function() { Array.from.call(thisArg, [], "noncallable"); },
assertThrows('Array.from.call(thisArg, [], "noncallable")', TypeError); TypeError);
this.nullIterator = {}; var nullIterator = {};
nullIterator[Symbol.iterator] = null; nullIterator[Symbol.iterator] = null;
assertThrows('Array.from.call(thisArg, nullIterator)', TypeError); assertArrayLikeEquals(Array.from.call(thisArg, nullIterator), [],
constructor);
this.nonObjIterator = {}; var nonObjIterator = {};
nonObjIterator[Symbol.iterator] = function() { return "nonObject"; }; nonObjIterator[Symbol.iterator] = function() { return "nonObject"; };
assertThrows('Array.from.call(thisArg, nonObjIterator)', TypeError); assertThrows(function() { Array.from.call(thisArg, nonObjIterator); },
TypeError);
assertThrows('Array.from.call(thisArg, [], null)', TypeError);
assertThrows(function() { Array.from.call(thisArg, [], null); }, TypeError);
// Ensure iterator is only accessed once, and only invoked once
var called = false;
var arr = [1, 2, 3];
var obj = {};
// Test order --- only get iterator method once
function testIterator() {
assertFalse(called, "@@iterator should be called only once");
called = true;
assertEquals(obj, this);
return arr[Symbol.iterator]();
}
var getCalled = false;
Object.defineProperty(obj, Symbol.iterator, {
get: function() {
assertFalse(getCalled, "@@iterator should be accessed only once");
getCalled = true;
return testIterator;
},
set: function() {
assertUnreachable("@@iterator should not be set");
}
});
assertArrayLikeEquals(Array.from.call(thisArg, obj), [1, 2, 3], constructor);
} }
function Other() {} function Other() {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment