Commit 40420f67 authored by littledan's avatar littledan Committed by Commit bot

Allow TypedArrays to be initialized with iterables

In ES6, the TypedArray constructor can be called either with an
array-like object or an iterable. The code previously handled
only array-like objects. This patch switches to supporting
iterables while throwing in an optimization to make Arrays
get allocated the old way, without an extra copy.

BUG=v8:4090
LOG=Y
R=adamk

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

Cr-Commit-Position: refs/heads/master@{#29031}
parent b7d8cb4a
......@@ -43,6 +43,8 @@ utils.Import(function(from) {
MathMin = from.MathMin;
});
var InternalArray = utils.InternalArray;
// --------------- Typed Arrays ---------------------
macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
......@@ -130,6 +132,24 @@ function NAMEConstructByArrayLike(obj, arrayLike) {
}
}
function NAMEConstructByIterable(obj, iterable, iteratorFn) {
var list = new InternalArray();
// Reading the Symbol.iterator property of iterable twice would be
// observable with getters, so instead, we call the function which
// was already looked up, and wrap it in another iterable. The
// __proto__ of the new iterable is set to null to avoid any chance
// of modifications to Object.prototype being observable here.
var iterator = %_CallFunction(iterable, iteratorFn);
var newIterable = {
__proto__: null,
[symbolIterator]() { return iterator; }
};
for (var value of newIterable) {
list.push(value);
}
NAMEConstructByArrayLike(obj, list);
}
function NAMEConstructor(arg1, arg2, arg3) {
if (%_IsConstructCall()) {
if (IS_ARRAYBUFFER(arg1) || IS_SHAREDARRAYBUFFER(arg1)) {
......@@ -138,7 +158,12 @@ function NAMEConstructor(arg1, arg2, arg3) {
IS_BOOLEAN(arg1) || IS_UNDEFINED(arg1)) {
NAMEConstructByLength(this, arg1);
} else {
NAMEConstructByArrayLike(this, arg1);
var iteratorFn = arg1[symbolIterator];
if (IS_UNDEFINED(iteratorFn) || iteratorFn === $arrayValues) {
NAMEConstructByArrayLike(this, arg1);
} else {
NAMEConstructByIterable(this, arg1, iteratorFn);
}
}
} else {
throw MakeTypeError(kConstructorNotFunction, "NAME")
......
......@@ -276,6 +276,43 @@ function TestTypedArray(constr, elementSize, typicalElement) {
assertFalse(!!desc.writable);
assertFalse(!!desc.set);
assertEquals("function", typeof desc.get);
// Test that the constructor can be called with an iterable
function* gen() { for (var i = 0; i < 10; i++) yield i; }
var genArr = new constr(gen());
assertEquals(10, genArr.length);
assertEquals(0, genArr[0]);
assertEquals(9, genArr[9]);
// Arrays can be converted to TypedArrays
genArr = new constr([1, 2, 3]);
assertEquals(3, genArr.length);
assertEquals(1, genArr[0]);
assertEquals(3, genArr[2]);
// Redefining Array.prototype[Symbol.iterator] still works
var arrayIterator = Array.prototype[Symbol.iterator];
Array.prototype[Symbol.iterator] = gen;
genArr = new constr([1, 2, 3]);
assertEquals(10, genArr.length);
assertEquals(0, genArr[0]);
assertEquals(9, genArr[9]);
Array.prototype[Symbol.iterator] = arrayIterator;
// Other array-like things can be made into a TypedArray
var myObject = { 0: 5, 1: 6, length: 2 };
genArr = new constr(myObject);
assertEquals(2, genArr.length);
assertEquals(5, genArr[0]);
assertEquals(6, genArr[1]);
// Iterator takes precedence over array-like, and the property
// is read only once.
var iteratorReadCount = 0;
Object.defineProperty(myObject, Symbol.iterator, {
get: function() { iteratorReadCount++; return gen; }
});
genArr = new constr(myObject);
assertEquals(10, genArr.length);
assertEquals(0, genArr[0]);
assertEquals(9, genArr[9]);
assertEquals(1, iteratorReadCount);
}
TestTypedArray(Uint8Array, 1, 0xFF);
......
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