Update typed arrays behavior to match ES6 rev 15. Remove TO_POSITIVE_INTEGER and...
authordslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 24 Jun 2013 13:58:52 +0000 (13:58 +0000)
committerdslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 24 Jun 2013 13:58:52 +0000 (13:58 +0000)
R=rossberg@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15298 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arraybuffer.js
src/macros.py
src/messages.js
src/runtime.js
src/typedarray.js
test/mjsunit/harmony/dataview-accessors.js
test/mjsunit/harmony/typedarrays.js

index 2b0c3dd..06cc653 100644 (file)
@@ -31,12 +31,12 @@ var $ArrayBuffer = global.ArrayBuffer;
 
 // -------------------------------------------------------------------
 
-function ArrayBufferConstructor(byteLength) { // length = 1
+function ArrayBufferConstructor(length) { // length = 1
   if (%_IsConstructCall()) {
-    var l = TO_POSITIVE_INTEGER(byteLength);
-    %ArrayBufferInitialize(this, l);
+    var byteLength = ToPositiveInteger(length, 'invalid_array_buffer_length');
+    %ArrayBufferInitialize(this, byteLength);
   } else {
-    return new $ArrayBuffer(byteLength);
+    return new $ArrayBuffer(length);
   }
 }
 
@@ -70,6 +70,9 @@ function ArrayBufferSlice(start, end) {
     fin = MathMin(relativeEnd, this.byteLength);
   }
 
+  if (fin < first) {
+    fin = first;
+  }
   var newLen = fin - first;
   // TODO(dslomov): implement inheritance
   var result = new $ArrayBuffer(newLen);
index 5b36421..e442b44 100644 (file)
@@ -145,7 +145,6 @@ const kBoundArgumentsStartIndex = 2;
 macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
 macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
 macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg)));
-macro TO_POSITIVE_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? (arg > 0 ? arg : 0) : %NumberToPositiveInteger(ToNumber(arg)));
 macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
 macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
 macro TO_UINT32(arg) = (arg >>> 0);
index 4778789..f515ca5 100644 (file)
@@ -112,13 +112,15 @@ var kMessages = {
   // RangeError
   invalid_array_length:          ["Invalid array length"],
   invalid_array_buffer_length:   ["Invalid array buffer length"],
-  invalid_typed_array_offset:    ["Start offset is too large"],
-  invalid_typed_array_length:    ["Length is too large"],
+  invalid_typed_array_offset:    ["Start offset is too large:"],
+  invalid_typed_array_length:    ["Invalid typed array length"],
   invalid_typed_array_alignment: ["%0", "of", "%1", "should be a multiple of", "%3"],
   typed_array_set_source_too_large:
                                  ["Source is too large"],
+  typed_array_set_negative_offset:
+                                 ["Start offset is negative"],
   invalid_data_view_offset:      ["Start offset is outside the bounds of the buffer"],
-  invalid_data_view_length:      ["Length is too large"],
+  invalid_data_view_length:      ["Invalid data view length"],
   invalid_data_view_accessor_offset:
                                  ["Offset is outside the bounds of the DataView"],
 
index 22f888d..348fd74 100644 (file)
@@ -658,7 +658,6 @@ function DefaultNumber(x) {
   throw %MakeTypeError('cannot_convert_to_primitive', []);
 }
 
-
 // ECMA-262, section 8.6.2.6, page 28.
 function DefaultString(x) {
   var toString = x.toString;
@@ -676,6 +675,12 @@ function DefaultString(x) {
   throw %MakeTypeError('cannot_convert_to_primitive', []);
 }
 
+function ToPositiveInteger(x, rangeErrorName) {
+  var i = TO_INTEGER(x);
+  if (i < 0) throw %MakeRangeError(rangeErrorName);
+  return i;
+}
+
 
 // NOTE: Setting the prototype for Array must take place as early as
 // possible due to code generation for array literals.  When
index 0e0b7fe..b14d65f 100644 (file)
@@ -37,7 +37,7 @@
 
 function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
   function ConstructByArrayBuffer(obj, buffer, byteOffset, length) {
-    var offset = IS_UNDEFINED(byteOffset) ? 0 : TO_POSITIVE_INTEGER(byteOffset);
+    var offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length")
 
     if (offset % elementSize !== 0) {
       throw MakeRangeError("invalid_typed_array_alignment",
@@ -58,7 +58,7 @@ function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
       newByteLength = bufferByteLength - offset;
       newLength = newByteLength / elementSize;
     } else {
-      var newLength = TO_POSITIVE_INTEGER(length);
+      var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
       newByteLength = newLength * elementSize;
     }
     if (offset + newByteLength > bufferByteLength) {
@@ -68,7 +68,7 @@ function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
   }
 
   function ConstructByLength(obj, length) {
-    var l = IS_UNDEFINED(length) ? 0 : TO_POSITIVE_INTEGER(length);
+    var l = ToPositiveInteger(length, "invalid_typed_array_length");
     var byteLength = l * elementSize;
     var buffer = new global.ArrayBuffer(byteLength);
     %TypedArrayInitialize(obj, arrayId, buffer, 0, byteLength);
@@ -76,7 +76,7 @@ function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
 
   function ConstructByArrayLike(obj, arrayLike) {
     var length = arrayLike.length;
-    var l =  IS_UNDEFINED(length) ? 0 : TO_POSITIVE_INTEGER(length);
+    var l =  ToPositiveInteger(length, "invalid_typed_array_length");
     var byteLength = l * elementSize;
     var buffer = new $ArrayBuffer(byteLength);
     %TypedArrayInitialize(obj, arrayId, buffer, 0, byteLength);
@@ -146,7 +146,10 @@ function CreateSubArray(elementSize, constructor) {
 }
 
 function TypedArraySet(obj, offset) {
-  var intOffset = IS_UNDEFINED(offset) ? 0 : TO_POSITIVE_INTEGER(offset);
+  var intOffset = IS_UNDEFINED(offset) ? 0 : TO_INTEGER(offset);
+  if (intOffset < 0) {
+    throw MakeTypeError("typed_array_set_negative_offset");
+  }
   if (%TypedArraySetFastCases(this, obj, intOffset))
     return;
 
@@ -209,13 +212,13 @@ function DataViewConstructor(buffer, byteOffset, byteLength) { // length = 3
       throw MakeTypeError('data_view_not_array_buffer', []);
     }
     var bufferByteLength = %ArrayBufferGetByteLength(buffer);
-    var offset = IS_UNDEFINED(byteOffset) ? 0 : TO_POSITIVE_INTEGER(byteOffset);
+    var offset = ToPositiveInteger(byteOffset, 'invalid_data_view_offset');
     if (offset > bufferByteLength) {
-      throw MakeRangeError('invalid_data_view_offset', []);
+      throw MakeRangeError('invalid_data_view_offset');
     }
     var length = IS_UNDEFINED(byteLength) ?
-      bufferByteLength - offset : TO_POSITIVE_INTEGER(byteLength);
-    if (offset + length > bufferByteLength) {
+      bufferByteLength - offset : TO_INTEGER(byteLength);
+    if (length < 0 || offset + length > bufferByteLength) {
       throw new MakeRangeError('invalid_data_view_length');
     }
     %DataViewInitialize(this, buffer, offset, length);
@@ -248,12 +251,18 @@ function DataViewGetByteLength() {
   return %DataViewGetByteLength(this);
 }
 
+function ToPositiveDataViewOffset(offset) {
+  return ToPositiveInteger(offset, 'invalid_data_view_accessor_offset');
+}
+
 function DataViewGetInt8(offset, little_endian) {
   if (!IS_DATAVIEW(this)) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.getInt8', this]);
   }
-  return %DataViewGetInt8(this, TO_POSITIVE_INTEGER(offset), !!little_endian);
+  return %DataViewGetInt8(this,
+                          ToPositiveDataViewOffset(offset),
+                          !!little_endian);
 }
 
 function DataViewSetInt8(offset, value, little_endian) {
@@ -262,7 +271,7 @@ function DataViewSetInt8(offset, value, little_endian) {
                         ['DataView.setInt8', this]);
   }
   %DataViewSetInt8(this,
-                   TO_POSITIVE_INTEGER(offset),
+                   ToPositiveDataViewOffset(offset),
                    TO_NUMBER_INLINE(value),
                    !!little_endian);
 }
@@ -272,7 +281,9 @@ function DataViewGetUint8(offset, little_endian) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.getUint8', this]);
   }
-  return %DataViewGetUint8(this, TO_POSITIVE_INTEGER(offset), !!little_endian);
+  return %DataViewGetUint8(this,
+                           ToPositiveDataViewOffset(offset),
+                           !!little_endian);
 }
 
 function DataViewSetUint8(offset, value, little_endian) {
@@ -281,7 +292,7 @@ function DataViewSetUint8(offset, value, little_endian) {
                         ['DataView.setUint8', this]);
   }
   %DataViewSetUint8(this,
-                   TO_POSITIVE_INTEGER(offset),
+                   ToPositiveDataViewOffset(offset),
                    TO_NUMBER_INLINE(value),
                    !!little_endian);
 }
@@ -291,7 +302,9 @@ function DataViewGetInt16(offset, little_endian) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.getInt16', this]);
   }
-  return %DataViewGetInt16(this, TO_POSITIVE_INTEGER(offset), !!little_endian);
+  return %DataViewGetInt16(this,
+                           ToPositiveDataViewOffset(offset),
+                           !!little_endian);
 }
 
 function DataViewSetInt16(offset, value, little_endian) {
@@ -300,7 +313,7 @@ function DataViewSetInt16(offset, value, little_endian) {
                         ['DataView.setInt16', this]);
   }
   %DataViewSetInt16(this,
-                    TO_POSITIVE_INTEGER(offset),
+                    ToPositiveDataViewOffset(offset),
                     TO_NUMBER_INLINE(value),
                     !!little_endian);
 }
@@ -310,7 +323,9 @@ function DataViewGetUint16(offset, little_endian) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.getUint16', this]);
   }
-  return %DataViewGetUint16(this, TO_POSITIVE_INTEGER(offset), !!little_endian);
+  return %DataViewGetUint16(this,
+                            ToPositiveDataViewOffset(offset),
+                            !!little_endian);
 }
 
 function DataViewSetUint16(offset, value, little_endian) {
@@ -319,7 +334,7 @@ function DataViewSetUint16(offset, value, little_endian) {
                         ['DataView.setUint16', this]);
   }
   %DataViewSetUint16(this,
-                     TO_POSITIVE_INTEGER(offset),
+                     ToPositiveDataViewOffset(offset),
                      TO_NUMBER_INLINE(value),
                      !!little_endian);
 }
@@ -329,7 +344,9 @@ function DataViewGetInt32(offset, little_endian) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.getInt32', this]);
   }
-  return %DataViewGetInt32(this, TO_POSITIVE_INTEGER(offset), !!little_endian);
+  return %DataViewGetInt32(this,
+                           ToPositiveDataViewOffset(offset),
+                           !!little_endian);
 }
 
 function DataViewSetInt32(offset, value, little_endian) {
@@ -338,7 +355,7 @@ function DataViewSetInt32(offset, value, little_endian) {
                         ['DataView.setInt32', this]);
   }
   %DataViewSetInt32(this,
-                    TO_POSITIVE_INTEGER(offset),
+                    ToPositiveDataViewOffset(offset),
                     TO_NUMBER_INLINE(value),
                     !!little_endian);
 }
@@ -348,7 +365,9 @@ function DataViewGetUint32(offset, little_endian) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.getUint32', this]);
   }
-  return %DataViewGetUint32(this, TO_POSITIVE_INTEGER(offset), !!little_endian);
+  return %DataViewGetUint32(this,
+                            ToPositiveDataViewOffset(offset),
+                            !!little_endian);
 }
 
 function DataViewSetUint32(offset, value, little_endian) {
@@ -357,7 +376,7 @@ function DataViewSetUint32(offset, value, little_endian) {
                         ['DataView.setUint32', this]);
   }
   %DataViewSetUint32(this,
-                     TO_POSITIVE_INTEGER(offset),
+                     ToPositiveDataViewOffset(offset),
                      TO_NUMBER_INLINE(value),
                      !!little_endian);
 }
@@ -367,7 +386,9 @@ function DataViewGetFloat32(offset, little_endian) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.getFloat32', this]);
   }
-  return %DataViewGetFloat32(this, TO_POSITIVE_INTEGER(offset), !!little_endian);
+  return %DataViewGetFloat32(this,
+                             ToPositiveDataViewOffset(offset),
+                             !!little_endian);
 }
 
 function DataViewSetFloat32(offset, value, little_endian) {
@@ -376,7 +397,7 @@ function DataViewSetFloat32(offset, value, little_endian) {
                         ['DataView.setFloat32', this]);
   }
   %DataViewSetFloat32(this,
-                      TO_POSITIVE_INTEGER(offset),
+                      ToPositiveDataViewOffset(offset),
                       TO_NUMBER_INLINE(value),
                       !!little_endian);
 }
@@ -386,7 +407,13 @@ function DataViewGetFloat64(offset, little_endian) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.getFloat64', this]);
   }
-  return %DataViewGetFloat64(this, TO_POSITIVE_INTEGER(offset), !!little_endian);
+  offset = TO_INTEGER(offset);
+  if (offset < 0) {
+    throw MakeRangeError("invalid_data_view_accessor_offset");
+  }
+  return %DataViewGetFloat64(this,
+                             ToPositiveDataViewOffset(offset),
+                             !!little_endian);
 }
 
 function DataViewSetFloat64(offset, value, little_endian) {
@@ -394,8 +421,12 @@ function DataViewSetFloat64(offset, value, little_endian) {
     throw MakeTypeError('incompatible_method_reciever',
                         ['DataView.setFloat64', this]);
   }
+  offset = TO_INTEGER(offset);
+  if (offset < 0) {
+    throw MakeRangeError("invalid_data_view_accessor_offset");
+  }
   %DataViewSetFloat64(this,
-                      TO_POSITIVE_INTEGER(offset),
+                      ToPositiveDataViewOffset(offset),
                       TO_NUMBER_INLINE(value),
                       !!little_endian);
 }
index 3b7cc09..9dd8fe3 100644 (file)
@@ -64,8 +64,7 @@ function checkGet(func, index, expected, littleEndian) {
   function doGet() {
     return view["get" + func](index, littleEndian);
   }
-  if (index < 0) index = 0;
-  if (index + getElementSize(func) - 1 < view.byteLength)
+  if (index >=0 && index + getElementSize(func) - 1 < view.byteLength)
       assertSame(expected, doGet());
   else
       assertThrows(doGet, RangeError);
@@ -75,9 +74,8 @@ function checkSet(func, index, value, littleEndian) {
   function doSet() {
     view["set" + func](index, value, littleEndian);
   }
-  actualIndex = index < 0 ? 0 : index;
-  if (actualIndex >= 0 &&
-      actualIndex + getElementSize(func) - 1 < view.byteLength) {
+  if (index >= 0 &&
+      index + getElementSize(func) - 1 < view.byteLength) {
     assertSame(undefined, doSet());
     checkGet(func, index, value, littleEndian);
   } else {
index e1048ec..c699f64 100644 (file)
@@ -35,14 +35,15 @@ function TestByteLength(param, expectedByteLength) {
 function TestArrayBufferCreation() {
   TestByteLength(1, 1);
   TestByteLength(256, 256);
-  TestByteLength(-10, 0);
   TestByteLength(2.567, 2);
-  TestByteLength(-2.567, 0);
 
   TestByteLength("abc", 0);
 
   TestByteLength(0, 0);
 
+  assertThrows(function() { new ArrayBuffer(-10); }, RangeError);
+  assertThrows(function() { new ArrayBuffer(-2.567); }, RangeError);
+
 /* TODO[dslomov]: Reenable the test
   assertThrows(function() {
     var ab1 = new ArrayBuffer(0xFFFFFFFFFFFF)
@@ -89,6 +90,7 @@ function TestArrayBufferSlice() {
   TestSlice(0, 0, 1, 20);
   TestSlice(100, 100, 0, 100);
   TestSlice(100, 100, 0, 1000);
+
   TestSlice(0, 100, 5, 1);
 
   TestSlice(1, 100, -11, -10);
@@ -99,7 +101,7 @@ function TestArrayBufferSlice() {
   TestSlice(10, 100, 90, "100");
   TestSlice(10, 100, "90", "100");
 
-  TestSlice(0, 100, 90, "abc");
+  TestSlice(0,  100, 90, "abc");
   TestSlice(10, 100, "abc", 10);
 
   TestSlice(10, 100, 0.96, 10.96);
@@ -107,7 +109,6 @@ function TestArrayBufferSlice() {
   TestSlice(10, 100, 0.01, 10.01);
   TestSlice(10, 100, 0.01, 10.96);
 
-
   TestSlice(10, 100, 90);
   TestSlice(10, 100, -10);
 }
@@ -489,24 +490,15 @@ function TestDataViewConstructor() {
   assertSame(256, d3c.byteOffset);
   assertSame(0, d3c.byteLength);
 
-  // weird args
-  var d4 = new DataView(ab, -1);
+  var d4 = new DataView(ab, 1, 3.1415926);
   assertSame(ab, d4.buffer);
-  assertSame(0, d4.byteOffset);
-  assertSame(256, d4.byteLength);
-
-  var d5 = new DataView(ab, 1, -1);
-  assertSame(ab, d5.buffer);
-  assertSame(1, d5.byteOffset);
-  assertSame(0, d5.byteLength);
-
-  var d6 = new DataView(ab, 1, 3.1415926);
-  assertSame(ab, d6.buffer);
-  assertSame(1, d6.byteOffset);
-  assertSame(3, d6.byteLength);
+  assertSame(1, d4.byteOffset);
+  assertSame(3, d4.byteLength);
 
 
   // error cases
+  assertThrows(function() { new DataView(ab, -1); }, RangeError);
+  assertThrows(function() { new DataView(ab, 1, -1); }, RangeError);
   assertThrows(function() { new DataView(); }, TypeError);
   assertThrows(function() { new DataView([]); }, TypeError);
   assertThrows(function() { new DataView(ab, 257); }, RangeError);