[maglev] Use ElementAccessInfos to build element access

... instead of LoadHandler, similar to TF.

Bug: v8:7700
Change-Id: I0460cce154fff1ecfb9dc1d45ecc98dc3b5e87e7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3951911
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83667}
This commit is contained in:
Victor Gomes 2022-10-13 10:15:27 +02:00 committed by V8 LUCI CQ
parent 145c1c7508
commit 3a8b7d62e6
2 changed files with 82 additions and 96 deletions

View File

@ -1461,90 +1461,92 @@ bool MaglevGraphBuilder::TryBuildNamedAccess(
}
}
bool MaglevGraphBuilder::TryBuildMonomorphicElementLoad(
ValueNode* object, ValueNode* index, const compiler::MapRef& map,
MaybeObjectHandle handler) {
if (handler.is_null()) return false;
if (handler->IsSmi()) {
return TryBuildMonomorphicElementLoadFromSmiHandler(
object, index, map, handler->ToSmi().value());
bool MaglevGraphBuilder::TryBuildElementAccess(
ValueNode* object, ValueNode* index,
compiler::ElementAccessFeedback const& feedback) {
// TODO(victorgomes): Implement other access modes.
if (feedback.keyed_mode().access_mode() != compiler::AccessMode::kLoad) {
return false;
}
return false;
}
bool MaglevGraphBuilder::TryBuildMonomorphicElementLoadFromSmiHandler(
ValueNode* object, ValueNode* index, const compiler::MapRef& map,
int32_t handler) {
LoadHandler::Kind kind = LoadHandler::KindBits::decode(handler);
// TODO(victorgomes): Add fast path for loading from HeapConstant.
// TODO(victorgomes): Add fast path for loading from String.
switch (kind) {
case LoadHandler::Kind::kElement: {
if (LoadHandler::AllowOutOfBoundsBits::decode(handler)) {
return false;
}
ElementsKind elements_kind =
LoadHandler::ElementsKindBits::decode(handler);
if (!IsFastElementsKind(elements_kind)) return false;
compiler::AccessInfoFactory access_info_factory(
broker(), broker()->dependencies(), zone());
ZoneVector<compiler::ElementAccessInfo> access_infos(zone());
if (!access_info_factory.ComputeElementAccessInfos(feedback, &access_infos) ||
access_infos.empty()) {
return false;
}
// TODO(leszeks): Handle holey elements.
if (IsHoleyElementsKind(elements_kind)) return false;
DCHECK(!LoadHandler::ConvertHoleBits::decode(handler));
// Check for monomorphic case.
if (access_infos.size() == 1) {
compiler::ElementAccessInfo access_info = access_infos.front();
BuildMapCheck(object, map);
switch (index->properties().value_representation()) {
case ValueRepresentation::kTagged: {
if (SmiConstant* constant = index->TryCast<SmiConstant>()) {
index = GetInt32Constant(constant->value().value());
} else {
NodeInfo* node_info =
known_node_aspects().GetOrCreateInfoFor(index);
if (node_info->is_smi()) {
if (!node_info->int32_alternative) {
// TODO(leszeks): This could be unchecked.
node_info->int32_alternative =
AddNewNode<CheckedSmiUntag>({index});
}
index = node_info->int32_alternative;
} else {
// TODO(leszeks): Cache this knowledge/converted value somehow on
// the node info.
index = AddNewNode<CheckedObjectToIndex>({index});
// TODO(victorgomes): Support elment kind transitions.
if (access_info.transition_sources().size() != 0) return false;
// TODO(victorgomes): Support more elements kind.
ElementsKind elements_kind = access_info.elements_kind();
if (!IsFastElementsKind(elements_kind)) return false;
if (IsHoleyElementsKind(elements_kind)) return false;
const compiler::MapRef& map =
access_info.lookup_start_object_maps().front();
BuildMapCheck(object, map);
switch (index->properties().value_representation()) {
case ValueRepresentation::kTagged: {
if (SmiConstant* constant = index->TryCast<SmiConstant>()) {
index = GetInt32Constant(constant->value().value());
} else {
NodeInfo* node_info = known_node_aspects().GetOrCreateInfoFor(index);
if (node_info->is_smi()) {
if (!node_info->int32_alternative) {
// TODO(leszeks): This could be unchecked.
node_info->int32_alternative =
AddNewNode<CheckedSmiUntag>({index});
}
index = node_info->int32_alternative;
} else {
// TODO(leszeks): Cache this knowledge/converted value somehow on
// the node info.
index = AddNewNode<CheckedObjectToIndex>({index});
}
break;
}
case ValueRepresentation::kInt32: {
// Already good.
break;
}
case ValueRepresentation::kFloat64: {
// TODO(leszeks): Pass in the index register (probably the
// accumulator), so that we can save this truncation on there as a
// conversion node.
index = AddNewNode<CheckedTruncateFloat64ToInt32>({index});
break;
}
break;
}
if (LoadHandler::IsJsArrayBits::decode(handler)) {
DCHECK(map.IsJSArrayMap());
AddNewNode<CheckJSArrayBounds>({object, index});
} else {
DCHECK(!map.IsJSArrayMap());
DCHECK(map.IsJSObjectMap());
AddNewNode<CheckJSObjectElementsBounds>({object, index});
case ValueRepresentation::kInt32: {
// Already good.
break;
}
if (elements_kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) {
SetAccumulator(AddNewNode<LoadDoubleElement>({object, index}));
} else {
DCHECK(!IsDoubleElementsKind(elements_kind));
SetAccumulator(AddNewNode<LoadTaggedElement>({object, index}));
case ValueRepresentation::kFloat64: {
// TODO(leszeks): Pass in the index register (probably the
// accumulator), so that we can save this truncation on there as a
// conversion node.
index = AddNewNode<CheckedTruncateFloat64ToInt32>({index});
break;
}
return true;
}
default:
return false;
if (map.IsJSArrayMap()) {
AddNewNode<CheckJSArrayBounds>({object, index});
} else {
DCHECK(map.IsJSObjectMap());
AddNewNode<CheckJSObjectElementsBounds>({object, index});
}
if (elements_kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) {
SetAccumulator(AddNewNode<LoadDoubleElement>({object, index}));
} else {
DCHECK(!IsDoubleElementsKind(elements_kind));
SetAccumulator(AddNewNode<LoadTaggedElement>({object, index}));
}
return true;
} else {
// TODO(victorgomes): polymorphic case.
return false;
}
}
@ -1643,23 +1645,13 @@ void MaglevGraphBuilder::VisitGetKeyedProperty() {
return;
case compiler::ProcessedFeedback::kElementAccess: {
const compiler::ElementAccessFeedback& element_feedback =
processed_feedback.AsElementAccess();
if (element_feedback.transition_groups().size() != 1) break;
if (element_feedback.transition_groups()[0].size() != 1) break;
compiler::MapRef map = MakeRefAssumeMemoryFence(
broker(), element_feedback.transition_groups()[0].front());
// Monomorphic load, check the handler.
// TODO(leszeks): Make GetFeedbackForPropertyAccess read the handler.
MaybeObjectHandle handler =
FeedbackNexusForSlot(slot).FindHandlerForMap(map.object());
// Get the accumulator without conversion. TryBuildMonomorphicElementLoad
// Get the accumulator without conversion. TryBuildElementAccess
// will try to pick the best representation.
ValueNode* key = current_interpreter_frame_.accumulator();
if (TryBuildMonomorphicElementLoad(object, key, map, handler)) return;
ValueNode* index = current_interpreter_frame_.accumulator();
if (TryBuildElementAccess(object, index,
processed_feedback.AsElementAccess())) {
return;
}
break;
}

View File

@ -948,14 +948,8 @@ class MaglevGraphBuilder {
bool TryBuildNamedAccess(ValueNode* receiver, ValueNode* lookup_start_object,
compiler::NamedAccessFeedback const& feedback,
compiler::AccessMode access_mode);
bool TryBuildMonomorphicElementLoad(ValueNode* object, ValueNode* index,
const compiler::MapRef& map,
MaybeObjectHandle handler);
bool TryBuildMonomorphicElementLoadFromSmiHandler(ValueNode* object,
ValueNode* index,
const compiler::MapRef& map,
int32_t handler);
bool TryBuildElementAccess(ValueNode* object, ValueNode* index,
compiler::ElementAccessFeedback const& feedback);
template <Operation kOperation>
void BuildGenericUnaryOperationNode();