14V8_INLINE bool EquivalentIndices(ModuleTypeIndex index1, ModuleTypeIndex index2,
17 DCHECK(index1 != index2 || module1 != module2);
18 return module1->canonical_type_id(index1) ==
19 module2->canonical_type_id(index2);
22bool ValidStructSubtypeDefinition(ModuleTypeIndex subtype_index,
23 ModuleTypeIndex supertype_index,
26 const TypeDefinition& sub_def = sub_module->type(subtype_index);
27 const TypeDefinition& super_def = super_module->type(supertype_index);
28 const StructType* sub_struct = sub_def.struct_type;
29 const StructType* super_struct = super_def.struct_type;
31 if (sub_struct->field_count() < super_struct->field_count()) {
35 for (uint32_t
i = 0;
i < super_struct->field_count();
i++) {
36 bool sub_mut = sub_struct->mutability(
i);
37 bool super_mut = super_struct->mutability(
i);
38 if (sub_mut != super_mut ||
41 sub_module, super_module)) ||
42 (!sub_mut && !
IsSubtypeOf(sub_struct->field(
i), super_struct->field(
i),
43 sub_module, super_module))) {
47 if (sub_def.descriptor.valid()) {
51 if (super_def.descriptor.valid() &&
53 super_module->heap_type(super_def.descriptor),
54 sub_module, super_module)) {
59 if (super_def.descriptor.valid())
return false;
62 if (sub_def.describes.valid() != super_def.describes.valid()) {
68bool ValidArraySubtypeDefinition(ModuleTypeIndex subtype_index,
69 ModuleTypeIndex supertype_index,
72 const ArrayType* sub_array = sub_module->type(subtype_index).array_type;
73 const ArrayType* super_array = super_module->type(supertype_index).array_type;
74 bool sub_mut = sub_array->mutability();
75 bool super_mut = super_array->mutability();
77 return (sub_mut && super_mut &&
79 super_array->element_type(), sub_module,
81 (!sub_mut && !super_mut &&
82 IsSubtypeOf(sub_array->element_type(), super_array->element_type(),
83 sub_module, super_module));
86bool ValidFunctionSubtypeDefinition(ModuleTypeIndex subtype_index,
87 ModuleTypeIndex supertype_index,
90 const FunctionSig* sub_func = sub_module->type(subtype_index).function_sig;
92 super_module->type(supertype_index).function_sig;
94 if (sub_func->parameter_count() != super_func->parameter_count() ||
95 sub_func->return_count() != super_func->return_count()) {
99 for (uint32_t
i = 0;
i < sub_func->parameter_count();
i++) {
101 if (!
IsSubtypeOf(super_func->parameters()[
i], sub_func->parameters()[
i],
102 super_module, sub_module)) {
106 for (uint32_t
i = 0;
i < sub_func->return_count();
i++) {
108 if (!
IsSubtypeOf(sub_func->returns()[
i], super_func->returns()[
i],
109 sub_module, super_module)) {
117bool ValidContinuationSubtypeDefinition(ModuleTypeIndex subtype_index,
118 ModuleTypeIndex supertype_index,
121 const ContType* sub_cont = sub_module->type(subtype_index).cont_type;
122 const ContType* super_cont = super_module->type(supertype_index).cont_type;
125 sub_module->heap_type(sub_cont->contfun_typeindex()),
126 super_module->heap_type(super_cont->contfun_typeindex()), sub_module,
133 if (!type.has_index())
return type.standard_type();
134 switch (type.ref_type_kind()) {
136 return StandardType::kStruct;
138 return StandardType::kArray;
140 return StandardType::kFunc;
142 return StandardType::kCont;
149#define FOREACH_SUBTYPING(V) \
163 V(ExternString, Extern) \
164 V(NoExtern, ExternString) \
170static constexpr uint32_t kNumStandardTypes =
173static constexpr std::array<GenericKind, kNumStandardTypes>
175#define ENTRY(name, ...) \
176 if (static_cast<size_t>(StandardType::k##name) == i) { \
177 return GenericKind::k##name; \
182 return GenericKind::kVoid;
185 DCHECK_LT(
static_cast<int>(type),
static_cast<int>(StandardType::kI32));
186 return kValueTypeLookupMap[
static_cast<size_t>(
type)];
194#define CASE(sub, super) \
195 if (type == StandardType::k##sub || type == StandardType::k##super) return 0;
200static constexpr uint32_t kNumNonTrivial =
201#define CASE(name, ...) (NotInSubtypeRelation(StandardType::k##name) ? 0 : 1) +
207enum class CondensedIndices :
int {
212#define ENTRY(name, ...) \
214 k##name##AdjustNext = \
215 k##name - NotInSubtypeRelation(StandardType::k##name),
219static constexpr uint8_t kNotRelatedSentinel = 0xFF;
220static_assert(kNumStandardTypes < kNotRelatedSentinel);
222constexpr uint8_t ComputeCondensedIndex(
StandardType type) {
224#define BAILOUT(name, ...) case StandardType::k##name:
226 return kNotRelatedSentinel;
228#define CASE(name, ...) \
229 case StandardType::k##name: \
230 if (NotInSubtypeRelation(type)) return kNotRelatedSentinel; \
231 return static_cast<uint8_t>(CondensedIndices::k##name);
236constexpr StandardType ComputeStandardType(uint8_t condensed_index) {
237#define CASE(name, ...) \
238 if (ComputeCondensedIndex(StandardType::k##name) == condensed_index) \
239 return StandardType::k##name;
245static constexpr std::array<uint8_t, kNumStandardTypes>
246 kCondensedIndexLookupMap =
250static constexpr std::array<uint8_t, kNumNonTrivial> kCondensedToStandardMap =
252 [](
size_t i) {
return static_cast<uint8_t
>(ComputeStandardType(
i)); });
255 return kCondensedIndexLookupMap[
static_cast<size_t>(
type)];
257constexpr StandardType CondensedToStandard(uint8_t condensed) {
258 return static_cast<StandardType>(kCondensedToStandardMap[condensed]);
265constexpr bool ComputeIsSubtype(
size_t sub,
size_t super) {
266 if (sub == super)
return true;
269 size_t raw_a = static_cast<size_t>(CondensedIndices::k##a); \
270 size_t raw_b = static_cast<size_t>(CondensedIndices::k##b); \
271 if (sub == raw_a) { \
272 if (super == raw_b) return true; \
273 if (ComputeIsSubtype(raw_b, super)) return true; \
283static constexpr std::array<std::array<bool, kNumNonTrivial>, kNumNonTrivial>
286 [sub](
size_t super) {
return ComputeIsSubtype(sub, super); });
295 if (sub == StandardType::kBottom)
return true;
296 if (super == StandardType::kTop)
return true;
297 uint8_t sub_condensed = CondensedIndex(sub);
298 if (sub_condensed == kNotRelatedSentinel)
return sub == super;
299 uint8_t super_condensed = CondensedIndex(super);
300 if (super_condensed == kNotRelatedSentinel)
return false;
301 return kSubtypeLookupMap2[sub_condensed][super_condensed];
309constexpr StandardType ComputeCommonAncestor(
size_t t1,
size_t t2) {
310 if (kSubtypeLookupMap2[t1][t2])
return CondensedToStandard(t2);
311 if (kSubtypeLookupMap2[t2][t1])
return CondensedToStandard(t1);
313 if (t1 == static_cast<size_t>(CondensedIndices::k##a)) { \
314 return ComputeCommonAncestor(static_cast<size_t>(CondensedIndices::k##b), \
319 return StandardType::kTop;
324static constexpr std::array<std::array<StandardType, kNumNonTrivial>,
328 [sub](
size_t super) {
return ComputeCommonAncestor(sub, super); });
333 if (t1 == StandardType::kBottom)
return t2;
334 if (t2 == StandardType::kBottom)
return t1;
335 if (t1 == StandardType::kTop)
return t1;
336 if (t2 == StandardType::kTop)
return t2;
337 uint8_t t1_condensed = CondensedIndex(t1);
338 if (t1_condensed == kNotRelatedSentinel) {
339 return t2 == t1 ? t1 : StandardType::kTop;
341 uint8_t t2_condensed = CondensedIndex(t2);
342 if (t2_condensed == kNotRelatedSentinel)
return StandardType::kTop;
343 return kCommonAncestorLookupMap[t1_condensed][t2_condensed];
349HeapType NullSentinelImpl(HeapType type) {
352#define NULLTYPE(name, ...) StandardType::k##name,
357 if (SubtypeLookup(candidate, standard)) {
361 if (type.is_string_view()) {
369bool IsNullSentinel(HeapType type) {
370 if (type.has_index())
return false;
374bool IsGenericSubtypeOfIndexedTypes(ValueTypeBase type) {
375 DCHECK(type.is_generic());
388 if (subtype.
kind != supertype.
kind)
return false;
389 if (supertype.
is_final)
return false;
391 switch (subtype.
kind) {
393 return ValidFunctionSubtypeDefinition(subtype_index, supertype_index,
394 sub_module, super_module);
396 return ValidStructSubtypeDefinition(subtype_index, supertype_index,
397 sub_module, super_module);
399 return ValidArraySubtypeDefinition(subtype_index, supertype_index,
400 sub_module, super_module);
402 return ValidContinuationSubtypeDefinition(subtype_index, supertype_index,
403 sub_module, super_module);
409std::optional<bool> IsSubtypeOf_Abstract(ValueTypeBase subtype,
410 ValueTypeBase supertype) {
411 DCHECK(!subtype.is_numeric() && !supertype.is_numeric());
413 if (subtype.is_shared() != supertype.is_shared())
return false;
414 if (supertype.is_exact()) {
415 if (!subtype.is_exact())
return false;
416 if (subtype.is_bottom())
return true;
417 if (supertype.has_index()) {
418 if (!subtype.has_index())
return false;
422 return !subtype.has_index() &&
423 subtype.generic_kind() == supertype.generic_kind();
425 if (supertype.has_index()) {
428 if (subtype.has_index())
return {};
430 if (!IsGenericSubtypeOfIndexedTypes(subtype))
return false;
432 return SubtypeLookup(UpcastToStandardType(subtype),
433 UpcastToStandardType(supertype));
441 DCHECK(subtype != supertype || sub_module != super_module);
443 std::optional<bool>
result = IsSubtypeOf_Abstract(subtype, supertype);
456 sub_index = sub_module->
supertype(sub_index);
457 }
while (sub_index.
valid());
469 if (supertype.
is_top())
return true;
470 if (subtype.
is_numeric())
return subtype == supertype;
475 if (sub_heap == super_heap && sub_module == super_module)
return true;
476 return IsSubtypeOfImpl(sub_heap, super_heap, sub_module, super_module);
482 if (supertype.
is_top())
return true;
487 std::optional<bool>
result = IsSubtypeOf_Abstract(subtype, supertype);
493 if (sub_index == super_index)
return true;
494 if (supertype.
is_exact())
return false;
501 if (type1 == type2 && module1 == module2)
return true;
516HeapType CommonAncestor(HeapType type1, HeapType type2,
518 DCHECK(type1.has_index() && type2.has_index());
519 bool both_shared = type1.is_shared();
520 if (both_shared != type2.is_shared())
return HeapType{
kWasmTop};
522 ModuleTypeIndex type_index1 = type1.ref_index();
523 ModuleTypeIndex type_index2 = type2.ref_index();
527 while (depth1 > depth2) {
528 type_index1 = module1->
supertype(type_index1);
531 while (depth2 > depth1) {
532 type_index2 = module2->
supertype(type_index2);
539 !(type_index1 == type_index2 && module1 == module2) &&
540 !EquivalentIndices(type_index1, type_index2, module1, module2)) {
541 type_index1 = module1->
supertype(type_index1);
542 type_index2 = module2->
supertype(type_index2);
553 UpcastToStandardType(type1), UpcastToStandardType(type2));
559HeapType CommonAncestorWithAbstract(HeapType heap1, HeapType heap2,
561 DCHECK(heap1.is_abstract_ref());
567 std::optional<bool> is_sub = IsSubtypeOf_Abstract(heap1, heap2);
568 DCHECK(is_sub.has_value());
569 if (is_sub.value())
return heap2;
574 UpcastToStandardType(heap1), UpcastToStandardType(heap2));
578Exactness UnionExactness(ValueType type1, ValueType type2,
583 if (!type1.has_index()) {
584 DCHECK(IsNullSentinel(type1.heap_type()));
587 if (!type2.has_index()) {
588 DCHECK(IsNullSentinel(type2.heap_type()));
592 EquivalentIndices(type1.ref_index(), type2.ref_index(), module1, module2);
605 return {type1 == type2 ? type1 :
kWasmTop, module1};
609 Exactness exactness = UnionExactness(type1, type2, module1, module2);
612 if (heap1 == heap2 && module1 == module2) {
618 result_type = CommonAncestorWithAbstract(heap1, heap2, module2);
619 result_module = module2;
621 result_type = CommonAncestorWithAbstract(heap2, heap1, module1);
622 result_module = module1;
624 result_type = CommonAncestor(heap1, heap2, module1, module2);
625 result_module = module1;
638 if (type1 ==
kWasmTop)
return {type2, module2};
639 if (type2 ==
kWasmTop)
return {type1, module1};
641 return {type1 == type2 ? type1 :
kWasmBottom, module1};
667 return {null_type1, module1};
673 HeapType null_heap = NullSentinelImpl(type.type.heap_type());
680 return NullSentinelImpl(type1) == NullSentinelImpl(type2);
constexpr CanonicalTypeIndex ref_index() const
static constexpr HeapType Generic(GenericKind kind, bool shared)
static constexpr HeapType Index(ModuleTypeIndex index, bool shared, RefTypeKind kind, Exactness exact=Exactness::kAnySubtype)
constexpr ModuleTypeIndex ref_index() const
bool IsHeapSubtype(CanonicalTypeIndex sub, CanonicalTypeIndex super) const
constexpr bool is_ref() const
constexpr bool is_bottom() const
constexpr bool has_index() const
constexpr Nullability nullability() const
constexpr bool is_numeric() const
constexpr bool is_nullable() const
constexpr bool is_exact() const
constexpr bool is_abstract_ref() const
constexpr bool is_top() const
constexpr ValueType AsExact(Exactness exact=Exactness::kExact) const
constexpr HeapType heap_type() const
static constexpr ValueType RefNull(ModuleTypeIndex index, bool shared, RefTypeKind kind)
constexpr ModuleTypeIndex ref_index() const
static constexpr ValueType RefMaybeNull(ModuleTypeIndex index, Nullability nullable, bool shared, RefTypeKind kind)
constexpr ValueType AsNullable(Nullability nullable=kNullable) const
ZoneVector< OpIndex > candidates
ZoneVector< RpoNumber > & result
#define BAILOUT(name,...)
constexpr auto make_array(Function f)
static constexpr uint32_t kNumberOfStandardTypes
constexpr bool IsNullKind(GenericKind kind)
ValueType ToNullSentinel(TypeInModule type)
int GetSubtypingDepth(const WasmModule *module, ModuleTypeIndex type_index)
bool IsSameTypeHierarchy(HeapType type1, HeapType type2, const WasmModule *module)
V8_NOINLINE V8_EXPORT_PRIVATE bool IsSubtypeOfImpl(HeapType subtype, HeapType supertype, const WasmModule *sub_module, const WasmModule *super_module)
V8_NOINLINE bool EquivalentTypes(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
V8_INLINE bool IsHeapSubtypeOf(HeapType subtype, HeapType supertype, const WasmModule *sub_module, const WasmModule *super_module)
TypeCanonicalizer * GetTypeCanonicalizer()
TypeInModule Intersection(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
V8_EXPORT_PRIVATE TypeInModule Union(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
constexpr ModuleTypeIndex kNoSuperType
constexpr IndependentHeapType kWasmTop
bool ValidSubtypeDefinition(ModuleTypeIndex subtype_index, ModuleTypeIndex supertype_index, const WasmModule *sub_module, const WasmModule *super_module)
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype, const WasmModule *sub_module, const WasmModule *super_module)
constexpr IndependentHeapType kWasmBottom
Signature< ValueType > FunctionSig
wasm::WasmModule WasmModule
JSArrayBuffer::IsDetachableBit is_shared
#define DCHECK_NE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define V8_EXPORT_PRIVATE
constexpr bool valid() const
CanonicalTypeIndex canonical_type_id(ModuleTypeIndex index) const
const TypeDefinition & type(ModuleTypeIndex index) const
ModuleTypeIndex supertype(ModuleTypeIndex index) const
bool has_type(ModuleTypeIndex index) const
#define NULLTYPE(name,...)
#define FOREACH_NUMERIC_VALUE_TYPE(V)
#define FOREACH_NONE_TYPE(V)
#define FOREACH_SUBTYPING(V)