Implement %TypedArray%.prototype.{toString,toLocaleString,join}
authordehrenberg <dehrenberg@chromium.org>
Tue, 2 Jun 2015 18:58:12 +0000 (11:58 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 2 Jun 2015 18:58:24 +0000 (18:58 +0000)
Implementations factored out from Array. Tests are derived from
normal array toString tests.

BUG=v8:3578
LOG=Y
R=adamk

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

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

src/array.js
src/harmony-typedarray.js
src/prologue.js
test/mjsunit/harmony/typedarray-tostring.js [new file with mode: 0644]

index 7a23fc8314f89a98180072b2141f7e5d1986d35a..4ccff1f5f32f8b0b46e68348c70f9dff27cca358 100644 (file)
@@ -398,20 +398,21 @@ function ArrayToString() {
 }
 
 
-function ArrayToLocaleString() {
-  var array = $toObject(this);
-  var arrayLen = array.length;
-  var len = TO_UINT32(arrayLen);
+function InnerArrayToLocaleString(array, length) {
+  var len = TO_UINT32(length);
   if (len === 0) return "";
   return Join(array, len, ',', ConvertToLocaleString);
 }
 
 
-function ArrayJoin(separator) {
-  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join");
+function ArrayToLocaleString() {
+  var array = $toObject(this);
+  var arrayLen = array.length;
+  return InnerArrayToLocaleString(array, arrayLen);
+}
 
-  var array = TO_OBJECT_INLINE(this);
-  var length = TO_UINT32(array.length);
+
+function InnerArrayJoin(separator, array, length) {
   if (IS_UNDEFINED(separator)) {
     separator = ',';
   } else if (!IS_STRING(separator)) {
@@ -433,6 +434,16 @@ function ArrayJoin(separator) {
 }
 
 
+function ArrayJoin(separator) {
+  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join");
+
+  var array = TO_OBJECT_INLINE(this);
+  var length = TO_UINT32(array.length);
+
+  return InnerArrayJoin(separator, array, length);
+}
+
+
 function ObservedArrayPop(n) {
   n--;
   var value = this[n];
@@ -1654,15 +1665,18 @@ utils.SetUpLockedPrototype(InternalPackedArray, GlobalArray(), [
 
 utils.Export(function(to) {
   to.ArrayJoin = ArrayJoin;
+  to.ArrayToString = ArrayToString;
   to.InnerArrayEvery = InnerArrayEvery;
   to.InnerArrayFilter = InnerArrayFilter;
   to.InnerArrayForEach = InnerArrayForEach;
   to.InnerArrayIndexOf = InnerArrayIndexOf;
+  to.InnerArrayJoin = InnerArrayJoin;
   to.InnerArrayLastIndexOf = InnerArrayLastIndexOf;
   to.InnerArrayMap = InnerArrayMap;
   to.InnerArrayReverse = InnerArrayReverse;
   to.InnerArraySome = InnerArraySome;
   to.InnerArraySort = InnerArraySort;
+  to.InnerArrayToLocaleString = InnerArrayToLocaleString;
 });
 
 $arrayConcat = ArrayConcatJS;
index 88048b44c9e854cb5d57856b8abf86a4a3694a97..69512ca4b58c1d4b4512db68ea94defef4bcb83e 100644 (file)
@@ -32,6 +32,7 @@ TYPED_ARRAYS(DECLARE_GLOBALS)
 DECLARE_GLOBALS(Array)
 
 var ArrayFrom;
+var ArrayToString;
 var InnerArrayCopyWithin;
 var InnerArrayEvery;
 var InnerArrayFill;
@@ -40,15 +41,18 @@ var InnerArrayFind;
 var InnerArrayFindIndex;
 var InnerArrayForEach;
 var InnerArrayIndexOf;
+var InnerArrayJoin;
 var InnerArrayLastIndexOf;
 var InnerArrayMap;
 var InnerArrayReverse;
 var InnerArraySome;
 var InnerArraySort;
+var InnerArrayToLocaleString;
 var IsNaN;
 
 utils.Import(function(from) {
   ArrayFrom = from.ArrayFrom;
+  ArrayToString = from.ArrayToString;
   InnerArrayCopyWithin = from.InnerArrayCopyWithin;
   InnerArrayEvery = from.InnerArrayEvery;
   InnerArrayFill = from.InnerArrayFill;
@@ -57,11 +61,13 @@ utils.Import(function(from) {
   InnerArrayFindIndex = from.InnerArrayFindIndex;
   InnerArrayForEach = from.InnerArrayForEach;
   InnerArrayIndexOf = from.InnerArrayIndexOf;
+  InnerArrayJoin = from.InnerArrayJoin;
   InnerArrayLastIndexOf = from.InnerArrayLastIndexOf;
   InnerArrayMap = from.InnerArrayMap;
   InnerArrayReverse = from.InnerArrayReverse;
   InnerArraySome = from.InnerArraySome;
   InnerArraySort = from.InnerArraySort;
+  InnerArrayToLocaleString = from.InnerArrayToLocaleString;
   IsNaN = from.IsNaN;
 });
 
@@ -250,6 +256,30 @@ function TypedArraySome(f, receiver) {
 %FunctionSetLength(TypedArraySome, 1);
 
 
+// ES6 section 22.2.3.27
+function TypedArrayToLocaleString() {
+  if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+
+  var length = %_TypedArrayGetLength(this);
+
+  return InnerArrayToLocaleString(this, length);
+}
+
+// ES6 section 22.2.3.28
+function TypedArrayToString() {
+  return %_CallFunction(this, ArrayToString);
+}
+
+// ES6 section 22.2.3.14
+function TypedArrayJoin(separator) {
+  if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+
+  var length = %_TypedArrayGetLength(this);
+
+  return InnerArrayJoin(separator, this, length);
+}
+
+
 // ES6 draft 08-24-14, section 22.2.2.2
 function TypedArrayOf() {
   var length = %_ArgumentsLength();
@@ -286,12 +316,15 @@ macro EXTEND_TYPED_ARRAY(NAME)
     "find", TypedArrayFind,
     "findIndex", TypedArrayFindIndex,
     "indexOf", TypedArrayIndexOf,
+    "join", TypedArrayJoin,
     "lastIndexOf", TypedArrayLastIndexOf,
     "forEach", TypedArrayForEach,
     "map", TypedArrayMap,
     "reverse", TypedArrayReverse,
     "some", TypedArraySome,
-    "sort", TypedArraySort
+    "sort", TypedArraySort,
+    "toString", TypedArrayToString,
+    "toLocaleString", TypedArrayToLocaleString
   ]);
 endmacro
 
index 8052a49b6ecbacd1845bd0a04ff8f830101794e4..34cc68b98be3d8bacdcd00311a9523addd39aadf 100644 (file)
@@ -154,17 +154,20 @@ function PostNatives(utils) {
 
   // Whitelist of exports from normal natives to experimental natives.
   var expose_to_experimental = [
+    "ArrayToString",
     "GetIterator",
     "GetMethod",
     "InnerArrayEvery",
     "InnerArrayFilter",
     "InnerArrayForEach",
     "InnerArrayIndexOf",
+    "InnerArrayJoin",
     "InnerArrayLastIndexOf",
     "InnerArrayMap",
     "InnerArrayReverse",
     "InnerArraySome",
     "InnerArraySort",
+    "InnerArrayToLocaleString",
     "IsNaN",
     "MathMax",
     "MathMin",
diff --git a/test/mjsunit/harmony/typedarray-tostring.js b/test/mjsunit/harmony/typedarray-tostring.js
new file mode 100644 (file)
index 0000000..e3591d8
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2015 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
+
+// Array's toString should call the object's own join method, if one exists and
+// is callable. Otherwise, just use the original Object.toString function.
+
+var typedArrayConstructors = [
+  Uint8Array,
+  Int8Array,
+  Uint16Array,
+  Int16Array,
+  Uint32Array,
+  Int32Array,
+  Uint8ClampedArray,
+  Float32Array,
+  Float64Array
+];
+
+for (var constructor of typedArrayConstructors) {
+  var success = "[test success]";
+  var expectedThis;
+  function testJoin() {
+    assertEquals(0, arguments.length);
+    assertSame(expectedThis, this);
+    return success;
+  }
+
+
+  // On an Array object.
+
+  // Default case.
+  var a1 = new constructor([1, 2, 3]);
+  assertEquals("1,2,3", a1.toString());
+  assertEquals("1,2,3", a1.join());
+  assertEquals("1,2,3", a1.toLocaleString());
+
+  // Non-standard "join" function is called correctly.
+  var a2 = new constructor([1, 2, 3]);
+  a2.join = testJoin;
+  expectedThis = a2;
+  assertEquals(success, a2.toString());
+  assertEquals(success, a2.join());
+  assertEquals("1,2,3", a2.toLocaleString());
+
+  // Non-callable join function is ignored and Object.prototype.toString is
+  // used instead.
+  var a3 = new constructor([1, 2, 3]);
+  a3.join = "not callable";
+  assertEquals(0, a3.toString().search(/\[object .+Array\]/));
+
+  // Non-existing join function is treated same as non-callable.
+  var a4 = new constructor([1, 2, 3]);
+  a4.__proto__ = { toString: constructor.prototype.toString };
+  // No join on Array.
+  assertEquals(0, a3.toString().search(/\[object .+Array\]/));
+
+
+  // On a non-Array object, throws.
+  var o1 = {length: 3, 0: 1, 1: 2, 2: 3,
+            toString: constructor.prototype.toString,
+            join: constructor.prototype.join,
+            toLocaleString: constructor.prototype.toLocaleString};
+  assertThrows(function() { o1.join() }, TypeError);
+  assertThrows(function() { o1.toString() }, TypeError);
+  assertThrows(function() { o1.toLocaleString() }, TypeError);
+  // toString is OK if join not from here:
+  o1.join = Array.prototype.join;
+  assertEquals("1,2,3", o1.join());
+  assertEquals("1,2,3", o1.toString());
+  assertThrows(function() { o1.toLocaleString() }, TypeError);
+  // TODO(littledan): Use the same function for TypedArray as for
+  // Array, as the spec says (but Firefox doesn't do either).
+  // Currently, using the same method leads to a bootstrap failure.
+  // assertEquals(o1.toString, Array.prototype.toString);
+
+  // Redefining length does not change result
+  var a5 = new constructor([1, 2, 3])
+  Object.defineProperty(a5, 'length', { value: 2 });
+  assertEquals("1,2,3", a5.join());
+  assertEquals("1,2,3", a5.toString());
+  assertEquals("1,2,3", a5.toLocaleString());
+  assertEquals("1,2", Array.prototype.join.call(a5));
+  assertEquals("1,2,3", Array.prototype.toString.call(a5));
+  assertEquals("1,2", Array.prototype.toLocaleString.call(a5));
+}