170170// calls, so that you know when to start an asynchronous operation and
171171// when to propagate results back.
172172//
173- // * asyncify_get_catch_counter(): call this to get the current value of the
174- // internal "__asyncify_catch_counter" variable (only when assertions
175- // or ignore mode are enabled).
176- //
177173// These four functions are exported so that you can call them from the
178174// outside. If you want to manage things from inside the wasm, then you
179175// couldn't have called them before they were created by this pass. To work
251247//
252248// --pass-arg=asyncify-ignore-unwind-from-catch
253249//
254- // This enables extra check before unwind, if it called from within catch
255- // block then it silently ignored (-fwasm-exceptions support)
250+ // This enables additional check to be performed before unwinding. In
251+ // cases where the unwind operation is triggered from the catch block,
252+ // it will be silently ignored (-fwasm-exceptions support)
256253//
257254// --pass-arg=asyncify-verbose
258255//
329326#include " ir/literal-utils.h"
330327#include " ir/memory-utils.h"
331328#include " ir/module-utils.h"
329+ #include " ir/parents.h"
332330#include " ir/names.h"
333331#include " ir/utils.h"
334332#include " pass.h"
@@ -1154,15 +1152,17 @@ struct AsyncifyFlow : public Pass {
11541152 } else if (doesCall (curr)) {
11551153 results.push_back (makeCallSupport (curr));
11561154 continue ;
1157- } else if (auto * iTry = curr->dynCast <Try>()) {
1155+ } else if (auto * try_ = curr->dynCast <Try>()) {
11581156 if (item.phase == Work::Scan) {
11591157 work.push_back (Work{curr, Work::Finish});
1160- work.push_back (Work{iTry->body , Work::Scan});
1158+ work.push_back (Work{try_->body , Work::Scan});
1159+ // catchBodies are ignored because we assume that pause/resume will
1160+ // not happen inside them
11611161 continue ;
11621162 }
1163- iTry ->body = results.back ();
1163+ try_ ->body = results.back ();
11641164 results.pop_back ();
1165- results.push_back (iTry );
1165+ results.push_back (try_ );
11661166 continue ;
11671167 }
11681168 // We must handle all control flow above, and all things that can change
@@ -1244,7 +1244,7 @@ struct AsyncifyFlow : public Pass {
12441244 }
12451245};
12461246
1247- // Add catch block counters to verify that unwind is not called from catch block
1247+ // Add catch block counters to verify that unwind is not called from catch block.
12481248struct AsyncifyAddCatchCounters : public Pass {
12491249 bool isFunctionParallel () override { return true ; }
12501250
@@ -1269,80 +1269,43 @@ struct AsyncifyAddCatchCounters : public Pass {
12691269 makeBinary (SubInt32,
12701270 makeGlobalGet (ASYNCIFY_CATCH_COUNTER, Type::i32 ),
12711271 makeConst (int32_t (amount))));
1272- };
1273- };
1274- CountersBuilder builder (*module_);
1275- BranchUtils::BranchTargets branchTargets (func->body );
1276-
1277- // with this walker we will assign count of enclosing catch block to
1278- // each expression
1279- // ... - 0
1280- // catch
1281- // ... - 1
1282- // catch
1283- // ... - 2
1284- std::unordered_map<Expression*, int > expressionCatchCount;
1285- struct NestedLevelWalker
1286- : public PostWalker<NestedLevelWalker,
1287- UnifiedExpressionVisitor<NestedLevelWalker>> {
1288- std::unordered_map<Expression*, int >* expressionCatchCount;
1289- int catchCount = 0 ;
1290-
1291- static void doStartCatch (NestedLevelWalker* self, Expression** currp) {
1292- self->catchCount ++;
1293- }
1294-
1295- static void doEndCatch (NestedLevelWalker* self, Expression** currp) {
1296- self->catchCount --;
1297- }
1298-
1299- static void scan (NestedLevelWalker* self, Expression** currp) {
1300- auto curr = *currp;
1301- if (curr->_id == Expression::Id::TryId) {
1302- self->expressionCatchCount ->insert (
1303- std::make_pair<>(curr, self->catchCount ));
1304- auto & catchBodies = curr->cast <Try>()->catchBodies ;
1305- for (Index i = 0 ; i < catchBodies.size (); i++) {
1306- self->expressionCatchCount ->insert (
1307- std::make_pair<>(catchBodies[i], self->catchCount ));
1308- self->pushTask (doEndCatch, currp);
1309- self->pushTask (NestedLevelWalker::scan, &catchBodies[i]);
1310- self->pushTask (doStartCatch, currp);
1311- }
1312- self->pushTask (NestedLevelWalker::scan, &curr->cast <Try>()->body );
1313- return ;
1314- }
1315-
1316- PostWalker<NestedLevelWalker,
1317- UnifiedExpressionVisitor<NestedLevelWalker>>::scan (self,
1318- currp);
1319- }
1320-
1321- void visitExpression (Expression* curr) {
1322- expressionCatchCount->insert (std::make_pair<>(curr, catchCount));
13231272 }
13241273 };
1325- NestedLevelWalker nestedLevelWalker;
1326- nestedLevelWalker.expressionCatchCount = &expressionCatchCount;
1327- nestedLevelWalker.walk (func->body );
13281274
13291275 // with this walker we will handle those changes of counter:
1330- // - entering into catch (= pop) +1
1331- // - return -1
1332- // - break -1
1333- // - exiting from catch -1
1276+ // - entering top-level catch (= pop) +1
1277+ // - entering nested catch (= pop) 0 (ignored)
1278+ //
1279+ // - return inside top-level/nested catch -1
1280+ // - return outside top-level/nested catch 0 (ignored)
1281+ //
1282+ // - break target outside of top-level catch -1
1283+ // - break target inside of top-level catch 0 (ignored)
1284+ // - break outside top-level/nested catch 0 (ignored)
1285+ //
1286+ // - exiting from top-level catch -1
1287+ // - exiting from nested catch 0 (ignored)
13341288 struct AddCountersWalker : public PostWalker <AddCountersWalker> {
13351289 Function* func;
13361290 CountersBuilder* builder;
13371291 BranchUtils::BranchTargets* branchTargets;
1338- std::unordered_map<Expression*, int >* expressionCatchCount ;
1292+ Parents* parents ;
13391293 int finallyNum = 0 ;
13401294 int popNum = 0 ;
13411295
13421296 int getCatchCount (Expression* expression) {
1343- auto it = expressionCatchCount->find (expression);
1344- assert (it != expressionCatchCount->end ());
1345- return it->second ;
1297+ int catchCount = 0 ;
1298+ while (expression != func->body ) {
1299+ auto parent = parents->getParent (expression);
1300+ if (auto * try_ = parent->dynCast <Try>()) {
1301+ if (try_->body != expression) {
1302+ catchCount++;
1303+ }
1304+ }
1305+ expression = parent;
1306+ }
1307+
1308+ return catchCount;
13461309 }
13471310
13481311 // Each catch block except catch_all should have pop instruction
@@ -1461,11 +1424,15 @@ struct AsyncifyAddCatchCounters : public Pass {
14611424 }
14621425 };
14631426
1427+ Parents parents (func->body );
1428+ CountersBuilder builder (*module_);
1429+ BranchUtils::BranchTargets branchTargets (func->body );
1430+
14641431 AddCountersWalker addCountersWalker;
14651432 addCountersWalker.func = func;
14661433 addCountersWalker.builder = &builder;
14671434 addCountersWalker.branchTargets = &branchTargets;
1468- addCountersWalker.expressionCatchCount = &expressionCatchCount ;
1435+ addCountersWalker.parents = &parents ;
14691436 addCountersWalker.walk (func->body );
14701437
14711438 EHUtils::handleBlockNestedPops (func, *module_);
0 commit comments