diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 32 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 161 |
2 files changed, 20 insertions, 173 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index e85740614..967356210 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -229,40 +229,22 @@ void WasmBinaryWriter::writeTypes() { // the type section. With nominal typing there is always one group and with // equirecursive typing there is one group per type. size_t numGroups = 0; - // MVP types are structural and do not use recursion groups. - TypeSystem typeSystem = getTypeSystem(); - if (!wasm->features.hasGC()) { - typeSystem = TypeSystem::Isorecursive; - } - switch (typeSystem) { - case TypeSystem::Nominal: - numGroups = 1; - break; - case TypeSystem::Isorecursive: { - std::optional<RecGroup> lastGroup; - for (auto type : indexedTypes.types) { - auto currGroup = type.getRecGroup(); - numGroups += lastGroup != currGroup; - lastGroup = currGroup; - } + { + std::optional<RecGroup> lastGroup; + for (auto type : indexedTypes.types) { + auto currGroup = type.getRecGroup(); + numGroups += lastGroup != currGroup; + lastGroup = currGroup; } } BYN_TRACE("== writeTypes\n"); auto start = startSection(BinaryConsts::Section::Type); o << U32LEB(numGroups); - if (typeSystem == TypeSystem::Nominal) { - // The nominal recursion group contains every type. - o << S32LEB(BinaryConsts::EncodedType::Rec) - << U32LEB(indexedTypes.types.size()); - } std::optional<RecGroup> lastGroup = std::nullopt; for (Index i = 0; i < indexedTypes.types.size(); ++i) { auto type = indexedTypes.types[i]; // Check whether we need to start a new recursion group. Recursion groups of - // size 1 are implicit, so only emit a group header for larger groups. This - // gracefully handles non-isorecursive type systems, which only have groups - // of size 1 internally (even though nominal types are emitted as a single - // large group). + // size 1 are implicit, so only emit a group header for larger groups. auto currGroup = type.getRecGroup(); if (lastGroup != currGroup && currGroup.size() > 1) { o << S32LEB(BinaryConsts::EncodedType::Rec) << U32LEB(currGroup.size()); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 8b1dfb0af..c9c35ac49 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -44,12 +44,6 @@ namespace wasm { -static TypeSystem typeSystem = TypeSystem::Isorecursive; - -void setTypeSystem(TypeSystem system) { typeSystem = system; } - -TypeSystem getTypeSystem() { return typeSystem; } - namespace { struct TypeInfo { @@ -104,11 +98,10 @@ struct HeapTypeInfo { // Otherwise, the type definition tree is still being constructed via the // TypeBuilder interface, so hashing and equality use pointer identity. bool isFinalized = true; - // In nominal or isorecursive mode, the supertype of this HeapType, if it - // exists. + // The supertype of this HeapType, if it exists. HeapTypeInfo* supertype = nullptr; - // In isorecursive mode, the recursion group of this type or null if the - // recursion group is trivial (i.e. contains only this type). + // The recursion group of this type or null if the recursion group is trivial + // (i.e. contains only this type). RecGroupInfo* recGroup = nullptr; size_t recGroupIndex = 0; enum Kind { @@ -714,12 +707,6 @@ private: return *canonical; } std::lock_guard<std::recursive_mutex> lock(mutex); - // Nominal HeapTypes are always unique, so don't bother deduplicating them. - if constexpr (std::is_same_v<Info, HeapTypeInfo>) { - if (typeSystem == TypeSystem::Nominal) { - return insertNew(); - } - } // Check whether we already have a type for this structural Info. auto indexIt = typeIDs.find(std::cref(info)); if (indexIt != typeIDs.end()) { @@ -759,34 +746,6 @@ template<typename Info> bool Store<Info>::isGlobalStore() { } #endif -// 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; - } - - void insertType(HeapType type) { - std::lock_guard<std::mutex> lock(mutex); - cache.insert({type.getSignature(), type}); - } - - void clear() { cache.clear(); } -}; - -static SignatureTypeCache nominalSignatureCache; - // Keep track of the constructed recursion groups. struct RecGroupStore { std::mutex mutex; @@ -841,7 +800,6 @@ static RecGroupStore globalRecGroupStore; void destroyAllTypesForTestingPurposesOnly() { globalTypeStore.clear(); globalHeapTypeStore.clear(); - nominalSignatureCache.clear(); globalRecGroupStore.clear(); } @@ -1222,24 +1180,8 @@ const Type& Type::Iterator::operator*() const { HeapType::HeapType(Signature sig) { assert(!isTemp(sig.params) && "Leaking temporary type!"); assert(!isTemp(sig.results) && "Leaking temporary type!"); - switch (getTypeSystem()) { - case 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)); - return; - case TypeSystem::Isorecursive: - new (this) HeapType( - globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(sig))); - return; - } - WASM_UNREACHABLE("unexpected type system"); + new (this) + HeapType(globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(sig))); } HeapType::HeapType(const Struct& struct_) { @@ -1248,16 +1190,8 @@ HeapType::HeapType(const Struct& struct_) { assert(!isTemp(field.type) && "Leaking temporary type!"); } #endif - switch (getTypeSystem()) { - case TypeSystem::Nominal: - new (this) HeapType(globalHeapTypeStore.insert(struct_)); - return; - case TypeSystem::Isorecursive: - new (this) HeapType( - globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(struct_))); - return; - } - WASM_UNREACHABLE("unexpected type system"); + new (this) HeapType( + globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(struct_))); } HeapType::HeapType(Struct&& struct_) { @@ -1266,30 +1200,14 @@ HeapType::HeapType(Struct&& struct_) { assert(!isTemp(field.type) && "Leaking temporary type!"); } #endif - switch (getTypeSystem()) { - case TypeSystem::Nominal: - new (this) HeapType(globalHeapTypeStore.insert(std::move(struct_))); - return; - case TypeSystem::Isorecursive: - new (this) HeapType(globalRecGroupStore.insert( - std::make_unique<HeapTypeInfo>(std::move(struct_)))); - return; - } - WASM_UNREACHABLE("unexpected type system"); + new (this) HeapType(globalRecGroupStore.insert( + std::make_unique<HeapTypeInfo>(std::move(struct_)))); } HeapType::HeapType(Array array) { assert(!isTemp(array.element.type) && "Leaking temporary type!"); - switch (getTypeSystem()) { - case TypeSystem::Nominal: - new (this) HeapType(globalHeapTypeStore.insert(array)); - return; - case TypeSystem::Isorecursive: - new (this) HeapType( - globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(array))); - return; - } - WASM_UNREACHABLE("unexpected type system"); + new (this) + HeapType(globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(array))); } bool HeapType::isFunction() const { @@ -2774,39 +2692,6 @@ validateSubtyping(const std::vector<HeapType>& types) { return {}; } -std::optional<TypeBuilder::Error> -canonicalizeNominal(CanonicalizationState& state) { - for (auto& info : state.newInfos) { - info->recGroup = nullptr; - } - - // Nominal types do not require separate canonicalization, so just validate - // that their subtyping is correct. - - // Ensure there are no cycles in the subtype graph. This is the classic DFA - // algorithm for detecting cycles, but in the form of a simple loop because - // each node (type) has at most one child (supertype). - std::unordered_set<HeapTypeInfo*> checked; - for (size_t i = 0; i < state.results.size(); ++i) { - HeapType type = state.results[i]; - if (type.isBasic()) { - continue; - } - std::unordered_set<HeapTypeInfo*> path; - for (auto* curr = getHeapTypeInfo(type); - curr != nullptr && !checked.count(curr); - curr = curr->supertype) { - if (!path.insert(curr).second) { - return TypeBuilder::Error{i, TypeBuilder::ErrorReason::SelfSupertype}; - } - } - // None of the types in `path` reach themselves. - checked.insert(path.begin(), path.end()); - } - - return {}; -} - std::optional<TypeBuilder::Error> canonicalizeIsorecursive( CanonicalizationState& state, std::vector<std::unique_ptr<RecGroupInfo>>& recGroupInfos) { @@ -2992,17 +2877,8 @@ TypeBuilder::BuildResult TypeBuilder::build() { auto start = std::chrono::steady_clock::now(); #endif - switch (typeSystem) { - case TypeSystem::Nominal: - if (auto error = canonicalizeNominal(state)) { - return {*error}; - } - break; - case TypeSystem::Isorecursive: - if (auto error = canonicalizeIsorecursive(state, impl->recGroups)) { - return {*error}; - } - break; + if (auto error = canonicalizeIsorecursive(state, impl->recGroups)) { + return {*error}; } #if TIME_CANONICALIZATION @@ -3026,17 +2902,6 @@ TypeBuilder::BuildResult TypeBuilder::build() { return {*error}; } - // Note built signature types. See comment in `HeapType::HeapType(Signature)`. - for (auto type : state.results) { - // Do not cache types with explicit supertypes (that is, whose supertype is - // not HeapType::func). We don't want to reuse such types because then we'd - // be adding subtyping relationships that are not in the input. - if (type.isSignature() && (getTypeSystem() == TypeSystem::Nominal) && - !type.getSuperType()) { - nominalSignatureCache.insertType(type); - } - } - return {state.results}; } |