// 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. #include 'src/builtins/builtins-data-view-gen.h' namespace data_view { 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(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 DataViewBuiltinsAssembler::LoadUint8(RawPtr, uintptr): uint32; extern macro DataViewBuiltinsAssembler::LoadInt8(RawPtr, uintptr): int32; macro LoadDataView8( buffer: JSArrayBuffer, offset: uintptr, 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: uintptr, requestedLittleEndian: bool, signed: constexpr bool): Number { let dataPointer: 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 (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( buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, kind: constexpr ElementsKind): Number { let dataPointer: RawPtr = buffer.backing_store; 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( buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool): Number { let dataPointer: RawPtr = buffer.backing_store; 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, uint32): void; extern macro StoreBigIntDigit(BigInt, constexpr int31, uintptr): void; extern macro DataViewBuiltinsAssembler::DataViewEncodeBigIntBits( constexpr bool, constexpr int31): uint32; 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( buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, signed: constexpr bool): BigInt { let dataPointer: RawPtr = buffer.backing_store; 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 DataViewBuiltinsAssembler::DataViewElementSize( constexpr ElementsKind): constexpr int31; transitioning 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(kInvalidDataViewAccessorOffset); } let littleEndian: bool = ToBoolean(requestedLittleEndian); let buffer: JSArrayBuffer = dataView.buffer; if (IsDetachedBuffer(buffer)) { ThrowTypeError(kDetachedOperation, MakeDataViewGetterNameString(kind)); } let getIndexFloat: float64 = Convert<float64>(getIndex); let getIndexWord: uintptr = Convert<uintptr>(getIndexFloat); let viewOffsetWord: uintptr = dataView.byte_offset; let viewSizeFloat: float64 = Convert<float64>(dataView.byte_length); let elementSizeFloat: float64 = DataViewElementSize(kind); if (getIndexFloat + elementSizeFloat > viewSizeFloat) { ThrowRangeError(kInvalidDataViewAccessorOffset); } let bufferIndex: uintptr = getIndexWord + viewOffsetWord; 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; } } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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 TruncateFloat64ToWord32(float64): uint32; extern macro DataViewBuiltinsAssembler::StoreWord8(RawPtr, uintptr, uint32): void; macro StoreDataView8(buffer: JSArrayBuffer, offset: uintptr, value: uint32) { StoreWord8(buffer.backing_store, offset, value & 0xFF); } macro StoreDataView16( buffer: JSArrayBuffer, offset: uintptr, value: uint32, requestedLittleEndian: bool) { let dataPointer: RawPtr = buffer.backing_store; 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( buffer: JSArrayBuffer, offset: uintptr, value: uint32, requestedLittleEndian: bool) { let dataPointer: 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 (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( buffer: JSArrayBuffer, offset: uintptr, lowWord: uint32, highWord: uint32, requestedLittleEndian: bool) { let dataPointer: RawPtr = buffer.backing_store; 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 DataViewBuiltinsAssembler::DataViewDecodeBigIntLength(BigInt): uint32; extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntSign(BigInt): uint32; 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: uintptr, bigIntValue: BigInt, requestedLittleEndian: bool) { let length: uint32 = DataViewDecodeBigIntLength(bigIntValue); let sign: uint32 = 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(buffer, offset, lowWord, highWord, requestedLittleEndian); } transitioning 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(kInvalidDataViewAccessorOffset); } let littleEndian: bool = ToBoolean(requestedLittleEndian); let buffer: JSArrayBuffer = dataView.buffer; // 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) { let bigIntValue: BigInt = ToBigInt(context, value); if (IsDetachedBuffer(buffer)) { ThrowTypeError(kDetachedOperation, MakeDataViewSetterNameString(kind)); } let getIndexFloat: float64 = Convert<float64>(getIndex); let getIndexWord: uintptr = Convert<uintptr>(getIndexFloat); let viewOffsetWord: uintptr = dataView.byte_offset; let viewSizeFloat: float64 = Convert<float64>(dataView.byte_length); let elementSizeFloat: float64 = DataViewElementSize(kind); if (getIndexFloat + elementSizeFloat > viewSizeFloat) { ThrowRangeError(kInvalidDataViewAccessorOffset); } let bufferIndex: uintptr = getIndexWord + viewOffsetWord; StoreDataViewBigInt(buffer, bufferIndex, bigIntValue, littleEndian); } else { let numValue: Number = ToNumber(context, value); if (IsDetachedBuffer(buffer)) { ThrowTypeError(kDetachedOperation, MakeDataViewSetterNameString(kind)); } let getIndexFloat: float64 = Convert<float64>(getIndex); let getIndexWord: uintptr = Convert<uintptr>(getIndexFloat); let viewOffsetWord: uintptr = dataView.byte_offset; let viewSizeFloat: float64 = Convert<float64>(dataView.byte_length); let elementSizeFloat: float64 = DataViewElementSize(kind); if (getIndexFloat + elementSizeFloat > viewSizeFloat) { ThrowRangeError(kInvalidDataViewAccessorOffset); } let bufferIndex: uintptr = getIndexWord + viewOffsetWord; let doubleValue: float64 = ChangeNumberToFloat64(numValue); if constexpr (kind == UINT8_ELEMENTS || kind == INT8_ELEMENTS) { StoreDataView8( buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue)); } else if constexpr (kind == UINT16_ELEMENTS || kind == INT16_ELEMENTS) { StoreDataView16( buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue), littleEndian); } else if constexpr (kind == UINT32_ELEMENTS || kind == INT32_ELEMENTS) { StoreDataView32( buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue), littleEndian); } else if constexpr (kind == FLOAT32_ELEMENTS) { let floatValue: float32 = TruncateFloat64ToFloat32(doubleValue); StoreDataView32( buffer, bufferIndex, BitcastFloat32ToInt32(floatValue), littleEndian); } else if constexpr (kind == FLOAT64_ELEMENTS) { let lowWord: uint32 = Float64ExtractLowWord32(doubleValue); let highWord: uint32 = Float64ExtractHighWord32(doubleValue); StoreDataView64(buffer, bufferIndex, lowWord, highWord, littleEndian); } } return Undefined; } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } transitioning 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); } }