[maglev] Warm up NodeInfo with static knowledge

For constants and smi-tagging, we have some static knowledge of the node
type, so warm-up the NodeType of NodeInfo in the Build*Check helpers.
Similarly, don't emit map checks for constant nodes that have a known
stable map.

Bug: v8:7700
Change-Id: I36e4d3000cf2f4dc689e8a9ab612a88dd751cdb5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3918770
Commit-Queue: Jakob Linke <jgruber@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Jakob Linke <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83443}
This commit is contained in:
Leszek Swirski 2022-09-26 17:33:42 +02:00 committed by V8 LUCI CQ
parent 0688729cbe
commit 3b289d05d0
3 changed files with 73 additions and 8 deletions

View File

@ -1040,9 +1040,35 @@ void MaglevGraphBuilder::VisitStaLookupSlot() {
SetAccumulator(BuildCallRuntime(StaLookupSlotFunction(flags), {name, value})); SetAccumulator(BuildCallRuntime(StaLookupSlotFunction(flags), {name, value}));
} }
namespace {
NodeType StaticTypeForNode(ValueNode* node) {
DCHECK(node->is_tagged());
switch (node->opcode()) {
case Opcode::kCheckedSmiTag:
case Opcode::kSmiConstant:
return NodeType::kSmi;
case Opcode::kConstant: {
compiler::HeapObjectRef ref = node->Cast<Constant>()->object();
if (ref.IsString()) {
return NodeType::kString;
} else if (ref.IsSymbol()) {
return NodeType::kSymbol;
} else if (ref.IsHeapNumber()) {
return NodeType::kHeapNumber;
}
return NodeType::kHeapObjectWithKnownMap;
}
default:
return NodeType::kUnknown;
}
}
} // namespace
void MaglevGraphBuilder::BuildCheckSmi(ValueNode* object) { void MaglevGraphBuilder::BuildCheckSmi(ValueNode* object) {
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object); NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object);
if (known_info->is_smi()) return; if (known_info->is_smi()) return;
known_info->type = StaticTypeForNode(object);
if (known_info->is_smi()) return;
// TODO(leszeks): Figure out a way to also handle CheckedSmiUntag. // TODO(leszeks): Figure out a way to also handle CheckedSmiUntag.
AddNewNode<CheckSmi>({object}); AddNewNode<CheckSmi>({object});
@ -1052,6 +1078,8 @@ void MaglevGraphBuilder::BuildCheckSmi(ValueNode* object) {
void MaglevGraphBuilder::BuildCheckHeapObject(ValueNode* object) { void MaglevGraphBuilder::BuildCheckHeapObject(ValueNode* object) {
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object); NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object);
if (known_info->is_any_heap_object()) return; if (known_info->is_any_heap_object()) return;
known_info->type = StaticTypeForNode(object);
if (known_info->is_any_heap_object()) return;
AddNewNode<CheckHeapObject>({object}); AddNewNode<CheckHeapObject>({object});
known_info->type = NodeType::kAnyHeapObject; known_info->type = NodeType::kAnyHeapObject;
@ -1069,6 +1097,8 @@ CheckType GetCheckType(NodeInfo* known_info) {
void MaglevGraphBuilder::BuildCheckString(ValueNode* object) { void MaglevGraphBuilder::BuildCheckString(ValueNode* object) {
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object); NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object);
if (known_info->is_string()) return; if (known_info->is_string()) return;
known_info->type = StaticTypeForNode(object);
if (known_info->is_string()) return;
AddNewNode<CheckString>({object}, GetCheckType(known_info)); AddNewNode<CheckString>({object}, GetCheckType(known_info));
known_info->type = NodeType::kString; known_info->type = NodeType::kString;
@ -1077,6 +1107,8 @@ void MaglevGraphBuilder::BuildCheckString(ValueNode* object) {
void MaglevGraphBuilder::BuildCheckSymbol(ValueNode* object) { void MaglevGraphBuilder::BuildCheckSymbol(ValueNode* object) {
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object); NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object);
if (known_info->is_symbol()) return; if (known_info->is_symbol()) return;
known_info->type = StaticTypeForNode(object);
if (known_info->is_symbol()) return;
AddNewNode<CheckSymbol>({object}, GetCheckType(known_info)); AddNewNode<CheckSymbol>({object}, GetCheckType(known_info));
known_info->type = NodeType::kSymbol; known_info->type = NodeType::kSymbol;
@ -1093,10 +1125,32 @@ void MaglevGraphBuilder::BuildMapCheck(ValueNode* object,
// Map is already checked. // Map is already checked.
return; return;
} }
// TODO(leszeks): Insert an unconditional deopt if the known type doesn't // TODO(leszeks): Insert an unconditional deopt if the known map doesn't
// match the required type. // match the required map.
} }
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object); NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(object);
if (known_info->type == NodeType::kUnknown) {
known_info->type = StaticTypeForNode(object);
if (known_info->type == NodeType::kHeapObjectWithKnownMap) {
// The only case where the type becomes a heap-object with a known map is
// when the object is a constant.
DCHECK(object->Is<Constant>());
// For constants with stable maps that match the desired map, we don't
// need to emit a map check, and can use the dependency -- we can't do
// this for unstable maps because the constant could migrate during
// compilation.
// TODO(leszeks): Insert an unconditional deopt if the constant map
// doesn't match the required map.
compiler::MapRef constant_map = object->Cast<Constant>()->object().map();
if (constant_map.equals(map) && map.is_stable()) {
DCHECK_EQ(&map_of_maps, &known_node_aspects().stable_maps);
map_of_maps.emplace(object, map);
broker()->dependencies()->DependOnStableMap(map);
return;
}
}
}
if (map.is_migration_target()) { if (map.is_migration_target()) {
AddNewNode<CheckMapsWithMigration>({object}, map, GetCheckType(known_info)); AddNewNode<CheckMapsWithMigration>({object}, map, GetCheckType(known_info));
} else { } else {

View File

@ -72,6 +72,17 @@ enum class NodeType {
kHeapObjectWithKnownMap = (1 << 5) | kAnyHeapObject, kHeapObjectWithKnownMap = (1 << 5) | kAnyHeapObject,
}; };
inline bool NodeTypeIsSmi(NodeType type) { return type == NodeType::kSmi; }
inline bool NodeTypeIsAnyHeapObject(NodeType type) {
return static_cast<int>(type) & static_cast<int>(NodeType::kAnyHeapObject);
}
inline bool NodeTypeIsString(NodeType type) {
return type == NodeType::kString;
}
inline bool NodeTypeIsSymbol(NodeType type) {
return type == NodeType::kSymbol;
}
struct NodeInfo { struct NodeInfo {
NodeType type = NodeType::kUnknown; NodeType type = NodeType::kUnknown;
@ -83,12 +94,10 @@ struct NodeInfo {
ValueNode* int32_alternative = nullptr; ValueNode* int32_alternative = nullptr;
ValueNode* float64_alternative = nullptr; ValueNode* float64_alternative = nullptr;
bool is_smi() const { return type == NodeType::kSmi; } bool is_smi() const { return NodeTypeIsSmi(type); }
bool is_any_heap_object() const { bool is_any_heap_object() const { return NodeTypeIsAnyHeapObject(type); }
return static_cast<int>(type) & static_cast<int>(NodeType::kAnyHeapObject); bool is_string() const { return NodeTypeIsString(type); }
} bool is_symbol() const { return NodeTypeIsSymbol(type); }
bool is_string() const { return type == NodeType::kString; }
bool is_symbol() const { return type == NodeType::kSymbol; }
// Mutate this node info by merging in another node info, with the result // Mutate this node info by merging in another node info, with the result
// being a node info that is the subset of information valid in both inputs. // being a node info that is the subset of information valid in both inputs.

View File

@ -2250,6 +2250,8 @@ class Constant : public FixedInputValueNodeT<0, Constant> {
DECL_NODE_INTERFACE() DECL_NODE_INTERFACE()
compiler::HeapObjectRef object() { return object_; }
void DoLoadToRegister(MaglevAssembler*, OutputRegister); void DoLoadToRegister(MaglevAssembler*, OutputRegister);
Handle<Object> DoReify(LocalIsolate* isolate); Handle<Object> DoReify(LocalIsolate* isolate);