Skip to content

Commit 449dd40

Browse files
committed
[Asyncify] Add support for anyref local vars [wip]
1 parent 838de5c commit 449dd40

File tree

1 file changed

+63
-32
lines changed

1 file changed

+63
-32
lines changed

src/passes/Asyncify.cpp

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ static const Name START_REWIND = "start_rewind";
330330
static const Name STOP_REWIND = "stop_rewind";
331331
static const Name ASYNCIFY_GET_CALL_INDEX = "__asyncify_get_call_index";
332332
static const Name ASYNCIFY_CHECK_CALL_INDEX = "__asyncify_check_call_index";
333+
static const Name ASYNCIFY_BUFFER_TABLE = "__asyncify_buffer_table";
333334

334335
// TODO: having just normal/unwind_or_rewind would decrease code
335336
// size, but make debugging harder
@@ -1368,32 +1369,48 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
13681369
if (!relevantLiveLocals.count(i)) {
13691370
continue;
13701371
}
1371-
total += getByteSize(func->getLocalType(i));
1372+
auto localType = func->getLocalType(i);
1373+
// TODO[doe]: I'm not sure about tuple unpacking here, revisit, verify
1374+
for (const auto& type : localType) {
1375+
if (type.hasByteSize()) {
1376+
total += type.getByteSize();
1377+
}
1378+
}
13721379
}
13731380
auto* block = builder->makeBlock();
13741381
block->list.push_back(builder->makeIncStackPos(-total));
13751382
auto tempIndex = builder->addVar(func, Type::i32);
13761383
block->list.push_back(
13771384
builder->makeLocalSet(tempIndex, builder->makeGetStackPos()));
13781385
Index offset = 0;
1386+
Index table_idx = 0;
13791387
for (Index i = 0; i < numLocals; i++) {
13801388
if (!relevantLiveLocals.count(i)) {
13811389
continue;
13821390
}
13831391
auto localType = func->getLocalType(i);
13841392
SmallVector<Expression*, 1> loads;
13851393
for (const auto& type : localType) {
1386-
auto size = getByteSize(type);
1387-
assert(size % STACK_ALIGN == 0);
1388-
// TODO: higher alignment?
1389-
loads.push_back(
1390-
builder->makeLoad(size,
1391-
true,
1392-
offset,
1393-
STACK_ALIGN,
1394-
builder->makeLocalGet(tempIndex, Type::i32),
1395-
type));
1396-
offset += size;
1394+
if (type.hasByteSize()) {
1395+
auto size = type.getByteSize();
1396+
assert(size % STACK_ALIGN == 0);
1397+
// TODO: higher alignment?
1398+
loads.push_back(
1399+
builder->makeLoad(size,
1400+
true,
1401+
offset,
1402+
STACK_ALIGN,
1403+
builder->makeLocalGet(tempIndex, Type::i32),
1404+
type));
1405+
offset += size;
1406+
} else {
1407+
// TODO[doe]: revisit, verify
1408+
loads.push_back(
1409+
builder->makeTableGet(ASYNCIFY_BUFFER_TABLE,
1410+
builder->makeConst(Index(table_idx)),
1411+
type));
1412+
++table_idx;
1413+
}
13971414
}
13981415
Expression* load;
13991416
if (loads.size() == 1) {
@@ -1420,28 +1437,38 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
14201437
block->list.push_back(
14211438
builder->makeLocalSet(tempIndex, builder->makeGetStackPos()));
14221439
Index offset = 0;
1440+
Index table_idx = 0;
14231441
for (Index i = 0; i < numLocals; i++) {
14241442
if (!relevantLiveLocals.count(i)) {
14251443
continue;
14261444
}
14271445
auto localType = func->getLocalType(i);
14281446
size_t j = 0;
14291447
for (const auto& type : localType) {
1430-
auto size = getByteSize(type);
14311448
Expression* localGet = builder->makeLocalGet(i, localType);
14321449
if (localType.size() > 1) {
14331450
localGet = builder->makeTupleExtract(localGet, j);
14341451
}
1435-
assert(size % STACK_ALIGN == 0);
1436-
// TODO: higher alignment?
1437-
block->list.push_back(
1438-
builder->makeStore(size,
1439-
offset,
1440-
STACK_ALIGN,
1441-
builder->makeLocalGet(tempIndex, Type::i32),
1442-
localGet,
1443-
type));
1444-
offset += size;
1452+
if (type.hasByteSize()) {
1453+
auto size = type.getByteSize();
1454+
assert(size % STACK_ALIGN == 0);
1455+
// TODO: higher alignment?
1456+
block->list.push_back(
1457+
builder->makeStore(size,
1458+
offset,
1459+
STACK_ALIGN,
1460+
builder->makeLocalGet(tempIndex, Type::i32),
1461+
localGet,
1462+
type));
1463+
offset += size;
1464+
} else {
1465+
// TODO[doe]: revisit, verify
1466+
block->list.push_back(
1467+
builder->makeTableSet(ASYNCIFY_BUFFER_TABLE,
1468+
builder->makeConst(Index(table_idx)),
1469+
localGet));
1470+
++table_idx;
1471+
}
14451472
++j;
14461473
}
14471474
}
@@ -1461,15 +1488,6 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
14611488
Type::i32),
14621489
builder->makeIncStackPos(4));
14631490
}
1464-
1465-
unsigned getByteSize(Type type) {
1466-
if (!type.hasByteSize()) {
1467-
Fatal() << "Asyncify does not yet support non-number types, like "
1468-
"references (see "
1469-
"https://github.com/WebAssembly/binaryen/issues/3739)";
1470-
}
1471-
return type.getByteSize();
1472-
}
14731491
};
14741492

14751493
} // anonymous namespace
@@ -1561,6 +1579,9 @@ struct Asyncify : public Pass {
15611579
// Add necessary globals before we emit code to use them.
15621580
addGlobals(module, relocatable);
15631581

1582+
// TODO[doe]: revisit, not sure if it's a good place to add the table
1583+
addTable(module);
1584+
15641585
// Instrument the flow of code, adding code instrumentation and
15651586
// skips for when rewinding. We do this on flat IR so that it is
15661587
// practical to add code around each call, without affecting
@@ -1638,6 +1659,16 @@ struct Asyncify : public Pass {
16381659
module->addGlobal(std::move(asyncifyData));
16391660
}
16401661

1662+
// TODO[doe]: Revisit: name, initial, max
1663+
void addTable(Module* module) {
1664+
Builder builder(*module);
1665+
auto buffer_table = builder.makeTable(ASYNCIFY_BUFFER_TABLE,
1666+
Type::anyref,
1667+
0,
1668+
0);
1669+
module->addTable(std::move(buffer_table));
1670+
}
1671+
16411672
void addFunctions(Module* module) {
16421673
Builder builder(*module);
16431674
auto makeFunction = [&](Name name, bool setData, State state) {

0 commit comments

Comments
 (0)