Skip to content

Commit d12bbab

Browse files
committed
introduce visitCallLike to handle callRef, callIndirect
1 parent 378138e commit d12bbab

File tree

1 file changed

+65
-57
lines changed

1 file changed

+65
-57
lines changed

src/passes/Asyncify.cpp

Lines changed: 65 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
13441408
struct 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

Comments
 (0)