[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:
Théotime Grohens 2018-07-05 17:48:54 +02:00 committed by Commit Bot
parent 664bcd4944
commit e814ee3832
5 changed files with 101 additions and 12 deletions

View File

@ -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) {

View File

@ -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.

View File

@ -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;
}

View File

@ -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) \

View File

@ -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));