PR updates
diff --git a/src/ir/effects.h b/src/ir/effects.h index a31a994..4d4d5d5 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h
@@ -671,27 +671,32 @@ } } + // Handle effects due to an explicit null check on the given type. + // Returns true iff there is no need to consider further effects. + bool trapOnNull(Type type) { + if (type == Type::unreachable) { + return true; + } + assert(type.isRef()); + if (type.isNull()) { + parent.trap = true; + return true; + } + if (type.isNullable()) { + parent.implicitTrap = true; + } + + return false; + } + // Handle effects due to an explicit null check of the operands in `exprs`. // Returns true iff there is no need to consider further effects. bool trapOnNull(std::initializer_list<Expression*> exprs) { for (auto* expr : exprs) { - if (expr && expr->type == Type::unreachable) { + if (expr && trapOnNull(expr->type)) { return true; } } - for (auto* expr : exprs) { - assert(!expr || expr->type.isRef()); - if (expr && expr->type.isNull()) { - parent.trap = true; - return true; - } - } - for (auto* expr : exprs) { - if (expr && expr->type.isNullable()) { - parent.implicitTrap = true; - break; - } - } return false; } @@ -726,25 +731,25 @@ target && target->effects) { bodyEffects = target->effects.get(); } - populateEffectsForCall(curr, bodyEffects); + addCallEffects(curr, bodyEffects); } void visitCallIndirect(CallIndirect* curr) { auto* table = parent.module.getTable(curr->table); + if (trapOnNull(table->type)) { + return; + } if (!Type::isSubType(Type(curr->heapType, Nullability::Nullable), table->type)) { parent.trap = true; return; } - if (table->type.isNullable()) { - parent.implicitTrap = true; - } const EffectAnalyzer* bodyEffects = nullptr; if (auto it = parent.module.typeEffects.find(curr->heapType); - it != parent.module.typeEffects.end() && it->second) { + it != parent.module.typeEffects.end()) { bodyEffects = it->second.get(); } - populateEffectsForCall(curr, bodyEffects); + addCallEffects(curr, bodyEffects); } void visitCallRef(CallRef* curr) { if (trapOnNull(curr->target)) { @@ -754,10 +759,10 @@ const EffectAnalyzer* bodyEffects = nullptr; if (auto it = parent.module.typeEffects.find(curr->target->type.getHeapType()); - it != parent.module.typeEffects.end() && it->second) { + it != parent.module.typeEffects.end()) { bodyEffects = it->second.get(); } - populateEffectsForCall(curr, bodyEffects); + addCallEffects(curr, bodyEffects); } void visitLocalGet(LocalGet* curr) { parent.localsRead.insert(curr->index); @@ -1303,7 +1308,7 @@ // captured by the function body of the target (e.g. a call_ref may trap on // null refs). template<typename CallType> - void populateFunctionBodyEffects(const CallType* curr, + void addCallEffectsFromGlobalEffects(const CallType* curr, const EffectAnalyzer& funcEffects) { if (curr->isReturn) { if (funcEffects.throws()) { @@ -1320,16 +1325,18 @@ } } + // Common effects logic for the 3 types of call: `call`, `call_indirect`, + // and `call_ref`. template<typename CallType> void - populateEffectsForCall(const CallType* curr, - NullablePtr<const EffectAnalyzer*> bodyEffects) { + addCallEffects(const CallType* curr, + const EffectAnalyzer* bodyEffects) { if (curr->isReturn) { parent.branchesOut = true; } if (bodyEffects) { - populateFunctionBodyEffects(curr, *bodyEffects); + addCallEffectsFromGlobalEffects(curr, *bodyEffects); return; }
diff --git a/src/ir/type-updating.cpp b/src/ir/type-updating.cpp index 1d4ff36..81bb454 100644 --- a/src/ir/type-updating.cpp +++ b/src/ir/type-updating.cpp
@@ -326,10 +326,12 @@ } // Update indirect call effects per type. + // When A is rewritten to B, B inherits the effects of A and A loses its + // effects. std::unordered_map<HeapType, std::shared_ptr<const EffectAnalyzer>> newTypeEffects; - for (auto& [oldType, effects] : wasm.typeEffects) { - if (!effects) { + for (auto& [oldType, oldEffects] : wasm.typeEffects) { + if (!oldEffects) { continue; } @@ -337,10 +339,10 @@ std::shared_ptr<const EffectAnalyzer>& targetEffects = newTypeEffects[newType]; if (!targetEffects) { - targetEffects = effects; + targetEffects = oldEffects; } else { auto merged = std::make_shared<EffectAnalyzer>(*targetEffects); - merged->mergeIn(*effects); + merged->mergeIn(*oldEffects); targetEffects = merged; } }
diff --git a/src/support/utilities.h b/src/support/utilities.h index ac1e5cd..272488e 100644 --- a/src/support/utilities.h +++ b/src/support/utilities.h
@@ -105,8 +105,6 @@ using Ts::operator()...; }; -template<typename T> using NullablePtr = T; - } // namespace wasm #endif // wasm_support_utilities_h
diff --git a/src/wasm.h b/src/wasm.h index a14416a..7045a3f 100644 --- a/src/wasm.h +++ b/src/wasm.h
@@ -2722,7 +2722,17 @@ std::unordered_map<HeapType, TypeNames> typeNames; std::unordered_map<HeapType, Index> typeIndices; - // Potential effects for bodies of indirect calls to this type. + // Potential effects for bodies of indirect calls to this type. Populated by + // GlobalEffects when --closed-world is enabled. e.g. when we have a call to + // HeapType $A and functions $foo and $bar have types that are subtypes of $A, + // then an indirect call to $A has effects equal to the union of $foo and $bar. + // + // When types are rewritten globally, the target type inherits the effects of + // source type (see type-updating.cpp). If the type of just one function is + // rewritten, we don't update this, because such a rewrite is only valid + // if the function is not the target of an indirect call (otherwise the + // indirect call would have to be rewritten too). + // // TODO: Use Type instead of HeapType to account for nullability and // exactness. std::unordered_map<HeapType, std::shared_ptr<const EffectAnalyzer>>