Skip to content

Commit d0f4f88

Browse files
author
Atul Katti
committed
[MERGE #2289 @atulkatti] Resolves #1391: Implement TypedArray updates to index handling.
Merge pull request #2289 from atulkatti:TypedArray.Issue1391 Resolves #1391: Implement TypedArray updates to index handling. 1. Also, made changes to ArrayBuffer and DataView as per the spec updates. 2. Added some more tests for DataView.
2 parents 6f4c890 + 17b8f3a commit d0f4f88

File tree

10 files changed

+1251
-1137
lines changed

10 files changed

+1251
-1137
lines changed

lib/Runtime/Library/ArrayBuffer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ namespace Js
211211
uint32 byteLength = 0;
212212
if (args.Info.Count > 1)
213213
{
214-
byteLength = ToIndex(args[1], JSERR_ArrayLengthConstructIncorrect, scriptContext, MaxArrayBufferLength, false);
214+
byteLength = ToIndex(args[1], JSERR_ArrayLengthConstructIncorrect, scriptContext, MaxArrayBufferLength);
215215
}
216216

217217
RecyclableObject* newArr = scriptContext->GetLibrary()->CreateArrayBuffer(byteLength);

lib/Runtime/Library/DataView.cpp

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ namespace Js
2424
uint32 byteLength = 0;
2525
uint32 mappedLength;
2626
int32 offset = 0;
27-
double numberOffset = 0;
2827
ArrayBufferBase* arrayBuffer = nullptr;
2928
DataView* dataView;
3029

@@ -49,7 +48,7 @@ namespace Js
4948
{
5049
case S_OK:
5150
case S_FALSE:
52-
arrayBuffer = static_cast<ArrayBuffer *> (ab);
51+
arrayBuffer = ab;
5352
// Both of these cases will be handled by the arrayBuffer null check.
5453
break;
5554

@@ -74,50 +73,37 @@ namespace Js
7473
}
7574
}
7675

77-
//4. Let numberOffset be ToNumber(byteOffset).
78-
//5. Let offset be ToInteger(numberOffset).
79-
//6. ReturnIfAbrupt(offset).
80-
//7. If numberOffset <> offset or offset < 0, throw a RangeError exception.
76+
//4. Let offset be ToIndex(byteOffset).
8177
if (args.Info.Count > 2)
8278
{
8379
Var secondArgument = args[2];
84-
numberOffset = JavascriptConversion::ToNumber(secondArgument, scriptContext);
85-
offset = JavascriptConversion::ToInt32(numberOffset);
86-
87-
if (offset < 0 ||
88-
numberOffset != offset)
89-
{
90-
JavascriptError::ThrowRangeError(
91-
scriptContext, JSERR_DataView_InvalidArgument, _u("byteOffset"));
92-
}
80+
offset = ArrayBuffer::ToIndex(secondArgument, JSERR_ArrayLengthConstructIncorrect, scriptContext, ArrayBuffer::MaxArrayBufferLength, false);
9381
}
9482

95-
//8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
83+
//5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
9684
if (arrayBuffer->IsDetached())
9785
{
9886
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
9987
}
10088

101-
//9. Let bufferByteLength be the value of buffer's[[ArrayBufferByteLength]] internal slot.
102-
//10. If offset > bufferByteLength, throw a RangeError exception.
103-
89+
//6. Let bufferByteLength be the value of buffer's[[ArrayBufferByteLength]] internal slot.
90+
//7. If offset > bufferByteLength, throw a RangeError exception.
10491
byteLength = arrayBuffer->GetByteLength();
10592
if ((uint32)offset > byteLength)
10693
{
10794
JavascriptError::ThrowRangeError(
10895
scriptContext, JSERR_DataView_InvalidArgument, _u("byteOffset"));
10996
}
11097

111-
//11. If byteLength is undefined, then
98+
//8. If byteLength is either not present or is undefined, then
11299
// a. Let viewByteLength be bufferByteLength - offset.
113-
//12. Else,
114-
// a. Let viewByteLength be ToLength(byteLength).
115-
// b. ReturnIfAbrupt(viewLength).
116-
// c. If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
100+
//9. Else,
101+
// a. Let viewByteLength be ToIndex(byteLength).
102+
// b. If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
117103
if (args.Info.Count > 3 && !JavascriptOperators::IsUndefinedObject(args[3]))
118104
{
119105
Var thirdArgument = args[3];
120-
mappedLength = (uint32)JavascriptConversion::ToLength(thirdArgument, scriptContext);
106+
mappedLength = ArrayBuffer::ToIndex(thirdArgument, JSERR_ArrayLengthConstructIncorrect, scriptContext, ArrayBuffer::MaxArrayBufferLength, false);
121107
uint32 viewRange = mappedLength + offset;
122108

123109
if (viewRange > byteLength || viewRange < mappedLength) // overflow indicates out-of-range
@@ -131,13 +117,12 @@ namespace Js
131117
mappedLength = byteLength - offset;
132118
}
133119

134-
//13. Let O be OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]).
135-
//14. ReturnIfAbrupt(O).
136-
//15. Set O's[[DataView]] internal slot to true.
137-
//16. Set O's[[ViewedArrayBuffer]] internal slot to buffer.
138-
//17. Set O's[[ByteLength]] internal slot to viewByteLength.
139-
//18. Set O's[[ByteOffset]] internal slot to offset.
140-
//19. Return O.
120+
//10. Let O be OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]).
121+
//11. Set O's[[DataView]] internal slot to true.
122+
//12. Set O's[[ViewedArrayBuffer]] internal slot to buffer.
123+
//13. Set O's[[ByteLength]] internal slot to viewByteLength.
124+
//14. Set O's[[ByteOffset]] internal slot to offset.
125+
//15. Return O.
141126
dataView = scriptContext->GetLibrary()->CreateDataView(arrayBuffer, offset, mappedLength);
142127
return isCtorSuperCall ?
143128
JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), dataView, nullptr, scriptContext) :

lib/Runtime/Library/TypedArray.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ namespace Js
388388
Var TypedArrayBase::CreateNewInstance(Arguments& args, ScriptContext* scriptContext, uint32 elementSize, PFNCreateTypedArray pfnCreateTypedArray)
389389
{
390390
uint32 byteLength = 0;
391+
uint32 newByteLength = 0;
391392
int32 offset = 0;
392393
int32 mappedLength = -1;
393394
uint32 elementCount = 0;
@@ -509,12 +510,15 @@ namespace Js
509510
if (args.Info.Count > 3 && !JavascriptOperators::IsUndefinedObject(args[3]))
510511
{
511512
mappedLength = ArrayBuffer::ToIndex(args[3], JSERR_InvalidTypedArrayLength, scriptContext, ArrayBuffer::MaxArrayBufferLength / elementSize, false);
513+
newByteLength = mappedLength * elementSize;
512514

513-
if ((uint32)mappedLength > (byteLength - offset)/ elementSize)
515+
if (offset + newByteLength > byteLength)
514516
{
515517
JavascriptError::ThrowRangeError(
516518
scriptContext, JSERR_InvalidTypedArrayLength);
517519
}
520+
521+
byteLength = newByteLength;
518522
}
519523
else
520524
{

test/typedarray/TypedArrayBuiltins.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,60 @@ var tests = [
338338
test(taCtor);
339339
}
340340
}
341+
},
342+
{
343+
name: "TypedArray : Error cases for constructor TypedArray( buffer, byteOffset, length )",
344+
body: function () {
345+
var sourceArrayBuffer1 = new ArrayBuffer(10);
346+
347+
// offset > byteLength
348+
function TestOffsetBeyondSourceArrayBufferLength()
349+
{
350+
new Int16Array(sourceArrayBuffer1, 12);
351+
}
352+
353+
assert.throws(
354+
TestOffsetBeyondSourceArrayBufferLength,
355+
RangeError,
356+
"TypedArray: Expected the function to throw RangeError as (offset > byteLength).",
357+
"Invalid offset/length when creating typed array")
358+
359+
// offset % elementSize != 0
360+
function TestIncorrectOffset()
361+
{
362+
new Int16Array(sourceArrayBuffer1, 7, 1);
363+
}
364+
365+
assert.throws(
366+
TestIncorrectOffset,
367+
RangeError,
368+
"TypedArray: Expected the function to throw RangeError as (offset % elementSize) != 0.",
369+
"Invalid offset/length when creating typed array")
370+
371+
// (Length * elementSize + offset) beyond array buffer length.
372+
function TestLengthBeyondSourceArrayBufferLength()
373+
{
374+
new Int16Array(sourceArrayBuffer1, 6, 4);
375+
}
376+
377+
assert.throws(
378+
TestLengthBeyondSourceArrayBufferLength,
379+
RangeError,
380+
"TypedArray: Expected the function to throw RangeError as ((Length * elementSize + offset)) != byteLength.",
381+
"Invalid offset/length when creating typed array")
382+
383+
// (byteLength - offset) % elementSize != 0
384+
function TestOffsetPlusElementSizeBeyondSourceArrayBufferLength()
385+
{
386+
new Int32Array(sourceArrayBuffer1, 4);
387+
}
388+
389+
assert.throws(
390+
TestOffsetPlusElementSizeBeyondSourceArrayBufferLength,
391+
RangeError,
392+
"TypedArray: Expected the function to throw RangeError as (byteLength - offset) % elementSize != 0.",
393+
"Invalid offset/length when creating typed array")
394+
}
341395
}
342396
];
343397

0 commit comments

Comments
 (0)