diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/module-utils.h | 148 | ||||
-rw-r--r-- | src/passes/Print.cpp | 42 | ||||
-rw-r--r-- | src/wasm-binary.h | 4 | ||||
-rw-r--r-- | src/wasm-type.h | 4 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 21 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 35 |
6 files changed, 156 insertions, 98 deletions
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h index 008ec0714..de37e0875 100644 --- a/src/ir/module-utils.h +++ b/src/ir/module-utils.h @@ -392,29 +392,28 @@ template<typename T> struct CallGraphPropertyAnalysis { } }; -// Helper function for collecting the type signatures used in a module +// Helper function for collecting all the types that are declared in a module, +// which means the HeapTypes (that are non-basic, that is, not eqref etc., which +// do not need to be defined). // -// Used when emitting or printing a module to give signatures canonical -// indices. Signatures are sorted in order of decreasing frequency to minize the +// Used when emitting or printing a module to give HeapTypes canonical +// indices. HeapTypes are sorted in order of decreasing frequency to minize the // size of their collective encoding. Both a vector mapping indices to -// signatures and a map mapping signatures to indices are produced. -inline void -collectSignatures(Module& wasm, - std::vector<Signature>& signatures, - std::unordered_map<Signature, Index>& sigIndices) { - struct Counts : public std::unordered_map<Signature, size_t> { - void note(Signature sig) { (*this)[sig]++; } +// HeapTypes and a map mapping HeapTypes to indices are produced. +inline void collectHeapTypes(Module& wasm, + std::vector<HeapType>& types, + std::unordered_map<HeapType, Index>& typeIndices) { + struct Counts : public std::unordered_map<HeapType, size_t> { + bool isRelevant(Type type) { return !type.isBasic() && type.isRef(); } + void note(HeapType type) { (*this)[type]++; } void maybeNote(Type type) { - if (type.isRef()) { - auto heapType = type.getHeapType(); - if (heapType.isSignature()) { - note(heapType.getSignature()); - } + if (isRelevant(type)) { + note(type.getHeapType()); } } }; - // Collect the signature use counts for a single function + // Collect the type use counts for a single function auto updateCounts = [&](Function* func, Counts& counts) { if (func->imported()) { return; @@ -429,7 +428,7 @@ collectSignatures(Module& wasm, if (curr->is<RefNull>()) { counts.maybeNote(curr->type); } else if (auto* call = curr->dynCast<CallIndirect>()) { - counts[call->sig]++; + counts.note(call->sig); } else if (Properties::isControlFlowStructure(curr)) { counts.maybeNote(curr->type); if (curr->type.isTuple()) { @@ -437,6 +436,7 @@ collectSignatures(Module& wasm, counts.note(Signature(Type::none, curr->type)); } } + // TODO struct.get and others contain a type index } }; TypeCounter(counts).walk(func->body); @@ -447,7 +447,7 @@ collectSignatures(Module& wasm, // Collect all the counts. Counts counts; for (auto& curr : wasm.functions) { - counts[curr->sig]++; + counts.note(curr->sig); for (auto type : curr->vars) { counts.maybeNote(type); if (type.isTuple()) { @@ -458,7 +458,7 @@ collectSignatures(Module& wasm, } } for (auto& curr : wasm.events) { - counts[curr->sig]++; + counts.note(curr->sig); } for (auto& pair : analysis.map) { Counts& functionCounts = pair.second; @@ -466,74 +466,83 @@ collectSignatures(Module& wasm, counts[innerPair.first] += innerPair.second; } } - + // A generic utility to traverse the child types of a type. + // TODO: work with tlively to refactor this to a shared place + auto walkRelevantChildren = [&](HeapType type, + std::function<void(HeapType)> callback) { + auto callIfRelevant = [&](Type type) { + if (counts.isRelevant(type)) { + callback(type.getHeapType()); + } + }; + if (type.isSignature()) { + auto sig = type.getSignature(); + for (Type type : {sig.params, sig.results}) { + for (auto element : type) { + callIfRelevant(element); + } + } + } else if (type.isArray()) { + callIfRelevant(type.getArray().element.type); + } else if (type.isStruct()) { + auto fields = type.getStruct().fields; + for (auto field : fields) { + callIfRelevant(field.type); + } + } + }; // Recursively traverse each reference type, which may have a child type that // is itself a reference type. This reflects an appearance in the binary // format that is in the type section itself. - // As we do this we may find more and more signatures, as nested children of - // previous ones. Each such signature will appear in the type section once, so + // As we do this we may find more and more types, as nested children of + // previous ones. Each such type will appear in the type section once, so // we just need to visit it once. // TODO: handle struct and array fields - std::unordered_set<Signature> newSigs; + std::unordered_set<HeapType> newTypes; for (auto& pair : counts) { - newSigs.insert(pair.first); - } - while (!newSigs.empty()) { - auto iter = newSigs.begin(); - auto sig = *iter; - newSigs.erase(iter); - for (Type type : {sig.params, sig.results}) { - for (auto element : type) { - if (element.isRef()) { - auto heapType = element.getHeapType(); - if (heapType.isSignature()) { - auto sig = heapType.getSignature(); - if (!counts.count(sig)) { - newSigs.insert(sig); - } - counts[sig]++; - } - } + newTypes.insert(pair.first); + } + while (!newTypes.empty()) { + auto iter = newTypes.begin(); + auto type = *iter; + newTypes.erase(iter); + walkRelevantChildren(type, [&](HeapType type) { + if (!counts.count(type)) { + newTypes.insert(type); } - } + counts.note(type); + }); } - // We must sort all the dependencies of a signature before it. For example, + // We must sort all the dependencies of a type before it. For example, // (func (param (ref (func)))) must appear after (func). To do that, find the - // depth of dependencies of each signature. For example, if A depends on B + // depth of dependencies of each type. For example, if A depends on B // which depends on C, then A's depth is 2, B's is 1, and C's is 0 (assuming // no other dependencies). Counts depthOfDependencies; - std::unordered_map<Signature, std::unordered_set<Signature>> isDependencyOf; + std::unordered_map<HeapType, std::unordered_set<HeapType>> isDependencyOf; // To calculate the depth of dependencies, we'll do a flow analysis, visiting - // each signature as we find out new things about it. - std::set<Signature> toVisit; + // each type as we find out new things about it. + std::set<HeapType> toVisit; for (auto& pair : counts) { - auto sig = pair.first; - depthOfDependencies[sig] = 0; - toVisit.insert(sig); - for (Type type : {sig.params, sig.results}) { - for (auto element : type) { - if (element.isRef()) { - auto heapType = element.getHeapType(); - if (heapType.isSignature()) { - isDependencyOf[heapType.getSignature()].insert(sig); - } - } - } - } + auto type = pair.first; + depthOfDependencies[type] = 0; + toVisit.insert(type); + walkRelevantChildren(type, [&](HeapType childType) { + isDependencyOf[childType].insert(type); // XXX flip? + }); } while (!toVisit.empty()) { auto iter = toVisit.begin(); - auto sig = *iter; + auto type = *iter; toVisit.erase(iter); // Anything that depends on this has a depth of dependencies equal to this - // signature's, plus this signature itself. - auto newDepth = depthOfDependencies[sig] + 1; + // type's, plus this type itself. + auto newDepth = depthOfDependencies[type] + 1; if (newDepth > counts.size()) { - Fatal() << "Cyclic signatures detected, cannot sort them."; + Fatal() << "Cyclic types detected, cannot sort them."; } - for (auto& other : isDependencyOf[sig]) { + for (auto& other : isDependencyOf[type]) { if (depthOfDependencies[other] < newDepth) { // We found something new to propagate. depthOfDependencies[other] = newDepth; @@ -541,10 +550,9 @@ collectSignatures(Module& wasm, } } } - // Sort by frequency and then simplicity, and also keeping every signature + // Sort by frequency and then simplicity, and also keeping every type // before things that depend on it. - std::vector<std::pair<Signature, size_t>> sorted(counts.begin(), - counts.end()); + std::vector<std::pair<HeapType, size_t>> sorted(counts.begin(), counts.end()); std::sort(sorted.begin(), sorted.end(), [&](auto a, auto b) { if (depthOfDependencies[a.first] != depthOfDependencies[b.first]) { return depthOfDependencies[a.first] < depthOfDependencies[b.first]; @@ -555,8 +563,8 @@ collectSignatures(Module& wasm, return a.first < b.first; }); for (Index i = 0; i < sorted.size(); ++i) { - sigIndices[sorted[i].first] = i; - signatures.push_back(sorted[i].first); + typeIndices[sorted[i].first] = i; + types.push_back(sorted[i].first); } } diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index c597028be..ba3981e21 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -141,6 +141,11 @@ struct TypeName { TypeName(Type type) : type(type) {} }; +struct HeapTypeName { + HeapType type; + HeapTypeName(HeapType type) : type(type) {} +}; + std::ostream& operator<<(std::ostream& os, TypeName typeName) { auto type = typeName.type; if (type.isRef() && !type.isBasic()) { @@ -160,6 +165,16 @@ std::ostream& operator<<(std::ostream& os, TypeName typeName) { return os << SExprType(typeName.type); } +std::ostream& operator<<(std::ostream& os, HeapTypeName typeName) { + auto type = typeName.type; + if (type.isSignature()) { + os << SigName(type.getSignature()); + } else { + os << type; + } + return os; +} + } // anonymous namespace // Printing "unreachable" as a instruction prefix type is not valid in wasm text @@ -2348,10 +2363,10 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { WASM_UNREACHABLE("TODO (gc): array.len"); } // Module-level visitors - void handleSignature(Signature curr, Name* funcName = nullptr) { + void handleSignature(Signature curr, Name name = Name()) { o << "(func"; - if (funcName) { - o << " $" << *funcName; + if (name.is()) { + o << " $" << name; } if (curr.params.size() > 0) { o << maybeSpace; @@ -2375,6 +2390,13 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { } o << ")"; } + void handleHeapType(HeapType type) { + if (type.isSignature()) { + handleSignature(type.getSignature()); + } else { + WASM_UNREACHABLE("unsupported heap type"); + } + } void visitExport(Export* curr) { o << '('; printMedium(o, "export "); @@ -2453,7 +2475,7 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { lastPrintedLocation = {0, 0, 0}; o << '('; emitImportHeader(curr); - handleSignature(curr->sig, &curr->name); + handleSignature(curr->sig, curr->name); o << ')'; o << maybeNewLine; } @@ -2702,15 +2724,15 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { printName(curr->name, o); } incIndent(); - std::vector<Signature> signatures; - std::unordered_map<Signature, Index> indices; - ModuleUtils::collectSignatures(*curr, signatures, indices); - for (auto sig : signatures) { + std::vector<HeapType> types; + std::unordered_map<HeapType, Index> indices; + ModuleUtils::collectHeapTypes(*curr, types, indices); + for (auto type : types) { doIndent(o, indent); o << '('; printMedium(o, "type") << ' '; - o << SigName(sig) << ' '; - handleSignature(sig); + o << HeapTypeName(type) << ' '; + handleHeapType(type); o << ")" << maybeNewLine; } ModuleUtils::iterImportedMemories( diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 532cfb7ec..d7257f560 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1175,8 +1175,8 @@ private: Module* wasm; BufferWithRandomAccess& o; BinaryIndexes indexes; - std::unordered_map<Signature, Index> typeIndices; - std::vector<Signature> types; + std::unordered_map<HeapType, Index> typeIndices; + std::vector<HeapType> types; bool debugInfo = true; std::ostream* sourceMap = nullptr; diff --git a/src/wasm-type.h b/src/wasm-type.h index 77f7120bf..39ec1640e 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -304,6 +304,7 @@ struct Field { mutable_ == other.mutable_; } bool operator!=(const Field& other) const { return !(*this == other); } + bool operator<(const Field& other) const; std::string toString() const; }; @@ -316,6 +317,7 @@ struct Struct { Struct(FieldList&& fields) : fields(std::move(fields)) {} bool operator==(const Struct& other) const { return fields == other.fields; } bool operator!=(const Struct& other) const { return !(*this == other); } + bool operator<(const Struct& other) const { return fields < other.fields; } std::string toString() const; }; @@ -326,6 +328,7 @@ struct Array { Array(Field&& element) : element(std::move(element)) {} bool operator==(const Array& other) const { return element == other.element; } bool operator!=(const Array& other) const { return !(*this == other); } + bool operator<(const Array& other) const { return element < other.element; } std::string toString() const; }; @@ -378,6 +381,7 @@ struct HeapType { bool operator==(const HeapType& other) const; bool operator!=(const HeapType& other) const { return !(*this == other); } + bool operator<(const HeapType& other) const; HeapType& operator=(const HeapType& other); std::string toString() const; }; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 7a6d4d35d..54e417b8c 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -31,7 +31,7 @@ namespace wasm { void WasmBinaryWriter::prepare() { // Collect function types and their frequencies. Collect information in each // function in parallel, then merge. - ModuleUtils::collectSignatures(*wasm, types, typeIndices); + ModuleUtils::collectHeapTypes(*wasm, types, typeIndices); importInfo = wasm::make_unique<ImportInfo>(*wasm); } @@ -215,14 +215,19 @@ void WasmBinaryWriter::writeTypes() { auto start = startSection(BinaryConsts::Section::Type); o << U32LEB(types.size()); for (Index i = 0; i < types.size(); ++i) { - Signature& sig = types[i]; - BYN_TRACE("write " << sig.params << " -> " << sig.results << std::endl); - o << S32LEB(BinaryConsts::EncodedType::Func); - for (auto& sigType : {sig.params, sig.results}) { - o << U32LEB(sigType.size()); - for (const auto& type : sigType) { - writeType(type); + auto type = types[i]; + BYN_TRACE("write " << type << std::endl); + if (type.isSignature()) { + o << S32LEB(BinaryConsts::EncodedType::Func); + auto sig = type.getSignature(); + for (auto& sigType : {sig.params, sig.results}) { + o << U32LEB(sigType.size()); + for (const auto& type : sigType) { + writeType(type); + } } + } else { + WASM_UNREACHABLE("TODO GC type writing"); } } finishSection(start); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index be017140d..fd49c5b93 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -405,14 +405,7 @@ bool Type::operator<(const Type& other) const { if (a.isNullable() != b.isNullable()) { return a.isNullable(); } - auto aHeap = a.getHeapType(); - auto bHeap = b.getHeapType(); - if (aHeap.isSignature() && bHeap.isSignature()) { - return aHeap.getSignature() < bHeap.getSignature(); - } - TODO_SINGLE_COMPOUND(a); - TODO_SINGLE_COMPOUND(b); - WASM_UNREACHABLE("unimplemented type comparison"); + return a.getHeapType() < b.getHeapType(); }; return std::lexicographical_compare( begin(), end(), other.begin(), other.end(), comp); @@ -738,6 +731,22 @@ bool HeapType::operator==(const HeapType& other) const { WASM_UNREACHABLE("unexpected kind"); } +bool HeapType::operator<(const HeapType& other) const { + if (kind != other.kind) { + return kind < other.kind; + } + if (isSignature()) { + return getSignature() < other.getSignature(); + } + if (isStruct()) { + return getStruct() < other.getStruct(); + } + if (isArray()) { + return getArray() < other.getArray(); + } + WASM_UNREACHABLE("unimplemented type comparison"); +} + HeapType& HeapType::operator=(const HeapType& other) { if (&other != this) { this->~HeapType(); @@ -746,6 +755,16 @@ HeapType& HeapType::operator=(const HeapType& other) { return *this; } +bool Field::operator<(const Field& other) const { + if (mutable_ != other.mutable_) { + return mutable_ < other.mutable_; + } + if (type == Type::i32) { + return packedType < other.packedType; + } + return type < other.type; +} + namespace { std::ostream& |