diff options
author | Alon Zakai <azakai@google.com> | 2022-10-12 14:54:07 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-12 21:54:07 +0000 |
commit | f04fafebe8cb3aaa5751bffc2ab1e7695f7b17bb (patch) | |
tree | 41f594cd7e046a53d16d5bccafaaa2e997f29577 /src | |
parent | 5449744d79ec996c7334681ac1b85e5461194dc8 (diff) | |
download | binaryen-f04fafebe8cb3aaa5751bffc2ab1e7695f7b17bb.tar.gz binaryen-f04fafebe8cb3aaa5751bffc2ab1e7695f7b17bb.tar.bz2 binaryen-f04fafebe8cb3aaa5751bffc2ab1e7695f7b17bb.zip |
[Wasm GC] Add a method to traverse subtypes (#5131)
This will be useful in further cone type optimizations.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/subtypes.h | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/src/ir/subtypes.h b/src/ir/subtypes.h index 5a4ff87fc..969685292 100644 --- a/src/ir/subtypes.h +++ b/src/ir/subtypes.h @@ -24,19 +24,23 @@ namespace wasm { // Analyze subtyping relationships and provide useful interfaces to discover // them. +// +// This only scans user types, and not basic types like HeapType::eq. struct SubTypes { - SubTypes(Module& wasm) { + SubTypes(const std::vector<HeapType>& types) : types(types) { if (getTypeSystem() != TypeSystem::Nominal && getTypeSystem() != TypeSystem::Isorecursive) { Fatal() << "SubTypes requires explicit supers"; } - types = ModuleUtils::collectHeapTypes(wasm); for (auto type : types) { note(type); } } + SubTypes(Module& wasm) : SubTypes(ModuleUtils::collectHeapTypes(wasm)) {} + const std::vector<HeapType>& getStrictSubTypes(HeapType type) { + assert(!type.isBasic()); if (auto iter = typeSubTypes.find(type); iter != typeSubTypes.end()) { return iter->second; } @@ -69,6 +73,49 @@ struct SubTypes { return ret; } + // Efficiently iterate on subtypes of a type, up to a particular depth (depth + // 0 means not to traverse subtypes, etc.). The callback function receives + // (type, depth). + template<typename F> void iterSubTypes(HeapType type, Index depth, F func) { + // Start by traversing the type itself. + func(type, 0); + + if (depth == 0) { + // Nothing else to scan. + return; + } + + // getStrictSubTypes() returns vectors of subtypes, so for efficiency store + // pointers to those in our work queue to avoid allocations. See the note + // below on typeSubTypes for why this is safe. + struct Item { + const std::vector<HeapType>* vec; + Index depth; + }; + + // Real-world type hierarchies tend to have a limited depth, so try to avoid + // allocations in our work queue with a SmallVector. + SmallVector<Item, 10> work; + + // Start with the subtypes of the base type. Those have depth 1. + work.push_back({&getStrictSubTypes(type), 1}); + + while (!work.empty()) { + auto& item = work.back(); + work.pop_back(); + auto currDepth = item.depth; + auto& currVec = *item.vec; + assert(currDepth <= depth); + for (auto type : currVec) { + func(type, currDepth); + auto* subVec = &getStrictSubTypes(type); + if (currDepth + 1 <= depth && !subVec->empty()) { + work.push_back({subVec, currDepth + 1}); + } + } + } + } + // All the types in the program. This is computed here anyhow, and can be // useful for callers to iterate on, so it is public. std::vector<HeapType> types; |