v8 maglev 编译器 NodeType 介绍
1. StaticType (静态类型)-完全可信
基于底层的 ValueRepresentation 与 opcode 获取静态的 Node 类型,完全绑定到节点,基于节点的定义获取类型,不会修改
// maglev-ir.cc:506-585
NodeType ValueNode::GetStaticType(compiler::JSHeapBroker* broker) {
// 第一层:基于 ValueRepresentation
switch (properties().value_representation()) {
case ValueRepresentation::kInt32:
case ValueRepresentation::kUint32:
case ValueRepresentation::kFloat64:
case ValueRepresentation::kIntPtr:
return NodeType::kNumber; // 已经是数字表示,100% 确定
case ValueRepresentation::kHoleyFloat64:
return NodeType::kNumberOrOddball;
case ValueRepresentation::kTagged:
break; // 继续下一层判断
}
// 第二层:基于节点类型(Opcode)
switch (opcode()) {
case Opcode::kSmiConstant:
return NodeType::kSmi; // Smi 常量,100% 确定
case Opcode::kCheckedSmiTagInt32:
case Opcode::kUnsafeSmiTagInt32:
return NodeType::kSmi; // 生成 Smi 的操作,100% 确定
case Opcode::kToNumberOrNumeric:
return NodeType::kNumber; // ToNumber 结果必是 Number
case Opcode::kConstant:
return StaticTypeForConstant(broker, ref); // 常量的类型
default:
return NodeType::kUnknown; // 未知类型,保守处理
}
}
2. KnownNodeAspects 中的类型
NodeInfos 中维护了 Node 到 NodeInfo 的映射。GetType 优先从 NodeInfos 获取类型信息,因为有一些 Node 可能一开始类型是 unknown,后续特化出具体类型并存在 NodeInfos 中,这里面的类型比 StaticType 更精确。如果没有特化的类型再回退到 StaticType。
之后处理 phi 节点,因为 NodeInfos 保存的是一个精确的类型,所以要对所有可能的 NodeType 取交集。
TODO: 对 ReturnedValue 的特殊处理。跟 inline 有关系,暂时遗留???
DEBUG 模式下验证 actual_type <= static_type 这种偏序关系
using NodeInfos = ZoneMap<ValueNode*, NodeInfo>;
NodeType GetType(compiler::JSHeapBroker* broker, ValueNode* node) const {
// We first check the KnownNodeAspects in order to return the most precise
// type possible.
auto info = TryGetInfoFor(node);
if (info == nullptr) {
// If this node has no NodeInfo (or not known type in its NodeInfo), we
// fall back to its static type.
return node->GetStaticType(broker);
}
NodeType actual_type = info->type();
if (auto phi = node->TryCast<Phi>()) {
actual_type = IntersectType(actual_type, phi->type());
}
if (node->Is<ReturnedValue>()) {
// The returned value might be more precise than the one stored in the
// node info.
actual_type =
IntersectType(actual_type, GetType(broker, node->input_node(0)));
}
#ifdef DEBUG
NodeType static_type = node->GetStaticType(broker);
if (!NodeTypeIs(actual_type, static_type)) {
// In case we needed a numerical alternative of a smi value, the type
// must generalize. In all other cases the node info type should reflect
// the actual type.
DCHECK(static_type == NodeType::kSmi &&
actual_type == NodeType::kNumber &&
!TryGetInfoFor(node)->alternative().has_none());
}
#endif // DEBUG
return actual_type;
}
NodeType 维护
EnsureType 特化
Node 创建的以后只有 StaticType,在 graph_builder 的时候会添加一些 check 节点,这这个时候会进行类型特化。
以 buildchecksmi 为例,EnsureType 检查 Node 的 Type 是不是已经确定是 NodeType::kSmi 了,是的话就返回,不用生成后面的 Check 节点。不是的话会把 NodeType::kSmi 这个特化后的值 KnownNodeAspects 中并生成 Check 节点。在后续的使用中因为 Check 的保证,这个 Node 的类型被特化到 NodeType::kSmi。
ReduceResult MaglevGraphBuilder::BuildCheckSmi(ValueNode* object,
bool elidable) {
if (object->StaticTypeIs(broker(), NodeType::kSmi)) return object;
// Check for the empty type first so that we catch the case where
// GetType(object) is already empty.
if (IsEmptyNodeType(IntersectType(GetType(object), NodeType::kSmi))) {
return EmitUnconditionalDeopt(DeoptimizeReason::kSmi);
}
if (EnsureType(object, NodeType::kSmi) && elidable) return object;
// 生成 type check 节点
}
按照 known_info_type <= static_type 的关系判断特化类型。如果 static_type 类型满足,那记录中的类型肯定也满足。否则的话调用 GetOrCreateInfoFor(broker, node) 查询或者创建出 KnownNodeAspects 中保存的类型,初始值赋值为 static_type。后续就是判断,取交集特化类型。
bool EnsureType(compiler::JSHeapBroker* broker, ValueNode* node,
NodeType type, NodeType* old_type = nullptr) {
NodeType static_type = node->GetStaticType(broker);
if (old_type) *old_type = static_type;
if (NodeTypeIs(static_type, type)) return true;
NodeInfo* known_info = GetOrCreateInfoFor(broker, node);
if (old_type) *old_type = known_info->type();
if (NodeTypeIs(known_info->type(), type)) return true;
known_info->IntersectType(type);
if (auto phi = node->TryCast<Phi>()) {
known_info->IntersectType(phi->type());
}
if (NodeTypeIsUnstable(type)) {
known_info->set_node_type_is_unstable();
any_map_for_any_node_is_unstable_ = true;
}
return false;
}
控制流合并
对维护的 NodeType 取并集,泛化类型