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"
2628
2729namespace wasm {
2830
29- namespace emscripten {
30-
3131cashew::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
3535void 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
162142static 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
211197struct 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