Reland [rab/gsab] Add RAB / GSAB support to DataViews
Previous version: https://chromium-review.googlesource.com/c/v8/v8/+/3259648 Fix 1: ValueSerializer <3 JSArrayBufferView Fix 2: set flags correctly when creating DataViews via the API Bug: v8:11111 Change-Id: I9cbfdaff29f97c7823eaa3d931689b363e1f4cf7 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3297708 Reviewed-by: Marja Hölttä <marja@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/main@{#78046}
This commit is contained in:
parent
9c8a8c6d5d
commit
8d0404d80b
@ -21,6 +21,7 @@ namespace internal {
|
||||
BUILTIN(DataViewConstructor) {
|
||||
const char* const kMethodName = "DataView constructor";
|
||||
HandleScope scope(isolate);
|
||||
// 1. If NewTarget is undefined, throw a TypeError exception.
|
||||
if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
|
||||
@ -55,8 +56,8 @@ BUILTIN(DataViewConstructor) {
|
||||
kMethodName)));
|
||||
}
|
||||
|
||||
// 5. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
|
||||
size_t const buffer_byte_length = array_buffer->byte_length();
|
||||
// 5. Let bufferByteLength be ArrayBufferByteLength(buffer, SeqCst).
|
||||
size_t buffer_byte_length = array_buffer->GetByteLength();
|
||||
|
||||
// 6. If offset > bufferByteLength, throw a RangeError exception.
|
||||
if (view_byte_offset > buffer_byte_length) {
|
||||
@ -64,15 +65,22 @@ BUILTIN(DataViewConstructor) {
|
||||
isolate, NewRangeError(MessageTemplate::kInvalidOffset, byte_offset));
|
||||
}
|
||||
|
||||
// 7. Let bufferIsResizable be IsResizableArrayBuffer(buffer).
|
||||
// 8. Let byteLengthChecked be empty.
|
||||
// 9. If bufferIsResizable is true and byteLength is undefined, then
|
||||
// a. Let viewByteLength be auto.
|
||||
// 10. Else if byteLength is undefined, then
|
||||
// a. Let viewByteLength be bufferByteLength - offset.
|
||||
size_t view_byte_length;
|
||||
bool length_tracking = false;
|
||||
if (byte_length->IsUndefined(isolate)) {
|
||||
// 7. If byteLength is undefined, then
|
||||
// a. Let viewByteLength be bufferByteLength - offset.
|
||||
view_byte_length = buffer_byte_length - view_byte_offset;
|
||||
length_tracking = array_buffer->is_resizable();
|
||||
} else {
|
||||
// 8. Else,
|
||||
// a. Let viewByteLength be ? ToIndex(byteLength).
|
||||
// b. If offset+viewByteLength > bufferByteLength, throw a
|
||||
// 11. Else,
|
||||
// a. Set byteLengthChecked be ? ToIndex(byteLength).
|
||||
// b. Let viewByteLength be byteLengthChecked.
|
||||
// c. If offset + viewByteLength > bufferByteLength, throw a
|
||||
// RangeError exception.
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, byte_length,
|
||||
@ -85,9 +93,9 @@ BUILTIN(DataViewConstructor) {
|
||||
view_byte_length = byte_length->Number();
|
||||
}
|
||||
|
||||
// 9. Let O be ? OrdinaryCreateFromConstructor(NewTarget,
|
||||
// "%DataViewPrototype%", «[[DataView]], [[ViewedArrayBuffer]],
|
||||
// [[ByteLength]], [[ByteOffset]]»).
|
||||
// 12. Let O be ? OrdinaryCreateFromConstructor(NewTarget,
|
||||
// "%DataViewPrototype%", «[[DataView]], [[ViewedArrayBuffer]],
|
||||
// [[ByteLength]], [[ByteOffset]]»).
|
||||
Handle<JSObject> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result,
|
||||
@ -97,26 +105,29 @@ BUILTIN(DataViewConstructor) {
|
||||
// TODO(v8:10391, saelo): Handle external pointers in EmbedderDataSlot
|
||||
data_view->SetEmbedderField(i, Smi::zero());
|
||||
}
|
||||
data_view->set_is_backed_by_rab(array_buffer->is_resizable() &&
|
||||
!array_buffer->is_shared());
|
||||
data_view->set_is_length_tracking(length_tracking);
|
||||
|
||||
// We have to set the internal slots before the detached check on step 10 or
|
||||
// We have to set the internal slots before the checks on steps 13 - 17 or
|
||||
// the TorqueGeneratedClassVerifier ended up complaining that the slot is
|
||||
// empty or invalid on heap teardown.
|
||||
// The result object is not observable from JavaScript when step 10 early
|
||||
// aborts so it is fine to set internal slots here.
|
||||
// The result object is not observable from JavaScript when steps 13 - 17
|
||||
// early abort so it is fine to set internal slots here.
|
||||
|
||||
// 11. Set O.[[ViewedArrayBuffer]] to buffer.
|
||||
// 18. Set O.[[ViewedArrayBuffer]] to buffer.
|
||||
data_view->set_buffer(*array_buffer);
|
||||
|
||||
// 12. Set O.[[ByteLength]] to viewByteLength.
|
||||
data_view->set_byte_length(view_byte_length);
|
||||
// 19. Set O.[[ByteLength]] to viewByteLength.
|
||||
data_view->set_byte_length(length_tracking ? 0 : view_byte_length);
|
||||
|
||||
// 13. Set O.[[ByteOffset]] to offset.
|
||||
// 20. Set O.[[ByteOffset]] to offset.
|
||||
data_view->set_byte_offset(view_byte_offset);
|
||||
data_view->set_data_pointer(
|
||||
isolate,
|
||||
static_cast<uint8_t*>(array_buffer->backing_store()) + view_byte_offset);
|
||||
|
||||
// 10. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
// 13. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
if (array_buffer->was_detached()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kDetachedOperation,
|
||||
@ -124,7 +135,27 @@ BUILTIN(DataViewConstructor) {
|
||||
kMethodName)));
|
||||
}
|
||||
|
||||
// 14. Return O.
|
||||
// 14. Let getBufferByteLength be
|
||||
// MakeIdempotentArrayBufferByteLengthGetter(SeqCst).
|
||||
// 15. Set bufferByteLength be getBufferByteLength(buffer).
|
||||
buffer_byte_length = array_buffer->GetByteLength();
|
||||
|
||||
// 16. If offset > bufferByteLength, throw a RangeError exception.
|
||||
if (view_byte_offset > buffer_byte_length) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewRangeError(MessageTemplate::kInvalidOffset, byte_offset));
|
||||
}
|
||||
|
||||
// 17. If byteLengthChecked is not empty, then
|
||||
// a. If offset + viewByteLength > bufferByteLength, throw a RangeError
|
||||
// exception.
|
||||
if (!length_tracking &&
|
||||
view_byte_offset + view_byte_length > buffer_byte_length) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewRangeError(MessageTemplate::kInvalidDataViewLength));
|
||||
}
|
||||
|
||||
// 21. Return O.
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,8 @@ TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
|
||||
LoadJSArrayBufferViewBuffer(receiver_array);
|
||||
|
||||
Label variable_length(this), normal(this);
|
||||
Branch(IsVariableLengthTypedArray(receiver_array), &variable_length, &normal);
|
||||
Branch(IsVariableLengthJSArrayBufferView(receiver_array), &variable_length,
|
||||
&normal);
|
||||
BIND(&variable_length);
|
||||
{
|
||||
Return(ChangeUintPtrToTagged(LoadVariableLengthJSTypedArrayByteLength(
|
||||
@ -155,8 +156,8 @@ TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
|
||||
|
||||
// Default to zero if the {receiver}s buffer was detached / out of bounds.
|
||||
Label detached_or_oob(this), not_detached_nor_oob(this);
|
||||
IsJSTypedArrayDetachedOrOutOfBounds(CAST(receiver), &detached_or_oob,
|
||||
¬_detached_nor_oob);
|
||||
IsJSArrayBufferViewDetachedOrOutOfBounds(CAST(receiver), &detached_or_oob,
|
||||
¬_detached_nor_oob);
|
||||
BIND(&detached_or_oob);
|
||||
Return(ChangeUintPtrToTagged(UintPtrConstant(0)));
|
||||
|
||||
|
@ -84,15 +84,32 @@ javascript builtin DataViewPrototypeGetBuffer(
|
||||
return dataView.buffer;
|
||||
}
|
||||
|
||||
extern macro IsJSArrayBufferViewDetachedOrOutOfBounds(JSArrayBufferView):
|
||||
never labels DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
|
||||
extern macro LoadVariableLengthJSArrayBufferViewByteLength(
|
||||
JSArrayBufferView, JSArrayBuffer): uintptr labels DetachedOrOutOfBounds;
|
||||
|
||||
// ES6 section 24.2.4.2 get DataView.prototype.byteLength
|
||||
javascript builtin DataViewPrototypeGetByteLength(
|
||||
js-implicit context: NativeContext, receiver: JSAny)(...arguments): Number {
|
||||
const dataView: JSDataView =
|
||||
ValidateDataView(context, receiver, 'get DataView.prototype.byte_length');
|
||||
if (WasDetached(dataView)) {
|
||||
ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameByteLength);
|
||||
if (IsVariableLengthJSArrayBufferView(dataView)) {
|
||||
try {
|
||||
const byteLength = LoadVariableLengthJSArrayBufferViewByteLength(
|
||||
dataView, dataView.buffer) otherwise DetachedOrOutOfBounds;
|
||||
return Convert<Number>(byteLength);
|
||||
} label DetachedOrOutOfBounds {
|
||||
ThrowTypeError(
|
||||
MessageTemplate::kDetachedOperation, kBuiltinNameByteLength);
|
||||
}
|
||||
} else {
|
||||
if (WasDetached(dataView)) {
|
||||
ThrowTypeError(
|
||||
MessageTemplate::kDetachedOperation, kBuiltinNameByteLength);
|
||||
}
|
||||
return Convert<Number>(dataView.byte_length);
|
||||
}
|
||||
return Convert<Number>(dataView.byte_length);
|
||||
}
|
||||
|
||||
// ES6 section 24.2.4.3 get DataView.prototype.byteOffset
|
||||
@ -100,10 +117,14 @@ javascript builtin DataViewPrototypeGetByteOffset(
|
||||
js-implicit context: NativeContext, receiver: JSAny)(...arguments): Number {
|
||||
const dataView: JSDataView =
|
||||
ValidateDataView(context, receiver, 'get DataView.prototype.byte_offset');
|
||||
if (WasDetached(dataView)) {
|
||||
try {
|
||||
IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
|
||||
otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
|
||||
} label DetachedOrOutOfBounds {
|
||||
ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameByteOffset);
|
||||
} label NotDetachedNorOutOfBounds {
|
||||
return Convert<Number>(dataView.byte_offset);
|
||||
}
|
||||
return Convert<Number>(dataView.byte_offset);
|
||||
}
|
||||
|
||||
extern macro BitcastInt32ToFloat32(uint32): float32;
|
||||
@ -373,28 +394,40 @@ transitioning macro DataViewGet(
|
||||
// 5. Let buffer be view.[[ViewedArrayBuffer]].
|
||||
const buffer: JSArrayBuffer = dataView.buffer;
|
||||
|
||||
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
if (IsDetachedBuffer(buffer)) {
|
||||
// 6. Let getBufferByteLength be
|
||||
// MakeIdempotentArrayBufferByteLengthGetter(Unordered).
|
||||
// 7. If IsViewOutOfBounds(view, getBufferByteLength) is true, throw a
|
||||
// TypeError exception.
|
||||
try {
|
||||
IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
|
||||
otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
|
||||
} label DetachedOrOutOfBounds {
|
||||
ThrowTypeError(
|
||||
MessageTemplate::kDetachedOperation,
|
||||
MakeDataViewGetterNameString(kind));
|
||||
}
|
||||
} label NotDetachedNorOutOfBounds {}
|
||||
|
||||
// 7. Let viewOffset be view.[[ByteOffset]].
|
||||
// 8. Let viewOffset be view.[[ByteOffset]].
|
||||
const viewOffset: uintptr = dataView.byte_offset;
|
||||
|
||||
// 8. Let viewSize be view.[[ByteLength]].
|
||||
const viewSize: uintptr = dataView.byte_length;
|
||||
// 9. Let viewSize be GetViewByteLength(view, getBufferByteLength).
|
||||
let viewSize: uintptr;
|
||||
if (dataView.bit_field.is_length_tracking) {
|
||||
viewSize = LoadVariableLengthJSArrayBufferViewByteLength(
|
||||
dataView, dataView.buffer) otherwise unreachable;
|
||||
} else {
|
||||
viewSize = dataView.byte_length;
|
||||
}
|
||||
|
||||
// 9. Let elementSize be the Element Size value specified in Table 62
|
||||
// 10. Let elementSize be the Element Size value specified in Table 62
|
||||
// for Element Type type.
|
||||
const elementSize: uintptr = DataViewElementSize(kind);
|
||||
|
||||
// 10. If getIndex + elementSize > viewSize, throw a RangeError exception.
|
||||
// 11. If getIndex + elementSize > viewSize, throw a RangeError exception.
|
||||
CheckIntegerIndexAdditionOverflow(getIndex, elementSize, viewSize)
|
||||
otherwise RangeError;
|
||||
|
||||
// 11. Let bufferIndex be getIndex + viewOffset.
|
||||
// 12. Let bufferIndex be getIndex + viewOffset.
|
||||
const bufferIndex: uintptr = getIndex + viewOffset;
|
||||
|
||||
if constexpr (kind == ElementsKind::UINT8_ELEMENTS) {
|
||||
@ -654,9 +687,6 @@ transitioning macro DataViewSet(
|
||||
// 3. Let getIndex be ? ToIndex(requestIndex).
|
||||
const getIndex: uintptr = ToIndex(requestIndex) otherwise RangeError;
|
||||
|
||||
const littleEndian: bool = ToBoolean(requestedLittleEndian);
|
||||
const buffer: JSArrayBuffer = dataView.buffer;
|
||||
|
||||
let numberValue: Numeric;
|
||||
if constexpr (
|
||||
kind == ElementsKind::BIGUINT64_ELEMENTS ||
|
||||
@ -669,28 +699,54 @@ transitioning macro DataViewSet(
|
||||
numberValue = ToNumber(context, value);
|
||||
}
|
||||
|
||||
// 6. Set isLittleEndian to !ToBoolean(isLittleEndian).
|
||||
const littleEndian: bool = ToBoolean(requestedLittleEndian);
|
||||
|
||||
// 7. Let buffer be view.[[ViewedArrayBuffer]].
|
||||
const buffer: JSArrayBuffer = dataView.buffer;
|
||||
|
||||
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
if (IsDetachedBuffer(buffer)) {
|
||||
ThrowTypeError(
|
||||
MessageTemplate::kDetachedOperation,
|
||||
MakeDataViewSetterNameString(kind));
|
||||
}
|
||||
// 8. Let getBufferByteLength be
|
||||
// MakeIdempotentArrayBufferByteLengthGetter(Unordered).
|
||||
// 9. NOTE: Bounds checking is not a synchronizing operation when view's
|
||||
// backing buffer is a growable SharedArrayBuffer.
|
||||
// 10. If IsViewOutOfBounds(view, getBufferByteLength) is true, throw a
|
||||
// TypeError exception.
|
||||
try {
|
||||
IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
|
||||
otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
|
||||
} label DetachedOrOutOfBounds {
|
||||
ThrowTypeError(
|
||||
MessageTemplate::kDetachedOperation,
|
||||
MakeDataViewGetterNameString(kind));
|
||||
} label NotDetachedNorOutOfBounds {}
|
||||
|
||||
// 9. Let viewOffset be view.[[ByteOffset]].
|
||||
// 11. Let viewOffset be view.[[ByteOffset]].
|
||||
const viewOffset: uintptr = dataView.byte_offset;
|
||||
|
||||
// 10. Let viewSize be view.[[ByteLength]].
|
||||
const viewSize: uintptr = dataView.byte_length;
|
||||
// 12. Let viewSize be GetViewByteLength(view, getBufferByteLength).
|
||||
let viewSize: uintptr;
|
||||
if (dataView.bit_field.is_length_tracking) {
|
||||
viewSize = LoadVariableLengthJSArrayBufferViewByteLength(
|
||||
dataView, dataView.buffer) otherwise unreachable;
|
||||
} else {
|
||||
viewSize = dataView.byte_length;
|
||||
}
|
||||
|
||||
// 11. Let elementSize be the Element Size value specified in Table 62
|
||||
// 13. Let elementSize be the Element Size value specified in Table 62
|
||||
// for Element Type type.
|
||||
const elementSize: uintptr = DataViewElementSize(kind);
|
||||
|
||||
// 12. If getIndex + elementSize > viewSize, throw a RangeError exception.
|
||||
// 14. If getIndex + elementSize > viewSize, throw a RangeError exception.
|
||||
CheckIntegerIndexAdditionOverflow(getIndex, elementSize, viewSize)
|
||||
otherwise RangeError;
|
||||
|
||||
// 13. Let bufferIndex be getIndex + viewOffset.
|
||||
// 15. Let bufferIndex be getIndex + viewOffset.
|
||||
const bufferIndex: uintptr = getIndex + viewOffset;
|
||||
|
||||
if constexpr (
|
||||
|
@ -180,17 +180,18 @@ extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr(
|
||||
JSTypedArray, ByteArray, uintptr): void;
|
||||
extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr(
|
||||
JSTypedArray, RawPtr, uintptr): void;
|
||||
extern macro IsJSTypedArrayDetachedOrOutOfBounds(JSTypedArray):
|
||||
never labels Detached, NotDetached;
|
||||
extern macro IsJSArrayBufferViewDetachedOrOutOfBounds(JSArrayBufferView):
|
||||
never labels DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
|
||||
|
||||
// AttachedJSTypedArray guards that the array's buffer is not detached.
|
||||
transient type AttachedJSTypedArray extends JSTypedArray;
|
||||
|
||||
macro EnsureAttached(array: JSTypedArray): AttachedJSTypedArray
|
||||
labels Detached {
|
||||
labels DetachedOrOutOfBounds {
|
||||
try {
|
||||
IsJSTypedArrayDetachedOrOutOfBounds(array) otherwise Detached, NotDetached;
|
||||
} label NotDetached {
|
||||
IsJSArrayBufferViewDetachedOrOutOfBounds(array)
|
||||
otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
|
||||
} label NotDetachedNorOutOfBounds {
|
||||
return %RawDownCast<AttachedJSTypedArray>(array);
|
||||
}
|
||||
}
|
||||
|
@ -13888,7 +13888,7 @@ TNode<UintPtrT> CodeStubAssembler::LoadJSTypedArrayLengthAndCheckDetached(
|
||||
TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(typed_array);
|
||||
|
||||
Label variable_length(this), fixed_length(this), end(this);
|
||||
Branch(IsVariableLengthTypedArray(typed_array), &variable_length,
|
||||
Branch(IsVariableLengthJSArrayBufferView(typed_array), &variable_length,
|
||||
&fixed_length);
|
||||
BIND(&variable_length);
|
||||
{
|
||||
@ -13911,36 +13911,55 @@ TNode<UintPtrT> CodeStubAssembler::LoadJSTypedArrayLengthAndCheckDetached(
|
||||
|
||||
// ES #sec-integerindexedobjectlength
|
||||
TNode<UintPtrT> CodeStubAssembler::LoadVariableLengthJSTypedArrayLength(
|
||||
TNode<JSTypedArray> array, TNode<JSArrayBuffer> buffer, Label* miss) {
|
||||
TNode<JSTypedArray> array, TNode<JSArrayBuffer> buffer,
|
||||
Label* detached_or_out_of_bounds) {
|
||||
// byte_length already takes array's offset into account.
|
||||
TNode<UintPtrT> byte_length = LoadVariableLengthJSArrayBufferViewByteLength(
|
||||
array, buffer, detached_or_out_of_bounds);
|
||||
TNode<IntPtrT> element_size =
|
||||
RabGsabElementsKindToElementByteSize(LoadElementsKind(array));
|
||||
return Unsigned(IntPtrDiv(Signed(byte_length), element_size));
|
||||
}
|
||||
|
||||
TNode<UintPtrT>
|
||||
CodeStubAssembler::LoadVariableLengthJSArrayBufferViewByteLength(
|
||||
TNode<JSArrayBufferView> array, TNode<JSArrayBuffer> buffer,
|
||||
Label* detached_or_out_of_bounds) {
|
||||
Label is_gsab(this), is_rab(this), end(this);
|
||||
TVARIABLE(UintPtrT, result);
|
||||
TNode<UintPtrT> array_byte_offset = LoadJSArrayBufferViewByteOffset(array);
|
||||
|
||||
Branch(IsSharedArrayBuffer(buffer), &is_gsab, &is_rab);
|
||||
BIND(&is_gsab);
|
||||
{
|
||||
// Non-length-tracking GSAB-backed TypedArrays shouldn't end up here.
|
||||
CSA_DCHECK(this, IsLengthTrackingTypedArray(array));
|
||||
// Non-length-tracking GSAB-backed ArrayBufferViews shouldn't end up here.
|
||||
CSA_DCHECK(this, IsLengthTrackingJSArrayBufferView(array));
|
||||
// Read the byte length from the BackingStore.
|
||||
const TNode<ExternalReference> length_function = ExternalConstant(
|
||||
ExternalReference::length_tracking_gsab_backed_typed_array_length());
|
||||
const TNode<ExternalReference> byte_length_function =
|
||||
ExternalConstant(ExternalReference::gsab_byte_length());
|
||||
TNode<ExternalReference> isolate_ptr =
|
||||
ExternalConstant(ExternalReference::isolate_address(isolate()));
|
||||
result = UncheckedCast<UintPtrT>(
|
||||
CallCFunction(length_function, MachineType::UintPtr(),
|
||||
TNode<UintPtrT> buffer_byte_length = UncheckedCast<UintPtrT>(
|
||||
CallCFunction(byte_length_function, MachineType::UintPtr(),
|
||||
std::make_pair(MachineType::Pointer(), isolate_ptr),
|
||||
std::make_pair(MachineType::AnyTagged(), array)));
|
||||
std::make_pair(MachineType::AnyTagged(), buffer)));
|
||||
// Since the SharedArrayBuffer can't shrink, and we've managed to create
|
||||
// this JSArrayBufferDataView without throwing an exception, we know that
|
||||
// buffer_byte_length >= array_byte_offset.
|
||||
CSA_CHECK(this,
|
||||
UintPtrGreaterThanOrEqual(buffer_byte_length, array_byte_offset));
|
||||
result = UintPtrSub(buffer_byte_length, array_byte_offset);
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&is_rab);
|
||||
{
|
||||
GotoIf(IsDetachedBuffer(buffer), miss);
|
||||
GotoIf(IsDetachedBuffer(buffer), detached_or_out_of_bounds);
|
||||
|
||||
TNode<UintPtrT> buffer_byte_length = LoadJSArrayBufferByteLength(buffer);
|
||||
TNode<UintPtrT> array_byte_offset = LoadJSArrayBufferViewByteOffset(array);
|
||||
|
||||
Label is_length_tracking(this), not_length_tracking(this);
|
||||
Branch(IsLengthTrackingTypedArray(array), &is_length_tracking,
|
||||
Branch(IsLengthTrackingJSArrayBufferView(array), &is_length_tracking,
|
||||
¬_length_tracking);
|
||||
|
||||
BIND(&is_length_tracking);
|
||||
@ -13948,16 +13967,8 @@ TNode<UintPtrT> CodeStubAssembler::LoadVariableLengthJSTypedArrayLength(
|
||||
// The backing RAB might have been shrunk so that the start of the
|
||||
// TypedArray is already out of bounds.
|
||||
GotoIfNot(UintPtrLessThanOrEqual(array_byte_offset, buffer_byte_length),
|
||||
miss);
|
||||
// length = (buffer_byte_length - byte_offset) / element_size
|
||||
// Conversion to signed is OK since buffer_byte_length <
|
||||
// JSArrayBuffer::kMaxByteLength.
|
||||
TNode<IntPtrT> element_size =
|
||||
RabGsabElementsKindToElementByteSize(LoadElementsKind(array));
|
||||
TNode<IntPtrT> length =
|
||||
IntPtrDiv(Signed(UintPtrSub(buffer_byte_length, array_byte_offset)),
|
||||
element_size);
|
||||
result = Unsigned(length);
|
||||
detached_or_out_of_bounds);
|
||||
result = UintPtrSub(buffer_byte_length, array_byte_offset);
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
@ -13970,8 +13981,8 @@ TNode<UintPtrT> CodeStubAssembler::LoadVariableLengthJSTypedArrayLength(
|
||||
GotoIfNot(UintPtrGreaterThanOrEqual(
|
||||
buffer_byte_length,
|
||||
UintPtrAdd(array_byte_offset, array_byte_length)),
|
||||
miss);
|
||||
result = LoadJSTypedArrayLength(array);
|
||||
detached_or_out_of_bounds);
|
||||
result = array_byte_length;
|
||||
Goto(&end);
|
||||
}
|
||||
}
|
||||
@ -13979,13 +13990,13 @@ TNode<UintPtrT> CodeStubAssembler::LoadVariableLengthJSTypedArrayLength(
|
||||
return result.value();
|
||||
}
|
||||
|
||||
void CodeStubAssembler::IsJSTypedArrayDetachedOrOutOfBounds(
|
||||
TNode<JSTypedArray> array, Label* detached_or_oob,
|
||||
void CodeStubAssembler::IsJSArrayBufferViewDetachedOrOutOfBounds(
|
||||
TNode<JSArrayBufferView> array, Label* detached_or_oob,
|
||||
Label* not_detached_nor_oob) {
|
||||
TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(array);
|
||||
|
||||
GotoIf(IsDetachedBuffer(buffer), detached_or_oob);
|
||||
GotoIfNot(IsVariableLengthTypedArray(array), not_detached_nor_oob);
|
||||
GotoIfNot(IsVariableLengthJSArrayBufferView(array), not_detached_nor_oob);
|
||||
GotoIf(IsSharedArrayBuffer(buffer), not_detached_nor_oob);
|
||||
|
||||
{
|
||||
@ -13993,7 +14004,7 @@ void CodeStubAssembler::IsJSTypedArrayDetachedOrOutOfBounds(
|
||||
TNode<UintPtrT> array_byte_offset = LoadJSArrayBufferViewByteOffset(array);
|
||||
|
||||
Label length_tracking(this), not_length_tracking(this);
|
||||
Branch(IsLengthTrackingTypedArray(array), &length_tracking,
|
||||
Branch(IsLengthTrackingJSArrayBufferView(array), &length_tracking,
|
||||
¬_length_tracking);
|
||||
|
||||
BIND(&length_tracking);
|
||||
|
@ -3609,15 +3609,20 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
// Helper for length tracking JSTypedArrays and JSTypedArrays backed by
|
||||
// ResizableArrayBuffer.
|
||||
TNode<UintPtrT> LoadVariableLengthJSTypedArrayLength(
|
||||
TNode<JSTypedArray> array, TNode<JSArrayBuffer> buffer, Label* miss);
|
||||
TNode<JSTypedArray> array, TNode<JSArrayBuffer> buffer,
|
||||
Label* detached_or_out_of_bounds);
|
||||
// Helper for length tracking JSTypedArrays and JSTypedArrays backed by
|
||||
// ResizableArrayBuffer.
|
||||
TNode<UintPtrT> LoadVariableLengthJSTypedArrayByteLength(
|
||||
TNode<Context> context, TNode<JSTypedArray> array,
|
||||
TNode<JSArrayBuffer> buffer);
|
||||
void IsJSTypedArrayDetachedOrOutOfBounds(TNode<JSTypedArray> array,
|
||||
Label* detached_or_oob,
|
||||
Label* not_detached_nor_oob);
|
||||
TNode<UintPtrT> LoadVariableLengthJSArrayBufferViewByteLength(
|
||||
TNode<JSArrayBufferView> array, TNode<JSArrayBuffer> buffer,
|
||||
Label* detached_or_out_of_bounds);
|
||||
|
||||
void IsJSArrayBufferViewDetachedOrOutOfBounds(TNode<JSArrayBufferView> array,
|
||||
Label* detached_or_oob,
|
||||
Label* not_detached_nor_oob);
|
||||
|
||||
TNode<IntPtrT> RabGsabElementsKindToElementByteSize(
|
||||
TNode<Int32T> elementsKind);
|
||||
|
@ -878,8 +878,7 @@ ExternalReference ExternalReference::search_string_raw() {
|
||||
FUNCTION_REFERENCE(jsarray_array_join_concat_to_sequential_string,
|
||||
JSArray::ArrayJoinConcatToSequentialString)
|
||||
|
||||
FUNCTION_REFERENCE(length_tracking_gsab_backed_typed_array_length,
|
||||
JSTypedArray::LengthTrackingGsabBackedTypedArrayLength)
|
||||
FUNCTION_REFERENCE(gsab_byte_length, JSArrayBuffer::GsabByteLength)
|
||||
|
||||
ExternalReference ExternalReference::search_string_raw_one_one() {
|
||||
return search_string_raw<const uint8_t, const uint8_t>();
|
||||
|
@ -134,6 +134,7 @@ class StatsCounter;
|
||||
V(f64_mod_wrapper_function, "f64_mod_wrapper") \
|
||||
V(get_date_field_function, "JSDate::GetField") \
|
||||
V(get_or_create_hash_raw, "get_or_create_hash_raw") \
|
||||
V(gsab_byte_length, "GsabByteLength") \
|
||||
V(ieee754_acos_function, "base::ieee754::acos") \
|
||||
V(ieee754_acosh_function, "base::ieee754::acosh") \
|
||||
V(ieee754_asin_function, "base::ieee754::asin") \
|
||||
@ -163,8 +164,6 @@ class StatsCounter;
|
||||
V(jsarray_array_join_concat_to_sequential_string, \
|
||||
"jsarray_array_join_concat_to_sequential_string") \
|
||||
V(jsreceiver_create_identity_hash, "jsreceiver_create_identity_hash") \
|
||||
V(length_tracking_gsab_backed_typed_array_length, \
|
||||
"LengthTrackingGsabBackedTypedArrayLength") \
|
||||
V(libc_memchr_function, "libc_memchr") \
|
||||
V(libc_memcpy_function, "libc_memcpy") \
|
||||
V(libc_memmove_function, "libc_memmove") \
|
||||
|
@ -350,7 +350,7 @@ namespace internal {
|
||||
T(InvalidCountValue, "Invalid count value") \
|
||||
T(InvalidDataViewAccessorOffset, \
|
||||
"Offset is outside the bounds of the DataView") \
|
||||
T(InvalidDataViewLength, "Invalid DataView length %") \
|
||||
T(InvalidDataViewLength, "Invalid DataView length") \
|
||||
T(InvalidOffset, "Start offset % is outside the bounds of the buffer") \
|
||||
T(InvalidHint, "Invalid hint: %") \
|
||||
T(InvalidIndex, "Invalid value: not (convertible to) a safe integer") \
|
||||
|
@ -2905,6 +2905,9 @@ Handle<JSDataView> Factory::NewJSDataView(Handle<JSArrayBuffer> buffer,
|
||||
map, empty_fixed_array(), buffer, byte_offset, byte_length));
|
||||
obj->set_data_pointer(
|
||||
isolate(), static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
|
||||
// TODO(v8:11111): Support creating length tracking DataViews via the API.
|
||||
obj->set_is_length_tracking(false);
|
||||
obj->set_is_backed_by_rab(!buffer->is_shared() && buffer->is_resizable());
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -178,12 +178,12 @@ bool JSArrayBufferView::WasDetached() const {
|
||||
return JSArrayBuffer::cast(buffer()).was_detached();
|
||||
}
|
||||
|
||||
BIT_FIELD_ACCESSORS(JSTypedArray, bit_field, is_length_tracking,
|
||||
JSTypedArray::IsLengthTrackingBit)
|
||||
BIT_FIELD_ACCESSORS(JSTypedArray, bit_field, is_backed_by_rab,
|
||||
JSTypedArray::IsBackedByRabBit)
|
||||
BIT_FIELD_ACCESSORS(JSArrayBufferView, bit_field, is_length_tracking,
|
||||
JSArrayBufferView::IsLengthTrackingBit)
|
||||
BIT_FIELD_ACCESSORS(JSArrayBufferView, bit_field, is_backed_by_rab,
|
||||
JSArrayBufferView::IsBackedByRabBit)
|
||||
|
||||
bool JSTypedArray::IsVariableLength() const {
|
||||
bool JSArrayBufferView::IsVariableLength() const {
|
||||
return is_length_tracking() || is_backed_by_rab();
|
||||
}
|
||||
|
||||
|
@ -141,6 +141,19 @@ size_t JSArrayBuffer::GetByteLength() const {
|
||||
return byte_length();
|
||||
}
|
||||
|
||||
size_t JSArrayBuffer::GsabByteLength(Isolate* isolate,
|
||||
Address raw_array_buffer) {
|
||||
// TODO(v8:11111): Cache the last seen length in JSArrayBuffer and use it
|
||||
// in bounds checks to minimize the need for calling this function.
|
||||
DCHECK(FLAG_harmony_rab_gsab);
|
||||
DisallowGarbageCollection no_gc;
|
||||
DisallowJavascriptExecution no_js(isolate);
|
||||
JSArrayBuffer buffer = JSArrayBuffer::cast(Object(raw_array_buffer));
|
||||
CHECK(buffer.is_resizable());
|
||||
CHECK(buffer.is_shared());
|
||||
return buffer.GetBackingStore()->byte_length(std::memory_order_seq_cst);
|
||||
}
|
||||
|
||||
ArrayBufferExtension* JSArrayBuffer::EnsureExtension() {
|
||||
ArrayBufferExtension* extension = this->extension();
|
||||
if (extension != nullptr) return extension;
|
||||
|
@ -108,6 +108,8 @@ class JSArrayBuffer
|
||||
|
||||
size_t GetByteLength() const;
|
||||
|
||||
static size_t GsabByteLength(Isolate* isolate, Address raw_array_buffer);
|
||||
|
||||
// Allocates an ArrayBufferExtension for this array buffer, unless it is
|
||||
// already associated with an extension.
|
||||
ArrayBufferExtension* EnsureExtension();
|
||||
@ -236,8 +238,15 @@ class JSArrayBufferView
|
||||
|
||||
DECL_VERIFIER(JSArrayBufferView)
|
||||
|
||||
// Bit positions for [bit_field].
|
||||
DEFINE_TORQUE_GENERATED_JS_ARRAY_BUFFER_VIEW_FLAGS()
|
||||
|
||||
inline bool WasDetached() const;
|
||||
|
||||
DECL_BOOLEAN_ACCESSORS(is_length_tracking)
|
||||
DECL_BOOLEAN_ACCESSORS(is_backed_by_rab)
|
||||
inline bool IsVariableLength() const;
|
||||
|
||||
static constexpr int kEndOfTaggedFieldsOffset = kByteOffsetOffset;
|
||||
|
||||
STATIC_ASSERT(IsAligned(kByteOffsetOffset, kUIntptrSize));
|
||||
@ -253,9 +262,6 @@ class JSTypedArray
|
||||
// eventually.
|
||||
static constexpr size_t kMaxLength = v8::TypedArray::kMaxLength;
|
||||
|
||||
// Bit positions for [bit_field].
|
||||
DEFINE_TORQUE_GENERATED_JS_TYPED_ARRAY_FLAGS()
|
||||
|
||||
// [length]: length of typed array in elements.
|
||||
DECL_PRIMITIVE_GETTER(length, size_t)
|
||||
|
||||
@ -287,9 +293,6 @@ class JSTypedArray
|
||||
inline bool is_on_heap() const;
|
||||
inline bool is_on_heap(AcquireLoadTag tag) const;
|
||||
|
||||
DECL_BOOLEAN_ACCESSORS(is_length_tracking)
|
||||
DECL_BOOLEAN_ACCESSORS(is_backed_by_rab)
|
||||
inline bool IsVariableLength() const;
|
||||
inline size_t GetLengthOrOutOfBounds(bool& out_of_bounds) const;
|
||||
inline size_t GetLength() const;
|
||||
|
||||
@ -332,8 +335,9 @@ class JSTypedArray
|
||||
DECL_PRINTER(JSTypedArray)
|
||||
DECL_VERIFIER(JSTypedArray)
|
||||
|
||||
STATIC_ASSERT(IsAligned(kLengthOffset, kUIntptrSize));
|
||||
STATIC_ASSERT(IsAligned(kExternalPointerOffset, kSystemPointerSize));
|
||||
// TODO(v8:9287): Re-enable when GCMole stops mixing 32/64 bit configs.
|
||||
// STATIC_ASSERT(IsAligned(kLengthOffset, kTaggedSize));
|
||||
// STATIC_ASSERT(IsAligned(kExternalPointerOffset, kTaggedSize));
|
||||
|
||||
static const int kSizeWithEmbedderFields =
|
||||
kHeaderSize +
|
||||
@ -379,7 +383,8 @@ class JSDataView
|
||||
DECL_PRINTER(JSDataView)
|
||||
DECL_VERIFIER(JSDataView)
|
||||
|
||||
STATIC_ASSERT(IsAligned(kDataPointerOffset, kUIntptrSize));
|
||||
// TODO(v8:9287): Re-enable when GCMole stops mixing 32/64 bit configs.
|
||||
// STATIC_ASSERT(IsAligned(kDataPointerOffset, kTaggedSize));
|
||||
|
||||
static const int kSizeWithEmbedderFields =
|
||||
kHeaderSize +
|
||||
|
@ -40,43 +40,44 @@ macro IsResizableArrayBuffer(buffer: JSArrayBuffer): bool {
|
||||
return buffer.bit_field.is_resizable;
|
||||
}
|
||||
|
||||
// We have 4 different DataViews & TypedArrays:
|
||||
// 1) Normal (backed by AB / SAB) or non-length tracking backed by GSAB (can't
|
||||
// go oob once constructed)
|
||||
// 2) Non-length tracking backed by RAB (can go oob once constructed)
|
||||
// 3) Length-tracking backed by RAB (JSArrayBuffer stores the length)
|
||||
// 4) Length-tracking backed by GSAB (BackingStore stores the length)
|
||||
bitfield struct JSArrayBufferViewFlags extends uint32 {
|
||||
is_length_tracking: bool: 1 bit;
|
||||
is_backed_by_rab: bool: 1 bit;
|
||||
}
|
||||
|
||||
@abstract
|
||||
extern class JSArrayBufferView extends JSObject {
|
||||
buffer: JSArrayBuffer;
|
||||
byte_offset: uintptr;
|
||||
byte_length: uintptr;
|
||||
}
|
||||
|
||||
// We have 4 different TypedArrays:
|
||||
// 1) Normal (backed by AB / SAB) or non-length tracking backed by GSAB (can't
|
||||
// go oob once constructed) 2) Non-length tracking backed by RAB (can go oob
|
||||
// once constructed) 3) Length-tracking backed by RAB (JSArrayBuffer stores the
|
||||
// length) 4) Length-tracking backed by GSAB (BackingStore stores the length)
|
||||
bitfield struct JSTypedArrayFlags extends uint32 {
|
||||
is_length_tracking: bool: 1 bit;
|
||||
is_backed_by_rab: bool: 1 bit;
|
||||
}
|
||||
|
||||
extern class JSTypedArray extends JSArrayBufferView {
|
||||
length: uintptr;
|
||||
external_pointer: ExternalPointer;
|
||||
base_pointer: ByteArray|Smi;
|
||||
bit_field: JSTypedArrayFlags;
|
||||
bit_field: JSArrayBufferViewFlags;
|
||||
// Pads header size to be a multiple of kTaggedSize.
|
||||
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
|
||||
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
|
||||
}
|
||||
|
||||
@export
|
||||
macro IsVariableLengthTypedArray(array: JSTypedArray): bool {
|
||||
macro IsVariableLengthJSArrayBufferView(array: JSArrayBufferView): bool {
|
||||
return array.bit_field.is_length_tracking || array.bit_field.is_backed_by_rab;
|
||||
}
|
||||
|
||||
@export
|
||||
macro IsLengthTrackingTypedArray(array: JSTypedArray): bool {
|
||||
macro IsLengthTrackingJSArrayBufferView(array: JSArrayBufferView): bool {
|
||||
return array.bit_field.is_length_tracking;
|
||||
}
|
||||
|
||||
extern class JSTypedArray extends JSArrayBufferView {
|
||||
length: uintptr;
|
||||
external_pointer: ExternalPointer;
|
||||
base_pointer: ByteArray|Smi;
|
||||
}
|
||||
|
||||
extern class JSDataView extends JSArrayBufferView {
|
||||
data_pointer: ExternalPointer;
|
||||
}
|
||||
|
@ -938,6 +938,7 @@ Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView view) {
|
||||
WriteVarint(static_cast<uint8_t>(tag));
|
||||
WriteVarint(static_cast<uint32_t>(view.byte_offset()));
|
||||
WriteVarint(static_cast<uint32_t>(view.byte_length()));
|
||||
WriteVarint(static_cast<uint8_t>(view.bit_field()));
|
||||
return ThrowIfOutOfMemory();
|
||||
}
|
||||
|
||||
@ -1862,10 +1863,11 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
|
||||
uint8_t tag = 0;
|
||||
uint32_t byte_offset = 0;
|
||||
uint32_t byte_length = 0;
|
||||
uint8_t flags = 0;
|
||||
if (!ReadVarint<uint8_t>().To(&tag) ||
|
||||
!ReadVarint<uint32_t>().To(&byte_offset) ||
|
||||
!ReadVarint<uint32_t>().To(&byte_length) ||
|
||||
byte_offset > buffer_byte_length ||
|
||||
!ReadVarint<uint8_t>().To(&flags) || byte_offset > buffer_byte_length ||
|
||||
byte_length > buffer_byte_length - byte_offset) {
|
||||
return MaybeHandle<JSArrayBufferView>();
|
||||
}
|
||||
@ -1878,6 +1880,7 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
|
||||
Handle<JSDataView> data_view =
|
||||
isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length);
|
||||
AddObjectWithID(id, data_view);
|
||||
data_view->set_bit_field(flags);
|
||||
return data_view;
|
||||
}
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
|
||||
@ -1894,6 +1897,7 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
|
||||
}
|
||||
Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray(
|
||||
external_array_type, buffer, byte_offset, byte_length / element_size);
|
||||
typed_array->set_bit_field(flags);
|
||||
AddObjectWithID(id, typed_array);
|
||||
return typed_array;
|
||||
}
|
||||
|
113
test/mjsunit/dataview-growablesharedarraybuffer.js
Normal file
113
test/mjsunit/dataview-growablesharedarraybuffer.js
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2021 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-rab-gsab --allow-natives-syntax
|
||||
|
||||
"use strict";
|
||||
|
||||
d8.file.execute('test/mjsunit/typedarray-helpers.js');
|
||||
|
||||
(function DataViewPrototype() {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(40, 80);
|
||||
const sab = new SharedArrayBuffer(80);
|
||||
|
||||
const dvGsab = new DataView(gsab, 0, 3);
|
||||
const dvSab = new DataView(sab, 0, 3);
|
||||
assertEquals(dvGsab.__proto__, dvSab.__proto__);
|
||||
})();
|
||||
|
||||
(function DataViewByteLength() {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(40, 80);
|
||||
|
||||
const dv = new DataView(gsab, 0, 3);
|
||||
assertEquals(gsab, dv.buffer);
|
||||
assertEquals(3, dv.byteLength);
|
||||
|
||||
const emptyDv = new DataView(gsab, 0, 0);
|
||||
assertEquals(gsab, emptyDv.buffer);
|
||||
assertEquals(0, emptyDv.byteLength);
|
||||
|
||||
const dvWithOffset = new DataView(gsab, 2, 3);
|
||||
assertEquals(gsab, dvWithOffset.buffer);
|
||||
assertEquals(3, dvWithOffset.byteLength);
|
||||
|
||||
const emptyDvWithOffset = new DataView(gsab, 2, 0);
|
||||
assertEquals(gsab, emptyDvWithOffset.buffer);
|
||||
assertEquals(0, emptyDvWithOffset.byteLength);
|
||||
|
||||
const lengthTracking = new DataView(gsab);
|
||||
assertEquals(gsab, lengthTracking.buffer);
|
||||
assertEquals(40, lengthTracking.byteLength);
|
||||
|
||||
const offset = 8;
|
||||
const lengthTrackingWithOffset = new DataView(gsab, offset);
|
||||
assertEquals(gsab, lengthTrackingWithOffset.buffer);
|
||||
assertEquals(40 - offset, lengthTrackingWithOffset.byteLength);
|
||||
|
||||
const emptyLengthTrackingWithOffset = new DataView(gsab, 40);
|
||||
assertEquals(gsab, emptyLengthTrackingWithOffset.buffer);
|
||||
assertEquals(0, emptyLengthTrackingWithOffset.byteLength);
|
||||
})();
|
||||
|
||||
(function ConstructInvalid() {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(40, 80);
|
||||
|
||||
// Length too big.
|
||||
assertThrows(() => { new DataView(gsab, 0, 41); }, RangeError);
|
||||
|
||||
// Offset too close to the end.
|
||||
assertThrows(() => { new DataView(gsab, 39, 2); }, RangeError);
|
||||
|
||||
// Offset beyond end.
|
||||
assertThrows(() => { new DataView(gsab, 40, 1); }, RangeError);
|
||||
})();
|
||||
|
||||
(function ConstructorParameterConversionGrows() {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(40, 80);
|
||||
const evil = { valueOf: () => {
|
||||
gsab.grow(50);
|
||||
return 0;
|
||||
}};
|
||||
|
||||
// Constructing will fail unless we take the new size into account.
|
||||
const dv = new DataView(gsab, evil, 50);
|
||||
assertEquals(50, dv.byteLength);
|
||||
})();
|
||||
|
||||
(function GetAndSet() {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(64, 128);
|
||||
const fixedLength = new DataView(gsab, 0, 32);
|
||||
const fixedLengthWithOffset = new DataView(gsab, 2, 32);
|
||||
const lengthTracking = new DataView(gsab, 0);
|
||||
const lengthTrackingWithOffset = new DataView(gsab, 2);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLength, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLength, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLengthWithOffset, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTracking, 64);
|
||||
assertAllDataViewMethodsThrow(lengthTracking, 65, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 64 - 2);
|
||||
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 64 - 2 + 1,
|
||||
RangeError);
|
||||
|
||||
// Grow.
|
||||
gsab.grow(100);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLength, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLength, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLengthWithOffset, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTracking, 100);
|
||||
assertAllDataViewMethodsThrow(lengthTracking, 101, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 100 - 2);
|
||||
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 100 - 2 + 1,
|
||||
RangeError);
|
||||
})();
|
193
test/mjsunit/dataview-resizablearraybuffer-detach.js
Normal file
193
test/mjsunit/dataview-resizablearraybuffer-detach.js
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright 2021 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-rab-gsab --allow-natives-syntax
|
||||
|
||||
"use strict";
|
||||
|
||||
d8.file.execute('test/mjsunit/typedarray-helpers.js');
|
||||
|
||||
(function ConstructorThrowsIfBufferDetached() {
|
||||
const rab = CreateResizableArrayBuffer(40, 80);
|
||||
%ArrayBufferDetach(rab);
|
||||
|
||||
assertThrows(() => { new DataView(rab); }, TypeError);
|
||||
})();
|
||||
|
||||
(function TypedArrayLengthAndByteLength() {
|
||||
const rab = CreateResizableArrayBuffer(40, 80);
|
||||
|
||||
let dvs = [];
|
||||
dvs.push(new DataView(rab, 0, 3));
|
||||
dvs.push(new DataView(rab, 8, 3));
|
||||
dvs.push(new DataView(rab));
|
||||
dvs.push(new DataView(rab, 8));
|
||||
|
||||
%ArrayBufferDetach(rab);
|
||||
|
||||
for (let dv of dvs) {
|
||||
assertThrows(() => { dv.byteLength });
|
||||
}
|
||||
})();
|
||||
|
||||
(function AccessDetachedDataView() {
|
||||
const rab = CreateResizableArrayBuffer(64, 128);
|
||||
|
||||
const fixedLength = new DataView(rab, 0, 32);
|
||||
const fixedLengthWithOffset = new DataView(rab, 2, 32);
|
||||
const lengthTracking = new DataView(rab, 0);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 2);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLength, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLength, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLengthWithOffset, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTracking, 64);
|
||||
assertAllDataViewMethodsThrow(lengthTracking, 65, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 64 - 2);
|
||||
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 64 - 2 + 1,
|
||||
RangeError);
|
||||
|
||||
%ArrayBufferDetach(rab);
|
||||
|
||||
assertAllDataViewMethodsThrow(fixedLength, 0, TypeError);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 0, TypeError);
|
||||
assertAllDataViewMethodsThrow(lengthTracking, 0, TypeError);
|
||||
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 0, TypeError);
|
||||
})();
|
||||
|
||||
(function GetParameterConversionDetaches() {
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLength = new DataView(rab, 0, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLength.getUint8(evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLengthWithOffset.getUint8(evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTracking = new DataView(rab);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { lengthTracking.getUint8(evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 2);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { lengthTrackingWithOffset.getUint8(evil); },
|
||||
TypeError);
|
||||
}
|
||||
})();
|
||||
|
||||
(function SetParameterConversionDetaches() {
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLength = new DataView(rab, 0, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLength.setUint8(evil, 0); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLengthWithOffset.setUint8(evil, 0); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTracking = new DataView(rab);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { lengthTracking.setUint8(evil, 0); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 2);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { lengthTrackingWithOffset.setUint8(evil, 0); },
|
||||
TypeError);
|
||||
}
|
||||
|
||||
// The same tests as before, except now the "detaching" parameter is the
|
||||
// second one, not the first one.
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLength = new DataView(rab, 0, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLength.setUint8(0, evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLengthWithOffset.setUint8(0, evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTracking = new DataView(rab);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { lengthTracking.setUint8(0, evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 2);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { lengthTrackingWithOffset.setUint8(0, evil); },
|
||||
TypeError);
|
||||
}
|
||||
})();
|
434
test/mjsunit/dataview-resizablearraybuffer.js
Normal file
434
test/mjsunit/dataview-resizablearraybuffer.js
Normal file
@ -0,0 +1,434 @@
|
||||
// Copyright 2021 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-rab-gsab --allow-natives-syntax
|
||||
|
||||
"use strict";
|
||||
|
||||
d8.file.execute('test/mjsunit/typedarray-helpers.js');
|
||||
|
||||
(function DataViewPrototype() {
|
||||
const rab = CreateResizableArrayBuffer(40, 80);
|
||||
const ab = new ArrayBuffer(80);
|
||||
|
||||
const dvRab = new DataView(rab, 0, 3);
|
||||
const dvAb = new DataView(ab, 0, 3);
|
||||
assertEquals(dvRab.__proto__, dvAb.__proto__);
|
||||
})();
|
||||
|
||||
(function DataViewByteLength() {
|
||||
const rab = CreateResizableArrayBuffer(40, 80);
|
||||
|
||||
const dv = new DataView(rab, 0, 3);
|
||||
assertEquals(rab, dv.buffer);
|
||||
assertEquals(3, dv.byteLength);
|
||||
|
||||
const emptyDv = new DataView(rab, 0, 0);
|
||||
assertEquals(rab, emptyDv.buffer);
|
||||
assertEquals(0, emptyDv.byteLength);
|
||||
|
||||
const dvWithOffset = new DataView(rab, 2, 3);
|
||||
assertEquals(rab, dvWithOffset.buffer);
|
||||
assertEquals(3, dvWithOffset.byteLength);
|
||||
|
||||
const emptyDvWithOffset = new DataView(rab, 2, 0);
|
||||
assertEquals(rab, emptyDvWithOffset.buffer);
|
||||
assertEquals(0, emptyDvWithOffset.byteLength);
|
||||
|
||||
const lengthTracking = new DataView(rab);
|
||||
assertEquals(rab, lengthTracking.buffer);
|
||||
assertEquals(40, lengthTracking.byteLength);
|
||||
|
||||
const offset = 8;
|
||||
const lengthTrackingWithOffset = new DataView(rab, offset);
|
||||
assertEquals(rab, lengthTrackingWithOffset.buffer);
|
||||
assertEquals(40 - offset, lengthTrackingWithOffset.byteLength);
|
||||
|
||||
const emptyLengthTrackingWithOffset = new DataView(rab, 40);
|
||||
assertEquals(rab, emptyLengthTrackingWithOffset.buffer);
|
||||
assertEquals(0, emptyLengthTrackingWithOffset.byteLength);
|
||||
})();
|
||||
|
||||
(function ConstructInvalid() {
|
||||
const rab = CreateResizableArrayBuffer(40, 80);
|
||||
|
||||
// Length too big.
|
||||
assertThrows(() => { new DataView(rab, 0, 41); }, RangeError);
|
||||
|
||||
// Offset too close to the end.
|
||||
assertThrows(() => { new DataView(rab, 39, 2); }, RangeError);
|
||||
|
||||
// Offset beyond end.
|
||||
assertThrows(() => { new DataView(rab, 40, 1); }, RangeError);
|
||||
})();
|
||||
|
||||
(function ConstructorParameterConversionShrinks() {
|
||||
const rab = CreateResizableArrayBuffer(40, 80);
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
|
||||
assertThrows(() => { new DataView(rab, evil, 20);}, RangeError);
|
||||
})();
|
||||
|
||||
(function ConstructorParameterConversionGrows() {
|
||||
const gsab = CreateResizableArrayBuffer(40, 80);
|
||||
const evil = { valueOf: () => {
|
||||
gsab.resize(50);
|
||||
return 0;
|
||||
}};
|
||||
|
||||
// Constructing will fail unless we take the new size into account.
|
||||
const dv = new DataView(gsab, evil, 50);
|
||||
assertEquals(50, dv.byteLength);
|
||||
})();
|
||||
|
||||
(function OrdinaryCreateFromConstructorShrinks() {
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(16, 40);
|
||||
const newTarget = function() {}.bind(null);
|
||||
Object.defineProperty(newTarget, "prototype", {
|
||||
get() {
|
||||
rab.resize(8);
|
||||
return DataView.prototype;
|
||||
}
|
||||
});
|
||||
assertThrows(() => {Reflect.construct(DataView, [rab, 0, 16], newTarget); },
|
||||
RangeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(16, 40);
|
||||
const newTarget = function() {}.bind(null);
|
||||
Object.defineProperty(newTarget, "prototype", {
|
||||
get() {
|
||||
rab.resize(6);
|
||||
return DataView.prototype;
|
||||
}
|
||||
});
|
||||
assertThrows(() => {Reflect.construct(DataView, [rab, 8, 2], newTarget); },
|
||||
RangeError);
|
||||
}
|
||||
})();
|
||||
|
||||
(function DataViewByteLengthWhenResizedOutOfBounds1() {
|
||||
const rab = CreateResizableArrayBuffer(16, 40);
|
||||
|
||||
const fixedLength = new DataView(rab, 0, 8);
|
||||
const lengthTracking = new DataView(rab);
|
||||
|
||||
assertEquals(8, fixedLength.byteLength);
|
||||
assertEquals(16, lengthTracking.byteLength);
|
||||
|
||||
assertEquals(0, fixedLength.byteOffset);
|
||||
assertEquals(0, lengthTracking.byteOffset);
|
||||
|
||||
rab.resize(2);
|
||||
|
||||
assertThrows(() => { fixedLength.byteLength; }, TypeError);
|
||||
assertEquals(2, lengthTracking.byteLength);
|
||||
|
||||
assertThrows(() => { fixedLength.byteOffset; }, TypeError);
|
||||
assertEquals(0, lengthTracking.byteOffset);
|
||||
|
||||
rab.resize(8);
|
||||
|
||||
assertEquals(8, fixedLength.byteLength);
|
||||
assertEquals(8, lengthTracking.byteLength);
|
||||
|
||||
assertEquals(0, fixedLength.byteOffset);
|
||||
assertEquals(0, lengthTracking.byteOffset);
|
||||
|
||||
rab.resize(40);
|
||||
|
||||
assertEquals(8, fixedLength.byteLength);
|
||||
assertEquals(40, lengthTracking.byteLength);
|
||||
|
||||
assertEquals(0, fixedLength.byteOffset);
|
||||
assertEquals(0, lengthTracking.byteOffset);
|
||||
|
||||
rab.resize(0);
|
||||
|
||||
assertThrows(() => { fixedLength.byteLength; }, TypeError);
|
||||
assertEquals(0, lengthTracking.byteLength);
|
||||
|
||||
assertThrows(() => { fixedLength.byteOffset; }, TypeError);
|
||||
assertEquals(0, lengthTracking.byteOffset);
|
||||
})();
|
||||
|
||||
// The previous test with offsets.
|
||||
(function DataViewByteLengthWhenResizedOutOfBounds2() {
|
||||
const rab = CreateResizableArrayBuffer(20, 40);
|
||||
|
||||
const fixedLengthWithOffset = new DataView(rab, 8, 8);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 8);
|
||||
|
||||
assertEquals(8, fixedLengthWithOffset.byteLength);
|
||||
assertEquals(12, lengthTrackingWithOffset.byteLength);
|
||||
|
||||
assertEquals(8, fixedLengthWithOffset.byteOffset);
|
||||
assertEquals(8, lengthTrackingWithOffset.byteOffset);
|
||||
|
||||
rab.resize(10);
|
||||
|
||||
assertThrows(() => { fixedLengthWithOffset.byteLength }, TypeError);
|
||||
assertEquals(2, lengthTrackingWithOffset.byteLength);
|
||||
|
||||
assertThrows(() => { fixedLengthWithOffset.byteOffset }, TypeError);
|
||||
assertEquals(8, lengthTrackingWithOffset.byteOffset);
|
||||
|
||||
rab.resize(16);
|
||||
|
||||
assertEquals(8, fixedLengthWithOffset.byteLength);
|
||||
assertEquals(8, lengthTrackingWithOffset.byteLength);
|
||||
|
||||
assertEquals(8, fixedLengthWithOffset.byteOffset);
|
||||
assertEquals(8, lengthTrackingWithOffset.byteOffset);
|
||||
|
||||
rab.resize(40);
|
||||
|
||||
assertEquals(8, fixedLengthWithOffset.byteLength);
|
||||
assertEquals(32, lengthTrackingWithOffset.byteLength);
|
||||
|
||||
assertEquals(8, fixedLengthWithOffset.byteOffset);
|
||||
assertEquals(8, lengthTrackingWithOffset.byteOffset);
|
||||
|
||||
rab.resize(6);
|
||||
|
||||
assertThrows(() => { fixedLengthWithOffset.byteLength }, TypeError);
|
||||
assertThrows(() => { lengthTrackingWithOffset.byteLength }, TypeError);
|
||||
|
||||
assertThrows(() => { fixedLengthWithOffset.byteOffset }, TypeError);
|
||||
assertThrows(() => { lengthTrackingWithOffset.byteOffset }, TypeError);
|
||||
})();
|
||||
|
||||
(function GetAndSet() {
|
||||
const rab = CreateResizableArrayBuffer(64, 128);
|
||||
const fixedLength = new DataView(rab, 0, 32);
|
||||
const fixedLengthWithOffset = new DataView(rab, 2, 32);
|
||||
const lengthTracking = new DataView(rab, 0);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 2);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLength, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLength, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLengthWithOffset, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTracking, 64);
|
||||
assertAllDataViewMethodsThrow(lengthTracking, 65, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 64 - 2);
|
||||
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 64 - 2 + 1,
|
||||
RangeError);
|
||||
|
||||
// Shrink so that fixed length TAs go out of bounds.
|
||||
rab.resize(30);
|
||||
|
||||
assertAllDataViewMethodsThrow(fixedLength, 0, TypeError);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 0, TypeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTracking, 30);
|
||||
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 30 - 2);
|
||||
|
||||
// Shrink so that the TAs with offset go out of bounds.
|
||||
rab.resize(1);
|
||||
|
||||
assertAllDataViewMethodsThrow(fixedLength, 0, TypeError);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 0, TypeError);
|
||||
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 0, TypeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTracking, 1);
|
||||
assertAllDataViewMethodsThrow(lengthTracking, 2, RangeError);
|
||||
|
||||
// Shrink to zero.
|
||||
rab.resize(0);
|
||||
|
||||
assertAllDataViewMethodsThrow(fixedLength, 0, TypeError);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 0, TypeError);
|
||||
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 0, TypeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTracking, 0);
|
||||
assertAllDataViewMethodsThrow(lengthTracking, 1, RangeError);
|
||||
|
||||
// Grow so that all views are back in-bounds.
|
||||
rab.resize(34);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLength, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLength, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(fixedLengthWithOffset, 32);
|
||||
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 33, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTracking, 34);
|
||||
assertAllDataViewMethodsThrow(lengthTracking, 35, RangeError);
|
||||
|
||||
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 34 - 2);
|
||||
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 34 - 2 + 1,
|
||||
RangeError);
|
||||
})();
|
||||
|
||||
(function GetParameterConversionShrinks() {
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLength = new DataView(rab, 0, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLength.getUint8(evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLengthWithOffset.getUint8(evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTracking = new DataView(rab);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 12;
|
||||
}};
|
||||
// The DataView is not out of bounds but the index is.
|
||||
assertThrows(() => { lengthTracking.getUint8(evil); }, RangeError);
|
||||
assertEquals(0, lengthTracking.getUint8(2));
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 2);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 12;
|
||||
}};
|
||||
// The DataView is not out of bounds but the index is.
|
||||
assertThrows(() => { lengthTrackingWithOffset.getUint8(evil); },
|
||||
RangeError);
|
||||
evil = { valueOf: () => {
|
||||
rab.resize(0);
|
||||
return 0;
|
||||
}};
|
||||
// Now the DataView is out of bounds.
|
||||
assertThrows(() => { lengthTrackingWithOffset.getUint8(evil); }, TypeError);
|
||||
}
|
||||
})();
|
||||
|
||||
(function SetParameterConversionShrinks() {
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLength = new DataView(rab, 0, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLength.setUint8(evil, 0); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLengthWithOffset.setUint8(evil, 0); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTracking = new DataView(rab);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 12;
|
||||
}};
|
||||
lengthTracking.setUint8(12, 0); // Does not throw.
|
||||
// The DataView is not out of bounds but the index is.
|
||||
assertThrows(() => { lengthTracking.setUint8(evil, 0); }, RangeError);
|
||||
lengthTracking.setUint8(2, 0); // Does not throw.
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 2);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 12;
|
||||
}};
|
||||
lengthTrackingWithOffset.setUint8(12, 0); // Does not throw.
|
||||
// The DataView is not out of bounds but the index is.
|
||||
assertThrows(() => { lengthTrackingWithOffset.setUint8(evil, 0); },
|
||||
RangeError);
|
||||
evil = { valueOf: () => {
|
||||
rab.resize(0);
|
||||
return 0;
|
||||
}};
|
||||
// Now the DataView is out of bounds.
|
||||
assertThrows(() => { lengthTrackingWithOffset.setUint8(evil, 0); },
|
||||
TypeError);
|
||||
}
|
||||
|
||||
// The same tests as before, except now the "resizing" parameter is the second
|
||||
// one, not the first one.
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLength = new DataView(rab, 0, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLength.setUint8(0, evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
assertThrows(() => { fixedLengthWithOffset.setUint8(0, evil); }, TypeError);
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTracking = new DataView(rab);
|
||||
|
||||
const evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
lengthTracking.setUint8(12, 0); // Does not throw.
|
||||
// The DataView is not out of bounds but the index is.
|
||||
assertThrows(() => { lengthTracking.setUint8(12, evil); }, RangeError);
|
||||
lengthTracking.setUint8(2, 0); // Does not throw.
|
||||
}
|
||||
{
|
||||
const rab = CreateResizableArrayBuffer(640, 1280);
|
||||
const lengthTrackingWithOffset = new DataView(rab, 2);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(10);
|
||||
return 0;
|
||||
}};
|
||||
// The DataView is not out of bounds but the index is.
|
||||
assertThrows(() => { lengthTrackingWithOffset.setUint8(12, evil); },
|
||||
RangeError);
|
||||
evil = { valueOf: () => {
|
||||
rab.resize(0);
|
||||
return 0;
|
||||
}};
|
||||
// Now the DataView is out of bounds.
|
||||
assertThrows(() => { lengthTrackingWithOffset.setUint8(0, evil); },
|
||||
TypeError);
|
||||
}
|
||||
})();
|
@ -8,14 +8,6 @@
|
||||
|
||||
d8.file.execute('test/mjsunit/typedarray-helpers.js');
|
||||
|
||||
function CreateResizableArrayBuffer(byteLength, maxByteLength) {
|
||||
return new ArrayBuffer(byteLength, {maxByteLength: maxByteLength});
|
||||
}
|
||||
|
||||
function CreateGrowableSharedArrayBuffer(byteLength, maxByteLength) {
|
||||
return new SharedArrayBuffer(byteLength, {maxByteLength: maxByteLength});
|
||||
}
|
||||
|
||||
function resizeHelper(ab, value) {
|
||||
const return_value = ab.resize(value);
|
||||
assertEquals(undefined, return_value);
|
||||
|
@ -9,10 +9,6 @@
|
||||
|
||||
d8.file.execute('test/mjsunit/typedarray-helpers.js');
|
||||
|
||||
function CreateGrowableSharedArrayBuffer(byteLength, maxByteLength) {
|
||||
return new SharedArrayBuffer(byteLength, {maxByteLength: maxByteLength});
|
||||
}
|
||||
|
||||
(function TypedArrayPrototype() {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(40, 80);
|
||||
const sab = new SharedArrayBuffer(80);
|
||||
|
@ -22,10 +22,34 @@ const ctors = [
|
||||
MyBigInt64Array,
|
||||
];
|
||||
|
||||
// Each element of the following array is [getter, setter, size, isBigInt].
|
||||
const dataViewAccessorsAndSizes = [[DataView.prototype.getUint8,
|
||||
DataView.prototype.setUint8, 1, false],
|
||||
[DataView.prototype.getInt8,
|
||||
DataView.prototype.setInt8, 1, false],
|
||||
[DataView.prototype.getUint16,
|
||||
DataView.prototype.setUint16, 2, false],
|
||||
[DataView.prototype.getInt16,
|
||||
DataView.prototype.setInt16, 2, false],
|
||||
[DataView.prototype.getInt32,
|
||||
DataView.prototype.setInt32, 4, false],
|
||||
[DataView.prototype.getFloat32,
|
||||
DataView.prototype.setFloat32, 4, false],
|
||||
[DataView.prototype.getFloat64,
|
||||
DataView.prototype.setFloat64, 8, false],
|
||||
[DataView.prototype.getBigUint64,
|
||||
DataView.prototype.setBigUint64, 8, true],
|
||||
[DataView.prototype.getBigInt64,
|
||||
DataView.prototype.setBigInt64, 8, true]];
|
||||
|
||||
function CreateResizableArrayBuffer(byteLength, maxByteLength) {
|
||||
return new ArrayBuffer(byteLength, {maxByteLength: maxByteLength});
|
||||
}
|
||||
|
||||
function CreateGrowableSharedArrayBuffer(byteLength, maxByteLength) {
|
||||
return new SharedArrayBuffer(byteLength, {maxByteLength: maxByteLength});
|
||||
}
|
||||
|
||||
function ReadDataFromBuffer(ab, ctor) {
|
||||
let result = [];
|
||||
const ta = new ctor(ab, 0, ab.byteLength / ctor.BYTES_PER_ELEMENT);
|
||||
@ -106,3 +130,35 @@ function IncludesHelper(array, n, fromIndex) {
|
||||
}
|
||||
return array.includes(n, fromIndex);
|
||||
}
|
||||
|
||||
function testDataViewMethodsUpToSize(view, bufferSize) {
|
||||
for (const [getter, setter, size, isBigInt] of dataViewAccessorsAndSizes) {
|
||||
for (let i = 0; i <= bufferSize - size; ++i) {
|
||||
if (isBigInt) {
|
||||
setter.call(view, i, 3n);
|
||||
} else {
|
||||
setter.call(view, i, 3);
|
||||
}
|
||||
assertEquals(3, Number(getter.call(view, i)));
|
||||
}
|
||||
if (isBigInt) {
|
||||
assertThrows(() => setter.call(view, bufferSize - size + 1, 0n),
|
||||
RangeError);
|
||||
} else {
|
||||
assertThrows(() => setter.call(view, bufferSize - size + 1, 0),
|
||||
RangeError);
|
||||
}
|
||||
assertThrows(() => getter.call(view, bufferSize - size + 1), RangeError);
|
||||
}
|
||||
}
|
||||
|
||||
function assertAllDataViewMethodsThrow(view, index, errorType) {
|
||||
for (const [getter, setter, size, isBigInt] of dataViewAccessorsAndSizes) {
|
||||
if (isBigInt) {
|
||||
assertThrows(() => { setter.call(view, index, 3n); }, errorType);
|
||||
} else {
|
||||
assertThrows(() => { setter.call(view, index, 3); }, errorType);
|
||||
}
|
||||
assertThrows(() => { getter.call(view, index); }, errorType);
|
||||
}
|
||||
}
|
||||
|
@ -283,30 +283,6 @@
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=11111
|
||||
'built-ins/ArrayBuffer/prototype/transfer/*': [FAIL],
|
||||
'built-ins/ArrayBuffer/prototype/transfer/this-is-sharedarraybuffer': [PASS],
|
||||
'built-ins/DataView/prototype/byteLength/resizable-array-buffer-auto': [FAIL],
|
||||
'built-ins/DataView/prototype/byteLength/resizable-array-buffer-fixed': [FAIL],
|
||||
'built-ins/DataView/prototype/byteOffset/resizable-array-buffer-auto': [FAIL],
|
||||
'built-ins/DataView/prototype/byteOffset/resizable-array-buffer-fixed': [FAIL],
|
||||
'built-ins/DataView/prototype/getBigInt64/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getBigUint64/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getFloat32/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getFloat64/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getInt16/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getInt32/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getInt8/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getUint16/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getUint32/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/getUint8/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setBigInt64/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setBigUint64/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setFloat32/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setFloat64/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setInt16/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setInt32/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setInt8/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setUint16/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setUint32/resizable-buffer': [FAIL],
|
||||
'built-ins/DataView/prototype/setUint8/resizable-buffer': [FAIL],
|
||||
'built-ins/TypedArray/prototype/indexOf/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/indexOf/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/join/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
|
@ -1859,15 +1859,16 @@ TEST_F(ValueSerializerTest, RoundTripTypedArray) {
|
||||
TEST_F(ValueSerializerTest, DecodeTypedArray) {
|
||||
// Check that the right type comes out the other side for every kind of typed
|
||||
// array.
|
||||
Local<Value> value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42,
|
||||
0x02, 0x00, 0x00, 0x56, 0x42, 0x00, 0x02});
|
||||
Local<Value> value =
|
||||
DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x02, 0x00, 0x00,
|
||||
0x56, 0x42, 0x00, 0x02, 0x00});
|
||||
ASSERT_TRUE(value->IsUint8Array());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->ByteLength());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
|
||||
ExpectScriptTrue("Object.getPrototypeOf(result) === Uint8Array.prototype");
|
||||
|
||||
value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x02, 0x00,
|
||||
0x00, 0x56, 0x62, 0x00, 0x02});
|
||||
0x00, 0x56, 0x62, 0x00, 0x02, 0x00});
|
||||
ASSERT_TRUE(value->IsInt8Array());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->ByteLength());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
|
||||
@ -1875,38 +1876,38 @@ TEST_F(ValueSerializerTest, DecodeTypedArray) {
|
||||
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x56, 0x57, 0x00, 0x04});
|
||||
0x00, 0x00, 0x00, 0x56, 0x57, 0x00, 0x04, 0x00});
|
||||
ASSERT_TRUE(value->IsUint16Array());
|
||||
EXPECT_EQ(4u, TypedArray::Cast(*value)->ByteLength());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
|
||||
ExpectScriptTrue("Object.getPrototypeOf(result) === Uint16Array.prototype");
|
||||
|
||||
value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x56, 0x77, 0x00, 0x04});
|
||||
0x00, 0x00, 0x00, 0x56, 0x77, 0x00, 0x04, 0x00});
|
||||
ASSERT_TRUE(value->IsInt16Array());
|
||||
EXPECT_EQ(4u, TypedArray::Cast(*value)->ByteLength());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
|
||||
ExpectScriptTrue("Object.getPrototypeOf(result) === Int16Array.prototype");
|
||||
|
||||
value =
|
||||
DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x44, 0x00, 0x08});
|
||||
value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x56, 0x44, 0x00, 0x08, 0x00});
|
||||
ASSERT_TRUE(value->IsUint32Array());
|
||||
EXPECT_EQ(8u, TypedArray::Cast(*value)->ByteLength());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
|
||||
ExpectScriptTrue("Object.getPrototypeOf(result) === Uint32Array.prototype");
|
||||
|
||||
value =
|
||||
DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x64, 0x00, 0x08});
|
||||
value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x56, 0x64, 0x00, 0x08, 0x00});
|
||||
ASSERT_TRUE(value->IsInt32Array());
|
||||
EXPECT_EQ(8u, TypedArray::Cast(*value)->ByteLength());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
|
||||
ExpectScriptTrue("Object.getPrototypeOf(result) === Int32Array.prototype");
|
||||
|
||||
value =
|
||||
DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x66, 0x00, 0x08});
|
||||
value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x56, 0x66, 0x00, 0x08, 0x00});
|
||||
ASSERT_TRUE(value->IsFloat32Array());
|
||||
EXPECT_EQ(8u, TypedArray::Cast(*value)->ByteLength());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
|
||||
@ -1915,7 +1916,7 @@ TEST_F(ValueSerializerTest, DecodeTypedArray) {
|
||||
value =
|
||||
DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x56, 0x46, 0x00, 0x10});
|
||||
0x00, 0x00, 0x00, 0x00, 0x56, 0x46, 0x00, 0x10, 0x00});
|
||||
ASSERT_TRUE(value->IsFloat64Array());
|
||||
EXPECT_EQ(16u, TypedArray::Cast(*value)->ByteLength());
|
||||
EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
|
||||
@ -1929,14 +1930,15 @@ TEST_F(ValueSerializerTest, DecodeTypedArray) {
|
||||
ExpectScriptTrue("result.toString() === '1,128,255'");
|
||||
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x06, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x80, 0x56, 0x77, 0x00, 0x06});
|
||||
value =
|
||||
DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x06, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x80, 0x56, 0x77, 0x00, 0x06, 0x00});
|
||||
ExpectScriptTrue("result.toString() === '0,256,-32768'");
|
||||
|
||||
value =
|
||||
DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0xC0, 0x7F,
|
||||
0x00, 0x00, 0x80, 0x7F, 0x56, 0x66, 0x00, 0x10});
|
||||
0x00, 0x00, 0x80, 0x7F, 0x56, 0x66, 0x00, 0x10, 0x00});
|
||||
ExpectScriptTrue("result.toString() === '0,-0.5,NaN,Infinity'");
|
||||
|
||||
#endif // V8_TARGET_LITTLE_ENDIAN
|
||||
@ -1948,10 +1950,10 @@ TEST_F(ValueSerializerTest, DecodeTypedArray) {
|
||||
0x01, 0x3F, 0x01, 0x42, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x56, 0x42, 0x00, 0x20, 0x3F, 0x03, 0x53, 0x04, 0x75, 0x38, 0x5F,
|
||||
0x32, 0x3F, 0x03, 0x5E, 0x02, 0x3F, 0x03, 0x53, 0x03, 0x66, 0x33, 0x32,
|
||||
0x3F, 0x03, 0x3F, 0x03, 0x5E, 0x01, 0x56, 0x66, 0x04, 0x14, 0x3F, 0x04,
|
||||
0x53, 0x01, 0x62, 0x3F, 0x04, 0x5E, 0x01, 0x7B, 0x04, 0x00});
|
||||
0x00, 0x56, 0x42, 0x00, 0x20, 0x00, 0x3F, 0x03, 0x53, 0x04, 0x75, 0x38,
|
||||
0x5F, 0x32, 0x3F, 0x03, 0x5E, 0x02, 0x3F, 0x03, 0x53, 0x03, 0x66, 0x33,
|
||||
0x32, 0x3F, 0x03, 0x3F, 0x03, 0x5E, 0x01, 0x56, 0x66, 0x04, 0x14, 0x00,
|
||||
0x3F, 0x04, 0x53, 0x01, 0x62, 0x3F, 0x04, 0x5E, 0x01, 0x7B, 0x04, 0x00});
|
||||
ExpectScriptTrue("result.u8 instanceof Uint8Array");
|
||||
ExpectScriptTrue("result.u8 === result.u8_2");
|
||||
ExpectScriptTrue("result.f32 instanceof Float32Array");
|
||||
@ -1990,7 +1992,7 @@ TEST_F(ValueSerializerTest, RoundTripDataView) {
|
||||
TEST_F(ValueSerializerTest, DecodeDataView) {
|
||||
Local<Value> value =
|
||||
DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x04, 0x00, 0x00,
|
||||
0x00, 0x00, 0x56, 0x3F, 0x01, 0x02});
|
||||
0x00, 0x00, 0x56, 0x3F, 0x01, 0x02, 0x00});
|
||||
ASSERT_TRUE(value->IsDataView());
|
||||
EXPECT_EQ(1u, DataView::Cast(*value)->ByteOffset());
|
||||
EXPECT_EQ(2u, DataView::Cast(*value)->ByteLength());
|
||||
|
Loading…
Reference in New Issue
Block a user