Skip to content

Commit 70434ef

Browse files
authored
Generate dynCall function for all signature used by invoke functions. (#2095)
Previously we were only creating `dynCall` functions for signatures that we have statically in the table. However for dynamic linking we may need to invoke functions that we don't have table entries for (e.g. table entries from a different module).
1 parent 4b35f38 commit 70434ef

File tree

3 files changed

+46
-29
lines changed

3 files changed

+46
-29
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ full changeset diff at the end of each section.
1515
Current Trunk
1616
-------------
1717

18+
v84
19+
---
20+
21+
- Generate dynCall thunks for any signatures used in "invoke" calls.
22+
1823
v81
1924
---
2025

src/wasm-emscripten.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,14 @@ class EmscriptenGlueGenerator {
6262
Builder builder;
6363
Address stackPointerOffset;
6464
bool useStackPointerGlobal;
65+
// Used by generateDynCallThunk to track all the dynCall functions created
66+
// so far.
67+
std::unordered_set<std::string> sigs;
6568

6669
Global* getStackPointerGlobal();
6770
Expression* generateLoadStackPointer();
6871
Expression* generateStoreStackPointer(Expression* value);
72+
void generateDynCallThunk(std::string sig);
6973
void generateStackSaveFunction();
7074
void generateStackAllocFunction();
7175
void generateStackRestoreFunction();

src/wasm/wasm-emscripten.cpp

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -334,41 +334,44 @@ inline void exportFunction(Module& wasm, Name name, bool must_export) {
334334
wasm.addExport(exp);
335335
}
336336

337+
void EmscriptenGlueGenerator::generateDynCallThunk(std::string sig) {
338+
auto* funcType = ensureFunctionType(sig, &wasm);
339+
if (!sigs.insert(sig).second) {
340+
return; // sig is already in the set
341+
}
342+
Name name = std::string("dynCall_") + sig;
343+
if (wasm.getFunctionOrNull(name) || wasm.getExportOrNull(name)) {
344+
return; // module already contains this dyncall
345+
}
346+
std::vector<NameType> params;
347+
params.emplace_back("fptr", i32); // function pointer param
348+
int p = 0;
349+
for (const auto& ty : funcType->params) {
350+
params.emplace_back(std::to_string(p++), ty);
351+
}
352+
Function* f =
353+
builder.makeFunction(name, std::move(params), funcType->result, {});
354+
Expression* fptr = builder.makeGetLocal(0, i32);
355+
std::vector<Expression*> args;
356+
for (unsigned i = 0; i < funcType->params.size(); ++i) {
357+
args.push_back(builder.makeGetLocal(i + 1, funcType->params[i]));
358+
}
359+
Expression* call = builder.makeCallIndirect(funcType, fptr, args);
360+
f->body = call;
361+
362+
wasm.addFunction(f);
363+
exportFunction(wasm, f->name, true);
364+
}
365+
337366
void EmscriptenGlueGenerator::generateDynCallThunks() {
338-
std::unordered_set<std::string> sigs;
339367
Builder builder(wasm);
340368
std::vector<Name> tableSegmentData;
341369
if (wasm.table.segments.size() > 0) {
342370
tableSegmentData = wasm.table.segments[0].data;
343371
}
344372
for (const auto& indirectFunc : tableSegmentData) {
345373
std::string sig = getSig(wasm.getFunction(indirectFunc));
346-
auto* funcType = ensureFunctionType(sig, &wasm);
347-
if (!sigs.insert(sig).second) {
348-
continue; // sig is already in the set
349-
}
350-
Name name = std::string("dynCall_") + sig;
351-
if (wasm.getFunctionOrNull(name) || wasm.getExportOrNull(name)) {
352-
continue; // module already contains this dyncall
353-
}
354-
std::vector<NameType> params;
355-
params.emplace_back("fptr", i32); // function pointer param
356-
int p = 0;
357-
for (const auto& ty : funcType->params) {
358-
params.emplace_back(std::to_string(p++), ty);
359-
}
360-
Function* f =
361-
builder.makeFunction(name, std::move(params), funcType->result, {});
362-
Expression* fptr = builder.makeGetLocal(0, i32);
363-
std::vector<Expression*> args;
364-
for (unsigned i = 0; i < funcType->params.size(); ++i) {
365-
args.push_back(builder.makeGetLocal(i + 1, funcType->params[i]));
366-
}
367-
Expression* call = builder.makeCallIndirect(funcType, fptr, args);
368-
f->body = call;
369-
370-
wasm.addFunction(f);
371-
exportFunction(wasm, f->name, true);
374+
generateDynCallThunk(sig);
372375
}
373376
}
374377

@@ -769,6 +772,7 @@ struct FixInvokeFunctionNamesWalker
769772
std::map<Name, Name> importRenames;
770773
std::vector<Name> toRemove;
771774
std::set<Name> newImports;
775+
std::set<std::string> invokeSigs;
772776

773777
FixInvokeFunctionNamesWalker(Module& _wasm) : wasm(_wasm) {}
774778

@@ -791,7 +795,7 @@ struct FixInvokeFunctionNamesWalker
791795
// This function converts the names of invoke wrappers based on their lowered
792796
// argument types and a return type. In the example above, the resulting new
793797
// wrapper name becomes "invoke_vii".
794-
static Name fixEmExceptionInvoke(const Name& name, const std::string& sig) {
798+
Name fixEmExceptionInvoke(const Name& name, const std::string& sig) {
795799
std::string nameStr = name.c_str();
796800
if (nameStr.front() == '"' && nameStr.back() == '"') {
797801
nameStr = nameStr.substr(1, nameStr.size() - 2);
@@ -800,10 +804,11 @@ struct FixInvokeFunctionNamesWalker
800804
return name;
801805
}
802806
std::string sigWoOrigFunc = sig.front() + sig.substr(2, sig.size() - 2);
807+
invokeSigs.insert(sigWoOrigFunc);
803808
return Name("invoke_" + sigWoOrigFunc);
804809
}
805810

806-
static Name fixEmEHSjLjNames(const Name& name, const std::string& sig) {
811+
Name fixEmEHSjLjNames(const Name& name, const std::string& sig) {
807812
if (name == "emscripten_longjmp_jmpbuf") {
808813
return "emscripten_longjmp";
809814
}
@@ -843,6 +848,9 @@ struct FixInvokeFunctionNamesWalker
843848
void EmscriptenGlueGenerator::fixInvokeFunctionNames() {
844849
FixInvokeFunctionNamesWalker walker(wasm);
845850
walker.walkModule(&wasm);
851+
for (auto sig : walker.invokeSigs) {
852+
generateDynCallThunk(sig);
853+
}
846854
}
847855

848856
template<class C> void printSet(std::ostream& o, C& c) {

0 commit comments

Comments
 (0)