[turbofan][dataview] Add DataView Int16/Uint16 getters in TurboFan
This CL adds a Reduction for the DataViewGetInt16 and -Uint16 builtins, and the corresponding handling in LoadDataViewElement node in the effect control linearizer. It also adds tests for the new getters. Change-Id: I5101755e47657c25f10be1417f105e3ae72a3c39 Reviewed-on: https://chromium-review.googlesource.com/1126919 Commit-Queue: Théotime Grohens <theotime@google.com> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#54271}
This commit is contained in:
parent
664bcd4944
commit
e814ee3832
@ -3750,15 +3750,66 @@ Node* EffectControlLinearizer::LowerLoadDataViewElement(Node* node) {
|
||||
Node* buffer = node->InputAt(0);
|
||||
Node* storage = node->InputAt(1);
|
||||
Node* index = node->InputAt(2);
|
||||
Node* is_little_endian = node->InputAt(3);
|
||||
|
||||
// We need to keep the {buffer} alive so that the GC will not release the
|
||||
// ArrayBuffer (if there's any) as long as we are still operating on it.
|
||||
__ Retain(buffer);
|
||||
|
||||
// Perform the actual data view element access.
|
||||
return __ LoadElement(AccessBuilder::ForTypedArrayElement(
|
||||
element_type, true, LoadSensitivity::kCritical),
|
||||
storage, index);
|
||||
ElementAccess access_int8 = AccessBuilder::ForTypedArrayElement(
|
||||
kExternalInt8Array, true, LoadSensitivity::kCritical);
|
||||
ElementAccess access_uint8 = AccessBuilder::ForTypedArrayElement(
|
||||
kExternalUint8Array, true, LoadSensitivity::kCritical);
|
||||
|
||||
switch (element_type) {
|
||||
case kExternalUint8Array:
|
||||
return __ LoadElement(access_uint8, storage, index);
|
||||
|
||||
case kExternalInt8Array:
|
||||
return __ LoadElement(access_int8, storage, index);
|
||||
|
||||
case kExternalUint16Array: // Fall through.
|
||||
case kExternalInt16Array: {
|
||||
auto big_endian = __ MakeLabel();
|
||||
auto done = __ MakeLabel(MachineRepresentation::kWord32);
|
||||
|
||||
// If we're doing an Int16 load, sign-extend the most significant byte
|
||||
// by loading it as an Int8 instead of Uint8.
|
||||
ElementAccess access_msb =
|
||||
element_type == kExternalInt16Array ? access_int8 : access_uint8;
|
||||
|
||||
__ GotoIfNot(is_little_endian, &big_endian);
|
||||
{
|
||||
// Little-endian load.
|
||||
Node* b0 = __ LoadElement(access_uint8, storage, index);
|
||||
Node* b1 = __ LoadElement(access_msb, storage,
|
||||
__ Int32Add(index, __ Int32Constant(1)));
|
||||
|
||||
// result = (b1 << 8) + b0
|
||||
Node* result = __ Int32Add(__ Word32Shl(b1, __ Int32Constant(8)), b0);
|
||||
__ Goto(&done, result);
|
||||
}
|
||||
|
||||
__ Bind(&big_endian);
|
||||
{
|
||||
// Big-endian load.
|
||||
Node* b0 = __ LoadElement(access_msb, storage, index);
|
||||
Node* b1 = __ LoadElement(access_uint8, storage,
|
||||
__ Int32Add(index, __ Int32Constant(1)));
|
||||
|
||||
// result = (b0 << 8) + b1;
|
||||
Node* result = __ Int32Add(__ Word32Shl(b0, __ Int32Constant(8)), b1);
|
||||
__ Goto(&done, result);
|
||||
}
|
||||
|
||||
// We're done, return {result}.
|
||||
__ Bind(&done);
|
||||
return done.PhiAt(0);
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerLoadTypedElement(Node* node) {
|
||||
|
@ -3434,6 +3434,12 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
|
||||
case Builtins::kDataViewPrototypeGetInt8:
|
||||
return ReduceDataViewPrototypeGet(node,
|
||||
ExternalArrayType::kExternalInt8Array);
|
||||
case Builtins::kDataViewPrototypeGetUint16:
|
||||
return ReduceDataViewPrototypeGet(
|
||||
node, ExternalArrayType::kExternalUint16Array);
|
||||
case Builtins::kDataViewPrototypeGetInt16:
|
||||
return ReduceDataViewPrototypeGet(node,
|
||||
ExternalArrayType::kExternalInt16Array);
|
||||
case Builtins::kTypedArrayPrototypeByteLength:
|
||||
return ReduceArrayBufferViewAccessor(
|
||||
node, JS_TYPED_ARRAY_TYPE,
|
||||
@ -6692,9 +6698,10 @@ Reduction JSCallReducer::ReduceDataViewPrototypeGet(
|
||||
graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
|
||||
|
||||
// Perform the load.
|
||||
vfalse_range = efalse_range = graph()->NewNode(
|
||||
simplified()->LoadDataViewElement(element_type), buffer,
|
||||
backing_store, buffer_index, efalse_range, if_false_range);
|
||||
vfalse_range = efalse_range =
|
||||
graph()->NewNode(simplified()->LoadDataViewElement(element_type),
|
||||
buffer, backing_store, buffer_index,
|
||||
is_little_endian, efalse_range, if_false_range);
|
||||
}
|
||||
|
||||
// Rewire potential exception edges.
|
||||
|
@ -2636,7 +2636,8 @@ class RepresentationSelector {
|
||||
ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
|
||||
ProcessInput(node, 1, UseInfo::PointerInt()); // external pointer
|
||||
ProcessInput(node, 2, UseInfo::TruncatingWord32()); // index
|
||||
ProcessRemainingInputs(node, 3);
|
||||
ProcessInput(node, 3, UseInfo::Bool()); // little endian
|
||||
ProcessRemainingInputs(node, 4);
|
||||
SetOutput(node, rep);
|
||||
return;
|
||||
}
|
||||
|
@ -1531,7 +1531,7 @@ SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP)
|
||||
V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0) \
|
||||
V(LoadTypedElement, ExternalArrayType, Operator::kNoWrite, 4, 1, 1) \
|
||||
V(StoreTypedElement, ExternalArrayType, Operator::kNoRead, 5, 1, 0) \
|
||||
V(LoadDataViewElement, ExternalArrayType, Operator::kNoWrite, 3, 1, 1)
|
||||
V(LoadDataViewElement, ExternalArrayType, Operator::kNoWrite, 4, 1, 1)
|
||||
|
||||
#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
|
||||
output_count) \
|
||||
|
@ -9,6 +9,10 @@ var dataview = new DataView(buffer, 8, 24);
|
||||
|
||||
var values = [-1, 2, -3, 42];
|
||||
|
||||
function readUint8(offset) {
|
||||
return dataview.getUint8(offset);
|
||||
}
|
||||
|
||||
function readInt8Handled(offset) {
|
||||
try {
|
||||
return dataview.getInt8(offset);
|
||||
@ -17,8 +21,16 @@ function readInt8Handled(offset) {
|
||||
}
|
||||
}
|
||||
|
||||
function readUint8(offset) {
|
||||
return dataview.getUint8(offset);
|
||||
function readUint16(offset, little_endian) {
|
||||
return dataview.getUint16(offset, little_endian);
|
||||
}
|
||||
|
||||
function readInt16Handled(offset, little_endian) {
|
||||
try {
|
||||
return dataview.getInt16(offset, little_endian);
|
||||
} catch (e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
function warmup(f) {
|
||||
@ -49,10 +61,28 @@ assertEquals(0xad, readUint8(5));
|
||||
assertEquals(0xbe, readUint8(6));
|
||||
assertEquals(0xef, readUint8(7));
|
||||
|
||||
// TurboFan valid getUint16.
|
||||
dataview.setUint16(8, 0xabcd);
|
||||
warmup(readUint16);
|
||||
assertOptimized(readUint16);
|
||||
assertEquals(0xabcd, readUint16(8));
|
||||
assertEquals(0xcdab, readUint16(8, true));
|
||||
|
||||
// TurboFan valid getInt16.
|
||||
dataview.setInt16(10, -0x1234);
|
||||
warmup(readInt16Handled);
|
||||
assertEquals(-0x1234, readInt16Handled(10));
|
||||
dataview.setInt16(10, -0x1234, true);
|
||||
assertEquals(-0x1234, readInt16Handled(10, true));
|
||||
|
||||
// TurboFan out of bounds read, throw with exception handler.
|
||||
assertOptimized(readInt8Handled);
|
||||
assertInstanceof(readInt8Handled(64), RangeError);
|
||||
assertInstanceof(readInt8Handled(24), RangeError);
|
||||
assertOptimized(readInt8Handled);
|
||||
assertOptimized(readInt16Handled);
|
||||
assertInstanceof(readInt16Handled(23), RangeError);
|
||||
assertOptimized(readInt16Handled);
|
||||
|
||||
// Without exception handler.
|
||||
assertOptimized(readUint8);
|
||||
assertThrows(() => readUint8(64));
|
||||
|
Loading…
Reference in New Issue
Block a user