@@ -187,8 +187,6 @@ struct TypeBounder {
187187 // used directly.
188188 std::optional<Type> lub (Type a, Type b);
189189 HeapType lub (HeapType a, HeapType b);
190- HeapType::BasicHeapType lub (HeapType::BasicHeapType a,
191- HeapType::BasicHeapType b);
192190 std::optional<Tuple> lub (const Tuple& a, const Tuple& b);
193191 std::optional<Field> lub (const Field& a, const Field& b);
194192 std::optional<Signature> lub (const Signature& a, const Signature& b);
@@ -582,6 +580,52 @@ HeapType asCanonical(HeapType type) {
582580 }
583581}
584582
583+ HeapType::BasicHeapType getBasicHeapSupertype (HeapType type) {
584+ if (type.isBasic ()) {
585+ return type.getBasic ();
586+ }
587+ auto * info = getHeapTypeInfo (type);
588+ switch (info->kind ) {
589+ case HeapTypeInfo::BasicKind:
590+ break ;
591+ case HeapTypeInfo::SignatureKind:
592+ return HeapType::func;
593+ case HeapTypeInfo::StructKind:
594+ case HeapTypeInfo::ArrayKind:
595+ return HeapType::data;
596+ }
597+ WASM_UNREACHABLE (" unexpected kind" );
598+ };
599+
600+ HeapType getBasicHeapTypeLUB (HeapType::BasicHeapType a,
601+ HeapType::BasicHeapType b) {
602+ if (a == b) {
603+ return a;
604+ }
605+ // Canonicalize to have `a` be the lesser type.
606+ if (unsigned (a) > unsigned (b)) {
607+ std::swap (a, b);
608+ }
609+ switch (a) {
610+ case HeapType::func:
611+ case HeapType::any:
612+ return HeapType::any;
613+ case HeapType::eq:
614+ if (b == HeapType::i31 || b == HeapType::data) {
615+ return HeapType::eq;
616+ }
617+ return HeapType::any;
618+ case HeapType::i31:
619+ if (b == HeapType::data) {
620+ return HeapType::eq;
621+ }
622+ return HeapType::any;
623+ case HeapType::data:
624+ return HeapType::any;
625+ }
626+ WASM_UNREACHABLE (" unexpected basic type" );
627+ }
628+
585629TypeInfo::TypeInfo (const TypeInfo& other) {
586630 kind = other.kind ;
587631 switch (kind) {
@@ -1222,11 +1266,59 @@ std::vector<HeapType> Type::getHeapTypeChildren() {
12221266}
12231267
12241268bool Type::hasLeastUpperBound (Type a, Type b) {
1225- return TypeBounder ().hasLeastUpperBound (a, b);
1269+ if (getTypeSystem () == TypeSystem::Equirecursive) {
1270+ return TypeBounder ().hasLeastUpperBound (a, b);
1271+ }
1272+ return getLeastUpperBound (a, b) != Type::none;
12261273}
12271274
12281275Type Type::getLeastUpperBound (Type a, Type b) {
1229- return TypeBounder ().getLeastUpperBound (a, b);
1276+ if (a == b) {
1277+ return a;
1278+ }
1279+ if (getTypeSystem () == TypeSystem::Equirecursive) {
1280+ return TypeBounder ().getLeastUpperBound (a, b);
1281+ }
1282+ if (a == Type::unreachable) {
1283+ return b;
1284+ }
1285+ if (b == Type::unreachable) {
1286+ return a;
1287+ }
1288+ if (a.isTuple () && b.isTuple ()) {
1289+ auto size = a.size ();
1290+ if (size != b.size ()) {
1291+ return Type::none;
1292+ }
1293+ std::vector<Type> elems;
1294+ elems.reserve (size);
1295+ for (size_t i = 0 ; i < size; ++i) {
1296+ auto lub = Type::getLeastUpperBound (a[i], b[i]);
1297+ if (lub == Type::none) {
1298+ return Type::none;
1299+ }
1300+ elems.push_back (lub);
1301+ }
1302+ return Type (elems);
1303+ }
1304+ if (a.isRef () && b.isRef ()) {
1305+ auto nullability =
1306+ (a.isNullable () || b.isNullable ()) ? Nullable : NonNullable;
1307+ auto heapType =
1308+ HeapType::getLeastUpperBound (a.getHeapType (), b.getHeapType ());
1309+ return Type (heapType, nullability);
1310+ }
1311+ if (a.isRtt () && b.isRtt ()) {
1312+ auto heapType = a.getHeapType ();
1313+ if (heapType != b.getHeapType ()) {
1314+ return Type::none;
1315+ }
1316+ auto rttA = a.getRtt (), rttB = b.getRtt ();
1317+ auto depth = rttA.depth == rttB.depth ? rttA.depth : Rtt::NoDepth;
1318+ return Rtt (depth, heapType);
1319+ }
1320+ return Type::none;
1321+ WASM_UNREACHABLE (" unexpected type" );
12301322}
12311323
12321324size_t Type::size () const {
@@ -1426,7 +1518,53 @@ std::vector<HeapType> HeapType::getReferencedHeapTypes() const {
14261518}
14271519
14281520HeapType HeapType::getLeastUpperBound (HeapType a, HeapType b) {
1429- return TypeBounder ().getLeastUpperBound (a, b);
1521+ if (a == b) {
1522+ return a;
1523+ }
1524+ if (getTypeSystem () == TypeSystem::Equirecursive) {
1525+ return TypeBounder ().getLeastUpperBound (a, b);
1526+ }
1527+ if (a.isBasic () || b.isBasic ()) {
1528+ return getBasicHeapTypeLUB (getBasicHeapSupertype (a),
1529+ getBasicHeapSupertype (b));
1530+ }
1531+
1532+ auto * infoA = getHeapTypeInfo (a);
1533+ auto * infoB = getHeapTypeInfo (b);
1534+
1535+ if (infoA->kind != infoB->kind ) {
1536+ return getBasicHeapTypeLUB (getBasicHeapSupertype (a),
1537+ getBasicHeapSupertype (b));
1538+ }
1539+
1540+ // Walk up the subtype tree to find the LUB. Ascend the tree from both `a`
1541+ // and `b` in lockstep. The first type we see for a second time must be the
1542+ // LUB because there are no cycles and the only way to encounter a type
1543+ // twice is for it to be on the path above both `a` and `b`.
1544+ std::unordered_set<HeapTypeInfo*> seen;
1545+ seen.insert (infoA);
1546+ seen.insert (infoB);
1547+ while (true ) {
1548+ auto * nextA = infoA->supertype ;
1549+ auto * nextB = infoB->supertype ;
1550+ if (nextA == nullptr && nextB == nullptr ) {
1551+ // Did not find a LUB in the subtype tree.
1552+ return getBasicHeapTypeLUB (getBasicHeapSupertype (a),
1553+ getBasicHeapSupertype (b));
1554+ }
1555+ if (nextA) {
1556+ if (!seen.insert (nextA).second ) {
1557+ return HeapType (uintptr_t (nextA));
1558+ }
1559+ infoA = nextA;
1560+ }
1561+ if (nextB) {
1562+ if (!seen.insert (nextB).second ) {
1563+ return HeapType (uintptr_t (nextB));
1564+ }
1565+ infoB = nextB;
1566+ }
1567+ }
14301568}
14311569
14321570// Recursion groups with single elements are encoded as that single element's
@@ -1763,70 +1901,20 @@ HeapType TypeBounder::lub(HeapType a, HeapType b) {
17631901 return a;
17641902 }
17651903
1766- auto getBasicApproximation = [](HeapType x) {
1767- if (x.isBasic ()) {
1768- return x.getBasic ();
1769- }
1770- auto * info = getHeapTypeInfo (x);
1771- switch (info->kind ) {
1772- case HeapTypeInfo::BasicKind:
1773- break ;
1774- case HeapTypeInfo::SignatureKind:
1775- return HeapType::func;
1776- case HeapTypeInfo::StructKind:
1777- case HeapTypeInfo::ArrayKind:
1778- return HeapType::data;
1779- }
1780- WASM_UNREACHABLE (" unexpected kind" );
1781- };
1782-
1783- auto getBasicLUB = [&]() {
1784- return lub (getBasicApproximation (a), getBasicApproximation (b));
1785- };
1786-
17871904 if (a.isBasic () || b.isBasic ()) {
1788- return getBasicLUB ();
1905+ return getBasicHeapTypeLUB (getBasicHeapSupertype (a),
1906+ getBasicHeapSupertype (b));
17891907 }
17901908
17911909 HeapTypeInfo* infoA = getHeapTypeInfo (a);
17921910 HeapTypeInfo* infoB = getHeapTypeInfo (b);
17931911
17941912 if (infoA->kind != infoB->kind ) {
1795- return getBasicLUB ();
1913+ return getBasicHeapTypeLUB (getBasicHeapSupertype (a),
1914+ getBasicHeapSupertype (b));
17961915 }
17971916
1798- if (typeSystem == TypeSystem::Nominal ||
1799- typeSystem == TypeSystem::Isorecursive) {
1800- // Walk up the subtype tree to find the LUB. Ascend the tree from both `a`
1801- // and `b` in lockstep. The first type we see for a second time must be the
1802- // LUB because there are no cycles and the only way to encounter a type
1803- // twice is for it to be on the path above both `a` and `b`.
1804- std::unordered_set<HeapTypeInfo*> seen;
1805- auto * currA = infoA;
1806- auto * currB = infoB;
1807- seen.insert (currA);
1808- seen.insert (currB);
1809- while (true ) {
1810- auto * nextA = currA->supertype ;
1811- auto * nextB = currB->supertype ;
1812- if (nextA == nullptr && nextB == nullptr ) {
1813- // Did not find a LUB in the subtype tree.
1814- return getBasicLUB ();
1815- }
1816- if (nextA) {
1817- if (!seen.insert (nextA).second ) {
1818- return HeapType (uintptr_t (nextA));
1819- }
1820- currA = nextA;
1821- }
1822- if (nextB) {
1823- if (!seen.insert (nextB).second ) {
1824- return HeapType (uintptr_t (nextB));
1825- }
1826- currB = nextB;
1827- }
1828- }
1829- }
1917+ assert (getTypeSystem () == TypeSystem::Equirecursive);
18301918
18311919 // Allocate a new slot to construct the LUB of this pair if we have not
18321920 // already seen it before. Canonicalize the pair to have the element with the
@@ -1865,35 +1953,6 @@ HeapType TypeBounder::lub(HeapType a, HeapType b) {
18651953 WASM_UNREACHABLE (" unexpected kind" );
18661954}
18671955
1868- HeapType::BasicHeapType TypeBounder::lub (HeapType::BasicHeapType a,
1869- HeapType::BasicHeapType b) {
1870- if (a == b) {
1871- return a;
1872- }
1873- // Canonicalize to have `x` be the lesser type.
1874- if (unsigned (a) > unsigned (b)) {
1875- std::swap (a, b);
1876- }
1877- switch (a) {
1878- case HeapType::func:
1879- case HeapType::any:
1880- return HeapType::any;
1881- case HeapType::eq:
1882- if (b == HeapType::i31 || b == HeapType::data) {
1883- return HeapType::eq;
1884- }
1885- return HeapType::any;
1886- case HeapType::i31:
1887- if (b == HeapType::data) {
1888- return HeapType::eq;
1889- }
1890- return HeapType::any;
1891- case HeapType::data:
1892- return HeapType::any;
1893- }
1894- WASM_UNREACHABLE (" unexpected basic type" );
1895- }
1896-
18971956std::optional<Tuple> TypeBounder::lub (const Tuple& a, const Tuple& b) {
18981957 if (a.types .size () != b.types .size ()) {
18991958 return {};
0 commit comments