3838#include " ir/load-utils.h"
3939#include " ir/module-utils.h"
4040#include " ir/names.h"
41+ #include " ir/table-utils.h"
4142#include " ir/utils.h"
4243#include " passes/passes.h"
4344#include " support/base64.h"
@@ -267,15 +268,14 @@ class Wasm2JSBuilder {
267268 std::unordered_map<const char *, IString> mangledNames[(int ) NameScope::Max];
268269 std::unordered_set<IString> allMangledNames;
269270
270- // All our function tables have the same size TODO: optimize?
271271 size_t tableSize;
272272
273273 bool almostASM = false ;
274274
275275 void addBasics (Ref ast);
276276 void addFunctionImport (Ref ast, Function* import );
277277 void addGlobalImport (Ref ast, Global* import );
278- void addTables (Ref ast, Module* wasm);
278+ void addTable (Ref ast, Module* wasm);
279279 void addExports (Ref ast, Module* wasm);
280280 void addGlobal (Ref ast, Global* global);
281281 void setNeedsAlmostASM (const char *reason);
@@ -387,7 +387,7 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
387387 asmFunc[3 ]->push_back (ValueBuilder::makeName (" // EMSCRIPTEN_END_FUNCS" ));
388388 }
389389
390- addTables (asmFunc[3 ], wasm);
390+ addTable (asmFunc[3 ], wasm);
391391 // memory XXX
392392 addExports (asmFunc[3 ], wasm);
393393 return ret;
@@ -499,38 +499,43 @@ void Wasm2JSBuilder::addGlobalImport(Ref ast, Global* import) {
499499 );
500500}
501501
502- void Wasm2JSBuilder::addTables (Ref ast, Module* wasm) {
503- std::map<std::string, std::vector<IString>> tables; // asm.js tables, sig => contents of table
504- for (Table::Segment& seg : wasm->table .segments ) {
505- for (size_t i = 0 ; i < seg.data .size (); i++) {
506- Name name = seg.data [i];
507- auto func = wasm->getFunction (name);
508- std::string sig = getSig (func);
509- auto & table = tables[sig];
510- if (table.size () == 0 ) {
511- // fill it with the first of its type seen. we have to fill with something; and for asm2wasm output, the first is the null anyhow
512- table.resize (tableSize);
513- for (size_t j = 0 ; j < tableSize; j++) {
514- table[j] = fromName (name, NameScope::Top);
515- }
516- } else {
517- table[i + constOffset (seg)] = fromName (name, NameScope::Top);
518- }
519- }
520- }
521- for (auto & pair : tables) {
522- auto & sig = pair.first ;
523- auto & table = pair.second ;
524- std::string stable = std::string (" FUNCTION_TABLE_" ) + sig;
525- IString asmName = IString (stable.c_str (), false );
526- // add to asm module
502+ void Wasm2JSBuilder::addTable (Ref ast, Module* wasm) {
503+ // Emit a simple flat table as a JS array literal. Otherwise,
504+ // emit assignments separately for each index.
505+ FlatTable flat (wasm->table );
506+ assert (flat.valid ); // TODO: non-flat tables
507+ if (!wasm->table .imported ()) {
527508 Ref theVar = ValueBuilder::makeVar ();
528509 ast->push_back (theVar);
529510 Ref theArray = ValueBuilder::makeArray ();
530- ValueBuilder::appendToVar (theVar, asmName, theArray);
531- for (auto & name : table) {
511+ ValueBuilder::appendToVar (theVar, FUNCTION_TABLE , theArray);
512+ Name null (" null" );
513+ for (auto & name : flat.names ) {
514+ if (name.is ()) {
515+ name = fromName (name, NameScope::Top);
516+ } else {
517+ name = null;
518+ }
532519 ValueBuilder::appendToArray (theArray, ValueBuilder::makeName (name));
533520 }
521+ } else {
522+ // TODO: optimize for size
523+ for (auto & segment : wasm->table .segments ) {
524+ auto offset = segment.offset ;
525+ Index start = offset->cast <Const>()->value .geti32 ();
526+ for (Index i = 0 ; i < segment.data .size (); i++) {
527+ ast->push_back (ValueBuilder::makeStatement (
528+ ValueBuilder::makeBinary (
529+ ValueBuilder::makeSub (
530+ ValueBuilder::makeName (FUNCTION_TABLE ),
531+ ValueBuilder::makeInt (start + i)
532+ ),
533+ SET ,
534+ ValueBuilder::makeName (fromName (segment.data [i], NameScope::Top))
535+ )
536+ ));
537+ }
538+ }
534539 }
535540}
536541
@@ -1058,11 +1063,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, IString resul
10581063 Ref visitCallIndirect (CallIndirect* curr) {
10591064 // TODO: the codegen here is a pessimization of what the ideal codegen
10601065 // looks like. Eventually if necessary this should be tightened up in the
1061- // case that the argument expression don 't have any side effects.
1066+ // case that the argument expression doesn 't have any side effects.
10621067 assert (isStatement (curr));
1063- std::string stable = std::string (" FUNCTION_TABLE_" ) +
1064- getSig (module ->getFunctionType (curr->fullType ));
1065- IString table = IString (stable.c_str (), false );
10661068 Ref ret = ValueBuilder::makeBlock ();
10671069 ScopedTemp idx (i32 , parent, func);
10681070 return makeStatementizedCall (
@@ -1071,8 +1073,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, IString resul
10711073 [&]() {
10721074 flattenAppend (ret, visitAndAssign (curr->target , idx));
10731075 return ValueBuilder::makeCall (ValueBuilder::makeSub (
1074- ValueBuilder::makeName (table ),
1075- ValueBuilder::makeBinary ( idx.getAstName (), AND , ValueBuilder::makeInt (parent-> getTableSize ()- 1 ) )
1076+ ValueBuilder::makeName (FUNCTION_TABLE ),
1077+ idx.getAstName ()
10761078 ));
10771079 },
10781080 result,
@@ -2031,7 +2033,7 @@ void Wasm2JSGlue::emitPre() {
20312033}
20322034
20332035void Wasm2JSGlue::emitPreEmscripten () {
2034- out << " function instantiate(asmLibraryArg, wasmMemory, wasmTable ) {\n\n " ;
2036+ out << " function instantiate(asmLibraryArg, wasmMemory, FUNCTION_TABLE ) {\n\n " ;
20352037}
20362038
20372039void Wasm2JSGlue::emitPreES6 () {
0 commit comments