Commit 3e78711c authored by Théotime Grohens's avatar Théotime Grohens Committed by Commit Bot

[dataview] Add fast path for DataView methods

This CL adds a fast path for DataView getters and setters when the
load or store to be performed is aligned and when the requested
endianness matches the platform endianness.

In that case, we can just emit the right load/store instruction
instead of having to read and write data byte by byte.

Change-Id: I10bd95a7fe8d23f695899eb8173bc654fb38fbb0
Reviewed-on: https://chromium-review.googlesource.com/1106168
Commit-Queue: Théotime Grohens <theotime@google.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54005}
parent 541a0b75
......@@ -10,9 +10,8 @@ type Tagged generates 'TNode<Object>';
type Smi extends Tagged generates 'TNode<Smi>';
type HeapObject extends Tagged generates 'TNode<HeapObject>';
type Object = Smi|HeapObject;
type word32 generates 'TNode<Word32T>' constexpr 'uint32_t';
type int32 extends word32 generates 'TNode<Int32T>' constexpr 'int32_t';
type uint32 extends word32 generates 'TNode<Uint32T>' constexpr 'uint32_t';
type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
type uint32 generates 'TNode<Uint32T>' constexpr 'uint32_t';
type int64 generates 'TNode<Int64T>' constexpr 'int64_t';
type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t';
type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t';
......@@ -243,24 +242,29 @@ extern operator '>>>' macro SmiShr(Smi, constexpr int31): Smi;
extern operator '+' macro IntPtrAdd(intptr, intptr): intptr;
extern operator '-' macro IntPtrSub(intptr, intptr): intptr;
extern operator '>>>' macro WordShr(intptr, intptr): intptr;
extern operator '>>>' macro WordShr(uintptr, uintptr): uintptr;
extern operator '<<' macro WordShl(intptr, intptr): intptr;
extern operator '&' macro WordAnd(intptr, intptr): intptr;
extern operator '&' macro WordAnd(uintptr, uintptr): uintptr;
extern operator '+' macro Int32Add(int32, int32): int32;
extern operator '-' macro Int32Sub(int32, int32): int32;
extern operator '*' macro Int32Mul(int32, int32): int32;
extern operator '%' macro Int32Mod(int32, int32): int32;
extern operator '&' macro Word32And(word32, word32): int32;
extern operator '&' macro Word32And(int32, int32): int32;
extern operator '&' macro Word32And(uint32, uint32): uint32;
extern operator '==' macro
ConstexprInt31Equal(constexpr int31, constexpr int31): constexpr bool;
extern operator '==' macro Word32Equal(word32, word32): bool;
extern operator '!=' macro Word32NotEqual(word32, word32): bool;
extern operator '>>>' macro Word32Shr(word32, word32): word32;
extern operator '<<' macro Word32Shl(word32, word32): word32;
extern operator '|' macro Word32Or(word32, word32): word32;
extern operator '==' macro Word32Equal(int32, int32): bool;
extern operator '==' macro Word32Equal(uint32, uint32): bool;
extern operator '!=' macro Word32NotEqual(int32, int32): bool;
extern operator '!=' macro Word32NotEqual(uint32, uint32): bool;
extern operator '>>>' macro Word32Shr(uint32, uint32): uint32;
extern operator '<<' macro Word32Shl(int32, int32): int32;
extern operator '<<' macro Word32Shl(uint32, uint32): uint32;
extern operator '|' macro Word32Or(int32, int32): int32;
extern operator '|' macro Word32Or(uint32, uint32): uint32;
extern operator '+' macro NumberAdd(Number, Number): Number;
extern operator '-' macro NumberSub(Number, Number): Number;
......@@ -326,10 +330,12 @@ cast<FixedDoubleArray>(o: FixedArrayBase): FixedDoubleArray labels CastError {
extern macro AllocateHeapNumberWithValue(float64): HeapNumber;
extern macro ChangeInt32ToTagged(int32): Number;
extern macro ChangeUint32ToTagged(uint32): Number;
extern macro Unsigned(word32): uint32;
extern macro Unsigned(int32): uint32;
extern macro Unsigned(intptr): uintptr;
extern macro Signed(word32): int32;
extern macro Unsigned(RawPtr): uintptr;
extern macro Signed(uint32): int32;
extern macro Signed(uintptr): intptr;
extern macro Signed(RawPtr): intptr;
extern macro TruncateIntPtrToInt32(intptr): int32;
extern macro SmiTag(intptr): Smi;
extern macro SmiFromInt32(int32): Smi;
......@@ -338,8 +344,8 @@ extern macro SmiToInt32(Smi): int32;
extern macro LoadHeapNumberValue(HeapNumber): float64;
extern macro ChangeFloat32ToFloat64(float32): float64;
extern macro ChangeNumberToFloat64(Number): float64;
extern macro ChangeInt32ToIntPtr(word32): intptr; // Sign-extends.
extern macro ChangeUint32ToWord(word32): uintptr; // Doesn't sign-extend.
extern macro ChangeInt32ToIntPtr(int32): intptr; // Sign-extends.
extern macro ChangeUint32ToWord(uint32): uintptr; // Doesn't sign-extend.
extern macro NumberConstant(constexpr float64): Number;
extern macro NumberConstant(constexpr int32): Number;
......@@ -360,8 +366,8 @@ from_constexpr<intptr>(i: constexpr int31): intptr {
from_constexpr<int32>(i: constexpr int31): int32 {
return Int32Constant(i);
}
from_constexpr<word32>(i: constexpr int31): word32 {
return from_constexpr<int32>(i);
from_constexpr<uint32>(i: constexpr int31): uint32 {
return Unsigned(Int32Constant(i));
}
from_constexpr<uintptr>(i: constexpr int31): uintptr {
return ChangeUint32ToWord(i);
......@@ -379,9 +385,6 @@ from_constexpr<intptr>(i: constexpr int32): intptr {
from_constexpr<int32>(i: constexpr int32): int32 {
return Int32Constant(i);
}
from_constexpr<word32>(i: constexpr int32): word32 {
return from_constexpr<int32>(i);
}
from_constexpr<Number>(i: constexpr int32): Number {
return NumberConstant(i);
}
......@@ -413,9 +416,6 @@ macro convert<A : type>(i: int32): A;
convert<Number>(i: int32): Number {
return ChangeInt32ToTagged(i);
}
convert<uint32>(i: int32): uint32 {
return Unsigned(i);
}
convert<intptr>(i: int32): intptr {
return ChangeInt32ToIntPtr(i);
}
......@@ -426,32 +426,22 @@ macro convert<A : type>(ui: uint32): A;
convert<Number>(ui: uint32): Number {
return ChangeUint32ToTagged(ui);
}
macro convert<A : type>(word: word32): A;
convert<int32>(word: word32): int32 {
return Signed(word);
convert<Smi>(ui: uint32): Smi {
return SmiFromInt32(Signed(ui));
}
convert<uint32>(word: word32): uint32 {
return Unsigned(word);
}
convert<uintptr>(word: word32): uintptr {
return ChangeUint32ToWord(word);
convert<uintptr>(ui: uint32): uintptr {
return ChangeUint32ToWord(ui);
}
macro convert<A : type>(i: intptr): A;
convert<word32>(i: intptr): word32 {
convert<int32>(i: intptr): int32 {
return TruncateIntPtrToInt32(i);
}
convert<uintptr>(i: intptr): uintptr {
return Unsigned(i);
}
convert<Smi>(i: intptr): Smi {
return SmiTag(i);
}
macro convert<A : type>(ui: uintptr): A;
convert<intptr>(ui: uintptr): intptr {
return Signed(ui);
}
convert<word32>(ui: uintptr): word32 {
return TruncateIntPtrToInt32(Signed(ui));
convert<uint32>(ui: uintptr): uint32 {
return Unsigned(TruncateIntPtrToInt32(Signed(ui)));
}
macro convert<A : type>(s: Smi): A;
convert<intptr>(s: Smi): intptr {
......@@ -472,6 +462,17 @@ macro convert<A : type>(f: float32): A;
convert<float64>(f: float32): float64 {
return ChangeFloat32ToFloat64(f);
}
macro convert<A : type>(d: float64): A;
convert<Number>(d: float64): Number {
return AllocateHeapNumberWithValue(d);
}
macro convert<A : type>(r: RawPtr): A;
convert<uintptr>(r: RawPtr): uintptr {
return Unsigned(r);
}
convert<intptr>(r: RawPtr): intptr {
return Signed(r);
}
extern macro UnsafeCastNumberToHeapNumber(Number): HeapNumber;
extern macro UnsafeCastObjectToFixedArray(Object): FixedArray;
......
......@@ -25,6 +25,14 @@ class DataViewBuiltinsAssembler : public BaseBuiltinsFromDSLAssembler {
return CAST(LoadObjectField(data_view, JSDataView::kByteLengthOffset));
}
bool IsTargetLittleEndian() {
#ifdef V8_TARGET_LITTLE_ENDIAN
return true;
#else
return false;
#endif
}
TNode<Int32T> LoadUint8(TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset) {
return UncheckedCast<Int32T>(
Load(MachineType::Uint8(), data_pointer, offset));
......@@ -35,12 +43,57 @@ class DataViewBuiltinsAssembler : public BaseBuiltinsFromDSLAssembler {
Load(MachineType::Int8(), data_pointer, offset));
}
TNode<Int32T> LoadUint16(TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset) {
return UncheckedCast<Int32T>(
Load(MachineType::Uint16(), data_pointer, offset));
}
TNode<Int32T> LoadInt16(TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset) {
return UncheckedCast<Int32T>(
Load(MachineType::Int16(), data_pointer, offset));
}
TNode<Uint32T> LoadUint32(TNode<RawPtrT> data_pointer,
TNode<IntPtrT> offset) {
return UncheckedCast<Uint32T>(
Load(MachineType::Uint32(), data_pointer, offset));
}
TNode<Int32T> LoadInt32(TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset) {
return UncheckedCast<Int32T>(
Load(MachineType::Int32(), data_pointer, offset));
}
TNode<Float32T> LoadFloat32(TNode<RawPtrT> data_pointer,
TNode<IntPtrT> offset) {
return UncheckedCast<Float32T>(
Load(MachineType::Float32(), data_pointer, offset));
}
TNode<Float64T> LoadFloat64(TNode<RawPtrT> data_pointer,
TNode<IntPtrT> offset) {
return UncheckedCast<Float64T>(
Load(MachineType::Float64(), data_pointer, offset));
}
void StoreWord8(TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset,
TNode<Word32T> value) {
StoreNoWriteBarrier(MachineRepresentation::kWord8, data_pointer, offset,
value);
}
void StoreWord16(TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset,
TNode<Word32T> value) {
StoreNoWriteBarrier(MachineRepresentation::kWord16, data_pointer, offset,
value);
}
void StoreWord32(TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset,
TNode<Word32T> value) {
StoreNoWriteBarrier(MachineRepresentation::kWord32, data_pointer, offset,
value);
}
int32_t DataViewElementSize(ElementsKind elements_kind) {
return ElementsKindToByteSize(elements_kind);
}
......
......@@ -59,15 +59,43 @@ module data_view {
return data_view.byte_offset;
}
extern macro BitcastInt32ToFloat32(word32): float32;
extern macro BitcastFloat32ToInt32(float32): word32;
extern macro Float64ExtractLowWord32(float64): word32;
extern macro Float64ExtractHighWord32(float64): word32;
extern macro Float64InsertLowWord32(float64, word32): float64;
extern macro Float64InsertHighWord32(float64, word32): float64;
extern macro LoadUint8(RawPtr, intptr): int32;
extern macro IsTargetLittleEndian(): constexpr bool;
macro EndiannessMatchesTarget(requested_little_endian: bool): bool {
if constexpr (IsTargetLittleEndian()) {
return requested_little_endian;
} else {
return !requested_little_endian;
}
}
macro IsAddressAligned(address: intptr, width: constexpr int31): bool {
if constexpr (width == 2) {
return (address & 1) == 0;
} else if constexpr (width == 4) {
return (address & 3) == 0;
} else if constexpr (width == 8) {
return (address & 7) == 0;
} else {
unreachable;
}
}
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;
extern macro LoadUint16(RawPtr, intptr): int32;
extern macro LoadInt16(RawPtr, intptr): int32;
extern macro LoadUint32(RawPtr, intptr): uint32;
extern macro LoadInt32(RawPtr, intptr): int32;
extern macro LoadFloat32(RawPtr, intptr): float32;
extern macro LoadFloat64(RawPtr, intptr): float64;
macro LoadDataViewUint8(buffer: JSArrayBuffer, offset: intptr): Smi {
return convert<Smi>(LoadUint8(buffer.backing_store, offset));
......@@ -81,19 +109,31 @@ module data_view {
requested_little_endian: bool,
signed: constexpr bool): Number {
let data_pointer: RawPtr = buffer.backing_store;
// If endiannesses match and the pointer is aligned, we can
// directly load the value.
if (IsAddressAligned(convert<intptr>(data_pointer) + offset, 2) &&
EndiannessMatchesTarget(requested_little_endian)) {
if constexpr (signed) {
return convert<Number>(LoadInt16(data_pointer, offset));
} else {
return convert<Number>(LoadUint16(data_pointer, offset));
}
}
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 = LoadUint8(data_pointer, offset);
b0 = Signed(LoadUint8(data_pointer, offset));
b1 = LoadInt8(data_pointer, offset + 1);
result = convert<int32>(b1 << 8) + b0;
result = (b1 << 8) + b0;
} else {
b0 = LoadInt8(data_pointer, offset);
b1 = LoadUint8(data_pointer, offset + 1);
result = convert<int32>(b0 << 8) + b1;
b1 = Signed(LoadUint8(data_pointer, offset + 1));
result = (b0 << 8) + b1;
}
if constexpr (signed) {
return convert<Smi>(result);
......@@ -107,77 +147,99 @@ module data_view {
requested_little_endian: bool,
signed: constexpr bool): Number {
let data_pointer: RawPtr = buffer.backing_store;
let b0: word32 = LoadUint8(data_pointer, offset);
let b1: word32 = LoadUint8(data_pointer, offset + 1);
let b2: word32 = LoadUint8(data_pointer, offset + 2);
let b3: word32 = LoadUint8(data_pointer, offset + 3);
let result: word32;
// If endiannesses match and the pointer is aligned, we can
// directly load the value.
if (IsAddressAligned(convert<intptr>(data_pointer) + offset, 4) &&
EndiannessMatchesTarget(requested_little_endian)) {
if constexpr (signed) {
return convert<Number>(LoadInt32(data_pointer, offset));
} else {
return convert<Number>(LoadUint32(data_pointer, offset));
}
}
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) {
let low_part: word32 = (b1 << 8) | b0;
let high_part: word32 = (b3 << 8) | b2;
result = (high_part << 16) | low_part;
result = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
} else {
let high_part: word32 = (b0 << 8) | b1;
let low_part: word32 = (b2 << 8) | b3;
result = (high_part << 16) | low_part;
result = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
}
if constexpr (signed) {
return convert<Number>(convert<int32>(result));
return convert<Number>(Signed(result));
} else {
return convert<Number>(convert<uint32>(result));
return convert<Number>(result);
}
}
macro LoadDataViewFloat32(buffer: JSArrayBuffer, offset: intptr,
requested_little_endian: bool): HeapNumber {
requested_little_endian: bool): Number {
let data_pointer: RawPtr = buffer.backing_store;
let b0: word32 = LoadUint8(data_pointer, offset);
let b1: word32 = LoadUint8(data_pointer, offset + 1);
let b2: word32 = LoadUint8(data_pointer, offset + 2);
let b3: word32 = LoadUint8(data_pointer, offset + 3);
let result: word32;
// If endiannesses match and the pointer is aligned, we can
// directly load the value.
if (IsAddressAligned(convert<intptr>(data_pointer) + offset, 4) &&
EndiannessMatchesTarget(requested_little_endian)) {
let res: float64 = convert<float64>(LoadFloat32(data_pointer, offset));
return convert<Number>(res);
}
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) {
let low_part: word32 = (b1 << 8) | b0;
let high_part: word32 = (b3 << 8) | b2;
result = (high_part << 16) | low_part;
result = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
} else {
let high_part: word32 = (b0 << 8) | b1;
let low_part: word32 = (b2 << 8) | b3;
result = (high_part << 16) | low_part;
result = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
}
let float_res: float64 = convert<float64>(BitcastInt32ToFloat32(result));
return AllocateHeapNumberWithValue(float_res);
return convert<Number>(float_res);
}
macro LoadDataViewFloat64(buffer: JSArrayBuffer, offset: intptr,
requested_little_endian: bool): HeapNumber {
requested_little_endian: bool): Number {
let data_pointer: RawPtr = buffer.backing_store;
let b0: word32 = LoadUint8(data_pointer, offset);
let b1: word32 = LoadUint8(data_pointer, offset + 1);
let b2: word32 = LoadUint8(data_pointer, offset + 2);
let b3: word32 = LoadUint8(data_pointer, offset + 3);
let b4: word32 = LoadUint8(data_pointer, offset + 4);
let b5: word32 = LoadUint8(data_pointer, offset + 5);
let b6: word32 = LoadUint8(data_pointer, offset + 6);
let b7: word32 = LoadUint8(data_pointer, offset + 7);
// If endiannesses match and the pointer is aligned, we can
// directly load the value.
if (IsAddressAligned(convert<intptr>(data_pointer) + offset, 8) &&
EndiannessMatchesTarget(requested_little_endian)) {
return convert<Number>(LoadFloat64(data_pointer, offset));
}
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 result: float64 = convert<float64>(0);
if (requested_little_endian) {
let low_part: word32 = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
let high_part: word32 = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
result = Float64InsertLowWord32(result, low_part);
result = Float64InsertHighWord32(result, high_part);
let low_word: uint32 = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
let high_word: uint32 = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
result = Float64InsertLowWord32(result, low_word);
result = Float64InsertHighWord32(result, high_word);
} else {
let high_part: word32 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
let low_part: word32 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
result = Float64InsertLowWord32(result, low_part);
result = Float64InsertHighWord32(result, high_part);
let high_word: uint32 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
let low_word: uint32 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
result = Float64InsertLowWord32(result, low_word);
result = Float64InsertHighWord32(result, high_word);
}
return AllocateHeapNumberWithValue(result);
return convert<Number>(result);
}
extern macro AllocateBigInt(intptr): BigInt;
......@@ -188,13 +250,13 @@ module data_view {
constexpr int31): intptr;
// Create a BigInt on a 64-bit architecture from two 32-bit values.
macro MakeBigIntOn64Bit(low_word: word32, high_word: word32,
macro MakeBigIntOn64Bit(low_word: uint32, high_word: uint32,
signed: constexpr bool): BigInt {
// TODO(theotime): Replace magic numbers for the number of digits in
// AllocateRawBigInt and DataViewEncodeBigIntBits with constants.
let result: BigInt = AllocateRawBigInt(1);
let high_part: intptr = convert<intptr>(convert<uintptr>(high_word));
let low_part: intptr = convert<intptr>(convert<uintptr>(low_word));
let high_part: intptr = Signed(convert<uintptr>(high_word));
let low_part: intptr = Signed(convert<uintptr>(low_word));
let value: intptr = (high_part << 32) + low_part;
if constexpr (signed) {
......@@ -209,13 +271,13 @@ module data_view {
StoreBigIntBitfield(result, DataViewEncodeBigIntBits(false, 1));
}
StoreBigIntDigit(result, 0, convert<uintptr>(value));
StoreBigIntDigit(result, 0, Unsigned(value));
return result;
}
// Create a BigInt on a 32-bit architecture from two 32-bit values.
macro MakeBigIntOn32Bit(low_word: word32, high_word: word32,
macro MakeBigIntOn32Bit(low_word: uint32, high_word: uint32,
signed: constexpr bool): BigInt {
// TODO(theotime): Replace magic numbers for the number of digits in
// AllocateRawBigInt and DataViewEncodeBigIntBits with constants.
......@@ -227,8 +289,8 @@ module data_view {
// We need to do some math on low_word and high_word,
// so convert them to int32.
let low_part: int32 = convert<int32>(low_word);
let high_part: int32 = convert<int32>(high_word);
let low_part: int32 = Signed(low_word);
let high_part: int32 = Signed(high_word);
// If high_word == 0, the number is positive, so we only need 1 digit.
if (high_word == 0) {
......@@ -275,11 +337,9 @@ module data_view {
}
// Finally, write the digit(s) to the BigInt.
let low_intptr: intptr = convert<intptr>(low_part);
StoreBigIntDigit(result, 0, convert<uintptr>(low_intptr));
StoreBigIntDigit(result, 0, Unsigned(convert<intptr>(low_part)));
if (two_digits) {
let high_intptr: intptr = convert<intptr>(high_part);
StoreBigIntDigit(result, 1, convert<uintptr>(high_intptr));
StoreBigIntDigit(result, 1, Unsigned(convert<intptr>(high_part)));
}
return result;
......@@ -289,24 +349,39 @@ module data_view {
requested_little_endian: bool,
signed: constexpr bool): BigInt {
let data_pointer: RawPtr = buffer.backing_store;
let b0: word32 = LoadUint8(data_pointer, offset);
let b1: word32 = LoadUint8(data_pointer, offset + 1);
let b2: word32 = LoadUint8(data_pointer, offset + 2);
let b3: word32 = LoadUint8(data_pointer, offset + 3);
let b4: word32 = LoadUint8(data_pointer, offset + 4);
let b5: word32 = LoadUint8(data_pointer, offset + 5);
let b6: word32 = LoadUint8(data_pointer, offset + 6);
let b7: word32 = LoadUint8(data_pointer, offset + 7);
let low_word: word32;
let high_word: word32;
let low_word: uint32;
let high_word: uint32;
let result: BigInt;
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;
// If endiannesses match and the pointer is aligned, we can
// directly load the words.
if (IsAddressAligned(convert<intptr>(data_pointer) + offset, 4) &&
EndiannessMatchesTarget(requested_little_endian)) {
if (requested_little_endian) {
low_word = LoadUint32(data_pointer, offset);
high_word = LoadUint32(data_pointer, offset + 4);
} else {
high_word = LoadUint32(data_pointer, offset);
low_word = LoadUint32(data_pointer, offset + 4);
}
}
else { // We have to perform the loads byte by byte.
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);
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;
}
}
// 0 is a special case (0 BigInt digits), we handle it separately here.
......@@ -504,21 +579,32 @@ module data_view {
extern macro ToNumber(Context, Object): Number;
extern macro ToBigInt(Context, Object): BigInt;
extern macro TruncateFloat64ToFloat32(float64): float32;
extern macro TruncateFloat64ToWord32(float64): word32;
extern macro TruncateFloat64ToWord32(float64): uint32;
extern macro StoreWord8(RawPtr, intptr, word32): void;
extern macro StoreWord8(RawPtr, intptr, uint32): void;
extern macro StoreWord16(RawPtr, intptr, uint32): void;
extern macro StoreWord32(RawPtr, intptr, uint32): void;
macro StoreDataView8(buffer: JSArrayBuffer, offset: intptr,
value: word32): void {
value: uint32) {
StoreWord8(buffer.backing_store, offset, value & 0xFF);
}
macro StoreDataView16(buffer: JSArrayBuffer, offset: intptr, value: word32,
requested_little_endian: bool): void {
let b0: word32 = value & 0xFF;
let b1: word32 = (value >>> 8) & 0xFF;
macro StoreDataView16(buffer: JSArrayBuffer, offset: intptr, value: uint32,
requested_little_endian: bool) {
let data_pointer: RawPtr = buffer.backing_store;
// If endiannesses match and the pointer is aligned, we can
// directly store the value.
if (IsAddressAligned(convert<intptr>(data_pointer) + offset, 2) &&
EndiannessMatchesTarget(requested_little_endian)) {
StoreWord16(data_pointer, offset, value);
return;
}
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);
......@@ -528,14 +614,23 @@ module data_view {
}
}
macro StoreDataView32(buffer: JSArrayBuffer, offset: intptr, value: word32,
requested_little_endian: bool): void {
let b0: word32 = value & 0xFF;
let b1: word32 = (value >>> 8) & 0xFF;
let b2: word32 = (value >>> 16) & 0xFF;
let b3: word32 = value >>> 24; // We don't need to mask here.
macro StoreDataView32(buffer: JSArrayBuffer, offset: intptr, value: uint32,
requested_little_endian: bool) {
let data_pointer: RawPtr = buffer.backing_store;
// If endiannesses match and the pointer is aligned, we can
// directly store the value.
if (IsAddressAligned(convert<intptr>(data_pointer) + offset, 4) &&
EndiannessMatchesTarget(requested_little_endian)) {
StoreWord32(data_pointer, offset, value);
return;
}
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);
......@@ -550,20 +645,35 @@ module data_view {
}
macro StoreDataView64(buffer: JSArrayBuffer, offset: intptr,
low_word: word32, high_word: word32,
requested_little_endian: bool): void {
let b0: word32 = low_word & 0xFF;
let b1: word32 = (low_word >>> 8) & 0xFF;
let b2: word32 = (low_word >>> 16) & 0xFF;
let b3: word32 = low_word >>> 24;
let b4: word32 = high_word & 0xFF;
let b5: word32 = (high_word >>> 8) & 0xFF;
let b6: word32 = (high_word >>> 16) & 0xFF;
let b7: word32 = high_word >>> 24;
low_word: uint32, high_word: uint32,
requested_little_endian: bool) {
let data_pointer: RawPtr = buffer.backing_store;
// If endiannesses match and the pointer is aligned, we can
// directly store the words.
if (IsAddressAligned(convert<intptr>(data_pointer) + offset, 4) &&
EndiannessMatchesTarget(requested_little_endian)) {
if (requested_little_endian) {
StoreWord32(data_pointer, offset, low_word);
StoreWord32(data_pointer, offset + 4, high_word);
} else {
StoreWord32(data_pointer, offset, high_word);
StoreWord32(data_pointer, offset + 4, low_word);
}
return;
}
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);
......@@ -594,38 +704,38 @@ module data_view {
// 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): void {
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: word32 = 0;
let high_word: word32 = 0;
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<word32>(value); // Truncates value to 32 bits.
high_word = convert<word32>(value >>> 32);
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<word32>(LoadBigIntDigit(bigint_value, 0));
low_word = convert<uint32>(LoadBigIntDigit(bigint_value, 0));
if (length >= 2) { // Only load the second digit if there is one.
high_word = convert<word32>(LoadBigIntDigit(bigint_value, 1));
high_word = convert<uint32>(LoadBigIntDigit(bigint_value, 1));
}
}
}
if (sign != 0) { // The number is negative, convert it.
high_word = 0 - convert<int32>(high_word);
high_word = Unsigned(0 - Signed(high_word));
if (low_word != 0) {
high_word = convert<int32>(high_word) - 1;
high_word = Unsigned(Signed(high_word) - 1);
}
low_word = 0 - convert<int32>(low_word);
low_word = Unsigned(0 - Signed(low_word));
}
StoreDataView64(buffer, offset, low_word, high_word,
......@@ -705,8 +815,8 @@ module data_view {
BitcastFloat32ToInt32(float_value), littleEndian);
}
else if constexpr (kind == FLOAT64_ELEMENTS) {
let low_word: word32 = Float64ExtractLowWord32(double_value);
let high_word: word32 = Float64ExtractHighWord32(double_value);
let low_word: uint32 = Float64ExtractLowWord32(double_value);
let high_word: uint32 = Float64ExtractHighWord32(double_value);
StoreDataView64(buffer, bufferIndex, low_word, high_word,
littleEndian);
}
......
......@@ -174,8 +174,8 @@ module test {
}
macro TestVariableRedeclaration(context : Context) : Boolean {
let var1 : Number = 42 == 0 ? 0 : 1;
let var2 : Number = 42 == 0 ? 1 : 0;
let var1 : Number = from_constexpr<bool>(42 == 0) ? 0 : 1;
let var2 : Number = from_constexpr<bool>(42 == 0) ? 1 : 0;
return True;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment