// 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 LoadArrayBufferViewBuffer(JSArrayBufferView): JSArrayBuffer; extern operator '.byte_length' macro LoadDataViewByteLength(JSDataView): Number; extern operator '.byte_offset' macro LoadDataViewByteOffset(JSDataView): Number; extern operator '.backing_store' macro LoadArrayBufferBackingStore(JSArrayBuffer): 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 data_view: JSDataView = ValidateDataView( context, receiver, 'get DataView.prototype.buffer'); return data_view.buffer; } // ES6 section 24.2.4.2 get DataView.prototype.byteLength javascript builtin DataViewPrototypeGetByteLength( context: Context, receiver: Object, ...arguments): Number { let data_view: JSDataView = ValidateDataView( context, receiver, 'get DataView.prototype.byte_length'); if (WasNeutered(data_view)) { // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError // here if the JSArrayBuffer of the {data_view} was neutered. return 0; } return data_view.byte_length; } // ES6 section 24.2.4.3 get DataView.prototype.byteOffset javascript builtin DataViewPrototypeGetByteOffset( context: Context, receiver: Object, ...arguments): Number { let data_view: JSDataView = ValidateDataView( context, receiver, 'get DataView.prototype.byte_offset'); if (WasNeutered(data_view)) { // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError // here if the JSArrayBuffer of the {data_view} was neutered. return 0; } return data_view.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, intptr): uint32; extern macro LoadInt8(RawPtr, intptr): int32; macro LoadDataView8(buffer: JSArrayBuffer, offset: intptr, signed: constexpr bool): Smi { if constexpr (signed) { return convert<Smi>(LoadInt8(buffer.backing_store, offset)); } else { return convert<Smi>(LoadUint8(buffer.backing_store, offset)); } } macro LoadDataView16(buffer: JSArrayBuffer, offset: intptr, requested_little_endian: bool, signed: constexpr bool): Number { let data_pointer: RawPtr = buffer.backing_store; let b0: int32; let b1: int32; let result: int32; // Sign-extend the most significant byte by loading it as an Int8. if (requested_little_endian) { b0 = Signed(LoadUint8(data_pointer, offset)); b1 = LoadInt8(data_pointer, offset + 1); result = (b1 << 8) + b0; } else { b0 = LoadInt8(data_pointer, offset); b1 = Signed(LoadUint8(data_pointer, 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(buffer: JSArrayBuffer, offset: intptr, requested_little_endian: bool, kind: constexpr ElementsKind): Number { let data_pointer: RawPtr = buffer.backing_store; let b0: uint32 = LoadUint8(data_pointer, offset); let b1: uint32 = LoadUint8(data_pointer, offset + 1); let b2: uint32 = LoadUint8(data_pointer, offset + 2); let b3: uint32 = LoadUint8(data_pointer, offset + 3); let result: uint32; if (requested_little_endian) { 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 float_res: float64 = convert<float64>(BitcastInt32ToFloat32(result)); return convert<Number>(float_res); } else { unreachable; } } macro LoadDataViewFloat64(buffer: JSArrayBuffer, offset: intptr, requested_little_endian: bool): Number { let data_pointer: RawPtr = buffer.backing_store; let b0: uint32 = LoadUint8(data_pointer, offset); let b1: uint32 = LoadUint8(data_pointer, offset + 1); let b2: uint32 = LoadUint8(data_pointer, offset + 2); let b3: uint32 = LoadUint8(data_pointer, offset + 3); let b4: uint32 = LoadUint8(data_pointer, offset + 4); let b5: uint32 = LoadUint8(data_pointer, offset + 5); let b6: uint32 = LoadUint8(data_pointer, offset + 6); let b7: uint32 = LoadUint8(data_pointer, offset + 7); let low_word: uint32; let high_word: uint32; if (requested_little_endian) { low_word = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; high_word = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4; } else { high_word = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; low_word = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; } let result: float64 = 0; result = Float64InsertLowWord32(result, low_word); result = Float64InsertHighWord32(result, high_word); 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(is_positive: 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 (is_positive) { 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(low_word: uint32, high_word: uint32, signed: constexpr bool): BigInt { // 0n is represented by a zero-length BigInt. if (low_word == 0 && high_word == 0) { return AllocateBigInt(kZeroDigitBigInt); } let is_positive: bool = true; let high_part: intptr = Signed(convert<uintptr>(high_word)); let low_part: intptr = Signed(convert<uintptr>(low_word)); let raw_value: intptr = (high_part << 32) + low_part; if constexpr (signed) { if (raw_value < 0) { is_positive = false; // We have to store the absolute value of raw_value in the digit. raw_value = 0 - raw_value; } } // Allocate the BigInt and store the absolute value. let result: BigInt = CreateEmptyBigInt(is_positive, kOneDigitBigInt); StoreBigIntDigit(result, 0, Unsigned(raw_value)); return result; } // Create a BigInt on a 32-bit architecture from two 32-bit values. macro MakeBigIntOn32Bit(low_word: uint32, high_word: uint32, signed: constexpr bool): BigInt { // 0n is represented by a zero-length BigInt. if (low_word == 0 && high_word == 0) { return AllocateBigInt(kZeroDigitBigInt); } // On a 32-bit platform, we might need 1 or 2 digits to store the number. let need_two_digits: bool = false; let is_positive: bool = true; // We need to do some math on low_word and high_word, // so convert them to int32. let low_part: int32 = Signed(low_word); let high_part: int32 = Signed(high_word); // If high_word == 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 (high_word != 0) { if constexpr (signed) { // If high_part < 0, the number is always negative. if (high_part < 0) { is_positive = 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. high_part = 0 - high_part; if (low_part != 0) { high_part = high_part - 1; } low_part = 0 - low_part; // Here, high_part could be 0 again so we might have 1 or 2 digits. if (high_part != 0) { need_two_digits = true; } } else { // In this case, the number is positive, and we need 2 digits. need_two_digits = true; } } else { // In this case, the number is positive (unsigned), // and we need 2 digits. need_two_digits = true; } } // Allocate the BigInt with the right sign and length. let result: BigInt; if (need_two_digits) { result = CreateEmptyBigInt(is_positive, kTwoDigitBigInt); } else { result = CreateEmptyBigInt(is_positive, kOneDigitBigInt); } // Finally, write the digit(s) to the BigInt. StoreBigIntDigit(result, 0, Unsigned(convert<intptr>(low_part))); if (need_two_digits) { StoreBigIntDigit(result, 1, Unsigned(convert<intptr>(high_part))); } return result; } macro MakeBigInt(low_word: uint32, high_word: 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(low_word, high_word, signed); } else { return MakeBigIntOn32Bit(low_word, high_word, signed); } } macro LoadDataViewBigInt(buffer: JSArrayBuffer, offset: intptr, requested_little_endian: bool, signed: constexpr bool): BigInt { let data_pointer: RawPtr = buffer.backing_store; let b0: uint32 = LoadUint8(data_pointer, offset); let b1: uint32 = LoadUint8(data_pointer, offset + 1); let b2: uint32 = LoadUint8(data_pointer, offset + 2); let b3: uint32 = LoadUint8(data_pointer, offset + 3); let b4: uint32 = LoadUint8(data_pointer, offset + 4); let b5: uint32 = LoadUint8(data_pointer, offset + 5); let b6: uint32 = LoadUint8(data_pointer, offset + 6); let b7: uint32 = LoadUint8(data_pointer, offset + 7); let low_word: uint32; let high_word: uint32; if (requested_little_endian) { low_word = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; high_word = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4; } else { high_word = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; low_word = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; } return MakeBigInt(low_word, high_word, signed); } extern macro ToSmiIndex(Object, Context): Smi labels RangeError; extern macro DataViewElementSize(constexpr ElementsKind): constexpr int31; macro DataViewGet(context: Context, receiver: Object, offset: Object, requested_little_endian: Object, kind: constexpr ElementsKind): Numeric { let data_view: 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(requested_little_endian); let buffer: JSArrayBuffer = data_view.buffer; if (IsDetachedBuffer(buffer)) { ThrowTypeError(context, kDetachedOperation, MakeDataViewGetterNameString(kind)); } let viewOffset: Number = data_view.byte_offset; let viewSize: Number = data_view.byte_length; let elementSize: Number = DataViewElementSize(kind); if (getIndex + elementSize > viewSize) { ThrowRangeError(context, kInvalidDataViewAccessorOffset); } let getIndexFloat: float64 = convert<float64>(getIndex); let getIndexIntptr: intptr = Signed(convert<uintptr>(getIndexFloat)); let viewOffsetFloat: float64 = convert<float64>(viewOffset); let viewOffsetIntptr: intptr = Signed(convert<uintptr>(viewOffsetFloat)); let bufferIndex: intptr = getIndexIntptr + viewOffsetIntptr; if constexpr (kind == UINT8_ELEMENTS) { return LoadDataView8(buffer, bufferIndex, false); } else if constexpr (kind == INT8_ELEMENTS) { return LoadDataView8(buffer, bufferIndex, true); } else if constexpr (kind == UINT16_ELEMENTS) { return LoadDataView16(buffer, bufferIndex, littleEndian, false); } else if constexpr (kind == INT16_ELEMENTS) { return LoadDataView16(buffer, bufferIndex, littleEndian, true); } else if constexpr (kind == UINT32_ELEMENTS) { return LoadDataView32(buffer, bufferIndex, littleEndian, kind); } else if constexpr (kind == INT32_ELEMENTS) { return LoadDataView32(buffer, bufferIndex, littleEndian, kind); } else if constexpr (kind == FLOAT32_ELEMENTS) { return LoadDataView32(buffer, bufferIndex, littleEndian, kind); } else if constexpr (kind == FLOAT64_ELEMENTS) { return LoadDataViewFloat64(buffer, bufferIndex, littleEndian); } else if constexpr (kind == BIGUINT64_ELEMENTS) { return LoadDataViewBigInt(buffer, bufferIndex, littleEndian, false); } else if constexpr (kind == BIGINT64_ELEMENTS) { return LoadDataViewBigInt(buffer, bufferIndex, 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 is_little_endian : Object = arguments.length > 1 ? arguments[1] : Undefined; return DataViewGet(context, receiver, offset, is_little_endian, UINT16_ELEMENTS); } javascript builtin DataViewPrototypeGetInt16( context: Context, receiver: Object, ...arguments): Object { let offset: Object = arguments.length > 0 ? arguments[0] : Undefined; let is_little_endian : Object = arguments.length > 1 ? arguments[1] : Undefined; return DataViewGet(context, receiver, offset, is_little_endian, INT16_ELEMENTS); } javascript builtin DataViewPrototypeGetUint32( context: Context, receiver: Object, ...arguments): Object { let offset: Object = arguments.length > 0 ? arguments[0] : Undefined; let is_little_endian : Object = arguments.length > 1 ? arguments[1] : Undefined; return DataViewGet(context, receiver, offset, is_little_endian, UINT32_ELEMENTS); } javascript builtin DataViewPrototypeGetInt32( context: Context, receiver: Object, ...arguments): Object { let offset: Object = arguments.length > 0 ? arguments[0] : Undefined; let is_little_endian : Object = arguments.length > 1 ? arguments[1] : Undefined; return DataViewGet(context, receiver, offset, is_little_endian, INT32_ELEMENTS); } javascript builtin DataViewPrototypeGetFloat32( context: Context, receiver: Object, ...arguments): Object { let offset: Object = arguments.length > 0 ? arguments[0] : Undefined; let is_little_endian : Object = arguments.length > 1 ? arguments[1] : Undefined; return DataViewGet(context, receiver, offset, is_little_endian, FLOAT32_ELEMENTS); } javascript builtin DataViewPrototypeGetFloat64( context: Context, receiver: Object, ...arguments): Object { let offset: Object = arguments.length > 0 ? arguments[0] : Undefined; let is_little_endian : Object = arguments.length > 1 ? arguments[1] : Undefined; return DataViewGet(context, receiver, offset, is_little_endian, FLOAT64_ELEMENTS); } javascript builtin DataViewPrototypeGetBigUint64( context: Context, receiver: Object, ...arguments): Object { let offset: Object = arguments.length > 0 ? arguments[0] : Undefined; let is_little_endian : Object = arguments.length > 1 ? arguments[1] : Undefined; return DataViewGet(context, receiver, offset, is_little_endian, BIGUINT64_ELEMENTS); } javascript builtin DataViewPrototypeGetBigInt64( context: Context, receiver: Object, ...arguments): Object { let offset: Object = arguments.length > 0 ? arguments[0] : Undefined; let is_little_endian : Object = arguments.length > 1 ? arguments[1] : Undefined; return DataViewGet(context, receiver, offset, is_little_endian, 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, intptr, uint32): void; macro StoreDataView8(buffer: JSArrayBuffer, offset: intptr, value: uint32) { StoreWord8(buffer.backing_store, offset, value & 0xFF); } macro StoreDataView16(buffer: JSArrayBuffer, offset: intptr, value: uint32, requested_little_endian: bool) { let data_pointer: RawPtr = buffer.backing_store; let b0: uint32 = value & 0xFF; let b1: uint32 = (value >>> 8) & 0xFF; if (requested_little_endian) { StoreWord8(data_pointer, offset, b0); StoreWord8(data_pointer, offset + 1, b1); } else { StoreWord8(data_pointer, offset, b1); StoreWord8(data_pointer, offset + 1, b0); } } macro StoreDataView32(buffer: JSArrayBuffer, offset: intptr, value: uint32, requested_little_endian: bool) { let data_pointer: RawPtr = buffer.backing_store; 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 (requested_little_endian) { StoreWord8(data_pointer, offset, b0); StoreWord8(data_pointer, offset + 1, b1); StoreWord8(data_pointer, offset + 2, b2); StoreWord8(data_pointer, offset + 3, b3); } else { StoreWord8(data_pointer, offset, b3); StoreWord8(data_pointer, offset + 1, b2); StoreWord8(data_pointer, offset + 2, b1); StoreWord8(data_pointer, offset + 3, b0); } } macro StoreDataView64(buffer: JSArrayBuffer, offset: intptr, low_word: uint32, high_word: uint32, requested_little_endian: bool) { let data_pointer: RawPtr = buffer.backing_store; let b0: uint32 = low_word & 0xFF; let b1: uint32 = (low_word >>> 8) & 0xFF; let b2: uint32 = (low_word >>> 16) & 0xFF; let b3: uint32 = low_word >>> 24; let b4: uint32 = high_word & 0xFF; let b5: uint32 = (high_word >>> 8) & 0xFF; let b6: uint32 = (high_word >>> 16) & 0xFF; let b7: uint32 = high_word >>> 24; if (requested_little_endian) { StoreWord8(data_pointer, offset, b0); StoreWord8(data_pointer, offset + 1, b1); StoreWord8(data_pointer, offset + 2, b2); StoreWord8(data_pointer, offset + 3, b3); StoreWord8(data_pointer, offset + 4, b4); StoreWord8(data_pointer, offset + 5, b5); StoreWord8(data_pointer, offset + 6, b6); StoreWord8(data_pointer, offset + 7, b7); } else { StoreWord8(data_pointer, offset, b7); StoreWord8(data_pointer, offset + 1, b6); StoreWord8(data_pointer, offset + 2, b5); StoreWord8(data_pointer, offset + 3, b4); StoreWord8(data_pointer, offset + 4, b3); StoreWord8(data_pointer, offset + 5, b2); StoreWord8(data_pointer, offset + 6, b1); StoreWord8(data_pointer, 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(buffer: JSArrayBuffer, offset: intptr, bigint_value: BigInt, requested_little_endian: bool) { let length: uintptr = DataViewDecodeBigIntLength(bigint_value); let sign: uintptr = DataViewDecodeBigIntSign(bigint_value); // The 32-bit words that will hold the BigInt's value in // two's complement representation. let low_word: uint32 = 0; let high_word: 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(bigint_value, 0); low_word = convert<uint32>(value); // Truncates value to 32 bits. high_word = convert<uint32>(value >>> 32); } else { // There might be either 1 or 2 BigInt digits we need to load. low_word = convert<uint32>(LoadBigIntDigit(bigint_value, 0)); if (length >= 2) { // Only load the second digit if there is one. high_word = convert<uint32>(LoadBigIntDigit(bigint_value, 1)); } } } if (sign != 0) { // The number is negative, convert it. high_word = Unsigned(0 - Signed(high_word)); if (low_word != 0) { high_word = Unsigned(Signed(high_word) - 1); } low_word = Unsigned(0 - Signed(low_word)); } StoreDataView64(buffer, offset, low_word, high_word, requested_little_endian); } macro DataViewSet(context: Context, receiver: Object, offset: Object, value: Object, requested_little_endian: Object, kind: constexpr ElementsKind): Object { let data_view: 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(requested_little_endian); let buffer: JSArrayBuffer = data_view.buffer; let bigint_value: BigInt; let num_value: 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) { bigint_value = ToBigInt(context, value); } else { num_value = ToNumber(context, value); } if (IsDetachedBuffer(buffer)) { ThrowTypeError(context, kDetachedOperation, MakeDataViewSetterNameString(kind)); } let viewOffset: Number = data_view.byte_offset; let viewSize: Number = data_view.byte_length; let elementSize: Number = DataViewElementSize(kind); if (getIndex + elementSize > viewSize) { ThrowRangeError(context, kInvalidDataViewAccessorOffset); } let getIndexFloat: float64 = convert<float64>(getIndex); let getIndexIntptr: intptr = Signed(convert<uintptr>(getIndexFloat)); let viewOffsetFloat: float64 = convert<float64>(viewOffset); let viewOffsetIntptr: intptr = Signed(convert<uintptr>(viewOffsetFloat)); let bufferIndex: intptr = getIndexIntptr + viewOffsetIntptr; if constexpr (kind == BIGUINT64_ELEMENTS || kind == BIGINT64_ELEMENTS) { StoreDataViewBigInt(buffer, bufferIndex, bigint_value, littleEndian); } else { let double_value: float64 = ChangeNumberToFloat64(num_value); if constexpr (kind == UINT8_ELEMENTS || kind == INT8_ELEMENTS) { StoreDataView8(buffer, bufferIndex, TruncateFloat64ToWord32(double_value)); } else if constexpr (kind == UINT16_ELEMENTS || kind == INT16_ELEMENTS) { StoreDataView16(buffer, bufferIndex, TruncateFloat64ToWord32(double_value), littleEndian); } else if constexpr (kind == UINT32_ELEMENTS || kind == INT32_ELEMENTS) { StoreDataView32(buffer, bufferIndex, TruncateFloat64ToWord32(double_value), littleEndian); } else if constexpr (kind == FLOAT32_ELEMENTS) { let float_value: float32 = TruncateFloat64ToFloat32(double_value); StoreDataView32(buffer, bufferIndex, BitcastFloat32ToInt32(float_value), littleEndian); } else if constexpr (kind == FLOAT64_ELEMENTS) { let low_word: uint32 = Float64ExtractLowWord32(double_value); let high_word: uint32 = Float64ExtractHighWord32(double_value); StoreDataView64(buffer, bufferIndex, low_word, high_word, 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 is_little_endian : Object = arguments.length > 2 ? arguments[2] : Undefined; return DataViewSet(context, receiver, offset, value, is_little_endian, 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 is_little_endian : Object = arguments.length > 2 ? arguments[2] : Undefined; return DataViewSet(context, receiver, offset, value, is_little_endian, 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 is_little_endian : Object = arguments.length > 2 ? arguments[2] : Undefined; return DataViewSet(context, receiver, offset, value, is_little_endian, 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 is_little_endian : Object = arguments.length > 2 ? arguments[2] : Undefined; return DataViewSet(context, receiver, offset, value, is_little_endian, 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 is_little_endian : Object = arguments.length > 2 ? arguments[2] : Undefined; return DataViewSet(context, receiver, offset, value, is_little_endian, 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 is_little_endian : Object = arguments.length > 2 ? arguments[2] : Undefined; return DataViewSet(context, receiver, offset, value, is_little_endian, 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 is_little_endian : Object = arguments.length > 2 ? arguments[2] : Undefined; return DataViewSet(context, receiver, offset, value, is_little_endian, 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 is_little_endian : Object = arguments.length > 2 ? arguments[2] : Undefined; return DataViewSet(context, receiver, offset, value, is_little_endian, BIGINT64_ELEMENTS); } }