diff options
Diffstat (limited to 'deps/v8/src/builtins/data-view.tq')
-rw-r--r-- | deps/v8/src/builtins/data-view.tq | 896 |
1 files changed, 896 insertions, 0 deletions
diff --git a/deps/v8/src/builtins/data-view.tq b/deps/v8/src/builtins/data-view.tq new file mode 100644 index 0000000000..7cdc74a944 --- /dev/null +++ b/deps/v8/src/builtins/data-view.tq @@ -0,0 +1,896 @@ +// 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 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 LoadDataViewUint8(buffer: JSArrayBuffer, offset: intptr): Smi { + return convert<Smi>(LoadUint8(buffer.backing_store, offset)); + } + + macro LoadDataViewInt8(buffer: JSArrayBuffer, offset: intptr): Smi { + return convert<Smi>(LoadInt8(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, + signed: constexpr 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 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 (signed) { + return convert<Number>(Signed(result)); + } else { + return convert<Number>(result); + } + } + + macro LoadDataViewFloat32(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 result: uint32; + + if (requested_little_endian) { + result = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + } else { + result = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; + } + + let float_res: float64 = convert<float64>(BitcastInt32ToFloat32(result)); + return convert<Number>(float_res); + } + + 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 generates 'false'; + const kNegativeBigInt: constexpr bool generates 'true'; + const kZeroDigitBigInt: constexpr int31 generates '0'; + const kOneDigitBigInt: constexpr int31 generates '1'; + const kTwoDigitBigInt: constexpr int31 generates '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 { + + // TODO(theotime): add more specific method name to match + // the former implementation. + let data_view: JSDataView = ValidateDataView( + context, receiver, 'get DataView.prototype.get'); + + 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, 'DataView.prototype.get'); + } + + 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 LoadDataViewUint8(buffer, bufferIndex); + } else if constexpr (kind == INT8_ELEMENTS) { + return LoadDataViewInt8(buffer, bufferIndex); + } 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, false); + } else if constexpr (kind == INT32_ELEMENTS) { + return LoadDataView32(buffer, bufferIndex, littleEndian, true); + } else if constexpr (kind == FLOAT32_ELEMENTS) { + return LoadDataViewFloat32(buffer, bufferIndex, littleEndian); + } else if constexpr (kind == FLOAT64_ELEMENTS) { + return LoadDataViewFloat64(buffer, bufferIndex, littleEndian); + } else if constexpr (kind == BIGINT64_ELEMENTS) { + return LoadDataViewBigInt(buffer, bufferIndex, littleEndian, true); + } else if constexpr (kind == BIGUINT64_ELEMENTS) { + return LoadDataViewBigInt(buffer, bufferIndex, littleEndian, false); + } else { + unreachable; + } + } + + 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 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 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 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 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 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 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 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); + } + + 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); + } + + 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 { + + // TODO(theotime): add more specific method name to match + // the former implementation. + let data_view: JSDataView = ValidateDataView( + context, receiver, 'get DataView.prototype.get'); + + 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, 'DataView.prototype.get'); + } + + 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 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 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 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 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 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 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 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 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); + } + + 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); + } + +} |