diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 75c5452f238..8a1c72999ee 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -3903,4 +3903,12 @@ std::ostream& operator<<(std::ostream& o, wasm::ModuleType pair) { return o; } +std::ostream& operator<<(std::ostream& o, wasm::ModuleHeapType pair) { + if (auto it = pair.first.typeNames.find(pair.second); + it != pair.first.typeNames.end()) { + return o << it->second.name; + } + return o << "(unnamed)"; +} + } // namespace std diff --git a/src/passes/Unsubtyping.cpp b/src/passes/Unsubtyping.cpp index 13dc6432be4..6b8d56f33c4 100644 --- a/src/passes/Unsubtyping.cpp +++ b/src/passes/Unsubtyping.cpp @@ -37,6 +37,12 @@ #include "support/insert_ordered.h" #endif +#if UNSUBTYPING_DEBUG +#define DBG(x) x +#else +#define DBG(x) +#endif + // Compute and use the minimal subtype relation required to maintain module // validity and behavior. This minimal relation will be a subset of the original // subtype relation. Start by walking the IR and collecting pairs of types that @@ -122,6 +128,7 @@ template using Set = InsertOrderedSet; template using Map = std::unordered_map; template using Set = std::unordered_set; #endif + // A tree (or rather a forest) of types with the ability to query and set // supertypes in constant time and efficiently iterate over supertypes and // subtypes. @@ -272,6 +279,22 @@ struct TypeTree { Subtypes subtypes(HeapType type) { return {this, getIndex(type)}; } +#if UNSUBTYPING_DEBUG + void dump(Module& wasm) { + for (auto& node : nodes) { + std::cerr << ModuleHeapType(wasm, node.type); + if (auto super = getSupertype(node.type)) { + std::cerr << " <: " << ModuleHeapType(wasm, *super); + } + std::cerr << ", children:"; + for (auto child : node.children) { + std::cerr << " " << ModuleHeapType(wasm, nodes[child].type); + } + std::cerr << '\n'; + } + } +#endif + private: Index getIndex(HeapType type) { auto [it, inserted] = indices.insert({type, nodes.size()}); @@ -293,7 +316,10 @@ struct Unsubtyping : Pass { // Map from cast source types to their destinations. Map> casts; + DBG(Module* wasm = nullptr); + void run(Module* wasm) override { + DBG(this->wasm = wasm); if (!wasm->features.hasGC()) { return; } @@ -310,6 +336,7 @@ struct Unsubtyping : Pass { process(sub, super); } + DBG(types.dump(*wasm)); rewriteTypes(*wasm); // Cast types may be refinable if their source and target types are no @@ -324,6 +351,8 @@ struct Unsubtyping : Pass { if (sub == super || sub.isBottom()) { return; } + DBG(std::cerr << "noting " << ModuleHeapType(*wasm, sub) + << " <: " << ModuleHeapType(*wasm, super) << '\n'); work.push_back({sub, super}); } @@ -482,6 +511,8 @@ struct Unsubtyping : Pass { } void process(HeapType sub, HeapType super) { + DBG(std::cerr << "processing " << ModuleHeapType(*wasm, sub) + << " <: " << ModuleHeapType(*wasm, super) << '\n'); assert(HeapType::isSubType(sub, super)); auto oldSuper = types.getSupertype(sub); if (oldSuper) { diff --git a/src/wasm.h b/src/wasm.h index 945075c3e19..8ae52168304 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -2623,8 +2623,9 @@ class Module { // Utility for printing an expression with named types. using ModuleExpression = std::pair; -// Utility for printing an type with a name, if the module defines a name. +// Utilities for printing an type with a name, if the module defines a name. using ModuleType = std::pair; +using ModuleHeapType = std::pair; // Utility for printing only the top level of an expression. Named types will be // used if `module` is non-null. @@ -2648,6 +2649,7 @@ std::ostream& operator<<(std::ostream& o, wasm::Expression& expression); std::ostream& operator<<(std::ostream& o, wasm::ModuleExpression pair); std::ostream& operator<<(std::ostream& o, wasm::ShallowExpression expression); std::ostream& operator<<(std::ostream& o, wasm::ModuleType pair); +std::ostream& operator<<(std::ostream& o, wasm::ModuleHeapType pair); } // namespace std