Преглед изворни кода

Resolves #1391: Implement TypedArray updates to index handling.

Atul Katti пре 9 година
родитељ
комит
17b8f3aae8

+ 1 - 1
lib/Runtime/Library/ArrayBuffer.cpp

@@ -211,7 +211,7 @@ namespace Js
         uint32 byteLength = 0;
         if (args.Info.Count > 1)
         {
-            byteLength = ToIndex(args[1], JSERR_ArrayLengthConstructIncorrect, scriptContext, MaxArrayBufferLength, false);
+            byteLength = ToIndex(args[1], JSERR_ArrayLengthConstructIncorrect, scriptContext, MaxArrayBufferLength);
         }
 
         RecyclableObject* newArr = scriptContext->GetLibrary()->CreateArrayBuffer(byteLength);

+ 17 - 32
lib/Runtime/Library/DataView.cpp

@@ -24,7 +24,6 @@ namespace Js
         uint32 byteLength = 0;
         uint32 mappedLength;
         int32 offset = 0;
-        double numberOffset = 0;
         ArrayBufferBase* arrayBuffer = nullptr;
         DataView* dataView;
 
@@ -49,7 +48,7 @@ namespace Js
             {
             case S_OK:
             case S_FALSE:
-                arrayBuffer = static_cast<ArrayBuffer *> (ab);
+                arrayBuffer = ab;
                 // Both of these cases will be handled by the arrayBuffer null check.
                 break;
 
@@ -74,33 +73,21 @@ namespace Js
             }
         }
 
-        //4.    Let numberOffset be ToNumber(byteOffset).
-        //5.    Let offset be ToInteger(numberOffset).
-        //6.    ReturnIfAbrupt(offset).
-        //7.    If numberOffset <> offset or offset < 0, throw a RangeError exception.
+        //4.    Let offset be ToIndex(byteOffset).
         if (args.Info.Count > 2)
         {
             Var secondArgument = args[2];
-            numberOffset = JavascriptConversion::ToNumber(secondArgument, scriptContext);
-            offset = JavascriptConversion::ToInt32(numberOffset);
-
-            if (offset < 0 ||
-                numberOffset != offset)
-            {
-                JavascriptError::ThrowRangeError(
-                    scriptContext, JSERR_DataView_InvalidArgument, _u("byteOffset"));
-            }
+            offset = ArrayBuffer::ToIndex(secondArgument, JSERR_ArrayLengthConstructIncorrect, scriptContext, ArrayBuffer::MaxArrayBufferLength, false);
         }
 
-        //8.    If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
+        //5.    If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
         if (arrayBuffer->IsDetached())
         {
             JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
         }
 
-        //9.    Let bufferByteLength be the value of buffer's[[ArrayBufferByteLength]] internal slot.
-        //10.   If offset > bufferByteLength, throw a RangeError exception.
-
+        //6.    Let bufferByteLength be the value of buffer's[[ArrayBufferByteLength]] internal slot.
+        //7.   If offset > bufferByteLength, throw a RangeError exception.
         byteLength = arrayBuffer->GetByteLength();
         if ((uint32)offset > byteLength)
         {
@@ -108,16 +95,15 @@ namespace Js
                 scriptContext, JSERR_DataView_InvalidArgument, _u("byteOffset"));
         }
 
-        //11.   If byteLength is undefined, then
+        //8.   If byteLength is either not present or is undefined, then
         //      a.  Let viewByteLength be bufferByteLength - offset.
-        //12.   Else,
-        //      a.  Let viewByteLength be ToLength(byteLength).
-        //      b.  ReturnIfAbrupt(viewLength).
-        //      c.  If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
+        //9.   Else,
+        //      a.  Let viewByteLength be ToIndex(byteLength).
+        //      b.  If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
         if (args.Info.Count > 3 && !JavascriptOperators::IsUndefinedObject(args[3]))
             {
                 Var thirdArgument = args[3];
-                mappedLength = (uint32)JavascriptConversion::ToLength(thirdArgument, scriptContext);
+                mappedLength = ArrayBuffer::ToIndex(thirdArgument, JSERR_ArrayLengthConstructIncorrect, scriptContext, ArrayBuffer::MaxArrayBufferLength, false);
                 uint32 viewRange = mappedLength + offset;
 
                 if (viewRange > byteLength || viewRange < mappedLength) // overflow indicates out-of-range
@@ -131,13 +117,12 @@ namespace Js
             mappedLength = byteLength - offset;
         }
 
-        //13.   Let O be OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]).
-        //14.   ReturnIfAbrupt(O).
-        //15.   Set O's[[DataView]] internal slot to true.
-        //16.   Set O's[[ViewedArrayBuffer]] internal slot to buffer.
-        //17.   Set O's[[ByteLength]] internal slot to viewByteLength.
-        //18.   Set O's[[ByteOffset]] internal slot to offset.
-        //19.   Return O.
+        //10.   Let O be OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]).
+        //11.   Set O's[[DataView]] internal slot to true.
+        //12.   Set O's[[ViewedArrayBuffer]] internal slot to buffer.
+        //13.   Set O's[[ByteLength]] internal slot to viewByteLength.
+        //14.   Set O's[[ByteOffset]] internal slot to offset.
+        //15.   Return O.
         dataView = scriptContext->GetLibrary()->CreateDataView(arrayBuffer, offset, mappedLength);
         return isCtorSuperCall ?
             JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), dataView, nullptr, scriptContext) :

+ 5 - 1
lib/Runtime/Library/TypedArray.cpp

@@ -388,6 +388,7 @@ namespace Js
     Var TypedArrayBase::CreateNewInstance(Arguments& args, ScriptContext* scriptContext, uint32 elementSize, PFNCreateTypedArray pfnCreateTypedArray)
     {
         uint32 byteLength = 0;
+        uint32 newByteLength = 0;
         int32 offset = 0;
         int32 mappedLength = -1;
         uint32 elementCount = 0;
@@ -509,12 +510,15 @@ namespace Js
             if (args.Info.Count > 3 && !JavascriptOperators::IsUndefinedObject(args[3]))
             {
                 mappedLength = ArrayBuffer::ToIndex(args[3], JSERR_InvalidTypedArrayLength, scriptContext, ArrayBuffer::MaxArrayBufferLength / elementSize, false);
+                newByteLength = mappedLength * elementSize;
 
-                if ((uint32)mappedLength > (byteLength - offset)/ elementSize)
+                if (offset + newByteLength > byteLength)
                 {
                     JavascriptError::ThrowRangeError(
                         scriptContext, JSERR_InvalidTypedArrayLength);
                 }
+
+                byteLength = newByteLength;
             }
             else
             {

+ 54 - 0
test/typedarray/TypedArrayBuiltins.js

@@ -338,6 +338,60 @@ var tests = [
                 test(taCtor);
             }
         }
+    },
+    {
+        name: "TypedArray : Error cases for constructor TypedArray( buffer, byteOffset, length )",
+        body: function () {
+            var sourceArrayBuffer1 = new ArrayBuffer(10);
+
+            // offset > byteLength
+            function TestOffsetBeyondSourceArrayBufferLength()
+            {
+                new Int16Array(sourceArrayBuffer1, 12);
+            }
+
+            assert.throws(
+                TestOffsetBeyondSourceArrayBufferLength, 
+                RangeError, 
+                "TypedArray: Expected the function to throw RangeError as (offset > byteLength).", 
+                "Invalid offset/length when creating typed array")
+
+            // offset % elementSize != 0
+            function TestIncorrectOffset()
+            {
+                new Int16Array(sourceArrayBuffer1, 7, 1);
+            }
+
+            assert.throws(
+                TestIncorrectOffset, 
+                RangeError, 
+                "TypedArray: Expected the function to throw RangeError as (offset % elementSize) != 0.", 
+                "Invalid offset/length when creating typed array")
+
+            // (Length * elementSize + offset) beyond array buffer length.
+            function TestLengthBeyondSourceArrayBufferLength()
+            {
+                new Int16Array(sourceArrayBuffer1, 6, 4);
+            }
+
+            assert.throws(
+                TestLengthBeyondSourceArrayBufferLength, 
+                RangeError, 
+                "TypedArray: Expected the function to throw RangeError as ((Length * elementSize + offset)) != byteLength.", 
+                "Invalid offset/length when creating typed array")
+
+            // (byteLength - offset) % elementSize != 0
+            function TestOffsetPlusElementSizeBeyondSourceArrayBufferLength()
+            {
+                new Int32Array(sourceArrayBuffer1, 4);
+            }
+
+            assert.throws(
+                TestOffsetPlusElementSizeBeyondSourceArrayBufferLength, 
+                RangeError, 
+                "TypedArray: Expected the function to throw RangeError as (byteLength - offset) % elementSize != 0.", 
+                "Invalid offset/length when creating typed array")
+        }
     }
 ];
 

Разлика између датотеке није приказан због своје велике величине
+ 112 - 112
test/typedarray/dataview.baseline


+ 1 - 2
test/typedarray/dataview.js

@@ -2,7 +2,6 @@
 // Copyright (C) Microsoft. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
-
 var getFuncs = ['getInt8', 'getUint8', 'getInt16', 'getUint16', 'getInt32', 'getUint32', 'getFloat32', 'getFloat64'];
 var setFuncs = ['setInt8', 'setUint8', 'setInt16', 'setUint16', 'setInt32', 'setUint32', 'setFloat32', 'setFloat64'];
 var dataSize = [1,1,2,2,4,4,4,8];
@@ -104,7 +103,7 @@ function testOneOffset(dataView, offSet, value)
                 print(getFuncs[j] + " = " +  result);
                 }
 
-            print("set little endian value offset " + offSet + " value " + value + " method " + setFuncs[i]);
+            print("set big endian value offset " + offSet + " value " + value + " method " + setFuncs[i]);
             print("results of little endian reads are: ");
             dataView[setFuncs[i]](offSet, value, false);
             for (var j = 0; j < getFuncs.length; j++)

+ 4 - 0
test/typedarray/dataview1.baseline

@@ -22,3 +22,7 @@ PASS
 PASS
 PASS
 PASS
+16
+12
+16
+2

+ 56 - 1
test/typedarray/dataview1.js

@@ -96,8 +96,63 @@ function test5() {
         "DataView constructor argument byteLength is invalid");
 }
 
+function TestDataViewConstructorWithOffset()
+{
+    var arrayBuffer = new ArrayBuffer(16);
+    print(arrayBuffer.byteLength);
+    //Constructor with offset specified.
+    var dataView2 = new DataView(arrayBuffer, 4);
+    print(dataView2.byteLength);
+}
+
+function TestDataViewConstructorWithOffsetAndLength()
+{
+    var arrayBuffer = new ArrayBuffer(16);
+    print(arrayBuffer.byteLength);
+    // Constructor with offset and length specified.
+    var dataView3 = new DataView(arrayBuffer, 8, 2);
+    print(dataView3.byteLength);
+}
+
+function TestDataViewConstructorCalledWithoutNew()
+{
+    var arrayBuffer = new ArrayBuffer(16);
+    var dataView4 = DataView(arrayBuffer, 8, 2);
+}
+
+function TestDataViewConstructorCalledWithoutArguments()
+{
+    var dataView5 = new DataView();
+}
+
+function TestDataViewCostructorCalledWithJavascriptArray()
+{
+    var normalArray = [1, 2, 3, 4, 5];
+    var dataView6 = new DataView(normalArray);
+}
+
+function TestDataViewCostructorOffsetBeyondArrayBufferByteLength()
+{
+    var arrayBuffer = new ArrayBuffer(16);
+    var dataView7 = new DataView(arrayBuffer, 17);
+}
+
+function TestDataViewCostructorOffsetPlusLengthBeyondArrayBufferByteLength()
+{
+    var arrayBuffer = new ArrayBuffer(16);
+    var dataView7 = new DataView(arrayBuffer, 14, 16);
+}
+
 test1();
 test2();
 test3();
 test4();
-test5();
+test5();
+
+TestDataViewConstructorWithOffset();
+TestDataViewConstructorWithOffsetAndLength();
+assert.throws(TestDataViewConstructorCalledWithoutNew, TypeError, "", "DataView: cannot be called without the new keyword");
+assert.throws(TestDataViewConstructorCalledWithoutArguments, TypeError, "", "Required argument buffer in DataView method is not specified");
+assert.throws(TestDataViewCostructorCalledWithJavascriptArray, TypeError, "", "Required argument buffer in DataView method is not specified");
+assert.throws(TestDataViewCostructorOffsetBeyondArrayBufferByteLength, RangeError, "", "DataView constructor argument byteOffset is invalid");
+assert.throws(TestDataViewCostructorOffsetPlusLengthBeyondArrayBufferByteLength, RangeError, "", "DataView constructor argument byteLength is invalid");

Разлика између датотеке није приказан због своје велике величине
+ 112 - 112
test/typedarray/samethread.baseline


+ 13 - 0
test/typedarray/transfer.js

@@ -2,6 +2,9 @@
 // Copyright (C) Microsoft. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
+if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
+    this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+}
 
 var buf1 = new ArrayBuffer(1<<21);
 new Int8Array(buf1)[0] = 42;
@@ -32,3 +35,13 @@ print(buf6.byteLength);
 var buf7 = ArrayBuffer.transfer(buf6, 0);
 print(buf6.byteLength);
 print(buf7.byteLength);
+
+// Test the DataView constructor with a detached buffer.
+function TestDataViewCostructorDetachedBuffer()
+{
+    var arrayBufferToDetach = new ArrayBuffer(16);
+    var arrayBufferNew = ArrayBuffer.transfer(arrayBufferToDetach, 0);
+    var dataView8 = new DataView(arrayBufferToDetach);
+}
+
+assert.throws(TestDataViewCostructorDetachedBuffer, TypeError, "", "'this' is not a DataView object");

Неке датотеке нису приказане због велике количине промена