diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-ir-builder.h | 25 | ||||
-rw-r--r-- | src/wasm/wasm-ir-builder.cpp | 16 |
2 files changed, 38 insertions, 3 deletions
diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index d7a1dde87..40689a879 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -259,6 +259,10 @@ private: struct NoScope {}; struct FuncScope { Function* func; + // Used to determine whether we need to run a fixup after creating the + // function. + bool hasSyntheticBlock = false; + bool hasPop = false; }; struct BlockScope { Block* block; @@ -369,6 +373,27 @@ private: } return nullptr; } + void noteSyntheticBlock() { + if (auto* funcScope = std::get_if<FuncScope>(&scope)) { + funcScope->hasSyntheticBlock = true; + } + } + void notePop() { + if (auto* funcScope = std::get_if<FuncScope>(&scope)) { + funcScope->hasPop = true; + } + } + bool needsPopFixup() { + // If the function has a synthetic block and it has a pop, then it's + // possible that the pop is inside the synthetic block and we should run + // the fixup. Determining more precisely that a pop is inside the + // synthetic block when it is created would be complicated and expensive, + // so we are conservative here. + if (auto* funcScope = std::get_if<FuncScope>(&scope)) { + return funcScope->hasSyntheticBlock && funcScope->hasPop; + } + return false; + } Block* getBlock() { if (auto* blockScope = std::get_if<BlockScope>(&scope)) { return blockScope->block; diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index b238a926c..4cb9514f5 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -17,6 +17,7 @@ #include <cassert> #include "ir/child-typer.h" +#include "ir/eh-utils.h" #include "ir/names.h" #include "ir/properties.h" #include "ir/utils.h" @@ -98,7 +99,10 @@ Result<> IRBuilder::packageHoistedValue(const HoistedVal& hoisted, auto packageAsBlock = [&](Type type) { // Create a block containing the producer of the hoisted value, the final - // get of the hoisted value, and everything in between. + // get of the hoisted value, and everything in between. Record the fact that + // we are synthesizing a block to help us determine later whether we need to + // run the nested pop fixup. + scopeStack[0].noteSyntheticBlock(); std::vector<Expression*> exprs(scope.exprStack.begin() + hoisted.valIndex, scope.exprStack.end()); auto* block = builder.makeBlock(exprs, type); @@ -865,9 +869,12 @@ Result<> IRBuilder::visitCatch(Name tag) { tryy->catchTags.push_back(tag); pushScope( ScopeCtx::makeCatch(tryy, originalLabel, label, labelUsed, branchLabel)); - // Push a pop for the exception payload. + // Push a pop for the exception payload if necessary. auto params = wasm.getTag(tag)->sig.params; if (params != Type::none) { + // Note that we have a pop to help determine later whether we need to run + // the fixup for pops within blocks. + scopeStack[0].notePop(); push(builder.makePop(params)); } return Ok{}; @@ -935,7 +942,7 @@ Result<> IRBuilder::visitEnd() { if (scope.isNone()) { return Err{"unexpected end"}; } - if (auto* func = scope.getFunction(); func) { + if (auto* func = scope.getFunction()) { if (auto* loc = std::get_if<Function::DebugLocation>(&debugLoc)) { func->epilogLocation.insert(*loc); } @@ -970,6 +977,9 @@ Result<> IRBuilder::visitEnd() { if (auto* func = scope.getFunction()) { func->body = maybeWrapForLabel(*expr); labelDepths.clear(); + if (scope.needsPopFixup()) { + EHUtils::handleBlockNestedPops(func, wasm); + } } else if (auto* block = scope.getBlock()) { assert(*expr == block); block->name = scope.label; |