TypedArray.prototype.every method
authordehrenberg <dehrenberg@chromium.org>
Thu, 7 May 2015 15:54:16 +0000 (08:54 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 7 May 2015 15:54:19 +0000 (15:54 +0000)
BUG=v8:3578
LOG=Y
R=adamk@chromium.org, dslomov@chromium.org, svenpanne@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#28301}

src/harmony-typedarray.js
test/mjsunit/harmony/typedarrays-every.js [new file with mode: 0644]

index 9b7cd0debf7f3dc1938b89ab2d18eecb6ef0d155..5b666b5645f09a676b2cf8606f0f5a7b16d266dc 100644 (file)
@@ -31,6 +31,40 @@ TYPED_ARRAYS(DECLARE_GLOBALS)
 
 macro TYPED_ARRAY_HARMONY_ADDITIONS(ARRAY_ID, NAME, ELEMENT_SIZE)
 
+// ES6 draft 05-05-15, section 22.2.3.7
+function NAMEEvery(f /* thisArg */) {  // length == 1
+  if (!%IsTypedArray(this)) {
+    throw MakeTypeError('not_typed_array', []);
+  }
+  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;
+    if (!%_CallFunction(new_receiver, TO_OBJECT_INLINE(element), i, this, f)) {
+      return false;
+    }
+  }
+  return true;
+}
+
 // ES6 draft 08-24-14, section 22.2.3.12
 function NAMEForEach(f /* thisArg */) {  // length == 1
   if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
@@ -83,6 +117,7 @@ macro EXTEND_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
 
   // Set up non-enumerable functions on the prototype object.
   $installFunctions(GlobalNAME.prototype, DONT_ENUM, [
+    "every", NAMEEvery,
     "forEach", NAMEForEach
   ]);
 endmacro
diff --git a/test/mjsunit/harmony/typedarrays-every.js b/test/mjsunit/harmony/typedarrays-every.js
new file mode 100644 (file)
index 0000000..3f95ba9
--- /dev/null
@@ -0,0 +1,141 @@
+// 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.every.length);
+
+  var a = new constructor(3);
+  a[0] = 0;
+  a[1] = 1;
+  a[2] = 2;
+
+  var result = a.every(function (n) { return n < 2; });
+  assertFalse(result);
+
+  var result = a.every(function (n) { return n > 2; });
+  assertFalse(result);
+
+  var result = a.every(function (n) { return n >= 0; });
+  assertEquals(true, result);
+
+  // Use specified object as this object when calling the function.
+  var o = { value: 42 };
+  result = a.every(function (n, index, array) { return n == index && n < this.value; }, o);
+  assertEquals(true, result);
+
+  // Early exit happens when appropriate
+  count = 0;
+  result = a.every(function () { count++; return false; });
+  assertEquals(1, count);
+  assertFalse(result);
+
+  // Modify the original array.
+  count = 0;
+  result = a.every(function (n, index, array) {
+    array[index] = n + 1; count++; return true;
+  });
+  assertEquals(3, count);
+  assertEquals(true, result);
+  assertArrayEquals([1, 2, 3], 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.every(function () {
+      assertEquals("object", typeof this);
+      assertEquals(wrappedValue, this);
+    }, value);
+
+    a.every(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);
+
+  // 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 = new constructor(2);
+  result = a.every(function (n, index, array) {
+    if (count > 0) %ArrayBufferNeuter(array.buffer);
+    array[index] = n + 1;
+    count++;
+    return count > 1 ? array[index] === undefined : true;
+  });
+  assertEquals(2, count);
+  assertEquals(true, result);
+  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;
+  result = a.every(function (n) { return n == 0; });
+  assertEquals(result, true);
+
+  // Externalizing the array mid-way accessing the .buffer property
+  // should work.
+  a = new constructor(2);
+  count = 0;
+  var buffer = undefined;
+  a.every(function (n, index, array) {
+    if (count++ > 0)
+      buffer = array.buffer;
+    return true;
+  });
+  assertEquals(2, count);
+  assertTrue(!!buffer);
+  assertEquals("ArrayBuffer", %_ClassOf(buffer));
+  assertSame(buffer, a.buffer);
+
+  // The %TypedArray%.every() method should not work when
+  // transplanted to objects that are not typed arrays.
+  assertThrows(function () { constructor.prototype.every.call([1, 2, 3], function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.every.call("abc", function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.every.call({}, function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.every.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.every.call(a, function (x) { count++; return true; });
+    assertEquals(a.length, count);
+  }
+}
+
+for (i = 0; i < typedArrayConstructors.length; i++) {
+  TestTypedArrayForEach(typedArrayConstructors[i]);
+}