107
107
// contains a pointer to a data structure with the info needed to rewind
108
108
// and unwind:
109
109
//
110
- // { // offsets
110
+ // { // offsets
111
111
// i32 - current asyncify stack location // 0
112
112
// i32 - asyncify stack end // 4
113
113
// }
114
114
//
115
+ // Or for wasm64:
116
+ //
117
+ // { // offsets
118
+ // i64 - current asyncify stack location // 0
119
+ // i64 - asyncify stack end // 8
120
+ // }
121
+ //
115
122
// The asyncify stack is a representation of the call frame, as a list of
116
123
// indexes of calls. In the example above, we saw index "0" for calling "bar"
117
124
// from "foo". When unwinding, the indexes are added to the stack; when
130
137
// The pass will also create five functions that let you control unwinding
131
138
// and rewinding:
132
139
//
133
- // * asyncify_start_unwind(data : i32 ): call this to start unwinding the
140
+ // * asyncify_start_unwind(data : iPTR ): call this to start unwinding the
134
141
// stack from the current location. "data" must point to a data
135
142
// structure as described above (with fields containing valid data).
136
143
//
142
149
// the code will think it is still unwinding when it should not be,
143
150
// which means it will keep unwinding in a meaningless way.
144
151
//
145
- // * asyncify_start_rewind(data : i32 ): call this to start rewinding the
152
+ // * asyncify_start_rewind(data : iPTR ): call this to start rewinding the
146
153
// stack vack up to the location stored in the provided data. This prepares
147
154
// for the rewind; to start it, you must call the first function in the
148
155
// call stack to be unwound.
@@ -335,7 +342,7 @@ static const Name ASYNCIFY_CHECK_CALL_INDEX = "__asyncify_check_call_index";
335
342
// size, but make debugging harder
336
343
enum class State { Normal = 0 , Unwinding = 1 , Rewinding = 2 };
337
344
338
- enum class DataOffset { BStackPos = 0 , BStackEnd = 4 };
345
+ enum class DataOffset { BStackPos = 0 , BStackEnd = 4 , BStackEnd64 = 8 };
339
346
340
347
const auto STACK_ALIGN = 4 ;
341
348
@@ -795,31 +802,35 @@ static bool doesCall(Expression* curr) {
795
802
class AsyncifyBuilder : public Builder {
796
803
public:
797
804
Module& wasm;
805
+ Type pointerType;
798
806
799
- AsyncifyBuilder (Module& wasm) : Builder(wasm), wasm(wasm) {}
807
+ AsyncifyBuilder (Module& wasm)
808
+ : Builder(wasm), wasm(wasm), pointerType(wasm.memories[0 ]->indexType) {}
800
809
801
810
Expression* makeGetStackPos () {
802
- return makeLoad (4 ,
811
+ return makeLoad (pointerType. getByteSize () ,
803
812
false ,
804
- int32_t (DataOffset::BStackPos),
805
- 4 ,
806
- makeGlobalGet (ASYNCIFY_DATA, Type::i32 ),
807
- Type::i32 ,
813
+ int (DataOffset::BStackPos),
814
+ pointerType. getByteSize () ,
815
+ makeGlobalGet (ASYNCIFY_DATA, pointerType ),
816
+ pointerType ,
808
817
wasm.memories [0 ]->name );
809
818
}
810
819
811
820
Expression* makeIncStackPos (int32_t by) {
812
821
if (by == 0 ) {
813
822
return makeNop ();
814
823
}
815
- return makeStore (
816
- 4 ,
817
- int32_t (DataOffset::BStackPos),
818
- 4 ,
819
- makeGlobalGet (ASYNCIFY_DATA, Type::i32),
820
- makeBinary (AddInt32, makeGetStackPos (), makeConst (Literal (by))),
821
- Type::i32,
822
- wasm.memories [0 ]->name );
824
+ auto literal = Literal::makeFromInt64 (by, pointerType);
825
+ return makeStore (pointerType.getByteSize (),
826
+ int (DataOffset::BStackPos),
827
+ pointerType.getByteSize (),
828
+ makeGlobalGet (ASYNCIFY_DATA, pointerType),
829
+ makeBinary (Abstract::getBinary (pointerType, Abstract::Add),
830
+ makeGetStackPos (),
831
+ makeConst (literal)),
832
+ pointerType,
833
+ wasm.memories [0 ]->name );
823
834
}
824
835
825
836
Expression* makeStateCheck (State value) {
@@ -829,7 +840,8 @@ class AsyncifyBuilder : public Builder {
829
840
}
830
841
831
842
Expression* makeNegatedStateCheck (State value) {
832
- return makeUnary (EqZInt32, makeStateCheck (value));
843
+ return makeUnary (Abstract::getUnary (pointerType, Abstract::EqZ),
844
+ makeStateCheck (value));
833
845
}
834
846
};
835
847
@@ -1384,7 +1396,7 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
1384
1396
}
1385
1397
auto * block = builder->makeBlock ();
1386
1398
block->list .push_back (builder->makeIncStackPos (-total));
1387
- auto tempIndex = builder->addVar (func, Type::i32 );
1399
+ auto tempIndex = builder->addVar (func, builder-> pointerType );
1388
1400
block->list .push_back (
1389
1401
builder->makeLocalSet (tempIndex, builder->makeGetStackPos ()));
1390
1402
Index offset = 0 ;
@@ -1398,14 +1410,14 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
1398
1410
auto size = getByteSize (type);
1399
1411
assert (size % STACK_ALIGN == 0 );
1400
1412
// TODO: higher alignment?
1401
- loads.push_back (
1402
- builder-> makeLoad ( size,
1403
- true ,
1404
- offset,
1405
- STACK_ALIGN,
1406
- builder->makeLocalGet (tempIndex, Type::i32 ),
1407
- type,
1408
- getModule ()->memories [0 ]->name ));
1413
+ loads.push_back (builder-> makeLoad (
1414
+ size,
1415
+ true ,
1416
+ offset,
1417
+ STACK_ALIGN,
1418
+ builder->makeLocalGet (tempIndex, builder-> pointerType ),
1419
+ type,
1420
+ getModule ()->memories [0 ]->name ));
1409
1421
offset += size;
1410
1422
}
1411
1423
Expression* load;
@@ -1429,7 +1441,7 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
1429
1441
auto * func = getFunction ();
1430
1442
auto numLocals = func->getNumLocals ();
1431
1443
auto * block = builder->makeBlock ();
1432
- auto tempIndex = builder->addVar (func, Type::i32 );
1444
+ auto tempIndex = builder->addVar (func, builder-> pointerType );
1433
1445
block->list .push_back (
1434
1446
builder->makeLocalSet (tempIndex, builder->makeGetStackPos ()));
1435
1447
Index offset = 0 ;
@@ -1447,14 +1459,14 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
1447
1459
}
1448
1460
assert (size % STACK_ALIGN == 0 );
1449
1461
// TODO: higher alignment?
1450
- block->list .push_back (
1451
- builder-> makeStore ( size,
1452
- offset,
1453
- STACK_ALIGN,
1454
- builder->makeLocalGet (tempIndex, Type::i32 ),
1455
- localGet,
1456
- type,
1457
- getModule ()->memories [0 ]->name ));
1462
+ block->list .push_back (builder-> makeStore (
1463
+ size,
1464
+ offset,
1465
+ STACK_ALIGN,
1466
+ builder->makeLocalGet (tempIndex, builder-> pointerType ),
1467
+ localGet,
1468
+ type,
1469
+ getModule ()->memories [0 ]->name ));
1458
1470
offset += size;
1459
1471
++j;
1460
1472
}
@@ -1497,6 +1509,8 @@ struct Asyncify : public Pass {
1497
1509
void run (Module* module) override {
1498
1510
auto & options = getPassOptions ();
1499
1511
bool optimize = options.optimizeLevel > 0 ;
1512
+ is64 = module->memories .size () && module->memories [0 ]->is64 ();
1513
+ pointerType = is64 ? Type::i64 : Type::i32;
1500
1514
1501
1515
// Ensure there is a memory, as we need it.
1502
1516
MemoryUtils::ensureExists (module);
@@ -1640,8 +1654,8 @@ struct Asyncify : public Pass {
1640
1654
module->addGlobal (std::move (asyncifyState));
1641
1655
1642
1656
auto asyncifyData = builder.makeGlobal (ASYNCIFY_DATA,
1643
- Type::i32 ,
1644
- builder.makeConst (int32_t ( 0 ) ),
1657
+ pointerType ,
1658
+ builder.makeConst (pointerType ),
1645
1659
Builder::Mutable);
1646
1660
if (imported) {
1647
1661
asyncifyData->module = ENV;
@@ -1655,35 +1669,36 @@ struct Asyncify : public Pass {
1655
1669
auto makeFunction = [&](Name name, bool setData, State state) {
1656
1670
std::vector<Type> params;
1657
1671
if (setData) {
1658
- params.push_back (Type::i32 );
1672
+ params.push_back (pointerType );
1659
1673
}
1660
1674
auto * body = builder.makeBlock ();
1661
1675
body->list .push_back (builder.makeGlobalSet (
1662
1676
ASYNCIFY_STATE, builder.makeConst (int32_t (state))));
1663
1677
if (setData) {
1664
1678
body->list .push_back (builder.makeGlobalSet (
1665
- ASYNCIFY_DATA, builder.makeLocalGet (0 , Type::i32 )));
1679
+ ASYNCIFY_DATA, builder.makeLocalGet (0 , pointerType )));
1666
1680
}
1667
1681
// Verify the data is valid.
1668
1682
auto * stackPos =
1669
- builder.makeLoad (4 ,
1670
- false ,
1671
- int32_t (DataOffset::BStackPos),
1672
- 4 ,
1673
- builder.makeGlobalGet (ASYNCIFY_DATA, Type::i32),
1674
- Type::i32,
1675
- module->memories [0 ]->name );
1676
- auto * stackEnd =
1677
- builder.makeLoad (4 ,
1683
+ builder.makeLoad (pointerType.getByteSize (),
1678
1684
false ,
1679
- int32_t (DataOffset::BStackEnd ),
1680
- 4 ,
1681
- builder.makeGlobalGet (ASYNCIFY_DATA, Type::i32 ),
1682
- Type::i32 ,
1685
+ int (DataOffset::BStackPos ),
1686
+ pointerType. getByteSize () ,
1687
+ builder.makeGlobalGet (ASYNCIFY_DATA, pointerType ),
1688
+ pointerType ,
1683
1689
module->memories [0 ]->name );
1684
- body->list .push_back (
1685
- builder.makeIf (builder.makeBinary (GtUInt32, stackPos, stackEnd),
1686
- builder.makeUnreachable ()));
1690
+ auto * stackEnd = builder.makeLoad (
1691
+ pointerType.getByteSize (),
1692
+ false ,
1693
+ int (is64 ? DataOffset::BStackEnd64 : DataOffset::BStackEnd),
1694
+ pointerType.getByteSize (),
1695
+ builder.makeGlobalGet (ASYNCIFY_DATA, pointerType),
1696
+ pointerType,
1697
+ module->memories [0 ]->name );
1698
+ body->list .push_back (builder.makeIf (
1699
+ builder.makeBinary (
1700
+ Abstract::getBinary (pointerType, Abstract::GtU), stackPos, stackEnd),
1701
+ builder.makeUnreachable ()));
1687
1702
body->finalize ();
1688
1703
auto func = builder.makeFunction (
1689
1704
name, Signature (Type (params), Type::none), {}, body);
@@ -1704,6 +1719,9 @@ struct Asyncify : public Pass {
1704
1719
module->addExport (builder.makeExport (
1705
1720
ASYNCIFY_GET_STATE, ASYNCIFY_GET_STATE, ExternalKind::Function));
1706
1721
}
1722
+
1723
+ bool is64;
1724
+ Type pointerType;
1707
1725
};
1708
1726
1709
1727
Pass* createAsyncifyPass () { return new Asyncify (); }
0 commit comments