From: dslomov@chromium.org Date: Mon, 24 Jun 2013 13:58:52 +0000 (+0000) Subject: Update typed arrays behavior to match ES6 rev 15. Remove TO_POSITIVE_INTEGER and... X-Git-Tag: upstream/4.7.83~13704 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e6e0ee07089fb85909ae85cc43512a83154bc1e2;p=platform%2Fupstream%2Fv8.git Update typed arrays behavior to match ES6 rev 15. Remove TO_POSITIVE_INTEGER and throw on negative length arguments. 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 --- diff --git a/src/arraybuffer.js b/src/arraybuffer.js index 2b0c3dd..06cc653 100644 --- a/src/arraybuffer.js +++ b/src/arraybuffer.js @@ -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); diff --git a/src/macros.py b/src/macros.py index 5b36421..e442b44 100644 --- a/src/macros.py +++ b/src/macros.py @@ -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); diff --git a/src/messages.js b/src/messages.js index 4778789..f515ca5 100644 --- a/src/messages.js +++ b/src/messages.js @@ -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"], diff --git a/src/runtime.js b/src/runtime.js index 22f888d..348fd74 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -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 diff --git a/src/typedarray.js b/src/typedarray.js index 0e0b7fe..b14d65f 100644 --- a/src/typedarray.js +++ b/src/typedarray.js @@ -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); } diff --git a/test/mjsunit/harmony/dataview-accessors.js b/test/mjsunit/harmony/dataview-accessors.js index 3b7cc09..9dd8fe3 100644 --- a/test/mjsunit/harmony/dataview-accessors.js +++ b/test/mjsunit/harmony/dataview-accessors.js @@ -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 { diff --git a/test/mjsunit/harmony/typedarrays.js b/test/mjsunit/harmony/typedarrays.js index e1048ec..c699f64 100644 --- a/test/mjsunit/harmony/typedarrays.js +++ b/test/mjsunit/harmony/typedarrays.js @@ -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);