Skip to content

wasm-emscripten-finalize: Make EM_ASM modifications optional #3044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/tools/wasm-emscripten-finalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ int main(int argc, const char* argv[]) {
bool checkStackOverflow = false;
uint64_t globalBase = INVALID_BASE;
bool standaloneWasm = false;
bool minimizeWasmChanges = false;

ToolOptions options("wasm-emscripten-finalize",
"Performs Emscripten-specific transforms on .wasm files");
Expand Down Expand Up @@ -162,6 +163,15 @@ int main(int argc, const char* argv[]) {
[&standaloneWasm](Options* o, const std::string&) {
standaloneWasm = true;
})
.add("--minimize-wasm-changes",
"",
"Modify the wasm as little as possible. This is useful during "
"development as we reduce the number of changes to the wasm, as it "
"lets emscripten control how much modifications to do.",
Options::Arguments::Zero,
[&minimizeWasmChanges](Options* o, const std::string&) {
minimizeWasmChanges = true;
})
.add_positional("INFILE",
Options::Arguments::One,
[&infile](Options* o, const std::string& argument) {
Expand Down Expand Up @@ -224,6 +234,7 @@ int main(int argc, const char* argv[]) {
EmscriptenGlueGenerator generator(wasm);
generator.setStandalone(standaloneWasm);
generator.setSideModule(sideModule);
generator.setMinimizeWasmChanges(minimizeWasmChanges);

generator.fixInvokeFunctionNames();

Expand Down
4 changes: 4 additions & 0 deletions src/wasm-emscripten.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class EmscriptenGlueGenerator {

void setStandalone(bool standalone_) { standalone = standalone_; }
void setSideModule(bool sideModule_) { sideModule = sideModule_; }
void setMinimizeWasmChanges(bool minimizeWasmChanges_) {
minimizeWasmChanges = minimizeWasmChanges_;
}

Function* generateMemoryGrowthFunction();
Function* generateAssignGOTEntriesFunction();
Expand Down Expand Up @@ -71,6 +74,7 @@ class EmscriptenGlueGenerator {
bool useStackPointerGlobal;
bool standalone;
bool sideModule;
bool minimizeWasmChanges;
// Used by generateDynCallThunk to track all the dynCall functions created
// so far.
std::unordered_set<Signature> sigs;
Expand Down
40 changes: 27 additions & 13 deletions src/wasm/wasm-emscripten.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ std::string proxyingSuffix(Proxying proxy) {

struct AsmConstWalker : public LinearExecutionWalker<AsmConstWalker> {
Module& wasm;
bool minimizeWasmChanges;
std::vector<Address> segmentOffsets; // segment index => address offset

struct AsmConst {
Expand All @@ -334,8 +335,9 @@ struct AsmConstWalker : public LinearExecutionWalker<AsmConstWalker> {
// last sets in the current basic block, per index
std::map<Index, LocalSet*> sets;

AsmConstWalker(Module& _wasm)
: wasm(_wasm), segmentOffsets(getSegmentOffsets(wasm)) {}
AsmConstWalker(Module& _wasm, bool minimizeWasmChanges)
: wasm(_wasm), minimizeWasmChanges(minimizeWasmChanges),
segmentOffsets(getSegmentOffsets(wasm)) {}

void noteNonLinear(Expression* curr);

Expand Down Expand Up @@ -426,7 +428,9 @@ void AsmConstWalker::visitCall(Call* curr) {
int32_t address = value->value.geti32();
auto code = codeForConstAddr(wasm, segmentOffsets, address);
auto& asmConst = createAsmConst(address, code, sig, importName);
fixupName(curr->target, baseSig, asmConst.proxy);
if (!minimizeWasmChanges) {
fixupName(curr->target, baseSig, asmConst.proxy);
}
}

Proxying AsmConstWalker::proxyType(Name name) {
Expand All @@ -439,6 +443,9 @@ Proxying AsmConstWalker::proxyType(Name name) {
}

void AsmConstWalker::visitTable(Table* curr) {
if (minimizeWasmChanges) {
return;
}
for (auto& segment : curr->segments) {
for (auto& name : segment.data) {
auto* func = wasm.getFunction(name);
Expand Down Expand Up @@ -515,24 +522,30 @@ void AsmConstWalker::addImports() {
}
}

AsmConstWalker fixEmAsmConstsAndReturnWalker(Module& wasm) {
static AsmConstWalker fixEmAsmConstsAndReturnWalker(Module& wasm,
bool minimizeWasmChanges) {
// Collect imports to remove
// This would find our generated functions if we ran it later
std::vector<Name> toRemove;
for (auto& import : wasm.functions) {
if (import->imported() && import->base.hasSubstring(EM_ASM_PREFIX)) {
toRemove.push_back(import->name);
if (!minimizeWasmChanges) {
for (auto& import : wasm.functions) {
if (import->imported() && import->base.hasSubstring(EM_ASM_PREFIX)) {
toRemove.push_back(import->name);
}
}
}

// Walk the module, generate _sig versions of EM_ASM functions
AsmConstWalker walker(wasm);
AsmConstWalker walker(wasm, minimizeWasmChanges);
walker.process();

// Remove the base functions that we didn't generate
for (auto importName : toRemove) {
wasm.removeFunction(importName);
if (!minimizeWasmChanges) {
// Remove the base functions that we didn't generate
for (auto importName : toRemove) {
wasm.removeFunction(importName);
}
}

return walker;
}

Expand Down Expand Up @@ -754,7 +767,8 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
std::stringstream meta;
meta << "{\n";

AsmConstWalker emAsmWalker = fixEmAsmConstsAndReturnWalker(wasm);
AsmConstWalker emAsmWalker =
fixEmAsmConstsAndReturnWalker(wasm, minimizeWasmChanges);

// print
commaFirst = true;
Expand Down Expand Up @@ -810,7 +824,7 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
commaFirst = true;
ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
if (emJsWalker.codeByName.count(import->base.str) == 0 &&
!import->base.startsWith(EM_ASM_PREFIX.str) &&
(minimizeWasmChanges || !import->base.startsWith(EM_ASM_PREFIX.str)) &&
!import->base.startsWith("invoke_")) {
if (declares.insert(import->base.str).second) {
meta << nextElement() << '"' << import->base.str << '"';
Expand Down