summaryrefslogtreecommitdiff
path: root/src/wasm2js.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm2js.h')
-rw-r--r--src/wasm2js.h205
1 files changed, 150 insertions, 55 deletions
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 7377dad31..5cf01ea84 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -80,6 +80,18 @@ void sequenceAppend(Ref& ast, Ref extra) {
ast = ValueBuilder::makeSeq(ast, extra);
}
+bool isTableExported(Module& wasm) {
+ if (!wasm.table.exists || wasm.table.imported()) {
+ return false;
+ }
+ for (auto& ex : wasm.exports) {
+ if (ex->kind == ExternalKind::Table && ex->value == wasm.table.name) {
+ return true;
+ }
+ }
+ return false;
+}
+
IString stringToIString(std::string str) { return IString(str.c_str(), false); }
// Used when taking a wasm name and generating a JS identifier. Each scope here
@@ -384,13 +396,14 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
ValueBuilder::makeDot(ValueBuilder::makeName(ENV),
ValueBuilder::makeName(wasm->memory.base)));
}
- // for emscripten, add a table import - otherwise we would have
- // FUNCTION_TABLE be an upvar, and not as easy to be minified.
- if (flags.emscripten && wasm->table.exists && wasm->table.imported()) {
+ // add table import
+ if (wasm->table.exists && wasm->table.imported()) {
Ref theVar = ValueBuilder::makeVar();
asmFunc[3]->push_back(theVar);
ValueBuilder::appendToVar(
- theVar, FUNCTION_TABLE, ValueBuilder::makeName("wasmTable"));
+ theVar,
+ FUNCTION_TABLE,
+ ValueBuilder::makeDot(ValueBuilder::makeName(ENV), wasm->table.base));
}
// create heaps, etc
addBasics(asmFunc[3]);
@@ -541,31 +554,60 @@ void Wasm2JSBuilder::addGlobalImport(Ref ast, Global* import) {
}
void Wasm2JSBuilder::addTable(Ref ast, Module* wasm) {
+ if (!wasm->table.exists) {
+ return;
+ }
+
+ bool perElementInit = false;
+
// Emit a simple flat table as a JS array literal. Otherwise,
// emit assignments separately for each index.
- TableUtils::FlatTable flat(wasm->table);
- if (flat.valid && !wasm->table.imported()) {
- Ref theVar = ValueBuilder::makeVar();
- ast->push_back(theVar);
- Ref theArray = ValueBuilder::makeArray();
- ValueBuilder::appendToVar(theVar, FUNCTION_TABLE, theArray);
- Name null("null");
- for (auto& name : flat.names) {
- if (name.is()) {
- name = fromName(name, NameScope::Top);
- } else {
- name = null;
+ Ref theArray = ValueBuilder::makeArray();
+ if (!wasm->table.imported()) {
+ TableUtils::FlatTable flat(wasm->table);
+ if (flat.valid) {
+ Name null("null");
+ for (auto& name : flat.names) {
+ if (name.is()) {
+ name = fromName(name, NameScope::Top);
+ } else {
+ name = null;
+ }
+ ValueBuilder::appendToArray(theArray, ValueBuilder::makeName(name));
}
- ValueBuilder::appendToArray(theArray, ValueBuilder::makeName(name));
+ } else {
+ perElementInit = true;
+ Ref initial =
+ ValueBuilder::makeInt(Address::address32_t(wasm->table.initial.addr));
+ theArray = ValueBuilder::makeNew(
+ ValueBuilder::makeCall(IString("Array"), initial));
}
} else {
- if (!wasm->table.imported()) {
- Ref theVar = ValueBuilder::makeVar();
- ast->push_back(theVar);
- ValueBuilder::appendToVar(
- theVar, FUNCTION_TABLE, ValueBuilder::makeArray());
+ perElementInit = true;
+ }
+
+ if (isTableExported(*wasm)) {
+ // If the table is exported use a fake WebAssembly.Table object
+ // We don't handle the case where a table is both imported and exported.
+ if (wasm->table.imported()) {
+ Fatal() << "wasm2js doesn't support a table that is both imported and "
+ "exported\n";
}
+ Ref theVar = ValueBuilder::makeVar();
+ ast->push_back(theVar);
+ Ref table =
+ ValueBuilder::makeNew(ValueBuilder::makeCall(IString("Table"), theArray));
+ ValueBuilder::appendToVar(theVar, FUNCTION_TABLE, table);
+ } else if (!wasm->table.imported()) {
+ // Otherwise if the table is internal (neither imported not exported).
+ // Just use a plain array in this case, avoiding the Table.
+ Ref theVar = ValueBuilder::makeVar();
+ ast->push_back(theVar);
+ ValueBuilder::appendToVar(theVar, FUNCTION_TABLE, theArray);
+ }
+
+ if (perElementInit) {
// TODO: optimize for size
for (auto& segment : wasm->table.segments) {
auto offset = segment.offset;
@@ -600,36 +642,60 @@ void Wasm2JSBuilder::addStart(Ref ast, Module* wasm) {
void Wasm2JSBuilder::addExports(Ref ast, Module* wasm) {
Ref exports = ValueBuilder::makeObject();
for (auto& export_ : wasm->exports) {
- if (export_->kind == ExternalKind::Function) {
- ValueBuilder::appendToObjectWithQuotes(
- exports,
- fromName(export_->name, NameScope::Export),
- ValueBuilder::makeName(fromName(export_->value, NameScope::Top)));
- }
- if (export_->kind == ExternalKind::Memory) {
- Ref descs = ValueBuilder::makeObject();
- Ref growDesc = ValueBuilder::makeObject();
- ValueBuilder::appendToObjectWithQuotes(descs, IString("grow"), growDesc);
- if (wasm->memory.max > wasm->memory.initial) {
+ switch (export_->kind) {
+ case ExternalKind::Function: {
+ ValueBuilder::appendToObjectWithQuotes(
+ exports,
+ fromName(export_->name, NameScope::Export),
+ ValueBuilder::makeName(fromName(export_->value, NameScope::Top)));
+ break;
+ }
+ case ExternalKind::Memory: {
+ Ref descs = ValueBuilder::makeObject();
+ Ref growDesc = ValueBuilder::makeObject();
+ ValueBuilder::appendToObjectWithQuotes(
+ descs, IString("grow"), growDesc);
+ if (wasm->memory.max > wasm->memory.initial) {
+ ValueBuilder::appendToObjectWithQuotes(
+ growDesc,
+ IString("value"),
+ ValueBuilder::makeName(WASM_MEMORY_GROW));
+ }
+ Ref bufferDesc = ValueBuilder::makeObject();
+ Ref bufferGetter = ValueBuilder::makeFunction(IString(""));
+ bufferGetter[3]->push_back(
+ ValueBuilder::makeReturn(ValueBuilder::makeName(BUFFER)));
+ ValueBuilder::appendToObjectWithQuotes(
+ bufferDesc, IString("get"), bufferGetter);
+ ValueBuilder::appendToObjectWithQuotes(
+ descs, IString("buffer"), bufferDesc);
+ Ref memory = ValueBuilder::makeCall(
+ ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")),
+ IString("create")),
+ ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")),
+ IString("prototype")));
+ ValueBuilder::appendToCall(memory, descs);
+ ValueBuilder::appendToObjectWithQuotes(
+ exports, fromName(export_->name, NameScope::Export), memory);
+ break;
+ }
+ case ExternalKind::Table: {
ValueBuilder::appendToObjectWithQuotes(
- growDesc, IString("value"), ValueBuilder::makeName(WASM_MEMORY_GROW));
+ exports,
+ fromName(export_->name, NameScope::Export),
+ ValueBuilder::makeName(FUNCTION_TABLE));
+ break;
}
- Ref bufferDesc = ValueBuilder::makeObject();
- Ref bufferGetter = ValueBuilder::makeFunction(IString(""));
- bufferGetter[3]->push_back(
- ValueBuilder::makeReturn(ValueBuilder::makeName(BUFFER)));
- ValueBuilder::appendToObjectWithQuotes(
- bufferDesc, IString("get"), bufferGetter);
- ValueBuilder::appendToObjectWithQuotes(
- descs, IString("buffer"), bufferDesc);
- Ref memory = ValueBuilder::makeCall(
- ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")),
- IString("create")),
- ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")),
- IString("prototype")));
- ValueBuilder::appendToCall(memory, descs);
- ValueBuilder::appendToObjectWithQuotes(
- exports, fromName(export_->name, NameScope::Export), memory);
+ case ExternalKind::Global: {
+ ValueBuilder::appendToObjectWithQuotes(
+ exports,
+ fromName(export_->name, NameScope::Export),
+ ValueBuilder::makeName(fromName(export_->value, NameScope::Top)));
+ break;
+ }
+ case ExternalKind::Event:
+ case ExternalKind::Invalid:
+ Fatal() << "unsupported export type: " << export_->name << "\n";
}
}
if (wasm->memory.exists) {
@@ -2244,11 +2310,32 @@ void Wasm2JSGlue::emitPre() {
emitPreES6();
}
+ if (isTableExported(wasm)) {
+ out << "function Table(ret) {\n";
+ if (wasm.table.initial == wasm.table.max) {
+ out << " // grow method not included; table is not growable\n";
+ } else {
+ out << " ret.grow = function(by) {\n"
+ << " var old = this.length;\n"
+ << " this.length = this.length + by;\n"
+ << " return old;\n"
+ << " };\n";
+ }
+ out << " ret.set = function(i, func) {\n"
+ << " this[i] = func;\n"
+ << " };\n"
+ << " ret.get = function(i) {\n"
+ << " return this[i];\n"
+ << " };\n"
+ << " return ret;\n"
+ << "}\n\n";
+ }
+
emitSpecialSupport();
}
void Wasm2JSGlue::emitPreEmscripten() {
- out << "function instantiate(asmLibraryArg, wasmMemory, wasmTable) {\n\n";
+ out << "function instantiate(asmLibraryArg, wasmMemory) {\n";
}
void Wasm2JSGlue::emitPreES6() {
@@ -2272,6 +2359,8 @@ void Wasm2JSGlue::emitPreES6() {
ModuleUtils::iterImportedGlobals(
wasm, [&](Global* import) { noteImport(import->module, import->base); });
+ ModuleUtils::iterImportedTables(
+ wasm, [&](Table* import) { noteImport(import->module, import->base); });
ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
// The special helpers are emitted in the glue, see code and comments
// below.
@@ -2281,10 +2370,6 @@ void Wasm2JSGlue::emitPreES6() {
noteImport(import->module, import->base);
});
- if (wasm.table.exists && wasm.table.imported()) {
- out << "import { FUNCTION_TABLE } from 'env';\n";
- }
-
out << '\n';
}
@@ -2365,6 +2450,16 @@ void Wasm2JSGlue::emitPostES6() {
}
out << "," << asmangle(import->base.str);
});
+
+ ModuleUtils::iterImportedTables(wasm, [&](Table* import) {
+ // The special helpers are emitted in the glue, see code and comments
+ // below.
+ if (ABI::wasm2js::isHelper(import->base)) {
+ return;
+ }
+ out << "," << asmangle(import->base.str);
+ });
+
out << "},mem" << moduleName.str << ");\n";
if (flags.allowAsserts) {