Skip to content

Commit 50d0593

Browse files
committed
Add --allow-memory-growth to wasm2asm to generate "almost asm" js
1 parent a0de358 commit 50d0593

File tree

7 files changed

+367
-9
lines changed

7 files changed

+367
-9
lines changed

scripts/test/wasm2asm.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
sorted(os.listdir(os.path.join('test', 'wasm2asm')))]
1515
assert_tests = ['wasm2asm.wast.asserts']
1616

17+
memory_tests = ['wasm2asm.wast.memory']
18+
1719

1820
def test_wasm2asm_output():
1921
for wasm in tests + spec_tests + extra_tests:
@@ -81,11 +83,23 @@ def test_asserts_output():
8183
expected = open(traps_expected_file).read()
8284
fail_if_not_identical(out, expected)
8385

86+
def test_almostasm_output():
87+
for wasm in memory_tests:
88+
print '..', wasm
89+
90+
memory_growth = os.path.basename(wasm).replace('.wast.memory', '.memory.js')
91+
memory_growth_expected_file = os.path.join('test', memory_growth)
92+
93+
cmd = WASM2ASM + [os.path.join('test', wasm), '--allow-memory-growth']
94+
out = run_command(cmd)
95+
expected = open(memory_growth_expected_file).read()
96+
fail_if_not_identical(out, expected)
8497

8598
def test_wasm2asm():
8699
print '\n[ checking wasm2asm testcases... ]\n'
87100
test_wasm2asm_output()
88101
test_asserts_output()
102+
test_almostasm_output()
89103

90104

91105
if __name__ == "__main__":

src/asmjs/shared-constants.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ cashew::IString GLOBAL("global"),
6262
I32_TEMP("asm2wasm_i32_temp"),
6363
DEBUGGER("debugger"),
6464
USE_ASM("use asm"),
65+
ALMOST_ASM("almost asm"),
6566
BUFFER("buffer"),
6667
ENV("env"),
6768
INSTRUMENT("instrument"),
@@ -84,5 +85,7 @@ cashew::IString GLOBAL("global"),
8485
WASM_ROTL32("__wasm_rotl_i32"),
8586
WASM_ROTL64("__wasm_rotl_i64"),
8687
WASM_ROTR32("__wasm_rotr_i32"),
87-
WASM_ROTR64("__wasm_rotr_i64");
88+
WASM_ROTR64("__wasm_rotr_i64"),
89+
WASM_GROW_MEMORY("__wasm_grow_memory"),
90+
WASM_CURRENT_MEMORY("__wasm_current_memory");
8891
}

src/asmjs/shared-constants.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ extern cashew::IString GLOBAL,
6565
I32_TEMP,
6666
DEBUGGER,
6767
USE_ASM,
68+
ALMOST_ASM,
6869
BUFFER,
6970
ENV,
7071
INSTRUMENT,
@@ -87,7 +88,9 @@ extern cashew::IString GLOBAL,
8788
WASM_ROTL32,
8889
WASM_ROTL64,
8990
WASM_ROTR32,
90-
WASM_ROTR64;
91+
WASM_ROTR64,
92+
WASM_GROW_MEMORY,
93+
WASM_CURRENT_MEMORY;
9194
}
9295

9396
#endif // wasm_asmjs_shared_constants_h

src/tools/wasm2asm.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ int main(int argc, const char *argv[]) {
4747
[&](Options* o, const std::string& argument) {
4848
builderFlags.pedantic = true;
4949
})
50+
.add("--allow-memory-growth", "", "Allow memory growth (disables asm.js optimizations)",
51+
Options::Arguments::Zero,
52+
[&](Options* o, const std::string& argument) {
53+
builderFlags.allowMemoryGrowth = true;
54+
})
5055
.add_positional("INFILE", Options::Arguments::One,
5156
[](Options *o, const std::string &argument) {
5257
o->extra["infile"] = argument;

src/wasm2asm.h

Lines changed: 214 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class Wasm2AsmBuilder {
113113
struct Flags {
114114
bool debug = false;
115115
bool pedantic = false;
116+
bool allowMemoryGrowth = false;
116117
};
117118

118119
Wasm2AsmBuilder(Flags f) : flags(f) {}
@@ -210,13 +211,15 @@ class Wasm2AsmBuilder {
210211
void addTables(Ref ast, Module* wasm);
211212
void addExports(Ref ast, Module* wasm);
212213
void addWasmCompatibilityFuncs(Module* wasm);
214+
void addMemoryGrowthFuncs(Ref ast);
213215
bool isAssertHandled(Element& e);
214216
Ref makeAssertReturnFunc(SExpressionWasmBuilder& sexpBuilder,
215217
Builder& wasmBuilder,
216218
Element& e, Name testFuncName);
217219
Ref makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder,
218220
Builder& wasmBuilder,
219221
Element& e, Name testFuncName);
222+
Ref makeGrowMemory();
220223
Wasm2AsmBuilder() = delete;
221224
Wasm2AsmBuilder(const Wasm2AsmBuilder &) = delete;
222225
Wasm2AsmBuilder &operator=(const Wasm2AsmBuilder&) = delete;
@@ -397,7 +400,8 @@ Ref Wasm2AsmBuilder::processWasm(Module* wasm) {
397400
ValueBuilder::appendArgumentToFunction(asmFunc, GLOBAL);
398401
ValueBuilder::appendArgumentToFunction(asmFunc, ENV);
399402
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)));
401405
// create heaps, etc
402406
addBasics(asmFunc[3]);
403407
for (auto& import : wasm->imports) {
@@ -415,6 +419,10 @@ Ref Wasm2AsmBuilder::processWasm(Module* wasm) {
415419
}
416420
tableSize = pow2ed;
417421
// functions
422+
if (flags.allowMemoryGrowth) {
423+
addMemoryGrowthFuncs(asmFunc[3]);
424+
}
425+
418426
for (auto& func : wasm->functions) {
419427
asmFunc[3]->push_back(processFunction(func.get()));
420428
}
@@ -522,11 +530,48 @@ void Wasm2AsmBuilder::addTables(Ref ast, Module* wasm) {
522530
void Wasm2AsmBuilder::addExports(Ref ast, Module* wasm) {
523531
Ref exports = ValueBuilder::makeObject();
524532
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+
}
530575
}
531576
ast->push_back(ValueBuilder::makeStatement(ValueBuilder::makeReturn(exports)));
532577
}
@@ -1557,7 +1602,18 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
15571602
}
15581603

15591604
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);
15611617
}
15621618

15631619
Ref visitNop(Nop* curr) {
@@ -1696,6 +1752,157 @@ Ref Wasm2AsmBuilder::makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder,
16961752
return outerFunc;
16971753
}
16981754

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+
16991906
bool Wasm2AsmBuilder::isAssertHandled(Element& e) {
17001907
return e.isList() && e.size() >= 2 && e[0]->isStr()
17011908
&& (e[0]->str() == Name("assert_return") ||

0 commit comments

Comments
 (0)