@@ -113,6 +113,7 @@ class Wasm2AsmBuilder {
113
113
struct Flags {
114
114
bool debug = false ;
115
115
bool pedantic = false ;
116
+ bool allowMemoryGrowth = false ;
116
117
};
117
118
118
119
Wasm2AsmBuilder (Flags f) : flags(f) {}
@@ -210,13 +211,15 @@ class Wasm2AsmBuilder {
210
211
void addTables (Ref ast, Module* wasm);
211
212
void addExports (Ref ast, Module* wasm);
212
213
void addWasmCompatibilityFuncs (Module* wasm);
214
+ void addMemoryGrowthFuncs (Ref ast);
213
215
bool isAssertHandled (Element& e);
214
216
Ref makeAssertReturnFunc (SExpressionWasmBuilder& sexpBuilder,
215
217
Builder& wasmBuilder,
216
218
Element& e, Name testFuncName);
217
219
Ref makeAssertTrapFunc (SExpressionWasmBuilder& sexpBuilder,
218
220
Builder& wasmBuilder,
219
221
Element& e, Name testFuncName);
222
+ Ref makeGrowMemory ();
220
223
Wasm2AsmBuilder () = delete ;
221
224
Wasm2AsmBuilder (const Wasm2AsmBuilder &) = delete ;
222
225
Wasm2AsmBuilder &operator =(const Wasm2AsmBuilder&) = delete ;
@@ -397,7 +400,8 @@ Ref Wasm2AsmBuilder::processWasm(Module* wasm) {
397
400
ValueBuilder::appendArgumentToFunction (asmFunc, GLOBAL);
398
401
ValueBuilder::appendArgumentToFunction (asmFunc, ENV);
399
402
ValueBuilder::appendArgumentToFunction (asmFunc, BUFFER);
400
- asmFunc[3 ]->push_back (ValueBuilder::makeStatement (ValueBuilder::makeString (USE_ASM)));
403
+ asmFunc[3 ]->push_back (ValueBuilder::makeStatement (ValueBuilder::makeString (
404
+ flags.allowMemoryGrowth ? ALMOST_ASM : USE_ASM)));
401
405
// create heaps, etc
402
406
addBasics (asmFunc[3 ]);
403
407
for (auto & import : wasm->imports ) {
@@ -415,6 +419,10 @@ Ref Wasm2AsmBuilder::processWasm(Module* wasm) {
415
419
}
416
420
tableSize = pow2ed;
417
421
// functions
422
+ if (flags.allowMemoryGrowth ) {
423
+ addMemoryGrowthFuncs (asmFunc[3 ]);
424
+ }
425
+
418
426
for (auto & func : wasm->functions ) {
419
427
asmFunc[3 ]->push_back (processFunction (func.get ()));
420
428
}
@@ -522,11 +530,48 @@ void Wasm2AsmBuilder::addTables(Ref ast, Module* wasm) {
522
530
void Wasm2AsmBuilder::addExports (Ref ast, Module* wasm) {
523
531
Ref exports = ValueBuilder::makeObject ();
524
532
for (auto & export_ : wasm->exports ) {
525
- ValueBuilder::appendToObject (
526
- exports,
527
- fromName (export_->name ),
528
- ValueBuilder::makeName (fromName (export_->value ))
529
- );
533
+ if (export_->kind == ExternalKind::Function) {
534
+ ValueBuilder::appendToObject (
535
+ exports,
536
+ fromName (export_->name ),
537
+ ValueBuilder::makeName (fromName (export_->value ))
538
+ );
539
+ }
540
+ if (flags.allowMemoryGrowth && export_->kind == ExternalKind::Memory) {
541
+ Ref descs = ValueBuilder::makeObject ();
542
+ Ref growDesc = ValueBuilder::makeObject ();
543
+ ValueBuilder::appendToObject (
544
+ descs,
545
+ IString (" grow" ),
546
+ growDesc);
547
+ ValueBuilder::appendToObject (
548
+ growDesc,
549
+ IString (" value" ),
550
+ ValueBuilder::makeName (WASM_GROW_MEMORY));
551
+ Ref bufferDesc = ValueBuilder::makeObject ();
552
+ Ref bufferGetter = ValueBuilder::makeFunction (IString (" " ));
553
+ bufferGetter[3 ]->push_back (ValueBuilder::makeReturn (
554
+ ValueBuilder::makeName (BUFFER)
555
+ ));
556
+ ValueBuilder::appendToObject (
557
+ bufferDesc,
558
+ IString (" get" ),
559
+ bufferGetter);
560
+ ValueBuilder::appendToObject (
561
+ descs,
562
+ IString (" buffer" ),
563
+ bufferDesc);
564
+ Ref memory = ValueBuilder::makeCall (
565
+ ValueBuilder::makeDot (ValueBuilder::makeName (IString (" Object" )), IString (" create" )),
566
+ ValueBuilder::makeDot (ValueBuilder::makeName (IString (" Object" )), IString (" prototype" )));
567
+ ValueBuilder::appendToCall (
568
+ memory,
569
+ descs);
570
+ ValueBuilder::appendToObject (
571
+ exports,
572
+ fromName (export_->name ),
573
+ memory);
574
+ }
530
575
}
531
576
ast->push_back (ValueBuilder::makeStatement (ValueBuilder::makeReturn (exports)));
532
577
}
@@ -1557,7 +1602,18 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
1557
1602
}
1558
1603
1559
1604
Ref visitHost (Host* curr) {
1560
- abort ();
1605
+ if (parent->flags .allowMemoryGrowth ) {
1606
+ if (curr->op == HostOp::GrowMemory) {
1607
+ return ValueBuilder::makeCall (WASM_GROW_MEMORY,
1608
+ makeAsmCoercion (
1609
+ visit (curr->operands [0 ], EXPRESSION_RESULT),
1610
+ wasmToAsmType (curr->operands [0 ]->type )));
1611
+ }
1612
+ if (curr->op == HostOp::CurrentMemory) {
1613
+ return ValueBuilder::makeCall (WASM_CURRENT_MEMORY);
1614
+ }
1615
+ }
1616
+ return ValueBuilder::makeCall (ABORT_FUNC);
1561
1617
}
1562
1618
1563
1619
Ref visitNop (Nop* curr) {
@@ -1696,6 +1752,157 @@ Ref Wasm2AsmBuilder::makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder,
1696
1752
return outerFunc;
1697
1753
}
1698
1754
1755
+ void Wasm2AsmBuilder::addMemoryGrowthFuncs (Ref ast) {
1756
+ Ref growMemoryFunc = ValueBuilder::makeFunction (WASM_GROW_MEMORY);
1757
+ ValueBuilder::appendArgumentToFunction (growMemoryFunc, IString (" pagesToAdd" ));
1758
+
1759
+ growMemoryFunc[3 ]->push_back (
1760
+ ValueBuilder::makeStatement (
1761
+ ValueBuilder::makeBinary (
1762
+ ValueBuilder::makeName (IString (" pagesToAdd" )), SET,
1763
+ makeAsmCoercion (
1764
+ ValueBuilder::makeName (IString (" pagesToAdd" )),
1765
+ AsmType::ASM_INT
1766
+ )
1767
+ )
1768
+ )
1769
+ );
1770
+
1771
+ Ref oldPages = ValueBuilder::makeVar ();
1772
+ growMemoryFunc[3 ]->push_back (oldPages);
1773
+ ValueBuilder::appendToVar (
1774
+ oldPages,
1775
+ IString (" oldPages" ),
1776
+ makeAsmCoercion (ValueBuilder::makeCall (WASM_CURRENT_MEMORY), AsmType::ASM_INT));
1777
+
1778
+ Ref newPages = ValueBuilder::makeVar ();
1779
+ growMemoryFunc[3 ]->push_back (newPages);
1780
+ ValueBuilder::appendToVar (
1781
+ newPages,
1782
+ IString (" newPages" ),
1783
+ makeAsmCoercion (ValueBuilder::makeBinary (
1784
+ ValueBuilder::makeName (IString (" oldPages" )),
1785
+ PLUS,
1786
+ ValueBuilder::makeName (IString (" pagesToAdd" ))
1787
+ ), AsmType::ASM_INT));
1788
+
1789
+ Ref block = ValueBuilder::makeBlock ();
1790
+ growMemoryFunc[3 ]->push_back (ValueBuilder::makeIf (
1791
+ ValueBuilder::makeBinary (
1792
+ ValueBuilder::makeBinary (
1793
+ ValueBuilder::makeName (IString (" oldPages" )),
1794
+ LT,
1795
+ ValueBuilder::makeName (IString (" newPages" ))
1796
+ ),
1797
+ IString (" &&" ),
1798
+ ValueBuilder::makeBinary (
1799
+ ValueBuilder::makeName (IString (" newPages" )),
1800
+ LT,
1801
+ ValueBuilder::makeInt (Memory::kMaxSize )
1802
+ )
1803
+ ), block, NULL ));
1804
+
1805
+ Ref newBuffer = ValueBuilder::makeVar ();
1806
+ ValueBuilder::appendToBlock (block, newBuffer);
1807
+ ValueBuilder::appendToVar (
1808
+ newBuffer,
1809
+ IString (" newBuffer" ),
1810
+ ValueBuilder::makeNew (ValueBuilder::makeCall (
1811
+ ARRAY_BUFFER,
1812
+ ValueBuilder::makeCall (
1813
+ MATH_IMUL,
1814
+ ValueBuilder::makeName (IString (" newPages" )),
1815
+ ValueBuilder::makeInt (Memory::kPageSize )))));
1816
+
1817
+ Ref newHEAP8 = ValueBuilder::makeVar ();
1818
+ ValueBuilder::appendToBlock (block, newHEAP8);
1819
+ ValueBuilder::appendToVar (
1820
+ newHEAP8,
1821
+ IString (" newHEAP8" ),
1822
+ ValueBuilder::makeNew (
1823
+ ValueBuilder::makeCall (
1824
+ ValueBuilder::makeDot (
1825
+ ValueBuilder::makeName (GLOBAL),
1826
+ INT8ARRAY
1827
+ ),
1828
+ ValueBuilder::makeName (IString (" newBuffer" ))
1829
+ )
1830
+ ));
1831
+
1832
+ ValueBuilder::appendToBlock (block,
1833
+ ValueBuilder::makeCall (
1834
+ ValueBuilder::makeDot (
1835
+ ValueBuilder::makeName (IString (" newHEAP8" )),
1836
+ IString (" set" )
1837
+ ),
1838
+ ValueBuilder::makeName (HEAP8)
1839
+ )
1840
+ );
1841
+
1842
+ ValueBuilder::appendToBlock (block,
1843
+ ValueBuilder::makeBinary (
1844
+ ValueBuilder::makeName (HEAP8),
1845
+ SET,
1846
+ ValueBuilder::makeName (IString (" newHEAP8" ))
1847
+ )
1848
+ );
1849
+
1850
+ auto setHeap = [&](IString name, IString view) {
1851
+ ValueBuilder::appendToBlock (block,
1852
+ ValueBuilder::makeBinary (
1853
+ ValueBuilder::makeName (name),
1854
+ SET,
1855
+ ValueBuilder::makeNew (
1856
+ ValueBuilder::makeCall (
1857
+ ValueBuilder::makeDot (
1858
+ ValueBuilder::makeName (GLOBAL),
1859
+ view
1860
+ ),
1861
+ ValueBuilder::makeName (IString (" newBuffer" ))
1862
+ )
1863
+ )
1864
+ )
1865
+ );
1866
+ };
1867
+
1868
+ setHeap (HEAP16, INT16ARRAY);
1869
+ setHeap (HEAP32, INT32ARRAY);
1870
+ setHeap (HEAPU8, UINT8ARRAY);
1871
+ setHeap (HEAPU16, UINT16ARRAY);
1872
+ setHeap (HEAPU32, UINT32ARRAY);
1873
+ setHeap (HEAPF32, FLOAT32ARRAY);
1874
+ setHeap (HEAPF64, FLOAT64ARRAY);
1875
+
1876
+ ValueBuilder::appendToBlock (block,
1877
+ ValueBuilder::makeBinary (
1878
+ ValueBuilder::makeName (BUFFER),
1879
+ SET,
1880
+ ValueBuilder::makeName (IString (" newBuffer" ))
1881
+ )
1882
+ );
1883
+
1884
+ growMemoryFunc[3 ]->push_back (
1885
+ ValueBuilder::makeReturn (
1886
+ ValueBuilder::makeName (IString (" oldPages" ))));
1887
+
1888
+ Ref currentMemoryFunc = ValueBuilder::makeFunction (WASM_CURRENT_MEMORY);
1889
+ currentMemoryFunc[3 ]->push_back (ValueBuilder::makeReturn (
1890
+ makeAsmCoercion (
1891
+ ValueBuilder::makeBinary (
1892
+ ValueBuilder::makeDot (
1893
+ ValueBuilder::makeName (BUFFER),
1894
+ IString (" byteLength" )
1895
+ ),
1896
+ DIV,
1897
+ ValueBuilder::makeInt (Memory::kPageSize )
1898
+ ),
1899
+ AsmType::ASM_INT
1900
+ )
1901
+ ));
1902
+ ast->push_back (growMemoryFunc);
1903
+ ast->push_back (currentMemoryFunc);
1904
+ }
1905
+
1699
1906
bool Wasm2AsmBuilder::isAssertHandled (Element& e) {
1700
1907
return e.isList () && e.size () >= 2 && e[0 ]->isStr ()
1701
1908
&& (e[0 ]->str () == Name (" assert_return" ) ||
0 commit comments