@@ -79,6 +79,10 @@ void sequenceAppend(Ref& ast, Ref extra) {
7979 ast = ValueBuilder::makeSeq (ast, extra);
8080}
8181
82+ IString stringToIString (std::string str) {
83+ return IString (str.c_str (), false );
84+ }
85+
8286// Used when taking a wasm name and generating a JS identifier. Each scope here
8387// is used to ensure that all names have a unique name but the same wasm name
8488// within a scope always resolves to the same symbol.
@@ -89,16 +93,6 @@ enum class NameScope {
8993 Max,
9094};
9195
92- template <typename T>
93- static uint64_t constOffset (const T& segment) {
94- auto * c = segment.offset ->template dynCast <Const>();
95- if (!c) {
96- Fatal () << " non-constant offsets aren't supported yet\n " ;
97- abort ();
98- }
99- return c->value .getInteger ();
100- }
101-
10296//
10397// Wasm2JSBuilder - converts a WebAssembly module's functions into JS
10498//
@@ -196,7 +190,7 @@ class Wasm2JSBuilder {
196190 out << " _" << i;
197191 }
198192 auto mangled = asmangle (out.str ());
199- ret = IString (mangled. c_str (), false );
193+ ret = stringToIString (mangled);
200194 if (!allMangledNames.count (ret)) {
201195 break ;
202196 }
@@ -219,10 +213,6 @@ class Wasm2JSBuilder {
219213 return ret;
220214 }
221215
222- size_t getTableSize () {
223- return tableSize;
224- }
225-
226216private:
227217 Flags flags;
228218 PassOptions options;
@@ -237,8 +227,6 @@ class Wasm2JSBuilder {
237227 std::unordered_map<const char *, IString> mangledNames[(int ) NameScope::Max];
238228 std::unordered_set<IString> allMangledNames;
239229
240- size_t tableSize;
241-
242230 // If a function is callable from outside, we'll need to cast the inputs
243231 // and our return value. Otherwise, internally, casts are only needed
244232 // on operations.
@@ -331,17 +319,6 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
331319 ModuleUtils::iterImportedGlobals (*wasm, [&](Global* import ) {
332320 addGlobalImport (asmFunc[3 ], import );
333321 });
334- // figure out the table size
335- tableSize = std::accumulate (wasm->table .segments .begin (),
336- wasm->table .segments .end (),
337- 0 , [&](size_t size, Table::Segment seg) -> size_t {
338- return size + seg.data .size () + constOffset (seg);
339- });
340- size_t pow2ed = 1 ;
341- while (pow2ed < tableSize) {
342- pow2ed <<= 1 ;
343- }
344- tableSize = pow2ed;
345322
346323 // make sure exports get their expected names
347324 for (auto & e : wasm->exports ) {
@@ -509,8 +486,7 @@ void Wasm2JSBuilder::addTable(Ref ast, Module* wasm) {
509486 // Emit a simple flat table as a JS array literal. Otherwise,
510487 // emit assignments separately for each index.
511488 FlatTable flat (wasm->table );
512- assert (flat.valid ); // TODO: non-flat tables
513- if (!wasm->table .imported ()) {
489+ if (flat.valid && !wasm->table .imported ()) {
514490 Ref theVar = ValueBuilder::makeVar ();
515491 ast->push_back (theVar);
516492 Ref theArray = ValueBuilder::makeArray ();
@@ -525,16 +501,33 @@ void Wasm2JSBuilder::addTable(Ref ast, Module* wasm) {
525501 ValueBuilder::appendToArray (theArray, ValueBuilder::makeName (name));
526502 }
527503 } else {
504+ if (!wasm->table .imported ()) {
505+ Ref theVar = ValueBuilder::makeVar ();
506+ ast->push_back (theVar);
507+ ValueBuilder::appendToVar (theVar, FUNCTION_TABLE, ValueBuilder::makeArray ());
508+ }
509+
528510 // TODO: optimize for size
529511 for (auto & segment : wasm->table .segments ) {
530512 auto offset = segment.offset ;
531- Index start = offset->cast <Const>()->value .geti32 ();
532513 for (Index i = 0 ; i < segment.data .size (); i++) {
514+ Ref index;
515+ if (auto * c = offset->dynCast <Const>()) {
516+ index = ValueBuilder::makeInt (c->value .geti32 () + i);
517+ } else if (auto * get = offset->dynCast <GetGlobal>()) {
518+ index = ValueBuilder::makeBinary (
519+ ValueBuilder::makeName (stringToIString (asmangle (get->name .str ))),
520+ PLUS,
521+ ValueBuilder::makeNum (i)
522+ );
523+ } else {
524+ WASM_UNREACHABLE ();
525+ }
533526 ast->push_back (ValueBuilder::makeStatement (
534527 ValueBuilder::makeBinary (
535528 ValueBuilder::makeSub (
536529 ValueBuilder::makeName (FUNCTION_TABLE),
537- ValueBuilder::makeInt (start + i)
530+ index
538531 ),
539532 SET,
540533 ValueBuilder::makeName (fromName (segment.data [i], NameScope::Top))
@@ -1794,7 +1787,7 @@ class Wasm2JSGlue {
17941787 void emitPostEmscripten ();
17951788 void emitPostES6 ();
17961789
1797- void emitMemory (std::string buffer, std::string segmentWriter);
1790+ void emitMemory (std::string buffer, std::string segmentWriter, std::function<std::string (std::string)> accessGlobal );
17981791 void emitScratchMemorySupport ();
17991792};
18001793
@@ -1857,7 +1850,9 @@ void Wasm2JSGlue::emitPost() {
18571850}
18581851
18591852void Wasm2JSGlue::emitPostEmscripten () {
1860- emitMemory (" wasmMemory.buffer" , " writeSegment" );
1853+ emitMemory (" wasmMemory.buffer" , " writeSegment" , [](std::string globalName) {
1854+ return std::string (" asmLibraryArg['" ) + asmangle (globalName) + " ']" ;
1855+ });
18611856
18621857 out << " return asmFunc({\n "
18631858 << " 'Int8Array': Int8Array,\n "
@@ -1895,7 +1890,8 @@ void Wasm2JSGlue::emitPostES6() {
18951890 }
18961891
18971892 emitMemory (std::string (" mem" ) + moduleName.str ,
1898- std::string (" assign" ) + moduleName.str );
1893+ std::string (" assign" ) + moduleName.str ,
1894+ [](std::string globalName) { return globalName; });
18991895
19001896 // Actually invoke the `asmFunc` generated function, passing in all global
19011897 // values followed by all imports
@@ -1958,7 +1954,7 @@ void Wasm2JSGlue::emitPostES6() {
19581954 }
19591955}
19601956
1961- void Wasm2JSGlue::emitMemory (std::string buffer, std::string segmentWriter) {
1957+ void Wasm2JSGlue::emitMemory (std::string buffer, std::string segmentWriter, std::function<std::string (std::string)> accessGlobal ) {
19621958 if (wasm.memory .segments .empty ()) return ;
19631959
19641960 auto expr = R"(
@@ -1982,10 +1978,22 @@ void Wasm2JSGlue::emitMemory(std::string buffer, std::string segmentWriter) {
19821978 out << " var " << segmentWriter
19831979 << " = (" << expr << " )(" << buffer << " );\n " ;
19841980
1981+ auto globalOffset = [&](const Memory::Segment& segment) {
1982+ if (auto * c = segment.offset ->template dynCast <Const>()) {;
1983+ return std::to_string (c->value .getInteger ());
1984+ }
1985+ if (auto * get = segment.offset ->template dynCast <GetGlobal>()) {
1986+ auto internalName = get->name ;
1987+ auto importedName = wasm.getGlobal (internalName)->base ;
1988+ return accessGlobal (asmangle (importedName.str ));
1989+ }
1990+ Fatal () << " non-constant offsets aren't supported yet\n " ;
1991+ };
1992+
19851993 for (auto & seg : wasm.memory .segments ) {
19861994 assert (!seg.isPassive && " passive segments not implemented yet" );
19871995 out << segmentWriter << " ("
1988- << constOffset (seg)
1996+ << globalOffset (seg)
19891997 << " , \" "
19901998 << base64Encode (seg.data )
19911999 << " \" );\n " ;
0 commit comments