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,36 @@ 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),
809
+ pointerType (wasm.memories[0 ]->indexType) {}
800
810
801
811
Expression* makeGetStackPos () {
802
- return makeLoad (4 ,
812
+ return makeLoad (pointerType. getByteSize () ,
803
813
false ,
804
- int32_t (DataOffset::BStackPos),
805
- 4 ,
806
- makeGlobalGet (ASYNCIFY_DATA, Type::i32 ),
807
- Type::i32 ,
814
+ int (DataOffset::BStackPos),
815
+ pointerType. getByteSize () ,
816
+ makeGlobalGet (ASYNCIFY_DATA, pointerType ),
817
+ pointerType ,
808
818
wasm.memories [0 ]->name );
809
819
}
810
820
811
821
Expression* makeIncStackPos (int32_t by) {
812
822
if (by == 0 ) {
813
823
return makeNop ();
814
824
}
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 );
825
+ auto literal = Literal::makeFromInt64 (by, pointerType);
826
+ return makeStore (pointerType.getByteSize (),
827
+ int (DataOffset::BStackPos),
828
+ pointerType.getByteSize (),
829
+ makeGlobalGet (ASYNCIFY_DATA, pointerType),
830
+ makeBinary (Abstract::getBinary (pointerType, Abstract::Add),
831
+ makeGetStackPos (),
832
+ makeConst (literal)),
833
+ pointerType,
834
+ wasm.memories [0 ]->name );
823
835
}
824
836
825
837
Expression* makeStateCheck (State value) {
@@ -829,7 +841,8 @@ class AsyncifyBuilder : public Builder {
829
841
}
830
842
831
843
Expression* makeNegatedStateCheck (State value) {
832
- return makeUnary (EqZInt32, makeStateCheck (value));
844
+ return makeUnary (Abstract::getUnary (pointerType, Abstract::EqZ),
845
+ makeStateCheck (value));
833
846
}
834
847
};
835
848
@@ -1384,7 +1397,7 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
1384
1397
}
1385
1398
auto * block = builder->makeBlock ();
1386
1399
block->list .push_back (builder->makeIncStackPos (-total));
1387
- auto tempIndex = builder->addVar (func, Type::i32 );
1400
+ auto tempIndex = builder->addVar (func, builder-> pointerType );
1388
1401
block->list .push_back (
1389
1402
builder->makeLocalSet (tempIndex, builder->makeGetStackPos ()));
1390
1403
Index offset = 0 ;
@@ -1398,14 +1411,14 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
1398
1411
auto size = getByteSize (type);
1399
1412
assert (size % STACK_ALIGN == 0 );
1400
1413
// 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 ));
1414
+ loads.push_back (builder-> makeLoad (
1415
+ size,
1416
+ true ,
1417
+ offset,
1418
+ STACK_ALIGN,
1419
+ builder->makeLocalGet (tempIndex, builder-> pointerType ),
1420
+ type,
1421
+ getModule ()->memories [0 ]->name ));
1409
1422
offset += size;
1410
1423
}
1411
1424
Expression* load;
@@ -1429,7 +1442,7 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
1429
1442
auto * func = getFunction ();
1430
1443
auto numLocals = func->getNumLocals ();
1431
1444
auto * block = builder->makeBlock ();
1432
- auto tempIndex = builder->addVar (func, Type::i32 );
1445
+ auto tempIndex = builder->addVar (func, builder-> pointerType );
1433
1446
block->list .push_back (
1434
1447
builder->makeLocalSet (tempIndex, builder->makeGetStackPos ()));
1435
1448
Index offset = 0 ;
@@ -1447,14 +1460,14 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
1447
1460
}
1448
1461
assert (size % STACK_ALIGN == 0 );
1449
1462
// 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 ));
1463
+ block->list .push_back (builder-> makeStore (
1464
+ size,
1465
+ offset,
1466
+ STACK_ALIGN,
1467
+ builder->makeLocalGet (tempIndex, builder-> pointerType ),
1468
+ localGet,
1469
+ type,
1470
+ getModule ()->memories [0 ]->name ));
1458
1471
offset += size;
1459
1472
++j;
1460
1473
}
@@ -1497,6 +1510,8 @@ struct Asyncify : public Pass {
1497
1510
void run (Module* module) override {
1498
1511
auto & options = getPassOptions ();
1499
1512
bool optimize = options.optimizeLevel > 0 ;
1513
+ is64 = module->memories .size () && module->memories [0 ]->is64 ();
1514
+ pointerType = is64 ? Type::i64 : Type::i32;
1500
1515
1501
1516
// Ensure there is a memory, as we need it.
1502
1517
MemoryUtils::ensureExists (module);
@@ -1640,8 +1655,8 @@ struct Asyncify : public Pass {
1640
1655
module->addGlobal (std::move (asyncifyState));
1641
1656
1642
1657
auto asyncifyData = builder.makeGlobal (ASYNCIFY_DATA,
1643
- Type::i32 ,
1644
- builder.makeConst (int32_t ( 0 ) ),
1658
+ pointerType ,
1659
+ builder.makeConst (pointerType ),
1645
1660
Builder::Mutable);
1646
1661
if (imported) {
1647
1662
asyncifyData->module = ENV;
@@ -1655,35 +1670,36 @@ struct Asyncify : public Pass {
1655
1670
auto makeFunction = [&](Name name, bool setData, State state) {
1656
1671
std::vector<Type> params;
1657
1672
if (setData) {
1658
- params.push_back (Type::i32 );
1673
+ params.push_back (pointerType );
1659
1674
}
1660
1675
auto * body = builder.makeBlock ();
1661
1676
body->list .push_back (builder.makeGlobalSet (
1662
1677
ASYNCIFY_STATE, builder.makeConst (int32_t (state))));
1663
1678
if (setData) {
1664
1679
body->list .push_back (builder.makeGlobalSet (
1665
- ASYNCIFY_DATA, builder.makeLocalGet (0 , Type::i32 )));
1680
+ ASYNCIFY_DATA, builder.makeLocalGet (0 , pointerType )));
1666
1681
}
1667
1682
// Verify the data is valid.
1668
1683
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 ,
1684
+ builder.makeLoad (pointerType.getByteSize (),
1678
1685
false ,
1679
- int32_t (DataOffset::BStackEnd ),
1680
- 4 ,
1681
- builder.makeGlobalGet (ASYNCIFY_DATA, Type::i32 ),
1682
- Type::i32 ,
1686
+ int (DataOffset::BStackPos ),
1687
+ pointerType. getByteSize () ,
1688
+ builder.makeGlobalGet (ASYNCIFY_DATA, pointerType ),
1689
+ pointerType ,
1683
1690
module->memories [0 ]->name );
1684
- body->list .push_back (
1685
- builder.makeIf (builder.makeBinary (GtUInt32, stackPos, stackEnd),
1686
- builder.makeUnreachable ()));
1691
+ auto * stackEnd = builder.makeLoad (
1692
+ pointerType.getByteSize (),
1693
+ false ,
1694
+ int (is64 ? DataOffset::BStackEnd64 : DataOffset::BStackEnd),
1695
+ pointerType.getByteSize (),
1696
+ builder.makeGlobalGet (ASYNCIFY_DATA, pointerType),
1697
+ pointerType,
1698
+ module->memories [0 ]->name );
1699
+ body->list .push_back (builder.makeIf (
1700
+ builder.makeBinary (
1701
+ Abstract::getBinary (pointerType, Abstract::GtU), stackPos, stackEnd),
1702
+ builder.makeUnreachable ()));
1687
1703
body->finalize ();
1688
1704
auto func = builder.makeFunction (
1689
1705
name, Signature (Type (params), Type::none), {}, body);
@@ -1704,6 +1720,9 @@ struct Asyncify : public Pass {
1704
1720
module->addExport (builder.makeExport (
1705
1721
ASYNCIFY_GET_STATE, ASYNCIFY_GET_STATE, ExternalKind::Function));
1706
1722
}
1723
+
1724
+ bool is64;
1725
+ Type pointerType;
1707
1726
};
1708
1727
1709
1728
Pass* createAsyncifyPass () { return new Asyncify (); }
0 commit comments