Skip to content

Commit 27474b7

Browse files
Decouple wasm-linker from Emscripten glue (#1293)
1 parent dc0cd44 commit 27474b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+485
-454
lines changed

src/asm2wasm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,8 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
13311331

13321332
// apply memory growth, if relevant
13331333
if (preprocessor.memoryGrowth) {
1334-
emscripten::generateMemoryGrowthFunction(wasm);
1334+
EmscriptenGlueGenerator generator(wasm);
1335+
generator.generateMemoryGrowthFunction();
13351336
wasm.memory.max = Memory::kMaxSize;
13361337
}
13371338

src/tools/s2wasm.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,21 +175,21 @@ int main(int argc, const char *argv[]) {
175175
linker.linkArchive(lib);
176176
}
177177

178-
if (generateEmscriptenGlue) {
179-
emscripten::generateRuntimeFunctions(linker.getOutput());
180-
}
181-
182178
linker.layout();
183179

184-
std::stringstream meta;
180+
std::string metadata;
185181
if (generateEmscriptenGlue) {
186-
if (options.debug) std::cerr << "Emscripten gluing..." << std::endl;
187-
if (allowMemoryGrowth) {
188-
emscripten::generateMemoryGrowthFunction(linker.getOutput().wasm);
182+
Module& wasm = linker.getOutput().wasm;
183+
if (options.debug) {
184+
std::cerr << "Emscripten gluing..." << std::endl;
185+
WasmPrinter::printModule(&wasm, std::cerr);
189186
}
190-
191-
// dyncall thunks
192-
linker.emscriptenGlue(meta);
187+
metadata = emscriptenGlue(
188+
wasm,
189+
allowMemoryGrowth,
190+
linker.getStackPointerAddress(),
191+
linker.getStaticBump(),
192+
linker.getOutput().getInitializerFunctions());
193193
}
194194

195195
if (options.extra["validate"] != "none") {
@@ -205,7 +205,7 @@ int main(int argc, const char *argv[]) {
205205
if (options.debug) std::cerr << "Printing..." << std::endl;
206206
Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release);
207207
WasmPrinter::printModule(&linker.getOutput().wasm, output.getStream());
208-
output << meta.str();
208+
output << metadata;
209209

210210
if (options.debug) std::cerr << "Done." << std::endl;
211211
return 0;

src/wasm-emscripten.cpp

Lines changed: 90 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#include "wasm-emscripten.h"
1818

19+
#include <sstream>
20+
1921
#include "asm_v_wasm.h"
2022
#include "asmjs/shared-constants.h"
2123
#include "shared-constants.h"
@@ -26,11 +28,9 @@
2628

2729
namespace wasm {
2830

29-
namespace emscripten {
30-
3131
cashew::IString EMSCRIPTEN_ASM_CONST("emscripten_asm_const");
3232

33-
static constexpr const char* stackPointer = "__stack_pointer";
33+
static constexpr const char* dummyFunction = "__wasm_nullptr";
3434

3535
void addExportedFunction(Module& wasm, Function* function) {
3636
wasm.addFunction(function);
@@ -40,82 +40,49 @@ void addExportedFunction(Module& wasm, Function* function) {
4040
wasm.addExport(export_);
4141
}
4242

43-
void generateMemoryGrowthFunction(Module& wasm) {
44-
Builder builder(wasm);
45-
Name name(GROW_WASM_MEMORY);
46-
std::vector<NameType> params { { NEW_SIZE, i32 } };
47-
Function* growFunction = builder.makeFunction(
48-
name, std::move(params), i32, {}
49-
);
50-
growFunction->body = builder.makeHost(
51-
GrowMemory,
52-
Name(),
53-
{ builder.makeGetLocal(0, i32) }
54-
);
55-
56-
addExportedFunction(wasm, growFunction);
57-
}
58-
59-
void addStackPointerRelocation(LinkerObject& linker, uint32_t* data) {
60-
linker.addRelocation(new LinkerObject::Relocation(
61-
LinkerObject::Relocation::kData,
62-
data,
63-
Name(stackPointer),
64-
0
65-
));
66-
}
67-
68-
Load* generateLoadStackPointer(Builder& builder, LinkerObject& linker) {
43+
Load* EmscriptenGlueGenerator::generateLoadStackPointer() {
6944
Load* load = builder.makeLoad(
7045
/* bytes =*/ 4,
7146
/* signed =*/ false,
72-
/* offset =*/ 0,
47+
/* offset =*/ stackPointerOffset,
7348
/* align =*/ 4,
7449
/* ptr =*/ builder.makeConst(Literal(0)),
7550
/* type =*/ i32
7651
);
77-
addStackPointerRelocation(linker, &load->offset.addr);
7852
return load;
7953
}
8054

81-
Store* generateStoreStackPointer(Builder& builder,
82-
LinkerObject& linker,
83-
Expression* value) {
55+
Store* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) {
8456
Store* store = builder.makeStore(
8557
/* bytes =*/ 4,
86-
/* offset =*/ 0,
58+
/* offset =*/ stackPointerOffset,
8759
/* align =*/ 4,
8860
/* ptr =*/ builder.makeConst(Literal(0)),
8961
/* value =*/ value,
9062
/* type =*/ i32
9163
);
92-
addStackPointerRelocation(linker, &store->offset.addr);
9364
return store;
9465
}
9566

96-
void generateStackSaveFunction(LinkerObject& linker) {
97-
Module& wasm = linker.wasm;
98-
Builder builder(wasm);
67+
void EmscriptenGlueGenerator::generateStackSaveFunction() {
9968
Name name("stackSave");
10069
std::vector<NameType> params { };
10170
Function* function = builder.makeFunction(
10271
name, std::move(params), i32, {}
10372
);
10473

105-
function->body = generateLoadStackPointer(builder, linker);
74+
function->body = generateLoadStackPointer();
10675

10776
addExportedFunction(wasm, function);
10877
}
10978

110-
void generateStackAllocFunction(LinkerObject& linker) {
111-
Module& wasm = linker.wasm;
112-
Builder builder(wasm);
79+
void EmscriptenGlueGenerator::generateStackAllocFunction() {
11380
Name name("stackAlloc");
11481
std::vector<NameType> params { { "0", i32 } };
11582
Function* function = builder.makeFunction(
11683
name, std::move(params), i32, { { "1", i32 } }
11784
);
118-
Load* loadStack = generateLoadStackPointer(builder, linker);
85+
Load* loadStack = generateLoadStackPointer();
11986
SetLocal* setStackLocal = builder.makeSetLocal(1, loadStack);
12087
GetLocal* getStackLocal = builder.makeGetLocal(1, i32);
12188
GetLocal* getSizeArg = builder.makeGetLocal(0, i32);
@@ -124,7 +91,7 @@ void generateStackAllocFunction(LinkerObject& linker) {
12491
const static uint32_t bitMask = bitAlignment - 1;
12592
Const* subConst = builder.makeConst(Literal(~bitMask));
12693
Binary* maskedSub = builder.makeBinary(AndInt32, sub, subConst);
127-
Store* storeStack = generateStoreStackPointer(builder, linker, maskedSub);
94+
Store* storeStack = generateStoreStackPointer(maskedSub);
12895

12996
Block* block = builder.makeBlock();
13097
block->list.push_back(setStackLocal);
@@ -137,26 +104,39 @@ void generateStackAllocFunction(LinkerObject& linker) {
137104
addExportedFunction(wasm, function);
138105
}
139106

140-
void generateStackRestoreFunction(LinkerObject& linker) {
141-
Module& wasm = linker.wasm;
142-
Builder builder(wasm);
107+
void EmscriptenGlueGenerator::generateStackRestoreFunction() {
143108
Name name("stackRestore");
144109
std::vector<NameType> params { { "0", i32 } };
145110
Function* function = builder.makeFunction(
146111
name, std::move(params), none, {}
147112
);
148113
GetLocal* getArg = builder.makeGetLocal(0, i32);
149-
Store* store = generateStoreStackPointer(builder, linker, getArg);
114+
Store* store = generateStoreStackPointer(getArg);
150115

151116
function->body = store;
152117

153118
addExportedFunction(wasm, function);
154119
}
155120

156-
void generateRuntimeFunctions(LinkerObject& linker) {
157-
generateStackSaveFunction(linker);
158-
generateStackAllocFunction(linker);
159-
generateStackRestoreFunction(linker);
121+
void EmscriptenGlueGenerator::generateRuntimeFunctions() {
122+
generateStackSaveFunction();
123+
generateStackAllocFunction();
124+
generateStackRestoreFunction();
125+
}
126+
127+
void EmscriptenGlueGenerator::generateMemoryGrowthFunction() {
128+
Name name(GROW_WASM_MEMORY);
129+
std::vector<NameType> params { { NEW_SIZE, i32 } };
130+
Function* growFunction = builder.makeFunction(
131+
name, std::move(params), i32, {}
132+
);
133+
growFunction->body = builder.makeHost(
134+
GrowMemory,
135+
Name(),
136+
{ builder.makeGetLocal(0, i32) }
137+
);
138+
139+
addExportedFunction(wasm, growFunction);
160140
}
161141

162142
static bool hasI64ResultOrParam(FunctionType* ft) {
@@ -179,13 +159,19 @@ void removeImportsWithSubstring(Module& module, Name name) {
179159
}
180160
}
181161

182-
std::vector<Function*> makeDynCallThunks(Module& wasm, std::vector<Name> const& tableSegmentData) {
162+
void EmscriptenGlueGenerator::generateDynCallThunks() {
183163
removeImportsWithSubstring(wasm, EMSCRIPTEN_ASM_CONST); // we create _sig versions
184164

185-
std::vector<Function*> generatedFunctions;
186165
std::unordered_set<std::string> sigs;
187166
Builder builder(wasm);
167+
std::vector<Name> tableSegmentData;
168+
if (wasm.table.segments.size() > 0) {
169+
tableSegmentData = wasm.table.segments[0].data;
170+
}
188171
for (const auto& indirectFunc : tableSegmentData) {
172+
if (indirectFunc == dummyFunction) {
173+
continue;
174+
}
189175
std::string sig(getSig(wasm.getFunction(indirectFunc)));
190176
auto* funcType = ensureFunctionType(sig, &wasm);
191177
if (hasI64ResultOrParam(funcType)) continue; // Can't export i64s on the web.
@@ -202,10 +188,10 @@ std::vector<Function*> makeDynCallThunks(Module& wasm, std::vector<Name> const&
202188
}
203189
Expression* call = builder.makeCallIndirect(funcType, fptr, args);
204190
f->body = call;
191+
205192
wasm.addFunction(f);
206-
generatedFunctions.push_back(f);
193+
exportFunction(wasm, f->name, true);
207194
}
208-
return generatedFunctions;
209195
}
210196

211197
struct AsmConstWalker : public PostWalker<AsmConstWalker> {
@@ -216,8 +202,13 @@ struct AsmConstWalker : public PostWalker<AsmConstWalker> {
216202
std::map<std::string, Address> ids;
217203
std::set<std::string> allSigs;
218204

219-
AsmConstWalker(Module& _wasm, std::unordered_map<Address, Address> _segmentsByAddress) :
220-
wasm(_wasm), segmentsByAddress(_segmentsByAddress) { }
205+
AsmConstWalker(Module& _wasm) : wasm(_wasm) {
206+
for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) {
207+
Const* addrConst = wasm.memory.segments[i].offset->cast<Const>();
208+
auto address = addrConst->value.geti32();
209+
segmentsByAddress[address] = Address(i);
210+
}
211+
}
221212

222213
void visitCallImport(CallImport* curr);
223214

@@ -329,43 +320,62 @@ void printSet(std::ostream& o, C& c) {
329320
o << "]";
330321
}
331322

332-
void generateEmscriptenMetadata(std::ostream& o,
333-
Module& wasm,
334-
std::unordered_map<Address, Address> segmentsByAddress,
335-
Address staticBump,
336-
std::vector<Name> const& initializerFunctions) {
337-
o << ";; METADATA: { ";
323+
std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
324+
Address staticBump,
325+
std::vector<Name> const& initializerFunctions) {
326+
std::stringstream meta;
327+
meta << ";; METADATA: { ";
328+
338329
// find asmConst calls, and emit their metadata
339-
AsmConstWalker walker(wasm, segmentsByAddress);
330+
AsmConstWalker walker(wasm);
340331
walker.walkModule(&wasm);
332+
341333
// print
342-
o << "\"asmConsts\": {";
334+
meta << "\"asmConsts\": {";
343335
bool first = true;
344336
for (auto& pair : walker.sigsForCode) {
345337
auto& code = pair.first;
346338
auto& sigs = pair.second;
347339
if (first) first = false;
348-
else o << ",";
349-
o << '"' << walker.ids[code] << "\": [\"" << code << "\", ";
350-
printSet(o, sigs);
351-
o << "]";
340+
else meta << ",";
341+
meta << '"' << walker.ids[code] << "\": [\"" << code << "\", ";
342+
printSet(meta, sigs);
343+
meta << "]";
352344
}
353-
o << "}";
354-
o << ",";
355-
o << "\"staticBump\": " << staticBump << ", ";
345+
meta << "}";
346+
meta << ",";
347+
meta << "\"staticBump\": " << staticBump << ", ";
356348

357-
o << "\"initializers\": [";
349+
meta << "\"initializers\": [";
358350
first = true;
359351
for (const auto& func : initializerFunctions) {
360352
if (first) first = false;
361-
else o << ", ";
362-
o << "\"" << func.c_str() << "\"";
353+
else meta << ", ";
354+
meta << "\"" << func.c_str() << "\"";
363355
}
364-
o << "]";
356+
meta << "]";
357+
358+
meta << " }\n";
365359

366-
o << " }\n";
360+
return meta.str();
367361
}
368362

369-
} // namespace emscripten
363+
std::string emscriptenGlue(
364+
Module& wasm,
365+
bool allowMemoryGrowth,
366+
Address stackPointer,
367+
Address staticBump,
368+
std::vector<Name> const& initializerFunctions) {
369+
EmscriptenGlueGenerator generator(wasm, stackPointer);
370+
generator.generateRuntimeFunctions();
371+
372+
if (allowMemoryGrowth) {
373+
generator.generateMemoryGrowthFunction();
374+
}
375+
376+
generator.generateDynCallThunks();
377+
378+
return generator.generateEmscriptenMetadata(staticBump, initializerFunctions);
379+
}
370380

371381
} // namespace wasm

0 commit comments

Comments
 (0)