summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm/wasm-type.cpp67
1 files changed, 49 insertions, 18 deletions
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index e0b3d0262..f0c444da9 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -730,8 +730,8 @@ private:
using TypeStore = Store<TypeInfo>;
using HeapTypeStore = Store<HeapTypeInfo>;
-TypeStore globalTypeStore;
-HeapTypeStore globalHeapTypeStore;
+static TypeStore globalTypeStore;
+static HeapTypeStore globalHeapTypeStore;
// Specialized to simplify programming generically over Types and HeapTypes.
template<typename T> struct MetaTypeInfo {};
@@ -756,15 +756,31 @@ template<typename Info> bool Store<Info>::isGlobalStore() {
}
#endif
-template<typename Info>
-bool Store<Info>::hasCanonical(const Info& info, typename Info::type_t& out) {
- auto indexIt = typeIDs.find(std::cref(info));
- if (indexIt != typeIDs.end()) {
- out = typename Info::type_t(indexIt->second);
- return true;
+// Cache canonical nominal signature types. See comment in
+// `HeapType::HeapType(Signature)`.
+struct SignatureTypeCache {
+ std::unordered_map<Signature, HeapType> cache;
+ std::mutex mutex;
+
+ HeapType getType(Signature sig) {
+ std::lock_guard<std::mutex> lock(mutex);
+ // Try inserting a placeholder type, then replace it with a real type if we
+ // don't already have a canonical type for this signature.
+ auto [entry, inserted] = cache.insert({sig, {}});
+ auto& [_, type] = *entry;
+ if (inserted) {
+ type = globalHeapTypeStore.insert(sig);
+ }
+ return type;
}
- return false;
-}
+
+ void insertType(HeapType type) {
+ std::lock_guard<std::mutex> lock(mutex);
+ cache.insert({type.getSignature(), type});
+ }
+};
+
+static SignatureTypeCache nominalSignatureCache;
} // anonymous namespace
@@ -1105,10 +1121,16 @@ const Type& Type::operator[](size_t index) const {
HeapType::HeapType(Signature sig) {
assert(!isTemp(sig.params) && "Leaking temporary type!");
assert(!isTemp(sig.results) && "Leaking temporary type!");
- HeapType canonical;
- if (typeSystem == TypeSystem::Nominal &&
- globalHeapTypeStore.hasCanonical(sig, canonical)) {
- new (this) HeapType(canonical);
+ if (typeSystem == TypeSystem::Nominal) {
+ // Special case the creation of signature types in nominal mode to return a
+ // "canonical" type for the signature, which happens to be the first one
+ // created. We depend on being able to create new function signatures in
+ // many places, and historically they have always been structural, so
+ // creating a copy of an existing signature did not result in any code bloat
+ // or semantic changes. To avoid regressions or significant changes of
+ // behavior in nominal mode, we cache the canonical heap types for each
+ // signature to emulate structural behavior.
+ new (this) HeapType(nominalSignatureCache.getType(sig));
} else {
new (this) HeapType(globalHeapTypeStore.insert(sig));
}
@@ -3241,15 +3263,24 @@ std::vector<HeapType> TypeBuilder::build() {
}
// Combine the basic types with the built types.
- std::vector<HeapType> result(entryCount);
+ std::vector<HeapType> results(entryCount);
for (size_t i = 0, builtIndex = 0; i < entryCount; ++i) {
if (basicHeapTypes[i]) {
- result[i] = *basicHeapTypes[i];
+ results[i] = *basicHeapTypes[i];
} else {
- result[i] = built[builtIndex++];
+ results[i] = built[builtIndex++];
}
}
- return result;
+
+ // Note built signature types. See comment in `HeapType::HeapType(Signature)`.
+ for (auto type : results) {
+ if (type.isSignature() &&
+ (type.isNominal() || getTypeSystem() == TypeSystem::Nominal)) {
+ nominalSignatureCache.insertType(type);
+ }
+ }
+
+ return results;
}
} // namespace wasm