summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm/wasm-type.cpp31
1 files changed, 22 insertions, 9 deletions
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index a00b5043b..9006eb9f8 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -641,7 +641,7 @@ bool HeapTypeInfo::operator==(const HeapTypeInfo& other) const {
}
template<typename Info> struct Store {
- std::mutex mutex;
+ std::recursive_mutex mutex;
// Track unique_ptrs for constructed types to avoid leaks.
std::vector<std::unique_ptr<Info>> constructedTypes;
@@ -695,7 +695,7 @@ typename Info::type_t Store<Info>::canonicalize(const Info& info) {
if (info.getCanonical(canonical)) {
return canonical;
}
- std::lock_guard<std::mutex> lock(mutex);
+ std::lock_guard<std::recursive_mutex> lock(mutex);
auto indexIt = typeIDs.find(std::cref(info));
if (indexIt != typeIDs.end()) {
return typename Info::type_t(indexIt->second);
@@ -709,7 +709,7 @@ typename Info::type_t Store<Info>::canonicalize(std::unique_ptr<Info>&& info) {
if (info->getCanonical(canonical)) {
return canonical;
}
- std::lock_guard<std::mutex> lock(mutex);
+ std::lock_guard<std::recursive_mutex> lock(mutex);
auto indexIt = typeIDs.find(std::cref(*info));
if (indexIt != typeIDs.end()) {
return typename Info::type_t(indexIt->second);
@@ -1449,10 +1449,15 @@ Type TypeBounder::getLeastUpperBound(Type a, Type b) {
if (!lub(a, b, tempLUB)) {
return Type::none;
}
- // `tempLUB` is a temporary type owned by `builder`. Since TypeBuilder::build
- // returns HeapTypes rather than Types, create a new HeapType definition meant
- // only to get `tempLUB` canonicalized in a known location. The use of an
- // Array is arbitrary; it might as well have been a Struct.
+ if (!isTemp(tempLUB)) {
+ // The LUB is already canonical, so we're done.
+ return tempLUB;
+ }
+ // `tempLUB` is a temporary type owned by `builder`. Since
+ // TypeBuilder::build returns HeapTypes rather than Types, create a new
+ // HeapType definition meant only to get `tempLUB` canonicalized in a known
+ // location. The use of an Array is arbitrary; it might as well have been a
+ // Struct.
builder.grow(1);
builder[builder.size() - 1] = Array(Field(tempLUB, Mutable));
std::vector<HeapType> built = builder.build();
@@ -2543,8 +2548,8 @@ void ShapeCanonicalizer::translatePartitionsToTypes() {
}
for (auto* child : getChildren(asHeapType(info))) {
auto partitionIt = partitionIndices.find(*child);
- if (partitionIt == partitionIndices.end()) {
- // This child has already been replaced.
+ if (partitionIt == partitionIndices.end() || !isTemp(*child)) {
+ // This child has already been replaced or is already canonical.
continue;
}
*child = results.at(partitionIt->second);
@@ -2668,6 +2673,14 @@ globallyCanonicalize(std::vector<std::unique_ptr<HeapTypeInfo>>& infos) {
// Canonicalize non-tuple Types (which never directly refer to other Types)
// before tuple Types to avoid canonicalizing a tuple that still contains
// non-canonical Types.
+ //
+ // Keep a lock on the global HeapType store as long as it can reach temporary
+ // types to ensure that no other threads observe the temporary types, for
+ // example if another thread concurrently constructs a new HeapType with the
+ // same shape as one being canonicalized here. This cannot happen with Types
+ // because they are hashed in the global store by pointer identity, which has
+ // not yet escaped the builder, rather than shape.
+ std::lock_guard<std::recursive_mutex> lock(globalHeapTypeStore.mutex);
std::unordered_map<HeapType, HeapType> canonicalHeapTypes;
for (auto& info : infos) {
if (!info) {