Implement .forEach() on typed arrays
BUG=v8:3578 LOG=Y R=dslomov@chromium.org, wingo@igalia.com Review URL: https://codereview.chromium.org/583723002 Patch from Adrian Perez de Castro <aperez@igalia.com>. git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24657 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
15bc4aa2c8
commit
ee64a14b24
1
BUILD.gn
1
BUILD.gn
@ -243,6 +243,7 @@ action("js2c_experimental") {
|
||||
"src/generator.js",
|
||||
"src/harmony-string.js",
|
||||
"src/harmony-array.js",
|
||||
"src/harmony-typedarray.js",
|
||||
"src/harmony-classes.js",
|
||||
]
|
||||
|
||||
|
@ -2086,6 +2086,7 @@ bool Genesis::InstallExperimentalNatives() {
|
||||
INSTALL_EXPERIMENTAL_NATIVE(i, proxies, "proxy.js")
|
||||
INSTALL_EXPERIMENTAL_NATIVE(i, strings, "harmony-string.js")
|
||||
INSTALL_EXPERIMENTAL_NATIVE(i, arrays, "harmony-array.js")
|
||||
INSTALL_EXPERIMENTAL_NATIVE(i, arrays, "harmony-typedarray.js")
|
||||
INSTALL_EXPERIMENTAL_NATIVE(i, classes, "harmony-classes.js")
|
||||
}
|
||||
|
||||
|
79
src/harmony-typedarray.js
Normal file
79
src/harmony-typedarray.js
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
'use strict';
|
||||
|
||||
// This file relies on the fact that the following declaration has been made
|
||||
// in runtime.js:
|
||||
// var $Array = global.Array;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
macro TYPED_ARRAYS(FUNCTION)
|
||||
// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
|
||||
FUNCTION(1, Uint8Array, 1)
|
||||
FUNCTION(2, Int8Array, 1)
|
||||
FUNCTION(3, Uint16Array, 2)
|
||||
FUNCTION(4, Int16Array, 2)
|
||||
FUNCTION(5, Uint32Array, 4)
|
||||
FUNCTION(6, Int32Array, 4)
|
||||
FUNCTION(7, Float32Array, 4)
|
||||
FUNCTION(8, Float64Array, 8)
|
||||
FUNCTION(9, Uint8ClampedArray, 1)
|
||||
endmacro
|
||||
|
||||
|
||||
macro TYPED_ARRAY_HARMONY_ADDITIONS(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
|
||||
// ES6 draft 08-24-14, section 22.2.3.12
|
||||
function NAMEForEach(f /* thisArg */) { // length == 1
|
||||
if (!%IsTypedArray(this)) {
|
||||
throw MakeTypeError('not_typed_array', []);
|
||||
}
|
||||
if (!IS_SPEC_FUNCTION(f)) {
|
||||
throw MakeTypeError('called_non_callable', [ f ]);
|
||||
}
|
||||
|
||||
var length = %_TypedArrayGetLength(this);
|
||||
var receiver;
|
||||
|
||||
if (%_ArgumentsLength() > 1) {
|
||||
receiver = %_Arguments(1);
|
||||
}
|
||||
|
||||
var needs_wrapper = false;
|
||||
if (IS_NULL_OR_UNDEFINED(receiver)) {
|
||||
receiver = %GetDefaultReceiver(f) || receiver;
|
||||
} else {
|
||||
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
|
||||
}
|
||||
|
||||
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
|
||||
for (var i = 0; i < length; i++) {
|
||||
var element = this[i];
|
||||
// Prepare break slots for debugger step in.
|
||||
if (stepping) %DebugPrepareStepInIfStepping(f);
|
||||
var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
|
||||
%_CallFunction(new_receiver, TO_OBJECT_INLINE(element), i, this, f);
|
||||
}
|
||||
}
|
||||
endmacro
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_HARMONY_ADDITIONS)
|
||||
|
||||
|
||||
function HarmonyTypedArrayExtendPrototypes() {
|
||||
macro EXTEND_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
%CheckIsBootstrapping();
|
||||
|
||||
// Set up non-enumerable functions on the prototype object.
|
||||
InstallFunctions(global.NAME.prototype, DONT_ENUM, $Array(
|
||||
"forEach", NAMEForEach
|
||||
));
|
||||
endmacro
|
||||
|
||||
TYPED_ARRAYS(EXTEND_TYPED_ARRAY)
|
||||
}
|
||||
|
||||
HarmonyTypedArrayExtendPrototypes();
|
@ -500,6 +500,13 @@ RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_IsTypedArray) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
return isolate->heap()->ToBoolean(args[0]->IsJSTypedArray());
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 4);
|
||||
|
@ -351,6 +351,7 @@ namespace internal {
|
||||
F(ArrayBufferIsView, 1, 1) \
|
||||
F(ArrayBufferNeuter, 1, 1) \
|
||||
\
|
||||
F(IsTypedArray, 1, 1) \
|
||||
F(TypedArrayInitializeFromArrayLike, 4, 1) \
|
||||
F(TypedArrayGetBuffer, 1, 1) \
|
||||
F(TypedArraySetFastCases, 3, 1) \
|
||||
|
140
test/mjsunit/harmony/typedarrays-foreach.js
Normal file
140
test/mjsunit/harmony/typedarrays-foreach.js
Normal file
@ -0,0 +1,140 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-arrays --allow-natives-syntax
|
||||
|
||||
var typedArrayConstructors = [
|
||||
Uint8Array,
|
||||
Int8Array,
|
||||
Uint16Array,
|
||||
Int16Array,
|
||||
Uint32Array,
|
||||
Int32Array,
|
||||
Uint8ClampedArray,
|
||||
Float32Array,
|
||||
Float64Array];
|
||||
|
||||
function CheckTypedArrayIsNeutered(array) {
|
||||
assertEquals(0, array.byteLength);
|
||||
assertEquals(0, array.byteOffset);
|
||||
assertEquals(0, array.length);
|
||||
}
|
||||
|
||||
function TestTypedArrayForEach(constructor) {
|
||||
assertEquals(1, constructor.prototype.forEach.length);
|
||||
|
||||
var a = new constructor(2);
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
|
||||
var count = 0;
|
||||
a.forEach(function (n) { count++; });
|
||||
assertEquals(2, count);
|
||||
|
||||
// Use specified object as this object when calling the function.
|
||||
var o = { value: 42 };
|
||||
var result = [];
|
||||
a.forEach(function (n, index, array) { result.push(this.value); }, o);
|
||||
assertArrayEquals([42, 42], result);
|
||||
|
||||
// Modify the original array.
|
||||
count = 0;
|
||||
a.forEach(function (n, index, array) { array[index] = n + 1; count++ });
|
||||
assertEquals(2, count);
|
||||
assertArrayEquals([1, 2], a);
|
||||
|
||||
// Check that values passed as second argument are wrapped into
|
||||
// objects when calling into sloppy mode functions.
|
||||
function CheckWrapping(value, wrapper) {
|
||||
var wrappedValue = new wrapper(value);
|
||||
|
||||
a.forEach(function () {
|
||||
assertEquals("object", typeof this);
|
||||
assertEquals(wrappedValue, this);
|
||||
}, value);
|
||||
|
||||
a.forEach(function () {
|
||||
"use strict";
|
||||
assertEquals(typeof value, typeof this);
|
||||
assertEquals(value, this);
|
||||
}, value);
|
||||
}
|
||||
CheckWrapping(true, Boolean);
|
||||
CheckWrapping(false, Boolean);
|
||||
CheckWrapping("xxx", String);
|
||||
CheckWrapping(42, Number);
|
||||
CheckWrapping(3.14, Number);
|
||||
CheckWrapping({}, Object);
|
||||
|
||||
// Throw before completing iteration, only the first element
|
||||
// should be modified when thorwing mid-way.
|
||||
count = 0;
|
||||
a[0] = 42;
|
||||
a[1] = 42;
|
||||
try {
|
||||
a.forEach(function (n, index, array) {
|
||||
if (count > 0) throw "meh";
|
||||
array[index] = n + 1;
|
||||
count++;
|
||||
});
|
||||
} catch (e) {
|
||||
}
|
||||
assertEquals(1, count);
|
||||
assertEquals(43, a[0]);
|
||||
assertEquals(42, a[1]);
|
||||
|
||||
// Neutering the buffer backing the typed array mid-way should
|
||||
// still make .forEach() finish, and the array should keep being
|
||||
// empty after neutering it.
|
||||
count = 0;
|
||||
a.forEach(function (n, index, array) {
|
||||
if (count > 0) %ArrayBufferNeuter(array.buffer);
|
||||
array[index] = n + 1;
|
||||
count++;
|
||||
});
|
||||
assertEquals(2, count);
|
||||
CheckTypedArrayIsNeutered(a);
|
||||
assertEquals(undefined, a[0]);
|
||||
|
||||
// The method must work for typed arrays created from ArrayBuffer.
|
||||
// The length of the ArrayBuffer is chosen so it is a multiple of
|
||||
// all lengths of the typed array items.
|
||||
a = new constructor(new ArrayBuffer(64));
|
||||
count = 0;
|
||||
a.forEach(function (n) { count++ });
|
||||
assertEquals(a.length, count);
|
||||
|
||||
// Externalizing the array mid-way accessing the .buffer property
|
||||
// should work.
|
||||
a = new constructor(2);
|
||||
count = 0;
|
||||
var buffer = undefined;
|
||||
a.forEach(function (n, index, array) {
|
||||
if (count++ > 0)
|
||||
buffer = array.buffer;
|
||||
});
|
||||
assertEquals(2, count);
|
||||
assertTrue(!!buffer);
|
||||
assertEquals("ArrayBuffer", %_ClassOf(buffer));
|
||||
assertSame(buffer, a.buffer);
|
||||
|
||||
// The %TypedArray%.forEach() method should not work when
|
||||
// transplanted to objects that are not typed arrays.
|
||||
assertThrows(function () { constructor.prototype.forEach.call([1, 2, 3], function (x) {}) }, TypeError);
|
||||
assertThrows(function () { constructor.prototype.forEach.call("abc", function (x) {}) }, TypeError);
|
||||
assertThrows(function () { constructor.prototype.forEach.call({}, function (x) {}) }, TypeError);
|
||||
assertThrows(function () { constructor.prototype.forEach.call(0, function (x) {}) }, TypeError);
|
||||
|
||||
// Method must be useable on instances of other typed arrays.
|
||||
for (var i = 0; i < typedArrayConstructors.length; i++) {
|
||||
count = 0;
|
||||
a = new typedArrayConstructors[i](4);
|
||||
constructor.prototype.forEach.call(a, function (x) { count++ });
|
||||
assertEquals(a.length, count);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < typedArrayConstructors.length; i++) {
|
||||
TestTypedArrayForEach(typedArrayConstructors[i]);
|
||||
}
|
@ -1604,6 +1604,7 @@
|
||||
'../../src/generator.js',
|
||||
'../../src/harmony-string.js',
|
||||
'../../src/harmony-array.js',
|
||||
'../../src/harmony-typedarray.js',
|
||||
'../../src/harmony-classes.js',
|
||||
],
|
||||
'libraries_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries.bin',
|
||||
|
Loading…
Reference in New Issue
Block a user