summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-binary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-binary.cpp')
-rw-r--r--src/wasm/wasm-binary.cpp272
1 files changed, 113 insertions, 159 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index b643eaec8..1839c9cbd 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -35,6 +35,8 @@ void WasmBinaryWriter::prepare() {
ModuleUtils::BinaryIndexes indexes(*wasm);
mappedFunctions = std::move(indexes.functionIndexes);
mappedGlobals = std::move(indexes.globalIndexes);
+
+ importInfo = wasm::make_unique<ImportInfo>(*wasm);
}
void WasmBinaryWriter::write() {
@@ -136,7 +138,7 @@ void WasmBinaryWriter::writeStart() {
}
void WasmBinaryWriter::writeMemory() {
- if (!wasm->memory.exists || wasm->memory.imported) return;
+ if (!wasm->memory.exists || wasm->memory.imported()) return;
if (debug) std::cerr << "== writeMemory" << std::endl;
auto start = startSection(BinaryConsts::Section::Memory);
o << U32LEB(1); // Define 1 memory
@@ -176,46 +178,54 @@ int32_t WasmBinaryWriter::getFunctionTypeIndex(Name type) {
}
void WasmBinaryWriter::writeImports() {
- if (wasm->imports.size() == 0) return;
+ auto num = importInfo->getNumImports();
+ if (num == 0) return;
if (debug) std::cerr << "== writeImports" << std::endl;
auto start = startSection(BinaryConsts::Section::Import);
- o << U32LEB(wasm->imports.size());
- for (auto& import : wasm->imports) {
- if (debug) std::cerr << "write one" << std::endl;
+ o << U32LEB(num);
+ auto writeImportHeader = [&](Importable* import) {
writeInlineString(import->module.str);
writeInlineString(import->base.str);
- o << U32LEB(int32_t(import->kind));
- switch (import->kind) {
- case ExternalKind::Function: o << U32LEB(getFunctionTypeIndex(import->functionType)); break;
- case ExternalKind::Table: {
- o << S32LEB(BinaryConsts::EncodedType::AnyFunc);
- writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize, /*shared=*/false);
- break;
- }
- case ExternalKind::Memory: {
- writeResizableLimits(wasm->memory.initial, wasm->memory.max,
- wasm->memory.max != Memory::kMaxSize, wasm->memory.shared);
- break;
- }
- case ExternalKind::Global:
- o << binaryType(import->globalType);
- o << U32LEB(0); // Mutable global's can't be imported for now.
- break;
- default: WASM_UNREACHABLE();
- }
+ };
+ ModuleUtils::iterImportedFunctions(*wasm, [&](Function* func) {
+ if (debug) std::cerr << "write one function" << std::endl;
+ writeImportHeader(func);
+ o << U32LEB(int32_t(ExternalKind::Function));
+ o << U32LEB(getFunctionTypeIndex(func->type));
+ });
+ ModuleUtils::iterImportedGlobals(*wasm, [&](Global* global) {
+ if (debug) std::cerr << "write one global" << std::endl;
+ writeImportHeader(global);
+ o << U32LEB(int32_t(ExternalKind::Global));
+ o << binaryType(global->type);
+ o << U32LEB(0); // Mutable globals can't be imported for now.
+ });
+ if (wasm->memory.imported()) {
+ if (debug) std::cerr << "write one memory" << std::endl;
+ writeImportHeader(&wasm->memory);
+ o << U32LEB(int32_t(ExternalKind::Memory));
+ writeResizableLimits(wasm->memory.initial, wasm->memory.max,
+ wasm->memory.max != Memory::kMaxSize, wasm->memory.shared);
+ }
+ if (wasm->table.imported()) {
+ if (debug) std::cerr << "write one table" << std::endl;
+ writeImportHeader(&wasm->table);
+ o << U32LEB(int32_t(ExternalKind::Table));
+ o << S32LEB(BinaryConsts::EncodedType::AnyFunc);
+ writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize, /*shared=*/false);
}
finishSection(start);
}
void WasmBinaryWriter::writeFunctionSignatures() {
- if (wasm->functions.size() == 0) return;
+ if (importInfo->getNumDefinedFunctions() == 0) return;
if (debug) std::cerr << "== writeFunctionSignatures" << std::endl;
auto start = startSection(BinaryConsts::Section::Function);
- o << U32LEB(wasm->functions.size());
- for (auto& curr : wasm->functions) {
+ o << U32LEB(importInfo->getNumDefinedFunctions());
+ ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
if (debug) std::cerr << "write one" << std::endl;
- o << U32LEB(getFunctionTypeIndex(curr->type));
- }
+ o << U32LEB(getFunctionTypeIndex(func->type));
+ });
finishSection(start);
}
@@ -224,17 +234,15 @@ void WasmBinaryWriter::writeExpression(Expression* curr) {
}
void WasmBinaryWriter::writeFunctions() {
- if (wasm->functions.size() == 0) return;
+ if (importInfo->getNumDefinedFunctions() == 0) return;
if (debug) std::cerr << "== writeFunctions" << std::endl;
auto start = startSection(BinaryConsts::Section::Code);
- size_t total = wasm->functions.size();
- o << U32LEB(total);
- for (size_t i = 0; i < total; i++) {
+ o << U32LEB(importInfo->getNumDefinedFunctions());
+ ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size();
if (debug) std::cerr << "write one at" << o.size() << std::endl;
size_t sizePos = writeU32LEBPlaceholder();
size_t start = o.size();
- Function* func = wasm->functions[i].get();
if (debug) std::cerr << "writing" << func->name << std::endl;
// Emit Stack IR if present, and if we can
if (func->stackIR && !sourceMap) {
@@ -261,22 +269,23 @@ void WasmBinaryWriter::writeFunctions() {
}
}
tableOfContents.functionBodies.emplace_back(func->name, sizePos + sizeFieldSize, size);
- }
+ });
finishSection(start);
}
void WasmBinaryWriter::writeGlobals() {
- if (wasm->globals.size() == 0) return;
+ if (importInfo->getNumDefinedGlobals() == 0) return;
if (debug) std::cerr << "== writeglobals" << std::endl;
auto start = startSection(BinaryConsts::Section::Global);
- o << U32LEB(wasm->globals.size());
- for (auto& curr : wasm->globals) {
+ auto num = importInfo->getNumDefinedGlobals();
+ o << U32LEB(num);
+ ModuleUtils::iterDefinedGlobals(*wasm, [&](Global* global) {
if (debug) std::cerr << "write one" << std::endl;
- o << binaryType(curr->type);
- o << U32LEB(curr->mutable_);
- writeExpression(curr->init);
+ o << binaryType(global->type);
+ o << U32LEB(global->mutable_);
+ writeExpression(global->init);
o << int8_t(BinaryConsts::End);
- }
+ });
finishSection(start);
}
@@ -404,7 +413,7 @@ uint32_t WasmBinaryWriter::getGlobalIndex(Name name) {
}
void WasmBinaryWriter::writeFunctionTableDeclaration() {
- if (!wasm->table.exists || wasm->table.imported) return;
+ if (!wasm->table.exists || wasm->table.imported()) return;
if (debug) std::cerr << "== writeFunctionTableDeclaration" << std::endl;
auto start = startSection(BinaryConsts::Section::Table);
o << U32LEB(1); // Declare 1 table.
@@ -436,14 +445,6 @@ void WasmBinaryWriter::writeNames() {
if (wasm->functions.size() > 0) {
hasContents = true;
getFunctionIndex(wasm->functions[0]->name); // generate mappedFunctions
- } else {
- for (auto& import : wasm->imports) {
- if (import->kind == ExternalKind::Function) {
- hasContents = true;
- getFunctionIndex(import->name); // generate mappedFunctions
- break;
- }
- }
}
if (!hasContents) return;
if (debug) std::cerr << "== writeNames" << std::endl;
@@ -452,18 +453,13 @@ void WasmBinaryWriter::writeNames() {
auto substart = startSubsection(BinaryConsts::UserSections::Subsection::NameFunction);
o << U32LEB(mappedFunctions.size());
Index emitted = 0;
- for (auto& import : wasm->imports) {
- if (import->kind == ExternalKind::Function) {
- o << U32LEB(emitted);
- writeEscapedName(import->name.str);
- emitted++;
- }
- }
- for (auto& curr : wasm->functions) {
+ auto add = [&](Function* curr) {
o << U32LEB(emitted);
writeEscapedName(curr->name.str);
emitted++;
- }
+ };
+ ModuleUtils::iterImportedFunctions(*wasm, add);
+ ModuleUtils::iterDefinedFunctions(*wasm, add);
assert(emitted == mappedFunctions.size());
finishSubsection(substart);
/* TODO: locals */
@@ -480,14 +476,11 @@ void WasmBinaryWriter::writeSourceMapUrl() {
void WasmBinaryWriter::writeSymbolMap() {
std::ofstream file(symbolMap);
- for (auto& import : wasm->imports) {
- if (import->kind == ExternalKind::Function) {
- file << getFunctionIndex(import->name) << ":" << import->name.str << std::endl;
- }
- }
- for (auto& func : wasm->functions) {
+ auto write = [&](Function* func) {
file << getFunctionIndex(func->name) << ":" << func->name.str << std::endl;
- }
+ };
+ ModuleUtils::iterImportedFunctions(*wasm, write);
+ ModuleUtils::iterDefinedFunctions(*wasm, write);
file.close();
}
@@ -940,17 +933,7 @@ void WasmBinaryBuilder::readSignatures() {
}
Name WasmBinaryBuilder::getFunctionIndexName(Index i) {
- if (i < functionImports.size()) {
- auto* import = functionImports[i];
- assert(import->kind == ExternalKind::Function);
- return import->name;
- } else {
- i -= functionImports.size();
- if (i >= wasm.functions.size()) {
- throwError("bad function index");
- }
- return wasm.functions[i]->name;
- }
+ return wasm.functions[i]->name;
}
void WasmBinaryBuilder::getResizableLimits(Address& initial, Address& max, bool &shared, Address defaultIfNoMax) {
@@ -968,61 +951,69 @@ void WasmBinaryBuilder::readImports() {
if (debug) std::cerr << "== readImports" << std::endl;
size_t num = getU32LEB();
if (debug) std::cerr << "num: " << num << std::endl;
+ Builder builder(wasm);
for (size_t i = 0; i < num; i++) {
if (debug) std::cerr << "read one" << std::endl;
- auto curr = new Import;
- curr->module = getInlineString();
- curr->base = getInlineString();
- curr->kind = (ExternalKind)getU32LEB();
+ auto module = getInlineString();
+ auto base = getInlineString();
+ auto kind = (ExternalKind)getU32LEB();
// We set a unique prefix for the name based on the kind. This ensures no collisions
// between them, which can't occur here (due to the index i) but could occur later
// due to the names section.
- switch (curr->kind) {
+ switch (kind) {
case ExternalKind::Function: {
- curr->name = Name(std::string("fimport$") + std::to_string(i));
+ auto name = Name(std::string("fimport$") + std::to_string(i));
auto index = getU32LEB();
if (index >= wasm.functionTypes.size()) {
throwError("invalid function index " + std::to_string(index) + " / " + std::to_string(wasm.functionTypes.size()));
}
- curr->functionType = wasm.functionTypes[index]->name;
- assert(curr->functionType.is());
+ auto* functionType = wasm.functionTypes[index].get();
+ auto params = functionType->params;
+ auto result = functionType->result;
+ auto* curr = builder.makeFunction(name, std::move(params), result, {});
+ curr->module = module;
+ curr->base = base;
+ curr->type = functionType->name;
+ wasm.addFunction(curr);
functionImports.push_back(curr);
- continue; // don't add the import yet, we add them later after we know their names
break;
}
case ExternalKind::Table: {
- curr->name = Name(std::string("timport$") + std::to_string(i));
+ wasm.table.module = module;
+ wasm.table.base = base;
+ wasm.table.name = Name(std::string("timport$") + std::to_string(i));
auto elementType = getS32LEB();
WASM_UNUSED(elementType);
if (elementType != BinaryConsts::EncodedType::AnyFunc) throwError("Imported table type is not AnyFunc");
wasm.table.exists = true;
- wasm.table.imported = true;
bool is_shared;
getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kMaxSize);
if (is_shared) throwError("Tables may not be shared");
break;
}
case ExternalKind::Memory: {
- curr->name = Name(std::string("mimport$") + std::to_string(i));
+ wasm.memory.module = module;
+ wasm.memory.base = base;
+ wasm.memory.name = Name(std::to_string(i));
wasm.memory.exists = true;
- wasm.memory.imported = true;
getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kMaxSize);
break;
}
case ExternalKind::Global: {
- curr->name = Name(std::string("gimport$") + std::to_string(i));
- curr->globalType = getConcreteType();
- auto globalMutable = getU32LEB();
- // TODO: actually use the globalMutable flag. Currently mutable global
- // imports is a future feature, to be implemented with thread support.
- (void)globalMutable;
+ auto name = Name(std::string("gimport$") + std::to_string(i));
+ auto type = getConcreteType();
+ auto mutable_ = getU32LEB();
+ assert(!mutable_); // for now, until mutable globals
+ auto* curr = builder.makeGlobal(name, type, nullptr, mutable_ ? Builder::Mutable : Builder::Immutable);
+ curr->module = module;
+ curr->base = base;
+ wasm.addGlobal(curr);
break;
}
default: {
throwError("bad import kind");
}
}
- wasm.addImport(curr);
}
}
@@ -1332,7 +1323,7 @@ void WasmBinaryBuilder::readGlobals() {
if (mutable_ & ~1) throwError("Global mutability must be 0 or 1");
auto* init = readExpression();
wasm.addGlobal(Builder::makeGlobal(
- "global$" + std::to_string(wasm.globals.size()),
+ "global$" + std::to_string(i),
type,
init,
mutable_ ? Builder::Mutable : Builder::Immutable
@@ -1460,15 +1451,12 @@ Expression* WasmBinaryBuilder::popNonVoidExpression() {
Name WasmBinaryBuilder::getGlobalName(Index index) {
if (!mappedGlobals.size()) {
// Create name => index mapping.
- for (auto& import : wasm.imports) {
- if (import->kind != ExternalKind::Global) continue;
- auto index = mappedGlobals.size();
- mappedGlobals[index] = import->name;
- }
- for (size_t i = 0; i < wasm.globals.size(); i++) {
+ auto add = [&](Global* curr) {
auto index = mappedGlobals.size();
- mappedGlobals[index] = wasm.globals[i]->name;
- }
+ mappedGlobals[index] = curr->name;
+ };
+ ModuleUtils::iterImportedGlobals(wasm, add);
+ ModuleUtils::iterDefinedGlobals(wasm, add);
}
if (index == Index(-1)) return Name("null"); // just a force-rebuild
if (mappedGlobals.count(index) == 0) {
@@ -1482,17 +1470,6 @@ void WasmBinaryBuilder::processFunctions() {
wasm.addFunction(func);
}
- for (auto* import : functionImports) {
- wasm.addImport(import);
- }
-
- // we should have seen all the functions
- // we assume this later down in fact, when we read wasm.functions[index],
- // as index was validated vs functionTypes.size()
- if (wasm.functions.size() != functionTypes.size()) {
- throwError("did not see the right number of functions");
- }
-
// now that we have names for each function, apply things
if (startIndex != static_cast<Index>(-1)) {
@@ -1518,15 +1495,7 @@ void WasmBinaryBuilder::processFunctions() {
size_t index = iter.first;
auto& calls = iter.second;
for (auto* call : calls) {
- call->target = wasm.functions[index]->name;
- }
- }
-
- for (auto& iter : functionImportCalls) {
- size_t index = iter.first;
- auto& calls = iter.second;
- for (auto* call : calls) {
- call->target = functionImports[index]->name;
+ call->target = getFunctionIndexName(index);
}
}
@@ -1537,6 +1506,10 @@ void WasmBinaryBuilder::processFunctions() {
wasm.table.segments[i].data.push_back(getFunctionIndexName(j));
}
}
+
+ // Everything now has its proper name.
+
+ wasm.updateMaps();
}
void WasmBinaryBuilder::readDataSegments() {
@@ -1689,7 +1662,7 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
case BinaryConsts::Br:
case BinaryConsts::BrIf: visitBreak((curr = allocator.alloc<Break>())->cast<Break>(), code); break; // code distinguishes br from br_if
case BinaryConsts::TableSwitch: visitSwitch((curr = allocator.alloc<Switch>())->cast<Switch>()); break;
- case BinaryConsts::CallFunction: curr = visitCall(); break; // we don't know if it's a call or call_import yet
+ case BinaryConsts::CallFunction: visitCall((curr = allocator.alloc<Call>())->cast<Call>()); break;
case BinaryConsts::CallIndirect: visitCallIndirect((curr = allocator.alloc<CallIndirect>())->cast<CallIndirect>()); break;
case BinaryConsts::GetLocal: visitGetLocal((curr = allocator.alloc<GetLocal>())->cast<GetLocal>()); break;
case BinaryConsts::TeeLocal:
@@ -1928,35 +1901,26 @@ void WasmBinaryBuilder::visitSwitch(Switch* curr) {
curr->finalize();
}
-Expression* WasmBinaryBuilder::visitCall() {
+void WasmBinaryBuilder::visitCall(Call* curr) {
if (debug) std::cerr << "zz node: Call" << std::endl;
auto index = getU32LEB();
FunctionType* type;
- Expression* ret;
if (index < functionImports.size()) {
- // this is a call of an imported function
- auto* call = allocator.alloc<CallImport>();
auto* import = functionImports[index];
- type = wasm.getFunctionType(import->functionType);
- functionImportCalls[index].push_back(call);
- call->target = import->name; // name section may modify it
- fillCall(call, type);
- call->finalize();
- ret = call;
+ type = wasm.getFunctionType(import->type);
} else {
- // this is a call of a defined function
- auto* call = allocator.alloc<Call>();
auto adjustedIndex = index - functionImports.size();
- if (adjustedIndex >= functionTypes.size()) {
- throwError("bad call index");
- }
type = functionTypes[adjustedIndex];
- fillCall(call, type);
- functionCalls[adjustedIndex].push_back(call); // we don't know function names yet
- call->finalize();
- ret = call;
}
- return ret;
+ assert(type);
+ auto num = type->params.size();
+ curr->operands.resize(num);
+ for (size_t i = 0; i < num; i++) {
+ curr->operands[num - i - 1] = popNonVoidExpression();
+ }
+ curr->type = type->result;
+ functionCalls[index].push_back(curr); // we don't know function names yet
+ curr->finalize();
}
void WasmBinaryBuilder::visitCallIndirect(CallIndirect* curr) {
@@ -2007,17 +1971,7 @@ void WasmBinaryBuilder::visitGetGlobal(GetGlobal* curr) {
if (debug) std::cerr << "zz node: GetGlobal " << pos << std::endl;
auto index = getU32LEB();
curr->name = getGlobalName(index);
- auto* global = wasm.getGlobalOrNull(curr->name);
- if (global) {
- curr->type = global->type;
- return;
- }
- auto* import = wasm.getImportOrNull(curr->name);
- if (import && import->kind == ExternalKind::Global) {
- curr->type = import->globalType;
- return;
- }
- throwError("bad get_global");
+ curr->type = wasm.getGlobal(curr->name)->type;
}
void WasmBinaryBuilder::visitSetGlobal(SetGlobal* curr) {