Skip to content

Commit 2fde47b

Browse files
committed
wasm-emscripten-finalize: Add flags to limit dynCall creations
Two flags here, one to completely remove dynCalls, and another to limit them to only signatures that contains i64. See #3043
1 parent 18d6780 commit 2fde47b

8 files changed

+96
-15
lines changed

src/passes/GenerateDynCalls.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,25 @@
3434
namespace wasm {
3535

3636
struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> {
37+
GenerateDynCalls(bool onlyI64) : onlyI64(onlyI64) {}
38+
3739

3840
void visitTable(Table* table) {
3941
if (table->segments.size() > 0) {
4042
EmscriptenGlueGenerator generator(*getModule());
43+
generator.onlyI64DynCalls = onlyI64;
4144
std::vector<Name> tableSegmentData;
4245
for (const auto& indirectFunc : table->segments[0].data) {
4346
generator.generateDynCallThunk(
4447
getModule()->getFunction(indirectFunc)->sig);
4548
}
4649
}
4750
}
51+
52+
bool onlyI64;
4853
};
4954

50-
Pass* createGenerateDynCallsPass() { return new GenerateDynCalls; }
55+
Pass* createGenerateDynCallsPass() { return new GenerateDynCalls(false); }
56+
Pass* createGenerateI64DynCallsPass() { return new GenerateDynCalls(true); }
5157

5258
} // namespace wasm

src/passes/pass.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ void PassRegistry::registerPasses() {
146146
registerPass("generate-dyncalls",
147147
"generate dynCall fuctions used by emscripten ABI",
148148
createGenerateDynCallsPass);
149+
registerPass("generate-i64-dyncalls",
150+
"generate dynCall fuctions used by emscripten ABI, but only for "
151+
"functions with i64 in thier signature (which cannot be invoked "
152+
"via the wasm table without JavaScritp BigInt support).",
153+
createGenerateI64DynCallsPass);
149154
registerPass(
150155
"generate-stack-ir", "generate Stack IR", createGenerateStackIRPass);
151156
registerPass(

src/passes/passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Pass* createFuncCastEmulationPass();
4949
Pass* createFullPrinterPass();
5050
Pass* createFunctionMetricsPass();
5151
Pass* createGenerateDynCallsPass();
52+
Pass* createGenerateI64DynCallsPass();
5253
Pass* createGenerateStackIRPass();
5354
Pass* createI64ToI32LoweringPass();
5455
Pass* createInlineMainPass();

src/tools/wasm-emscripten-finalize.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ int main(int argc, const char* argv[]) {
5858
bool standaloneWasm = false;
5959
// TODO: remove after https://github.com/WebAssembly/binaryen/issues/3043
6060
bool minimizeWasmChanges = false;
61+
bool noDynCalls = false;
62+
bool onlyI64DynCalls = false;
6163

6264
ToolOptions options("wasm-emscripten-finalize",
6365
"Performs Emscripten-specific transforms on .wasm files");
@@ -174,6 +176,20 @@ int main(int argc, const char* argv[]) {
174176
[&minimizeWasmChanges](Options* o, const std::string&) {
175177
minimizeWasmChanges = true;
176178
})
179+
.add("--no-dyncalls",
180+
"",
181+
"",
182+
Options::Arguments::Zero,
183+
[&noDynCalls](Options* o, const std::string&) {
184+
noDynCalls = true;
185+
})
186+
.add("--dyncalls-i64",
187+
"",
188+
"",
189+
Options::Arguments::Zero,
190+
[&onlyI64DynCalls](Options* o, const std::string&) {
191+
onlyI64DynCalls = true;
192+
})
177193
.add_positional("INFILE",
178194
Options::Arguments::One,
179195
[&infile](Options* o, const std::string& argument) {
@@ -231,9 +247,11 @@ int main(int argc, const char* argv[]) {
231247
}
232248

233249
EmscriptenGlueGenerator generator(wasm);
234-
generator.setStandalone(standaloneWasm);
235-
generator.setSideModule(sideModule);
236-
generator.setMinimizeWasmChanges(minimizeWasmChanges);
250+
generator.standalone = standaloneWasm;
251+
generator.sideModule = sideModule;
252+
generator.minimizeWasmChanges = minimizeWasmChanges;
253+
generator.onlyI64DynCalls = onlyI64DynCalls;
254+
generator.noDynCalls = noDynCalls;
237255

238256
generator.fixInvokeFunctionNames();
239257

@@ -278,9 +296,13 @@ int main(int argc, const char* argv[]) {
278296
passRunner.add("emscripten-pic-main-module");
279297
}
280298

281-
if (!standaloneWasm) {
299+
if (!noDynCalls && !standaloneWasm) {
282300
// If not standalone wasm then JS is relevant and we need dynCalls.
283-
passRunner.add("generate-dyncalls");
301+
if (onlyI64DynCalls) {
302+
passRunner.add("generate-dyncalls-i64");
303+
} else {
304+
passRunner.add("generate-dyncalls");
305+
}
284306
}
285307

286308
// Legalize the wasm, if BigInts don't make that moot.

src/wasm-emscripten.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ class EmscriptenGlueGenerator {
3333
: wasm(wasm), builder(wasm), stackPointerOffset(stackPointerOffset),
3434
useStackPointerGlobal(stackPointerOffset == 0) {}
3535

36-
void setStandalone(bool standalone_) { standalone = standalone_; }
37-
void setSideModule(bool sideModule_) { sideModule = sideModule_; }
38-
void setMinimizeWasmChanges(bool minimizeWasmChanges_) {
39-
minimizeWasmChanges = minimizeWasmChanges_;
40-
}
41-
4236
Function* generateMemoryGrowthFunction();
4337
Function* generateAssignGOTEntriesFunction();
4438
void generatePostInstantiateFunction();
@@ -67,14 +61,17 @@ class EmscriptenGlueGenerator {
6761

6862
void generateDynCallThunk(Signature sig);
6963

64+
bool standalone = false;
65+
bool sideModule = false;
66+
bool minimizeWasmChanges = false;
67+
bool noDynCalls = false;
68+
bool onlyI64DynCalls = false;
69+
7070
private:
7171
Module& wasm;
7272
Builder builder;
7373
Address stackPointerOffset;
7474
bool useStackPointerGlobal;
75-
bool standalone;
76-
bool sideModule;
77-
bool minimizeWasmChanges;
7875
// Used by generateDynCallThunk to track all the dynCall functions created
7976
// so far.
8077
std::unordered_set<Signature> sigs;

src/wasm/wasm-emscripten.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,27 @@ inline void exportFunction(Module& wasm, Name name, bool must_export) {
143143
wasm.addExport(exp);
144144
}
145145

146+
static bool needsDynCall(Signature sig) {
147+
// We only generate dynCall functions for signatures that contain
148+
// i64. This is because any other function can be called directly
149+
// from JavaScript using the wasm table.
150+
for (auto t: sig.results) {
151+
if (t.getID() == Type::i64) {
152+
return true;
153+
}
154+
}
155+
for (auto t: sig.params) {
156+
if (t.getID() == Type::i64) {
157+
return true;
158+
}
159+
}
160+
return false;
161+
}
162+
146163
void EmscriptenGlueGenerator::generateDynCallThunk(Signature sig) {
164+
if (noDynCalls || (onlyI64DynCalls && !needsDynCall(sig))) {
165+
return;
166+
}
147167
if (!sigs.insert(sig).second) {
148168
return; // sig is already in the set
149169
}

test/passes/generate-i64-dyncalls.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
(module
2+
(type $i32_=>_i64 (func (param i32) (result i64)))
3+
(type $none_=>_i32 (func (result i32)))
4+
(type $i32_i32_=>_i64 (func (param i32 i32) (result i64)))
5+
(table $0 2 2 funcref)
6+
(elem (i32.const 0) $f1 $f2)
7+
(export "dynCall_ji" (func $dynCall_ji))
8+
(func $f1 (result i32)
9+
(i32.const 1024)
10+
)
11+
(func $f2 (param $0 i32) (result i64)
12+
(i64.const 42)
13+
)
14+
(func $dynCall_ji (param $fptr i32) (param $0 i32) (result i64)
15+
(call_indirect (type $i32_=>_i64)
16+
(local.get $0)
17+
(local.get $fptr)
18+
)
19+
)
20+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
(module
2+
(func $f1 (result i32)
3+
(i32.const 1024)
4+
)
5+
(func $f2 (param i32) (result i64)
6+
(i64.const 42)
7+
)
8+
(table 2 2 funcref)
9+
(elem (i32.const 0) $f1 $f2)
10+
)

0 commit comments

Comments
 (0)