diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/eh-utils.cpp | 84 | ||||
-rw-r--r-- | src/ir/eh-utils.h | 11 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 5 |
3 files changed, 55 insertions, 45 deletions
diff --git a/src/ir/eh-utils.cpp b/src/ir/eh-utils.cpp index 37af738ce..3d369573d 100644 --- a/src/ir/eh-utils.cpp +++ b/src/ir/eh-utils.cpp @@ -107,54 +107,56 @@ bool containsValidDanglingPop(Expression* catchBody) { return pop != nullptr && !isPopNested; } +void handleBlockNestedPop(Try* try_, Function* func, Module& wasm) { + Builder builder(wasm); + for (Index i = 0; i < try_->catchTags.size(); i++) { + Name tagName = try_->catchTags[i]; + auto* tag = wasm.getTag(tagName); + if (tag->sig.params == Type::none) { + continue; + } + + auto* catchBody = try_->catchBodies[i]; + bool isPopNested = false; + Expression** popPtr = nullptr; + Expression* pop = getFirstPop(catchBody, isPopNested, popPtr); + assert(pop && "Pop has not been found in this catch"); + + // Change code like + // (catch $e + // ... + // (block + // (pop i32) + // ) + // ) + // into + // (catch $e + // (local.set $new + // (pop i32) + // ) + // ... + // (block + // (local.get $new) + // ) + // ) + if (isPopNested) { + assert(popPtr); + Index newLocal = builder.addVar(func, pop->type); + try_->catchBodies[i] = + builder.makeSequence(builder.makeLocalSet(newLocal, pop), catchBody); + *popPtr = builder.makeLocalGet(newLocal, pop->type); + } + } +} + void handleBlockNestedPops(Function* func, Module& wasm) { if (!wasm.features.hasExceptionHandling()) { return; } - - Builder builder(wasm); FindAll<Try> trys(func->body); for (auto* try_ : trys.list) { - for (Index i = 0; i < try_->catchTags.size(); i++) { - Name tagName = try_->catchTags[i]; - auto* tag = wasm.getTag(tagName); - if (tag->sig.params == Type::none) { - continue; - } - - auto* catchBody = try_->catchBodies[i]; - bool isPopNested = false; - Expression** popPtr = nullptr; - Expression* pop = getFirstPop(catchBody, isPopNested, popPtr); - assert(pop && "Pop has not been found in this catch"); - - // Change code like - // (catch $e - // ... - // (block - // (pop i32) - // ) - // ) - // into - // (catch $e - // (local.set $new - // (pop i32) - // ) - // ... - // (block - // (local.get $new) - // ) - // ) - if (isPopNested) { - assert(popPtr); - Index newLocal = builder.addVar(func, pop->type); - try_->catchBodies[i] = - builder.makeSequence(builder.makeLocalSet(newLocal, pop), catchBody); - *popPtr = builder.makeLocalGet(newLocal, pop->type); - } - } + handleBlockNestedPop(try_, func, wasm); } - // Pops we handled can be of non-defaultable types, so we may have created // non-nullable type locals. Fix them. TypeUpdating::handleNonDefaultableLocals(func, wasm); diff --git a/src/ir/eh-utils.h b/src/ir/eh-utils.h index c0d6e59ea..25677a32e 100644 --- a/src/ir/eh-utils.h +++ b/src/ir/eh-utils.h @@ -31,10 +31,13 @@ namespace EHUtils { // catch body, which is invalid. That will be taken care of in validation. bool containsValidDanglingPop(Expression* catchBody); -// Fixes up 'pop's nested in blocks, which are currently not supported without -// block param types, by creating a new local, putting a (local.set $new (pop -// type)) right after 'catch', and putting a '(local.get $new)' where the 'pop' -// used to be. +// Given a 'Try' expression, fixes up 'pop's nested in blocks, which are +// currently not supported without block param types, by creating a new local, +// putting a (local.set $new (pop type)) right after 'catch', and putting a +// '(local.get $new)' where the 'pop' used to be. +void handleBlockNestedPop(Try* try_, Function* func, Module& wasm); + +// Calls handleBlockNestedPop for each 'Try's in a given function. void handleBlockNestedPops(Function* func, Module& wasm); } // namespace EHUtils diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index d8a3c2f74..57a2bc95c 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -17,6 +17,7 @@ #include <algorithm> #include <fstream> +#include "ir/eh-utils.h" #include "ir/module-utils.h" #include "ir/table-utils.h" #include "ir/type-updating.h" @@ -6419,6 +6420,10 @@ void WasmBinaryBuilder::visitTryOrTryInBlock(Expression*& out) { } exceptionTargetNames.erase(catchLabel); } + + // If catch bodies contained stacky code, 'pop's can be nested within a block. + // Fix that up. + EHUtils::handleBlockNestedPop(curr, currFunction, wasm); curr->finalize(curr->type); // For simplicity, we create an inner block within the catch body too, but the |