From 1ebbaaa0362ffc295fc4121bead8bb84a3cf5ec6 Mon Sep 17 00:00:00 2001 From: dehrenberg Date: Mon, 11 May 2015 18:32:26 -0700 Subject: [PATCH] Factor out core of Array.forEach and .every, for use in TypedArrays The idea is to make this the model for future TypedArray methods. A possible downside could be lower array method performance if everything gets polymorhpic (but if enough inlining happens, it should still be fast), but on the upside, this change means that the TypedArray methods won't create as much code size bloat. BUG=v8:3578 LOG=Y R=adamk@chromium.org CC=arv@chromium.org, caitpotter88@gmail.com Review URL: https://codereview.chromium.org/1133503003 Cr-Commit-Position: refs/heads/master@{#28351} --- src/array.js | 46 +++++++++++++--------- src/harmony-typedarray.js | 59 ++++------------------------- test/mjsunit/harmony/typedarrays-every.js | 3 +- test/mjsunit/harmony/typedarrays-foreach.js | 9 ++++- 4 files changed, 45 insertions(+), 72 deletions(-) diff --git a/src/array.js b/src/array.js index dc0b65f..3f9bd68 100644 --- a/src/array.js +++ b/src/array.js @@ -10,6 +10,8 @@ var $arrayShift; var $arraySlice; var $arraySplice; var $arrayUnshift; +var $innerArrayForEach; +var $innerArrayEvery; (function(global, shared, exports) { @@ -1179,15 +1181,7 @@ function ArrayFilter(f, receiver) { return result; } - -function ArrayForEach(f, receiver) { - CHECK_OBJECT_COERCIBLE(this, "Array.prototype.forEach"); - - // Pull out the length so that modifications to the length in the - // loop will not affect the looping and side effects are visible. - var array = $toObject(this); - var length = TO_UINT32(array.length); - +function InnerArrayForEach(f, receiver, array, length) { if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { @@ -1209,6 +1203,16 @@ function ArrayForEach(f, receiver) { } } +function ArrayForEach(f, receiver) { + CHECK_OBJECT_COERCIBLE(this, "Array.prototype.forEach"); + + // Pull out the length so that modifications to the length in the + // loop will not affect the looping and side effects are visible. + var array = $toObject(this); + var length = TO_UINT32(array.length); + InnerArrayForEach(f, receiver, array, length); +} + // Executes the function once for each element present in the // array until it finds one where callback returns true. @@ -1243,14 +1247,7 @@ function ArraySome(f, receiver) { } -function ArrayEvery(f, receiver) { - CHECK_OBJECT_COERCIBLE(this, "Array.prototype.every"); - - // Pull out the length so that modifications to the length in the - // loop will not affect the looping and side effects are visible. - var array = $toObject(this); - var length = TO_UINT32(array.length); - +function InnerArrayEvery(f, receiver, array, length) { if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { @@ -1273,6 +1270,16 @@ function ArrayEvery(f, receiver) { return true; } +function ArrayEvery(f, receiver) { + CHECK_OBJECT_COERCIBLE(this, "Array.prototype.every"); + + // Pull out the length so that modifications to the length in the + // loop will not affect the looping and side effects are visible. + var array = $toObject(this); + var length = TO_UINT32(array.length); + return InnerArrayEvery(f, receiver, array, length); +} + function ArrayMap(f, receiver) { CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map"); @@ -1595,4 +1602,7 @@ $arraySlice = ArraySlice; $arraySplice = ArraySplice; $arrayUnshift = ArrayUnshift; -}) +$innerArrayForEach = InnerArrayForEach; +$innerArrayEvery = InnerArrayEvery; + +}); diff --git a/src/harmony-typedarray.js b/src/harmony-typedarray.js index 900cd8f..18b4ca0 100644 --- a/src/harmony-typedarray.js +++ b/src/harmony-typedarray.js @@ -30,70 +30,27 @@ TYPED_ARRAYS(DECLARE_GLOBALS) // ------------------------------------------------------------------- // ES6 draft 05-05-15, section 22.2.3.7 -function TypedArrayEvery(f /* thisArg */) { // length == 1 - if (!%IsTypedArray(this)) { - throw MakeTypeError('not_typed_array', []); - } - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); +function TypedArrayEvery(f, receiver) { + if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); - var receiver; - - if (%_ArgumentsLength() > 1) { - receiver = %_Arguments(1); - } - var needs_wrapper = false; - if (IS_NULL(receiver)) { - if (%IsSloppyModeFunction(mapfn)) receiver = UNDEFINED; - } else if (!IS_UNDEFINED(receiver)) { - 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; - if (!%_CallFunction(new_receiver, TO_OBJECT_INLINE(element), i, this, f)) { - return false; - } - } - return true; + return $innerArrayEvery(f, receiver, this, length); } +%FunctionSetLength(TypedArrayEvery, 1); // ES6 draft 08-24-14, section 22.2.3.12 -function TypedArrayForEach(f /* thisArg */) { // length == 1 +function TypedArrayForEach(f, receiver) { if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); var length = %_TypedArrayGetLength(this); - var receiver; - - if (%_ArgumentsLength() > 1) { - receiver = %_Arguments(1); - } - var needs_wrapper = false; - if (IS_NULL(receiver)) { - if (%IsSloppyModeFunction(mapfn)) receiver = UNDEFINED; - } else if (!IS_UNDEFINED(receiver)) { - 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); - } + $innerArrayForEach(f, receiver, this, length); } +%FunctionSetLength(TypedArrayForEach, 1); // ES6 draft 08-24-14, section 22.2.2.2 -function TypedArrayOf() { // length == 0 +function TypedArrayOf() { var length = %_ArgumentsLength(); var array = new this(length); for (var i = 0; i < length; i++) { diff --git a/test/mjsunit/harmony/typedarrays-every.js b/test/mjsunit/harmony/typedarrays-every.js index 3f95ba9..c81fd96 100644 --- a/test/mjsunit/harmony/typedarrays-every.js +++ b/test/mjsunit/harmony/typedarrays-every.js @@ -85,8 +85,9 @@ function TestTypedArrayForEach(constructor) { // still make .forEach() finish, and the array should keep being // empty after neutering it. count = 0; - a = new constructor(2); + a = new constructor(3); result = a.every(function (n, index, array) { + assertFalse(array[index] === undefined); // don't get here if neutered if (count > 0) %ArrayBufferNeuter(array.buffer); array[index] = n + 1; count++; diff --git a/test/mjsunit/harmony/typedarrays-foreach.js b/test/mjsunit/harmony/typedarrays-foreach.js index 4bfa655..0d34c78 100644 --- a/test/mjsunit/harmony/typedarrays-foreach.js +++ b/test/mjsunit/harmony/typedarrays-foreach.js @@ -85,8 +85,13 @@ function TestTypedArrayForEach(constructor) { 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. + // still make .forEach() finish, but exiting early due to the missing + // elements, and the array should keep being empty after detaching it. + // TODO(dehrenberg): According to the ES6 spec, accessing or testing + // for members on a detached TypedArray should throw, so really this + // should throw in the third iteration. However, this behavior matches + // the Khronos spec. + a = new constructor(3); count = 0; a.forEach(function (n, index, array) { if (count > 0) %ArrayBufferNeuter(array.buffer); -- 2.7.4