[turbofan] Create new Operator LoadDataViewElement

This CL creates a new Operator called LoadDataViewElement, similar to
LoadTypedArray, for DataView getters.

This operator will be used as a wrapper around all the computations
that DataViews need to do when loading values, due to the endianness
parameter of DataView loads.

Change-Id: Ie67d63c9669142e539a5c8d7ae82dc1018ce5858
Reviewed-on: https://chromium-review.googlesource.com/1125928
Commit-Queue: Théotime Grohens <theotime@google.com>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54217}
This commit is contained in:
Théotime Grohens 2018-07-04 16:58:00 +02:00 committed by Commit Bot
parent 417f8ee62c
commit 9b2358d689
9 changed files with 68 additions and 6 deletions

View File

@ -935,6 +935,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kLoadTypedElement:
result = LowerLoadTypedElement(node);
break;
case IrOpcode::kLoadDataViewElement:
result = LowerLoadDataViewElement(node);
break;
case IrOpcode::kStoreTypedElement:
LowerStoreTypedElement(node);
break;
@ -3742,6 +3745,22 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) {
return done.PhiAt(0);
}
Node* EffectControlLinearizer::LowerLoadDataViewElement(Node* node) {
ExternalArrayType element_type = ExternalArrayTypeOf(node->op());
Node* buffer = node->InputAt(0);
Node* storage = node->InputAt(1);
Node* index = node->InputAt(2);
// 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);
}
Node* EffectControlLinearizer::LowerLoadTypedElement(Node* node) {
ExternalArrayType array_type = ExternalArrayTypeOf(node->op());
Node* buffer = node->InputAt(0);

View File

@ -151,6 +151,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
void LowerTransitionElementsKind(Node* node);
Node* LowerLoadFieldByIndex(Node* node);
Node* LowerLoadTypedElement(Node* node);
Node* LowerLoadDataViewElement(Node* node);
void LowerStoreTypedElement(Node* node);
void LowerStoreSignedSmallElement(Node* node);
Node* LowerFindOrderedHashMapEntry(Node* node);

View File

@ -6563,6 +6563,20 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
return NoChange();
}
namespace {
int ExternalArrayElementSize(const ExternalArrayType element_type) {
switch (element_type) {
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case kExternal##Type##Array: \
return size;
TYPED_ARRAYS(TYPED_ARRAY_CASE)
default:
UNREACHABLE();
#undef TYPED_ARRAY_CASE
}
}
} // namespace
Reduction JSCallReducer::ReduceDataViewPrototypeGet(
Node* node, ExternalArrayType element_type) {
Node* effect = NodeProperties::GetEffectInput(node);
@ -6641,9 +6655,9 @@ Reduction JSCallReducer::ReduceDataViewPrototypeGet(
// The end offset is the offset plus the element size
// of the type that we want to load.
// Since we only load int8 and uint8 for now, that size is 1.
int element_size = ExternalArrayElementSize(element_type);
Node* end_offset = graph()->NewNode(simplified()->NumberAdd(), offset,
jsgraph()->OneConstant());
jsgraph()->Constant(element_size));
// We need to check that {end_offset} <= {byte_length}, ie
// throw a RangeError if {byte_length} < {end_offset}.
@ -6679,8 +6693,7 @@ Reduction JSCallReducer::ReduceDataViewPrototypeGet(
// Perform the load.
vfalse_range = efalse_range = graph()->NewNode(
simplified()->LoadElement(AccessBuilder::ForTypedArrayElement(
element_type, true, LoadSensitivity::kCritical)),
simplified()->LoadDataViewElement(element_type), buffer,
backing_store, buffer_index, efalse_range, if_false_range);
}
@ -6699,7 +6712,7 @@ Reduction JSCallReducer::ReduceDataViewPrototypeGet(
if_true_range); // We threw because out of bounds.
if_true_range = graph()->NewNode(common()->IfSuccess(), if_true_range);
// We can't throw in LoadTypedElement(),
// We can't throw in LoadDataViewElement(),
// so we don't need to handle that path here.
// Join the exception edges.

View File

@ -380,6 +380,7 @@
V(LoadField) \
V(LoadElement) \
V(LoadTypedElement) \
V(LoadDataViewElement) \
V(StoreField) \
V(StoreElement) \
V(StoreTypedElement) \

View File

@ -2630,6 +2630,16 @@ class RepresentationSelector {
SetOutput(node, rep);
return;
}
case IrOpcode::kLoadDataViewElement: {
MachineRepresentation const rep =
MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
ProcessInput(node, 1, UseInfo::PointerInt()); // external pointer
ProcessInput(node, 2, UseInfo::TruncatingWord32()); // index
ProcessRemainingInputs(node, 3);
SetOutput(node, rep);
return;
}
case IrOpcode::kStoreTypedElement: {
MachineRepresentation const rep =
MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));

View File

@ -141,6 +141,7 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
ExternalArrayType ExternalArrayTypeOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kLoadTypedElement ||
op->opcode() == IrOpcode::kLoadDataViewElement ||
op->opcode() == IrOpcode::kStoreTypedElement);
return OpParameter<ExternalArrayType>(op);
}
@ -1529,7 +1530,8 @@ SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP)
V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
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(StoreTypedElement, ExternalArrayType, Operator::kNoRead, 5, 1, 0) \
V(LoadDataViewElement, ExternalArrayType, Operator::kNoWrite, 3, 1, 1)
#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
output_count) \

View File

@ -759,6 +759,9 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
// load-typed-element buffer, [base + external + index]
const Operator* LoadTypedElement(ExternalArrayType const&);
// load-data-view-element buffer, [base + index]
const Operator* LoadDataViewElement(ExternalArrayType const&);
// store-typed-element buffer, [base + external + index], value
const Operator* StoreTypedElement(ExternalArrayType const&);

View File

@ -2043,6 +2043,17 @@ Type Typer::Visitor::TypeLoadTypedElement(Node* node) {
UNREACHABLE();
}
Type Typer::Visitor::TypeLoadDataViewElement(Node* node) {
switch (ExternalArrayTypeOf(node->op())) {
#define TYPED_ARRAY_CASE(ElemType, type, TYPE, ctype, size) \
case kExternal##ElemType##Array: \
return typer_->cache_.k##ElemType;
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
}
UNREACHABLE();
}
Type Typer::Visitor::TypeStoreField(Node* node) { UNREACHABLE(); }
Type Typer::Visitor::TypeStoreElement(Node* node) { UNREACHABLE(); }

View File

@ -1498,6 +1498,8 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
break;
case IrOpcode::kLoadTypedElement:
break;
case IrOpcode::kLoadDataViewElement:
break;
case IrOpcode::kStoreField:
// (Object, fieldtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.