@@ -82,19 +82,6 @@ struct HeapTypeInfo {
8282 constexpr bool isData () const { return isStruct () || isArray (); }
8383};
8484
85- // Helper for coinductively checking whether a pair of Types or HeapTypes are in
86- // a subtype relation.
87- struct SubTyper {
88- bool isSubType (Type a, Type b);
89- bool isSubType (HeapType a, HeapType b);
90- bool isSubType (const Tuple& a, const Tuple& b);
91- bool isSubType (const Field& a, const Field& b);
92- bool isSubType (const Signature& a, const Signature& b);
93- bool isSubType (const Continuation& a, const Continuation& b);
94- bool isSubType (const Struct& a, const Struct& b);
95- bool isSubType (const Array& a, const Array& b);
96- };
97-
9885// Helper for finding the equirecursive least upper bound of two types.
9986// Helper for printing types.
10087struct TypePrinter {
@@ -720,12 +707,41 @@ Type Type::get(unsigned byteSize, bool float_) {
720707 WASM_UNREACHABLE (" invalid size" );
721708}
722709
723- bool Type::isSubType (Type left, Type right) {
724- // As an optimization, in the common case do not even construct a SubTyper.
725- if (left == right) {
710+ bool Type::isSubType (Type a, Type b) {
711+ if (a == b) {
712+ return true ;
713+ }
714+ if (a == Type::unreachable) {
715+ return true ;
716+ }
717+ if (a.isTuple () && b.isTuple ()) {
718+ if (a.size () != b.size ()) {
719+ return false ;
720+ }
721+ for (size_t i = 0 ; i < a.size (); ++i) {
722+ if (!isSubType (a[i], b[i])) {
723+ return false ;
724+ }
725+ }
726726 return true ;
727727 }
728- return SubTyper ().isSubType (left, right);
728+ if (!a.isRef () || !b.isRef ()) {
729+ return false ;
730+ }
731+ if (a.isNullable () && !b.isNullable ()) {
732+ return false ;
733+ }
734+ auto heapTypeA = a.getHeapType ();
735+ auto heapTypeB = b.getHeapType ();
736+ if (b.isExact ()) {
737+ if (a.isExact ()) {
738+ return heapTypeA == heapTypeB;
739+ }
740+ if (!heapTypeA.isBottom ()) {
741+ return false ;
742+ }
743+ }
744+ return HeapType::isSubType (heapTypeA, heapTypeB);
729745}
730746
731747HeapTypeChildren Type::getHeapTypeChildren () {
@@ -1118,12 +1134,64 @@ HeapType::BasicHeapType HeapType::getUnsharedTop() const {
11181134 WASM_UNREACHABLE (" unexpected type" );
11191135}
11201136
1121- bool HeapType::isSubType (HeapType left, HeapType right) {
1122- // As an optimization, in the common case do not even construct a SubTyper.
1123- if (left == right) {
1137+ bool HeapType::isSubType (HeapType a, HeapType b) {
1138+ if (a == b) {
11241139 return true ;
11251140 }
1126- return SubTyper ().isSubType (left, right);
1141+ if (a.isShared () != b.isShared ()) {
1142+ return false ;
1143+ }
1144+ if (b.isBasic ()) {
1145+ auto aTop = a.getUnsharedTop ();
1146+ auto aUnshared = a.isBasic () ? a.getBasic (Unshared) : a;
1147+ switch (b.getBasic (Unshared)) {
1148+ case HeapType::ext:
1149+ return aTop == HeapType::ext;
1150+ case HeapType::func:
1151+ return aTop == HeapType::func;
1152+ case HeapType::cont:
1153+ return aTop == HeapType::cont;
1154+ case HeapType::exn:
1155+ return aTop == HeapType::exn;
1156+ case HeapType::any:
1157+ return aTop == HeapType::any;
1158+ case HeapType::eq:
1159+ return aUnshared == HeapType::i31 || aUnshared == HeapType::none ||
1160+ aUnshared == HeapType::struct_ || aUnshared == HeapType::array ||
1161+ a.isStruct () || a.isArray ();
1162+ case HeapType::i31:
1163+ return aUnshared == HeapType::none;
1164+ case HeapType::string:
1165+ return aUnshared == HeapType::noext;
1166+ case HeapType::struct_:
1167+ return aUnshared == HeapType::none || a.isStruct ();
1168+ case HeapType::array:
1169+ return aUnshared == HeapType::none || a.isArray ();
1170+ case HeapType::none:
1171+ case HeapType::noext:
1172+ case HeapType::nofunc:
1173+ case HeapType::nocont:
1174+ case HeapType::noexn:
1175+ return false ;
1176+ }
1177+ }
1178+ if (a.isBasic ()) {
1179+ // Basic HeapTypes are only subtypes of compound HeapTypes if they are
1180+ // bottom types.
1181+ return a == b.getBottom ();
1182+ }
1183+ if (a.getKind () != b.getKind ()) {
1184+ return false ;
1185+ }
1186+ // Subtyping must be declared rather than derived from structure, so we will
1187+ // not recurse. TODO: optimize this search with some form of caching.
1188+ HeapTypeInfo* curr = getHeapTypeInfo (a);
1189+ while ((curr = curr->supertype )) {
1190+ if (curr == getHeapTypeInfo (b)) {
1191+ return true ;
1192+ }
1193+ }
1194+ return false ;
11271195}
11281196
11291197std::vector<Type> HeapType::getTypeChildren () const {
@@ -1497,141 +1565,6 @@ unsigned Field::getByteSize() const {
14971565
14981566namespace {
14991567
1500- bool SubTyper::isSubType (Type a, Type b) {
1501- if (a == b) {
1502- return true ;
1503- }
1504- if (a == Type::unreachable) {
1505- return true ;
1506- }
1507- if (a.isTuple () && b.isTuple ()) {
1508- return isSubType (a.getTuple (), b.getTuple ());
1509- }
1510- if (!a.isRef () || !b.isRef ()) {
1511- return false ;
1512- }
1513- if (a.isNullable () && !b.isNullable ()) {
1514- return false ;
1515- }
1516- auto heapTypeA = a.getHeapType ();
1517- auto heapTypeB = b.getHeapType ();
1518- if (b.isExact ()) {
1519- if (a.isExact ()) {
1520- return heapTypeA == heapTypeB;
1521- }
1522- if (!heapTypeA.isBottom ()) {
1523- return false ;
1524- }
1525- }
1526- return isSubType (heapTypeA, heapTypeB);
1527- }
1528-
1529- bool SubTyper::isSubType (HeapType a, HeapType b) {
1530- // See:
1531- // https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md#subtyping
1532- // https://github.com/WebAssembly/gc/blob/master/proposals/gc/MVP.md#defined-types
1533- if (a == b) {
1534- return true ;
1535- }
1536- if (a.isShared () != b.isShared ()) {
1537- return false ;
1538- }
1539- if (b.isBasic ()) {
1540- auto aTop = a.getUnsharedTop ();
1541- auto aUnshared = a.isBasic () ? a.getBasic (Unshared) : a;
1542- switch (b.getBasic (Unshared)) {
1543- case HeapType::ext:
1544- return aTop == HeapType::ext;
1545- case HeapType::func:
1546- return aTop == HeapType::func;
1547- case HeapType::cont:
1548- return aTop == HeapType::cont;
1549- case HeapType::exn:
1550- return aTop == HeapType::exn;
1551- case HeapType::any:
1552- return aTop == HeapType::any;
1553- case HeapType::eq:
1554- return aUnshared == HeapType::i31 || aUnshared == HeapType::none ||
1555- aUnshared == HeapType::struct_ || aUnshared == HeapType::array ||
1556- a.isStruct () || a.isArray ();
1557- case HeapType::i31:
1558- return aUnshared == HeapType::none;
1559- case HeapType::string:
1560- return aUnshared == HeapType::noext;
1561- case HeapType::struct_:
1562- return aUnshared == HeapType::none || a.isStruct ();
1563- case HeapType::array:
1564- return aUnshared == HeapType::none || a.isArray ();
1565- case HeapType::none:
1566- case HeapType::noext:
1567- case HeapType::nofunc:
1568- case HeapType::nocont:
1569- case HeapType::noexn:
1570- return false ;
1571- }
1572- }
1573- if (a.isBasic ()) {
1574- // Basic HeapTypes are only subtypes of compound HeapTypes if they are
1575- // bottom types.
1576- return a == b.getBottom ();
1577- }
1578- // Subtyping must be declared rather than derived from structure, so we will
1579- // not recurse. TODO: optimize this search with some form of caching.
1580- HeapTypeInfo* curr = getHeapTypeInfo (a);
1581- while ((curr = curr->supertype )) {
1582- if (curr == getHeapTypeInfo (b)) {
1583- return true ;
1584- }
1585- }
1586- return false ;
1587- }
1588-
1589- bool SubTyper::isSubType (const Tuple& a, const Tuple& b) {
1590- if (a.size () != b.size ()) {
1591- return false ;
1592- }
1593- for (size_t i = 0 ; i < a.size (); ++i) {
1594- if (!isSubType (a[i], b[i])) {
1595- return false ;
1596- }
1597- }
1598- return true ;
1599- }
1600-
1601- bool SubTyper::isSubType (const Field& a, const Field& b) {
1602- if (a == b) {
1603- return true ;
1604- }
1605- // Immutable fields can be subtypes.
1606- return a.mutable_ == Immutable && b.mutable_ == Immutable &&
1607- a.packedType == b.packedType && isSubType (a.type , b.type );
1608- }
1609-
1610- bool SubTyper::isSubType (const Signature& a, const Signature& b) {
1611- return isSubType (b.params , a.params ) && isSubType (a.results , b.results );
1612- }
1613-
1614- bool SubTyper::isSubType (const Continuation& a, const Continuation& b) {
1615- return isSubType (a.type , b.type );
1616- }
1617-
1618- bool SubTyper::isSubType (const Struct& a, const Struct& b) {
1619- // There may be more fields on the left, but not fewer.
1620- if (a.fields .size () < b.fields .size ()) {
1621- return false ;
1622- }
1623- for (size_t i = 0 ; i < b.fields .size (); ++i) {
1624- if (!isSubType (a.fields [i], b.fields [i])) {
1625- return false ;
1626- }
1627- }
1628- return true ;
1629- }
1630-
1631- bool SubTyper::isSubType (const Array& a, const Array& b) {
1632- return isSubType (a.element , b.element );
1633- }
1634-
16351568void TypePrinter::printHeapTypeName (HeapType type) {
16361569 if (type.isBasic ()) {
16371570 print (type);
@@ -2388,6 +2321,41 @@ void TypeBuilder::setShared(size_t i, Shareability share) {
23882321
23892322namespace {
23902323
2324+ bool isValidSupertype (const Field& a, const Field& b) {
2325+ if (a == b) {
2326+ return true ;
2327+ }
2328+ // Immutable fields can be subtypes.
2329+ return a.mutable_ == Immutable && b.mutable_ == Immutable &&
2330+ a.packedType == b.packedType && Type::isSubType (a.type , b.type );
2331+ }
2332+
2333+ bool isValidSupertype (const Signature& a, const Signature& b) {
2334+ return Type::isSubType (b.params , a.params ) &&
2335+ Type::isSubType (a.results , b.results );
2336+ }
2337+
2338+ bool isValidSupertype (const Continuation& a, const Continuation& b) {
2339+ return HeapType::isSubType (a.type , b.type );
2340+ }
2341+
2342+ bool isValidSupertype (const Struct& a, const Struct& b) {
2343+ // There may be more fields on the left, but not fewer.
2344+ if (a.fields .size () < b.fields .size ()) {
2345+ return false ;
2346+ }
2347+ for (size_t i = 0 ; i < b.fields .size (); ++i) {
2348+ if (!isValidSupertype (a.fields [i], b.fields [i])) {
2349+ return false ;
2350+ }
2351+ }
2352+ return true ;
2353+ }
2354+
2355+ bool isValidSupertype (const Array& a, const Array& b) {
2356+ return isValidSupertype (a.element , b.element );
2357+ }
2358+
23912359bool isValidSupertype (const HeapTypeInfo& sub, const HeapTypeInfo& super) {
23922360 if (!super.isOpen ) {
23932361 return false ;
@@ -2425,16 +2393,15 @@ bool isValidSupertype(const HeapTypeInfo& sub, const HeapTypeInfo& super) {
24252393 return false ;
24262394 }
24272395 }
2428- SubTyper typer;
24292396 switch (sub.kind ) {
24302397 case HeapTypeKind::Func:
2431- return typer. isSubType (sub.signature , super.signature );
2398+ return isValidSupertype (sub.signature , super.signature );
24322399 case HeapTypeKind::Cont:
2433- return typer. isSubType (sub.continuation , super.continuation );
2400+ return isValidSupertype (sub.continuation , super.continuation );
24342401 case HeapTypeKind::Struct:
2435- return typer. isSubType (sub.struct_ , super.struct_ );
2402+ return isValidSupertype (sub.struct_ , super.struct_ );
24362403 case HeapTypeKind::Array:
2437- return typer. isSubType (sub.array , super.array );
2404+ return isValidSupertype (sub.array , super.array );
24382405 case HeapTypeKind::Basic:
24392406 break ;
24402407 }
0 commit comments