@@ -776,11 +776,19 @@ Type Type::getLeastUpperBound(Type a, Type b) {
776
776
return Type (elems);
777
777
}
778
778
if (a.isRef () && b.isRef ()) {
779
- if (auto heapType =
780
- HeapType::getLeastUpperBound (a.getHeapType (), b.getHeapType ())) {
779
+ auto heapTypeA = a.getHeapType ();
780
+ auto heapTypeB = b.getHeapType ();
781
+ if (auto heapType = HeapType::getLeastUpperBound (heapTypeA, heapTypeB)) {
781
782
auto nullability =
782
783
(a.isNullable () || b.isNullable ()) ? Nullable : NonNullable;
783
- return Type (*heapType, nullability);
784
+ auto exactness = (a.isInexact () || b.isInexact ()) ? Inexact : Exact;
785
+ // The LUB can only be exact if the heap types are the same or one of them
786
+ // is bottom.
787
+ if (heapTypeA != heapTypeB && !heapTypeA.isBottom () &&
788
+ !heapTypeB.isBottom ()) {
789
+ exactness = Inexact;
790
+ }
791
+ return Type (*heapType, nullability, exactness);
784
792
}
785
793
}
786
794
return Type::none;
@@ -814,6 +822,7 @@ Type Type::getGreatestLowerBound(Type a, Type b) {
814
822
}
815
823
auto nullability =
816
824
(a.isNonNullable () || b.isNonNullable ()) ? NonNullable : Nullable;
825
+ auto exactness = (a.isExact () || b.isExact ()) ? Exact : Inexact;
817
826
HeapType heapType;
818
827
if (HeapType::isSubType (heapA, heapB)) {
819
828
heapType = heapA;
@@ -822,7 +831,13 @@ Type Type::getGreatestLowerBound(Type a, Type b) {
822
831
} else {
823
832
heapType = heapA.getBottom ();
824
833
}
825
- return Type (heapType, nullability);
834
+ // If one of the types is exact, but the GLB heap type is different than its
835
+ // heap type, then we must make the GLB heap type bottom.
836
+ if ((a.isExact () && heapType != heapA) ||
837
+ (b.isExact () && heapType != heapB)) {
838
+ heapType = heapA.getBottom ();
839
+ }
840
+ return Type (heapType, nullability, exactness);
826
841
}
827
842
828
843
const Type& Type::Iterator::operator *() const {
@@ -1432,14 +1447,24 @@ bool SubTyper::isSubType(Type a, Type b) {
1432
1447
if (a == Type::unreachable) {
1433
1448
return true ;
1434
1449
}
1435
- if (a.isRef () && b.isRef ()) {
1436
- return (a.isNullable () == b.isNullable () || !a.isNullable ()) &&
1437
- isSubType (a.getHeapType (), b.getHeapType ());
1438
- }
1439
1450
if (a.isTuple () && b.isTuple ()) {
1440
1451
return isSubType (a.getTuple (), b.getTuple ());
1441
1452
}
1442
- return false ;
1453
+ if (!a.isRef () || !b.isRef ()) {
1454
+ return false ;
1455
+ }
1456
+ if (a.isNullable () && !b.isNullable ()) {
1457
+ return false ;
1458
+ }
1459
+ if (a.isInexact () && !b.isInexact ()) {
1460
+ return false ;
1461
+ }
1462
+ auto heapTypeA = a.getHeapType ();
1463
+ auto heapTypeB = b.getHeapType ();
1464
+ if (b.isExact () && !heapTypeA.isBottom ()) {
1465
+ return heapTypeA == heapTypeB;
1466
+ }
1467
+ return isSubType (heapTypeA, heapTypeB);
1443
1468
}
1444
1469
1445
1470
bool SubTyper::isSubType (HeapType a, HeapType b) {
@@ -1586,44 +1611,69 @@ std::ostream& TypePrinter::print(Type type) {
1586
1611
} else if (type.isRef ()) {
1587
1612
auto heapType = type.getHeapType ();
1588
1613
if (type.isNullable () && heapType.isBasic () && !heapType.isShared ()) {
1614
+ if (type.isExact ()) {
1615
+ os << " (exact " ;
1616
+ }
1589
1617
// Print shorthands for certain basic heap types.
1590
1618
switch (heapType.getBasic (Unshared)) {
1591
1619
case HeapType::ext:
1592
- return os << " externref" ;
1620
+ os << " externref" ;
1621
+ break ;
1593
1622
case HeapType::func:
1594
- return os << " funcref" ;
1623
+ os << " funcref" ;
1624
+ break ;
1595
1625
case HeapType::cont:
1596
- return os << " contref" ;
1626
+ os << " contref" ;
1627
+ break ;
1597
1628
case HeapType::any:
1598
- return os << " anyref" ;
1629
+ os << " anyref" ;
1630
+ break ;
1599
1631
case HeapType::eq:
1600
- return os << " eqref" ;
1632
+ os << " eqref" ;
1633
+ break ;
1601
1634
case HeapType::i31:
1602
- return os << " i31ref" ;
1635
+ os << " i31ref" ;
1636
+ break ;
1603
1637
case HeapType::struct_:
1604
- return os << " structref" ;
1638
+ os << " structref" ;
1639
+ break ;
1605
1640
case HeapType::array:
1606
- return os << " arrayref" ;
1641
+ os << " arrayref" ;
1642
+ break ;
1607
1643
case HeapType::exn:
1608
- return os << " exnref" ;
1644
+ os << " exnref" ;
1645
+ break ;
1609
1646
case HeapType::string:
1610
- return os << " stringref" ;
1647
+ os << " stringref" ;
1648
+ break ;
1611
1649
case HeapType::none:
1612
- return os << " nullref" ;
1650
+ os << " nullref" ;
1651
+ break ;
1613
1652
case HeapType::noext:
1614
- return os << " nullexternref" ;
1653
+ os << " nullexternref" ;
1654
+ break ;
1615
1655
case HeapType::nofunc:
1616
- return os << " nullfuncref" ;
1656
+ os << " nullfuncref" ;
1657
+ break ;
1617
1658
case HeapType::nocont:
1618
- return os << " nullcontref" ;
1659
+ os << " nullcontref" ;
1660
+ break ;
1619
1661
case HeapType::noexn:
1620
- return os << " nullexnref" ;
1662
+ os << " nullexnref" ;
1663
+ break ;
1621
1664
}
1665
+ if (type.isExact ()) {
1666
+ os << ' )' ;
1667
+ }
1668
+ return os;
1622
1669
}
1623
1670
os << " (ref " ;
1624
1671
if (type.isNullable ()) {
1625
1672
os << " null " ;
1626
1673
}
1674
+ if (type.isExact ()) {
1675
+ os << " exact " ;
1676
+ }
1627
1677
printHeapTypeName (heapType);
1628
1678
os << ' )' ;
1629
1679
} else {
@@ -1851,8 +1901,9 @@ size_t RecGroupHasher::hash(Type type) const {
1851
1901
return digest;
1852
1902
}
1853
1903
assert (type.isRef ());
1854
- rehash (digest, type.getNullability ());
1855
- rehash (digest, hash (type.getHeapType ()));
1904
+ wasm::rehash (digest, type.getNullability ());
1905
+ wasm::rehash (digest, type.getExactness ());
1906
+ hash_combine (digest, hash (type.getHeapType ()));
1856
1907
return digest;
1857
1908
}
1858
1909
@@ -1974,6 +2025,7 @@ bool RecGroupEquator::eq(Type a, Type b) const {
1974
2025
}
1975
2026
if (a.isRef () && b.isRef ()) {
1976
2027
return a.getNullability () == b.getNullability () &&
2028
+ a.getExactness () == b.getExactness () &&
1977
2029
eq (a.getHeapType (), b.getHeapType ());
1978
2030
}
1979
2031
return false ;
@@ -2164,8 +2216,10 @@ Type TypeBuilder::getTempTupleType(const Tuple& tuple) {
2164
2216
return impl->tupleStore .insert (tuple);
2165
2217
}
2166
2218
2167
- Type TypeBuilder::getTempRefType (HeapType type, Nullability nullable) {
2168
- return Type (type, nullable);
2219
+ Type TypeBuilder::getTempRefType (HeapType type,
2220
+ Nullability nullable,
2221
+ Exactness exact) {
2222
+ return Type (type, nullable, exact);
2169
2223
}
2170
2224
2171
2225
void TypeBuilder::setSubType (size_t i, std::optional<HeapType> super) {
0 commit comments