blob: 58b1220fa09b1f1018fddc716524a455e9ebd232 [file] [log] [blame]
// Copyright 2018 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.
module data_view {
extern operator '.buffer'
macro LoadJSArrayBufferViewBuffer(JSArrayBufferView): JSArrayBuffer;
extern operator '.byte_length'
macro LoadJSArrayBufferViewByteLength(JSArrayBufferView): uintptr;
extern operator '.byte_offset'
macro LoadJSArrayBufferViewByteOffset(JSArrayBufferView): uintptr;
extern operator '.external_pointer'
macro LoadJSDataViewExternalPointer(JSDataView): RawPtr;
macro MakeDataViewGetterNameString(kind: constexpr ElementsKind): String {
if constexpr (kind == UINT8_ELEMENTS) {
return 'DataView.prototype.getUint8';
} else if constexpr (kind == INT8_ELEMENTS) {
return 'DataView.prototype.getInt8';
} else if constexpr (kind == UINT16_ELEMENTS) {
return 'DataView.prototype.getUint16';
} else if constexpr (kind == INT16_ELEMENTS) {
return 'DataView.prototype.getInt16';
} else if constexpr (kind == UINT32_ELEMENTS) {
return 'DataView.prototype.getUint32';
} else if constexpr (kind == INT32_ELEMENTS) {
return 'DataView.prototype.getInt32';
} else if constexpr (kind == FLOAT32_ELEMENTS) {
return 'DataView.prototype.getFloat32';
} else if constexpr (kind == FLOAT64_ELEMENTS) {
return 'DataView.prototype.getFloat64';
} else if constexpr (kind == BIGINT64_ELEMENTS) {
return 'DataView.prototype.getBigInt64';
} else if constexpr (kind == BIGUINT64_ELEMENTS) {
return 'DataView.prototype.getBigUint64';
} else {
unreachable;
}
}
macro MakeDataViewSetterNameString(kind: constexpr ElementsKind): String {
if constexpr (kind == UINT8_ELEMENTS) {
return 'DataView.prototype.setUint8';
} else if constexpr (kind == INT8_ELEMENTS) {
return 'DataView.prototype.setInt8';
} else if constexpr (kind == UINT16_ELEMENTS) {
return 'DataView.prototype.setUint16';
} else if constexpr (kind == INT16_ELEMENTS) {
return 'DataView.prototype.setInt16';
} else if constexpr (kind == UINT32_ELEMENTS) {
return 'DataView.prototype.setUint32';
} else if constexpr (kind == INT32_ELEMENTS) {
return 'DataView.prototype.setInt32';
} else if constexpr (kind == FLOAT32_ELEMENTS) {
return 'DataView.prototype.setFloat32';
} else if constexpr (kind == FLOAT64_ELEMENTS) {
return 'DataView.prototype.setFloat64';
} else if constexpr (kind == BIGINT64_ELEMENTS) {
return 'DataView.prototype.setBigInt64';
} else if constexpr (kind == BIGUINT64_ELEMENTS) {
return 'DataView.prototype.setBigUint64';
} else {
unreachable;
}
}
macro WasNeutered(view: JSArrayBufferView): bool {
return IsDetachedBuffer(view.buffer);
}
macro ValidateDataView(context: Context,
o: Object, method: String): JSDataView {
try {
return Cast<JSDataView>(o) otherwise CastError;
}
label CastError {
ThrowTypeError(context, kIncompatibleMethodReceiver, method);
}
}
// ES6 section 24.2.4.1 get DataView.prototype.buffer
javascript builtin DataViewPrototypeGetBuffer(
context: Context, receiver: Object, ...arguments): JSArrayBuffer {
let dataView: JSDataView = ValidateDataView(
context, receiver, 'get DataView.prototype.buffer');
return dataView.buffer;
}
// ES6 section 24.2.4.2 get DataView.prototype.byteLength
javascript builtin DataViewPrototypeGetByteLength(
context: Context, receiver: Object, ...arguments): Number {
let dataView: JSDataView = ValidateDataView(
context, receiver, 'get DataView.prototype.byte_length');
if (WasNeutered(dataView)) {
// TODO(bmeurer): According to the ES6 spec, we should throw a TypeError
// here if the JSArrayBuffer of the {dataView} was neutered.
return 0;
}
return Convert<Number>(dataView.byte_length);
}
// ES6 section 24.2.4.3 get DataView.prototype.byteOffset
javascript builtin DataViewPrototypeGetByteOffset(
context: Context, receiver: Object, ...arguments): Number {
let dataView: JSDataView = ValidateDataView(
context, receiver, 'get DataView.prototype.byte_offset');
if (WasNeutered(dataView)) {
// TODO(bmeurer): According to the ES6 spec, we should throw a TypeError
// here if the JSArrayBuffer of the {dataView} was neutered.
return 0;
}
return Convert<Number>(dataView.byte_offset);
}
extern macro BitcastInt32ToFloat32(uint32): float32;
extern macro BitcastFloat32ToInt32(float32): uint32;
extern macro Float64ExtractLowWord32(float64): uint32;
extern macro Float64ExtractHighWord32(float64): uint32;
extern macro Float64InsertLowWord32(float64, uint32): float64;
extern macro Float64InsertHighWord32(float64, uint32): float64;
extern macro LoadUint8(RawPtr, uintptr): uint32;
extern macro LoadInt8(RawPtr, uintptr): int32;
macro LoadDataView8(dataView: JSDataView, offset: uintptr,
signed: constexpr bool): Smi {
if constexpr (signed) {
return Convert<Smi>(LoadInt8(dataView.external_pointer, offset));
} else {
return Convert<Smi>(LoadUint8(dataView.external_pointer, offset));
}
}
macro LoadDataView16(dataView: JSDataView, offset: uintptr,
requestedLittleEndian: bool,
signed: constexpr bool): Number {
let dataPointer: RawPtr = dataView.external_pointer;
let b0: int32;
let b1: int32;
let result: int32;
// Sign-extend the most significant byte by loading it as an Int8.
if (requestedLittleEndian) {
b0 = Signed(LoadUint8(dataPointer, offset));
b1 = LoadInt8(dataPointer, offset + 1);
result = (b1 << 8) + b0;
} else {
b0 = LoadInt8(dataPointer, offset);
b1 = Signed(LoadUint8(dataPointer, offset + 1));
result = (b0 << 8) + b1;
}
if constexpr (signed) {
return Convert<Smi>(result);
} else {
// Bit-mask the higher bits to prevent sign extension if we're unsigned.
return Convert<Smi>(result & 0xFFFF);
}
}
macro LoadDataView32(dataView: JSDataView, offset: uintptr,
requestedLittleEndian: bool,
kind: constexpr ElementsKind): Number {
let dataPointer: RawPtr = dataView.external_pointer;
let b0: uint32 = LoadUint8(dataPointer, offset);
let b1: uint32 = LoadUint8(dataPointer, offset + 1);
let b2: uint32 = LoadUint8(dataPointer, offset + 2);
let b3: uint32 = LoadUint8(dataPointer, offset + 3);
let result: uint32;
if (requestedLittleEndian) {
result = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
} else {
result = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
}
if constexpr (kind == INT32_ELEMENTS) {
return Convert<Number>(Signed(result));
} else if constexpr (kind == UINT32_ELEMENTS) {
return Convert<Number>(result);
} else if constexpr (kind == FLOAT32_ELEMENTS) {
let floatRes: float64 = Convert<float64>(BitcastInt32ToFloat32(result));
return Convert<Number>(floatRes);
} else {
unreachable;
}
}
macro LoadDataViewFloat64(dataView: JSDataView, offset: uintptr,
requestedLittleEndian: bool): Number {
let dataPointer: RawPtr = dataView.external_pointer;
let b0: uint32 = LoadUint8(dataPointer, offset);
let b1: uint32 = LoadUint8(dataPointer, offset + 1);
let b2: uint32 = LoadUint8(dataPointer, offset + 2);
let b3: uint32 = LoadUint8(dataPointer, offset + 3);
let b4: uint32 = LoadUint8(dataPointer, offset + 4);
let b5: uint32 = LoadUint8(dataPointer, offset + 5);
let b6: uint32 = LoadUint8(dataPointer, offset + 6);
let b7: uint32 = LoadUint8(dataPointer, offset + 7);
let lowWord: uint32;
let highWord: uint32;
if (requestedLittleEndian) {
lowWord = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
highWord = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
} else {
highWord = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
lowWord = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
}
let result: float64 = 0;
result = Float64InsertLowWord32(result, lowWord);
result = Float64InsertHighWord32(result, highWord);
return Convert<Number>(result);
}
extern macro AllocateBigInt(intptr): BigInt;
extern macro StoreBigIntBitfield(BigInt, intptr): void;
extern macro StoreBigIntDigit(BigInt, constexpr int31, uintptr): void;
extern macro DataViewEncodeBigIntBits(constexpr bool,
constexpr int31): intptr;
const kPositiveBigInt: constexpr bool = false;
const kNegativeBigInt: constexpr bool = true;
const kZeroDigitBigInt: constexpr int31 = 0;
const kOneDigitBigInt: constexpr int31 = 1;
const kTwoDigitBigInt: constexpr int31 = 2;
macro CreateEmptyBigInt(isPositive: bool, length: constexpr int31): BigInt {
// Allocate a BigInt with the desired length (number of digits).
let result: BigInt = AllocateBigInt(length);
// Write the desired sign and length to the BigInt bitfield.
if (isPositive) {
StoreBigIntBitfield(result,
DataViewEncodeBigIntBits(kPositiveBigInt, length));
} else {
StoreBigIntBitfield(result,
DataViewEncodeBigIntBits(kNegativeBigInt, length));
}
return result;
}
// Create a BigInt on a 64-bit architecture from two 32-bit values.
macro MakeBigIntOn64Bit(lowWord: uint32, highWord: uint32,
signed: constexpr bool): BigInt {
// 0n is represented by a zero-length BigInt.
if (lowWord == 0 && highWord == 0) {
return AllocateBigInt(kZeroDigitBigInt);
}
let isPositive: bool = true;
let highPart: intptr = Signed(Convert<uintptr>(highWord));
let lowPart: intptr = Signed(Convert<uintptr>(lowWord));
let rawValue: intptr = (highPart << 32) + lowPart;
if constexpr (signed) {
if (rawValue < 0) {
isPositive = false;
// We have to store the absolute value of rawValue in the digit.
rawValue = 0 - rawValue;
}
}
// Allocate the BigInt and store the absolute value.
let result: BigInt = CreateEmptyBigInt(isPositive, kOneDigitBigInt);
StoreBigIntDigit(result, 0, Unsigned(rawValue));
return result;
}
// Create a BigInt on a 32-bit architecture from two 32-bit values.
macro MakeBigIntOn32Bit(lowWord: uint32, highWord: uint32,
signed: constexpr bool): BigInt {
// 0n is represented by a zero-length BigInt.
if (lowWord == 0 && highWord == 0) {
return AllocateBigInt(kZeroDigitBigInt);
}
// On a 32-bit platform, we might need 1 or 2 digits to store the number.
let needTwoDigits: bool = false;
let isPositive: bool = true;
// We need to do some math on lowWord and highWord,
// so Convert them to int32.
let lowPart: int32 = Signed(lowWord);
let highPart: int32 = Signed(highWord);
// If highWord == 0, the number is positive, and we only need 1 digit,
// so we don't have anything to do.
// Otherwise, all cases are possible.
if (highWord != 0) {
if constexpr (signed) {
// If highPart < 0, the number is always negative.
if (highPart < 0) {
isPositive = false;
// We have to compute the absolute value by hand.
// There will be a negative carry from the low word
// to the high word iff low != 0.
highPart = 0 - highPart;
if (lowPart != 0) {
highPart = highPart - 1;
}
lowPart = 0 - lowPart;
// Here, highPart could be 0 again so we might have 1 or 2 digits.
if (highPart != 0) {
needTwoDigits = true;
}
} else {
// In this case, the number is positive, and we need 2 digits.
needTwoDigits = true;
}
} else {
// In this case, the number is positive (unsigned),
// and we need 2 digits.
needTwoDigits = true;
}
}
// Allocate the BigInt with the right sign and length.
let result: BigInt;
if (needTwoDigits) {
result = CreateEmptyBigInt(isPositive, kTwoDigitBigInt);
} else {
result = CreateEmptyBigInt(isPositive, kOneDigitBigInt);
}
// Finally, write the digit(s) to the BigInt.
StoreBigIntDigit(result, 0, Unsigned(Convert<intptr>(lowPart)));
if (needTwoDigits) {
StoreBigIntDigit(result, 1, Unsigned(Convert<intptr>(highPart)));
}
return result;
}
macro MakeBigInt(lowWord: uint32, highWord: uint32,
signed: constexpr bool): BigInt {
// A BigInt digit has the platform word size, so we only need one digit
// on 64-bit platforms but may need two on 32-bit.
if constexpr (Is64()) {
return MakeBigIntOn64Bit(lowWord, highWord, signed);
} else {
return MakeBigIntOn32Bit(lowWord, highWord, signed);
}
}
macro LoadDataViewBigInt(dataView: JSDataView, offset: uintptr,
requestedLittleEndian: bool,
signed: constexpr bool): BigInt {
let dataPointer: RawPtr = dataView.external_pointer;
let b0: uint32 = LoadUint8(dataPointer, offset);
let b1: uint32 = LoadUint8(dataPointer, offset + 1);
let b2: uint32 = LoadUint8(dataPointer, offset + 2);
let b3: uint32 = LoadUint8(dataPointer, offset + 3);
let b4: uint32 = LoadUint8(dataPointer, offset + 4);
let b5: uint32 = LoadUint8(dataPointer, offset + 5);
let b6: uint32 = LoadUint8(dataPointer, offset + 6);
let b7: uint32 = LoadUint8(dataPointer, offset + 7);
let lowWord: uint32;
let highWord: uint32;
if (requestedLittleEndian) {
lowWord = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
highWord = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
} else {
highWord = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
lowWord = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
}
return MakeBigInt(lowWord, highWord, signed);
}
extern macro ToSmiIndex(Object, Context): Smi labels RangeError;
extern macro DataViewElementSize(constexpr ElementsKind): constexpr int31;
macro DataViewGet(context: Context,
receiver: Object,
offset: Object,
requestedLittleEndian: Object,
kind: constexpr ElementsKind): Numeric {
let dataView: JSDataView = ValidateDataView(
context, receiver, MakeDataViewGetterNameString(kind));
let getIndex: Number;
try {
getIndex = ToIndex(offset, context) otherwise RangeError;
}
label RangeError {
ThrowRangeError(context, kInvalidDataViewAccessorOffset);
}
let littleEndian: bool = ToBoolean(requestedLittleEndian);
let buffer: JSArrayBuffer = dataView.buffer;
if (IsDetachedBuffer(buffer)) {
ThrowTypeError(context, kDetachedOperation,
MakeDataViewGetterNameString(kind));
}
let getIndexFloat: float64 = Convert<float64>(getIndex);
let getIndexWord: uintptr = Convert<uintptr>(getIndexFloat);
let viewSizeFloat: float64 = Convert<float64>(dataView.byte_length);
let elementSizeFloat: float64 = Convert<float64>(DataViewElementSize(kind));
if (getIndexFloat + elementSizeFloat > viewSizeFloat) {
ThrowRangeError(context, kInvalidDataViewAccessorOffset);
}
if constexpr (kind == UINT8_ELEMENTS) {
return LoadDataView8(dataView, getIndexWord, false);
} else if constexpr (kind == INT8_ELEMENTS) {
return LoadDataView8(dataView, getIndexWord, true);
} else if constexpr (kind == UINT16_ELEMENTS) {
return LoadDataView16(dataView, getIndexWord, littleEndian, false);
} else if constexpr (kind == INT16_ELEMENTS) {
return LoadDataView16(dataView, getIndexWord, littleEndian, true);
} else if constexpr (kind == UINT32_ELEMENTS) {
return LoadDataView32(dataView, getIndexWord, littleEndian, kind);
} else if constexpr (kind == INT32_ELEMENTS) {
return LoadDataView32(dataView, getIndexWord, littleEndian, kind);
} else if constexpr (kind == FLOAT32_ELEMENTS) {
return LoadDataView32(dataView, getIndexWord, littleEndian, kind);
} else if constexpr (kind == FLOAT64_ELEMENTS) {
return LoadDataViewFloat64(dataView, getIndexWord, littleEndian);
} else if constexpr (kind == BIGUINT64_ELEMENTS) {
return LoadDataViewBigInt(dataView, getIndexWord, littleEndian, false);
} else if constexpr (kind == BIGINT64_ELEMENTS) {
return LoadDataViewBigInt(dataView, getIndexWord, littleEndian, true);
} else {
unreachable;
}
}
javascript builtin DataViewPrototypeGetUint8(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
return DataViewGet(context, receiver, offset, Undefined, UINT8_ELEMENTS);
}
javascript builtin DataViewPrototypeGetInt8(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
return DataViewGet(context, receiver, offset, Undefined, INT8_ELEMENTS);
}
javascript builtin DataViewPrototypeGetUint16(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let isLittleEndian : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewGet(context, receiver, offset, isLittleEndian,
UINT16_ELEMENTS);
}
javascript builtin DataViewPrototypeGetInt16(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let isLittleEndian : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewGet(context, receiver, offset, isLittleEndian,
INT16_ELEMENTS);
}
javascript builtin DataViewPrototypeGetUint32(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let isLittleEndian : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewGet(context, receiver, offset, isLittleEndian,
UINT32_ELEMENTS);
}
javascript builtin DataViewPrototypeGetInt32(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let isLittleEndian : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewGet(context, receiver, offset, isLittleEndian,
INT32_ELEMENTS);
}
javascript builtin DataViewPrototypeGetFloat32(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let isLittleEndian : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewGet(context, receiver, offset, isLittleEndian,
FLOAT32_ELEMENTS);
}
javascript builtin DataViewPrototypeGetFloat64(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let isLittleEndian : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewGet(context, receiver, offset, isLittleEndian,
FLOAT64_ELEMENTS);
}
javascript builtin DataViewPrototypeGetBigUint64(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let isLittleEndian : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewGet(context, receiver, offset, isLittleEndian,
BIGUINT64_ELEMENTS);
}
javascript builtin DataViewPrototypeGetBigInt64(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let isLittleEndian : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewGet(context, receiver, offset, isLittleEndian,
BIGINT64_ELEMENTS);
}
extern macro ToNumber(Context, Object): Number;
extern macro ToBigInt(Context, Object): BigInt;
extern macro TruncateFloat64ToFloat32(float64): float32;
extern macro TruncateFloat64ToWord32(float64): uint32;
extern macro StoreWord8(RawPtr, uintptr, uint32): void;
macro StoreDataView8(dataView: JSDataView, offset: uintptr,
value: uint32) {
StoreWord8(dataView.external_pointer, offset, value & 0xFF);
}
macro StoreDataView16(dataView: JSDataView, offset: uintptr, value: uint32,
requestedLittleEndian: bool) {
let dataPointer: RawPtr = dataView.external_pointer;
let b0: uint32 = value & 0xFF;
let b1: uint32 = (value >>> 8) & 0xFF;
if (requestedLittleEndian) {
StoreWord8(dataPointer, offset, b0);
StoreWord8(dataPointer, offset + 1, b1);
} else {
StoreWord8(dataPointer, offset, b1);
StoreWord8(dataPointer, offset + 1, b0);
}
}
macro StoreDataView32(dataView: JSDataView, offset: uintptr, value: uint32,
requestedLittleEndian: bool) {
let dataPointer: RawPtr = dataView.external_pointer;
let b0: uint32 = value & 0xFF;
let b1: uint32 = (value >>> 8) & 0xFF;
let b2: uint32 = (value >>> 16) & 0xFF;
let b3: uint32 = value >>> 24; // We don't need to mask here.
if (requestedLittleEndian) {
StoreWord8(dataPointer, offset, b0);
StoreWord8(dataPointer, offset + 1, b1);
StoreWord8(dataPointer, offset + 2, b2);
StoreWord8(dataPointer, offset + 3, b3);
} else {
StoreWord8(dataPointer, offset, b3);
StoreWord8(dataPointer, offset + 1, b2);
StoreWord8(dataPointer, offset + 2, b1);
StoreWord8(dataPointer, offset + 3, b0);
}
}
macro StoreDataView64(dataView: JSDataView, offset: uintptr,
lowWord: uint32, highWord: uint32,
requestedLittleEndian: bool) {
let dataPointer: RawPtr = dataView.external_pointer;
let b0: uint32 = lowWord & 0xFF;
let b1: uint32 = (lowWord >>> 8) & 0xFF;
let b2: uint32 = (lowWord >>> 16) & 0xFF;
let b3: uint32 = lowWord >>> 24;
let b4: uint32 = highWord & 0xFF;
let b5: uint32 = (highWord >>> 8) & 0xFF;
let b6: uint32 = (highWord >>> 16) & 0xFF;
let b7: uint32 = highWord >>> 24;
if (requestedLittleEndian) {
StoreWord8(dataPointer, offset, b0);
StoreWord8(dataPointer, offset + 1, b1);
StoreWord8(dataPointer, offset + 2, b2);
StoreWord8(dataPointer, offset + 3, b3);
StoreWord8(dataPointer, offset + 4, b4);
StoreWord8(dataPointer, offset + 5, b5);
StoreWord8(dataPointer, offset + 6, b6);
StoreWord8(dataPointer, offset + 7, b7);
} else {
StoreWord8(dataPointer, offset, b7);
StoreWord8(dataPointer, offset + 1, b6);
StoreWord8(dataPointer, offset + 2, b5);
StoreWord8(dataPointer, offset + 3, b4);
StoreWord8(dataPointer, offset + 4, b3);
StoreWord8(dataPointer, offset + 5, b2);
StoreWord8(dataPointer, offset + 6, b1);
StoreWord8(dataPointer, offset + 7, b0);
}
}
extern macro DataViewDecodeBigIntLength(BigInt): uintptr;
extern macro DataViewDecodeBigIntSign(BigInt): uintptr;
extern macro LoadBigIntDigit(BigInt, constexpr int31): uintptr;
// We might get here a BigInt that is bigger than 64 bits, but we're only
// interested in the 64 lowest ones. This means the lowest BigInt digit
// on 64-bit platforms, and the 2 lowest BigInt digits on 32-bit ones.
macro StoreDataViewBigInt(dataView: JSDataView, offset: uintptr,
bigIntValue: BigInt,
requestedLittleEndian: bool) {
let length: uintptr = DataViewDecodeBigIntLength(bigIntValue);
let sign: uintptr = DataViewDecodeBigIntSign(bigIntValue);
// The 32-bit words that will hold the BigInt's value in
// two's complement representation.
let lowWord: uint32 = 0;
let highWord: uint32 = 0;
// The length is nonzero if and only if the BigInt's value is nonzero.
if (length != 0) {
if constexpr (Is64()) {
// There is always exactly 1 BigInt digit to load in this case.
let value: uintptr = LoadBigIntDigit(bigIntValue, 0);
lowWord = Convert<uint32>(value); // Truncates value to 32 bits.
highWord = Convert<uint32>(value >>> 32);
}
else { // There might be either 1 or 2 BigInt digits we need to load.
lowWord = Convert<uint32>(LoadBigIntDigit(bigIntValue, 0));
if (length >= 2) { // Only load the second digit if there is one.
highWord = Convert<uint32>(LoadBigIntDigit(bigIntValue, 1));
}
}
}
if (sign != 0) { // The number is negative, Convert it.
highWord = Unsigned(0 - Signed(highWord));
if (lowWord != 0) {
highWord = Unsigned(Signed(highWord) - 1);
}
lowWord = Unsigned(0 - Signed(lowWord));
}
StoreDataView64(dataView, offset, lowWord, highWord,
requestedLittleEndian);
}
macro DataViewSet(context: Context,
receiver: Object,
offset: Object,
value: Object,
requestedLittleEndian: Object,
kind: constexpr ElementsKind): Object {
let dataView: JSDataView = ValidateDataView(
context, receiver, MakeDataViewSetterNameString(kind));
let getIndex: Number;
try {
getIndex = ToIndex(offset, context) otherwise RangeError;
}
label RangeError {
ThrowRangeError(context, kInvalidDataViewAccessorOffset);
}
let littleEndian: bool = ToBoolean(requestedLittleEndian);
let buffer: JSArrayBuffer = dataView.buffer;
let bigIntValue: BigInt;
let numValue: Number;
// According to ES6 section 24.2.1.2 SetViewValue, we must perform
// the conversion before doing the bounds check.
if constexpr (kind == BIGUINT64_ELEMENTS || kind == BIGINT64_ELEMENTS) {
bigIntValue = ToBigInt(context, value);
} else {
numValue = ToNumber(context, value);
}
if (IsDetachedBuffer(buffer)) {
ThrowTypeError(context, kDetachedOperation,
MakeDataViewSetterNameString(kind));
}
let getIndexFloat: float64 = Convert<float64>(getIndex);
let getIndexWord: uintptr = Convert<uintptr>(getIndexFloat);
let viewSizeFloat: float64 = Convert<float64>(dataView.byte_length);
let elementSizeFloat: float64 = Convert<float64>(DataViewElementSize(kind));
if (getIndexFloat + elementSizeFloat > viewSizeFloat) {
ThrowRangeError(context, kInvalidDataViewAccessorOffset);
}
if constexpr (kind == BIGUINT64_ELEMENTS || kind == BIGINT64_ELEMENTS) {
StoreDataViewBigInt(dataView, getIndexWord, bigIntValue,
littleEndian);
}
else {
let doubleValue: float64 = ChangeNumberToFloat64(numValue);
if constexpr (kind == UINT8_ELEMENTS || kind == INT8_ELEMENTS) {
StoreDataView8(dataView, getIndexWord,
TruncateFloat64ToWord32(doubleValue));
}
else if constexpr (kind == UINT16_ELEMENTS || kind == INT16_ELEMENTS) {
StoreDataView16(dataView, getIndexWord,
TruncateFloat64ToWord32(doubleValue), littleEndian);
}
else if constexpr (kind == UINT32_ELEMENTS || kind == INT32_ELEMENTS) {
StoreDataView32(dataView, getIndexWord,
TruncateFloat64ToWord32(doubleValue), littleEndian);
}
else if constexpr (kind == FLOAT32_ELEMENTS) {
let floatValue: float32 = TruncateFloat64ToFloat32(doubleValue);
StoreDataView32(dataView, getIndexWord,
BitcastFloat32ToInt32(floatValue), littleEndian);
}
else if constexpr (kind == FLOAT64_ELEMENTS) {
let lowWord: uint32 = Float64ExtractLowWord32(doubleValue);
let highWord: uint32 = Float64ExtractHighWord32(doubleValue);
StoreDataView64(dataView, getIndexWord, lowWord, highWord,
littleEndian);
}
}
return Undefined;
}
javascript builtin DataViewPrototypeSetUint8(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewSet(context, receiver, offset, value, Undefined,
UINT8_ELEMENTS);
}
javascript builtin DataViewPrototypeSetInt8(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
return DataViewSet(context, receiver, offset, value, Undefined,
INT8_ELEMENTS);
}
javascript builtin DataViewPrototypeSetUint16(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
let isLittleEndian : Object = arguments.length > 2 ?
arguments[2] :
Undefined;
return DataViewSet(context, receiver, offset, value,
isLittleEndian, UINT16_ELEMENTS);
}
javascript builtin DataViewPrototypeSetInt16(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
let isLittleEndian : Object = arguments.length > 2 ?
arguments[2] :
Undefined;
return DataViewSet(context, receiver, offset, value,
isLittleEndian, INT16_ELEMENTS);
}
javascript builtin DataViewPrototypeSetUint32(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
let isLittleEndian : Object = arguments.length > 2 ?
arguments[2] :
Undefined;
return DataViewSet(context, receiver, offset, value,
isLittleEndian, UINT32_ELEMENTS);
}
javascript builtin DataViewPrototypeSetInt32(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
let isLittleEndian : Object = arguments.length > 2 ?
arguments[2] :
Undefined;
return DataViewSet(context, receiver, offset, value,
isLittleEndian, INT32_ELEMENTS);
}
javascript builtin DataViewPrototypeSetFloat32(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
let isLittleEndian : Object = arguments.length > 2 ?
arguments[2] :
Undefined;
return DataViewSet(context, receiver, offset, value,
isLittleEndian, FLOAT32_ELEMENTS);
}
javascript builtin DataViewPrototypeSetFloat64(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
let isLittleEndian : Object = arguments.length > 2 ?
arguments[2] :
Undefined;
return DataViewSet(context, receiver, offset, value,
isLittleEndian, FLOAT64_ELEMENTS);
}
javascript builtin DataViewPrototypeSetBigUint64(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
let isLittleEndian : Object = arguments.length > 2 ?
arguments[2] :
Undefined;
return DataViewSet(context, receiver, offset, value,
isLittleEndian, BIGUINT64_ELEMENTS);
}
javascript builtin DataViewPrototypeSetBigInt64(
context: Context, receiver: Object, ...arguments): Object {
let offset: Object = arguments.length > 0 ?
arguments[0] :
Undefined;
let value : Object = arguments.length > 1 ?
arguments[1] :
Undefined;
let isLittleEndian : Object = arguments.length > 2 ?
arguments[2] :
Undefined;
return DataViewSet(context, receiver, offset, value,
isLittleEndian, BIGINT64_ELEMENTS);
}
}