170
170
// calls, so that you know when to start an asynchronous operation and
171
171
// when to propagate results back.
172
172
//
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
- //
177
173
// These four functions are exported so that you can call them from the
178
174
// outside. If you want to manage things from inside the wasm, then you
179
175
// couldn't have called them before they were created by this pass. To work
251
247
//
252
248
// --pass-arg=asyncify-ignore-unwind-from-catch
253
249
//
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)
256
253
//
257
254
// --pass-arg=asyncify-verbose
258
255
//
329
326
#include " ir/literal-utils.h"
330
327
#include " ir/memory-utils.h"
331
328
#include " ir/module-utils.h"
329
+ #include " ir/parents.h"
332
330
#include " ir/names.h"
333
331
#include " ir/utils.h"
334
332
#include " pass.h"
@@ -1154,15 +1152,17 @@ struct AsyncifyFlow : public Pass {
1154
1152
} else if (doesCall (curr)) {
1155
1153
results.push_back (makeCallSupport (curr));
1156
1154
continue ;
1157
- } else if (auto * iTry = curr->dynCast <Try>()) {
1155
+ } else if (auto * try_ = curr->dynCast <Try>()) {
1158
1156
if (item.phase == Work::Scan) {
1159
1157
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
1161
1161
continue ;
1162
1162
}
1163
- iTry ->body = results.back ();
1163
+ try_ ->body = results.back ();
1164
1164
results.pop_back ();
1165
- results.push_back (iTry );
1165
+ results.push_back (try_ );
1166
1166
continue ;
1167
1167
}
1168
1168
// We must handle all control flow above, and all things that can change
@@ -1244,7 +1244,7 @@ struct AsyncifyFlow : public Pass {
1244
1244
}
1245
1245
};
1246
1246
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.
1248
1248
struct AsyncifyAddCatchCounters : public Pass {
1249
1249
bool isFunctionParallel () override { return true ; }
1250
1250
@@ -1269,80 +1269,43 @@ struct AsyncifyAddCatchCounters : public Pass {
1269
1269
makeBinary (SubInt32,
1270
1270
makeGlobalGet (ASYNCIFY_CATCH_COUNTER, Type::i32),
1271
1271
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));
1323
1272
}
1324
1273
};
1325
- NestedLevelWalker nestedLevelWalker;
1326
- nestedLevelWalker.expressionCatchCount = &expressionCatchCount;
1327
- nestedLevelWalker.walk (func->body );
1328
1274
1329
1275
// 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)
1334
1288
struct AddCountersWalker : public PostWalker <AddCountersWalker> {
1335
1289
Function* func;
1336
1290
CountersBuilder* builder;
1337
1291
BranchUtils::BranchTargets* branchTargets;
1338
- std::unordered_map<Expression*, int >* expressionCatchCount ;
1292
+ Parents* parents ;
1339
1293
int finallyNum = 0 ;
1340
1294
int popNum = 0 ;
1341
1295
1342
1296
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;
1346
1309
}
1347
1310
1348
1311
// Each catch block except catch_all should have pop instruction
@@ -1461,11 +1424,15 @@ struct AsyncifyAddCatchCounters : public Pass {
1461
1424
}
1462
1425
};
1463
1426
1427
+ Parents parents (func->body );
1428
+ CountersBuilder builder (*module_);
1429
+ BranchUtils::BranchTargets branchTargets (func->body );
1430
+
1464
1431
AddCountersWalker addCountersWalker;
1465
1432
addCountersWalker.func = func;
1466
1433
addCountersWalker.builder = &builder;
1467
1434
addCountersWalker.branchTargets = &branchTargets;
1468
- addCountersWalker.expressionCatchCount = &expressionCatchCount ;
1435
+ addCountersWalker.parents = &parents ;
1469
1436
addCountersWalker.walk (func->body );
1470
1437
1471
1438
EHUtils::handleBlockNestedPops (func, *module_);
0 commit comments