@@ -1341,6 +1341,70 @@ struct AsyncifyAssertInNonInstrumented : public Pass {
13411341 Module* module ;
13421342};
13431343
1344+ struct AsyncifyUnwindWalker
1345+ : WalkerPass<ExpressionStackWalker<AsyncifyUnwindWalker>> {
1346+ Function* function;
1347+ Module* module ;
1348+
1349+ // Adds a check for Call that is inside a Catch block (we do not handle
1350+ // unwinding there).
1351+ template <typename T> void replaceCallWithCheck (T* call) {
1352+ auto builder = std::make_unique<Builder>(*module );
1353+ auto check = builder->makeIf (
1354+ builder->makeBinary (NeInt32,
1355+ builder->makeGlobalGet (ASYNCIFY_STATE, Type::i32 ),
1356+ builder->makeConst (int32_t (State::Normal))),
1357+ builder->makeUnreachable ());
1358+ if (call->type .isConcrete ()) {
1359+ auto temp = builder->addVar (function, call->type );
1360+ replaceCurrent (builder->makeBlock (
1361+ {
1362+ builder->makeLocalSet (temp, call),
1363+ check,
1364+ builder->makeLocalGet (temp, call->type ),
1365+ },
1366+ call->type ));
1367+ } else {
1368+ replaceCurrent (builder->makeBlock (
1369+ {
1370+ call,
1371+ check,
1372+ },
1373+ call->type ));
1374+ }
1375+ }
1376+
1377+ template <typename T> void visitCallLike (T* curr) {
1378+ assert (!expressionStack.empty ());
1379+ // A return_call (curr->isReturn) can be ignored here: It returns first,
1380+ // leaving the Catch, before calling.
1381+ if (curr->isReturn ) {
1382+ return ;
1383+ }
1384+ // Go up the stack and see if we are in a Catch.
1385+ Index i = expressionStack.size () - 1 ;
1386+ while (i > 0 ) {
1387+ auto * expr = expressionStack[i];
1388+ if (Try* aTry = expr->template dynCast <Try>()) {
1389+ // check if curr is inside body of aTry (which is safe),
1390+ // otherwise do replace a call
1391+ assert (i + 1 < expressionStack.size ());
1392+ if (expressionStack[i + 1 ] != aTry->body ) {
1393+ replaceCallWithCheck (curr);
1394+ }
1395+ break ;
1396+ }
1397+ i--;
1398+ }
1399+ }
1400+
1401+ void visitCall (Call* curr) { visitCallLike (curr); }
1402+
1403+ void visitCallRef (CallRef* curr) { visitCallLike (curr); }
1404+
1405+ void visitCallIndirect (CallIndirect* curr) { visitCallLike (curr); }
1406+ };
1407+
13441408struct AsyncifyAssertUnwindCorrectness : Pass {
13451409 bool isFunctionParallel () override { return true ; }
13461410
@@ -1357,63 +1421,7 @@ struct AsyncifyAssertUnwindCorrectness : Pass {
13571421 }
13581422
13591423 void runOnFunction (Module* module_, Function* function) override {
1360- struct UnwindWalker : WalkerPass<ExpressionStackWalker<UnwindWalker>> {
1361- Function* function;
1362- Module* module ;
1363-
1364- // Adds a check for Call that is inside a Catch block (we do not handle unwinding there).
1365- void replaceCallWithCheck (Call* call) {
1366- auto builder = std::make_unique<Builder>(*module );
1367- auto check = builder->makeIf (
1368- builder->makeBinary (NeInt32,
1369- builder->makeGlobalGet (ASYNCIFY_STATE, Type::i32 ),
1370- builder->makeConst (int32_t (State::Normal))),
1371- builder->makeUnreachable ());
1372- if (call->type .isConcrete ()) {
1373- auto temp = builder->addVar (function, call->type );
1374- replaceCurrent (builder->makeBlock (
1375- {
1376- builder->makeLocalSet (temp, call),
1377- check,
1378- builder->makeLocalGet (temp, call->type ),
1379- },
1380- call->type ));
1381- } else {
1382- replaceCurrent (builder->makeBlock (
1383- {
1384- call,
1385- check,
1386- },
1387- call->type ));
1388- }
1389- }
1390-
1391- void visitCall (Call* curr) {
1392- assert (!expressionStack.empty ());
1393- // A return_call (curr->isReturn) can be ignored here: It returns first,
1394- // leaving the Catch, before calling.
1395- if (curr->isReturn ) {
1396- return ;
1397- }
1398- // Go up the stack and see if we are in a Catch.
1399- Index i = expressionStack.size () - 1 ;
1400- while (i > 0 ) {
1401- auto * expr = expressionStack[i];
1402- if (Try* aTry = expr->template dynCast <Try>()) {
1403- // check if curr is inside body of aTry (which is safe),
1404- // otherwise do replace a call
1405- assert (i + 1 < expressionStack.size ());
1406- if (expressionStack[i + 1 ] != aTry->body ) {
1407- replaceCallWithCheck (curr);
1408- }
1409- break ;
1410- }
1411- i--;
1412- }
1413- };
1414- };
1415-
1416- UnwindWalker walker;
1424+ AsyncifyUnwindWalker walker;
14171425 walker.function = function;
14181426 walker.module = module_;
14191427 walker.walk (function->body );
0 commit comments