summaryrefslogtreecommitdiff
path: root/src/wasm-emscripten.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-emscripten.cpp')
-rw-r--r--src/wasm-emscripten.cpp170
1 files changed, 90 insertions, 80 deletions
diff --git a/src/wasm-emscripten.cpp b/src/wasm-emscripten.cpp
index 9c617a31e..14f93cff3 100644
--- a/src/wasm-emscripten.cpp
+++ b/src/wasm-emscripten.cpp
@@ -16,6 +16,8 @@
#include "wasm-emscripten.h"
+#include <sstream>
+
#include "asm_v_wasm.h"
#include "asmjs/shared-constants.h"
#include "shared-constants.h"
@@ -26,11 +28,9 @@
namespace wasm {
-namespace emscripten {
-
cashew::IString EMSCRIPTEN_ASM_CONST("emscripten_asm_const");
-static constexpr const char* stackPointer = "__stack_pointer";
+static constexpr const char* dummyFunction = "__wasm_nullptr";
void addExportedFunction(Module& wasm, Function* function) {
wasm.addFunction(function);
@@ -40,82 +40,49 @@ void addExportedFunction(Module& wasm, Function* function) {
wasm.addExport(export_);
}
-void generateMemoryGrowthFunction(Module& wasm) {
- Builder builder(wasm);
- Name name(GROW_WASM_MEMORY);
- std::vector<NameType> params { { NEW_SIZE, i32 } };
- Function* growFunction = builder.makeFunction(
- name, std::move(params), i32, {}
- );
- growFunction->body = builder.makeHost(
- GrowMemory,
- Name(),
- { builder.makeGetLocal(0, i32) }
- );
-
- addExportedFunction(wasm, growFunction);
-}
-
-void addStackPointerRelocation(LinkerObject& linker, uint32_t* data) {
- linker.addRelocation(new LinkerObject::Relocation(
- LinkerObject::Relocation::kData,
- data,
- Name(stackPointer),
- 0
- ));
-}
-
-Load* generateLoadStackPointer(Builder& builder, LinkerObject& linker) {
+Load* EmscriptenGlueGenerator::generateLoadStackPointer() {
Load* load = builder.makeLoad(
/* bytes =*/ 4,
/* signed =*/ false,
- /* offset =*/ 0,
+ /* offset =*/ stackPointerOffset,
/* align =*/ 4,
/* ptr =*/ builder.makeConst(Literal(0)),
/* type =*/ i32
);
- addStackPointerRelocation(linker, &load->offset.addr);
return load;
}
-Store* generateStoreStackPointer(Builder& builder,
- LinkerObject& linker,
- Expression* value) {
+Store* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) {
Store* store = builder.makeStore(
/* bytes =*/ 4,
- /* offset =*/ 0,
+ /* offset =*/ stackPointerOffset,
/* align =*/ 4,
/* ptr =*/ builder.makeConst(Literal(0)),
/* value =*/ value,
/* type =*/ i32
);
- addStackPointerRelocation(linker, &store->offset.addr);
return store;
}
-void generateStackSaveFunction(LinkerObject& linker) {
- Module& wasm = linker.wasm;
- Builder builder(wasm);
+void EmscriptenGlueGenerator::generateStackSaveFunction() {
Name name("stackSave");
std::vector<NameType> params { };
Function* function = builder.makeFunction(
name, std::move(params), i32, {}
);
- function->body = generateLoadStackPointer(builder, linker);
+ function->body = generateLoadStackPointer();
addExportedFunction(wasm, function);
}
-void generateStackAllocFunction(LinkerObject& linker) {
- Module& wasm = linker.wasm;
- Builder builder(wasm);
+void EmscriptenGlueGenerator::generateStackAllocFunction() {
Name name("stackAlloc");
std::vector<NameType> params { { "0", i32 } };
Function* function = builder.makeFunction(
name, std::move(params), i32, { { "1", i32 } }
);
- Load* loadStack = generateLoadStackPointer(builder, linker);
+ Load* loadStack = generateLoadStackPointer();
SetLocal* setStackLocal = builder.makeSetLocal(1, loadStack);
GetLocal* getStackLocal = builder.makeGetLocal(1, i32);
GetLocal* getSizeArg = builder.makeGetLocal(0, i32);
@@ -124,7 +91,7 @@ void generateStackAllocFunction(LinkerObject& linker) {
const static uint32_t bitMask = bitAlignment - 1;
Const* subConst = builder.makeConst(Literal(~bitMask));
Binary* maskedSub = builder.makeBinary(AndInt32, sub, subConst);
- Store* storeStack = generateStoreStackPointer(builder, linker, maskedSub);
+ Store* storeStack = generateStoreStackPointer(maskedSub);
Block* block = builder.makeBlock();
block->list.push_back(setStackLocal);
@@ -137,26 +104,39 @@ void generateStackAllocFunction(LinkerObject& linker) {
addExportedFunction(wasm, function);
}
-void generateStackRestoreFunction(LinkerObject& linker) {
- Module& wasm = linker.wasm;
- Builder builder(wasm);
+void EmscriptenGlueGenerator::generateStackRestoreFunction() {
Name name("stackRestore");
std::vector<NameType> params { { "0", i32 } };
Function* function = builder.makeFunction(
name, std::move(params), none, {}
);
GetLocal* getArg = builder.makeGetLocal(0, i32);
- Store* store = generateStoreStackPointer(builder, linker, getArg);
+ Store* store = generateStoreStackPointer(getArg);
function->body = store;
addExportedFunction(wasm, function);
}
-void generateRuntimeFunctions(LinkerObject& linker) {
- generateStackSaveFunction(linker);
- generateStackAllocFunction(linker);
- generateStackRestoreFunction(linker);
+void EmscriptenGlueGenerator::generateRuntimeFunctions() {
+ generateStackSaveFunction();
+ generateStackAllocFunction();
+ generateStackRestoreFunction();
+}
+
+void EmscriptenGlueGenerator::generateMemoryGrowthFunction() {
+ Name name(GROW_WASM_MEMORY);
+ std::vector<NameType> params { { NEW_SIZE, i32 } };
+ Function* growFunction = builder.makeFunction(
+ name, std::move(params), i32, {}
+ );
+ growFunction->body = builder.makeHost(
+ GrowMemory,
+ Name(),
+ { builder.makeGetLocal(0, i32) }
+ );
+
+ addExportedFunction(wasm, growFunction);
}
static bool hasI64ResultOrParam(FunctionType* ft) {
@@ -179,13 +159,19 @@ void removeImportsWithSubstring(Module& module, Name name) {
}
}
-std::vector<Function*> makeDynCallThunks(Module& wasm, std::vector<Name> const& tableSegmentData) {
+void EmscriptenGlueGenerator::generateDynCallThunks() {
removeImportsWithSubstring(wasm, EMSCRIPTEN_ASM_CONST); // we create _sig versions
- std::vector<Function*> generatedFunctions;
std::unordered_set<std::string> sigs;
Builder builder(wasm);
+ std::vector<Name> tableSegmentData;
+ if (wasm.table.segments.size() > 0) {
+ tableSegmentData = wasm.table.segments[0].data;
+ }
for (const auto& indirectFunc : tableSegmentData) {
+ if (indirectFunc == dummyFunction) {
+ continue;
+ }
std::string sig(getSig(wasm.getFunction(indirectFunc)));
auto* funcType = ensureFunctionType(sig, &wasm);
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&
}
Expression* call = builder.makeCallIndirect(funcType, fptr, args);
f->body = call;
+
wasm.addFunction(f);
- generatedFunctions.push_back(f);
+ exportFunction(wasm, f->name, true);
}
- return generatedFunctions;
}
struct AsmConstWalker : public PostWalker<AsmConstWalker> {
@@ -216,8 +202,13 @@ struct AsmConstWalker : public PostWalker<AsmConstWalker> {
std::map<std::string, Address> ids;
std::set<std::string> allSigs;
- AsmConstWalker(Module& _wasm, std::unordered_map<Address, Address> _segmentsByAddress) :
- wasm(_wasm), segmentsByAddress(_segmentsByAddress) { }
+ AsmConstWalker(Module& _wasm) : wasm(_wasm) {
+ for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) {
+ Const* addrConst = wasm.memory.segments[i].offset->cast<Const>();
+ auto address = addrConst->value.geti32();
+ segmentsByAddress[address] = Address(i);
+ }
+ }
void visitCallImport(CallImport* curr);
@@ -329,43 +320,62 @@ void printSet(std::ostream& o, C& c) {
o << "]";
}
-void generateEmscriptenMetadata(std::ostream& o,
- Module& wasm,
- std::unordered_map<Address, Address> segmentsByAddress,
- Address staticBump,
- std::vector<Name> const& initializerFunctions) {
- o << ";; METADATA: { ";
+std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
+ Address staticBump,
+ std::vector<Name> const& initializerFunctions) {
+ std::stringstream meta;
+ meta << ";; METADATA: { ";
+
// find asmConst calls, and emit their metadata
- AsmConstWalker walker(wasm, segmentsByAddress);
+ AsmConstWalker walker(wasm);
walker.walkModule(&wasm);
+
// print
- o << "\"asmConsts\": {";
+ meta << "\"asmConsts\": {";
bool first = true;
for (auto& pair : walker.sigsForCode) {
auto& code = pair.first;
auto& sigs = pair.second;
if (first) first = false;
- else o << ",";
- o << '"' << walker.ids[code] << "\": [\"" << code << "\", ";
- printSet(o, sigs);
- o << "]";
+ else meta << ",";
+ meta << '"' << walker.ids[code] << "\": [\"" << code << "\", ";
+ printSet(meta, sigs);
+ meta << "]";
}
- o << "}";
- o << ",";
- o << "\"staticBump\": " << staticBump << ", ";
+ meta << "}";
+ meta << ",";
+ meta << "\"staticBump\": " << staticBump << ", ";
- o << "\"initializers\": [";
+ meta << "\"initializers\": [";
first = true;
for (const auto& func : initializerFunctions) {
if (first) first = false;
- else o << ", ";
- o << "\"" << func.c_str() << "\"";
+ else meta << ", ";
+ meta << "\"" << func.c_str() << "\"";
}
- o << "]";
+ meta << "]";
+
+ meta << " }\n";
- o << " }\n";
+ return meta.str();
}
-} // namespace emscripten
+std::string emscriptenGlue(
+ Module& wasm,
+ bool allowMemoryGrowth,
+ Address stackPointer,
+ Address staticBump,
+ std::vector<Name> const& initializerFunctions) {
+ EmscriptenGlueGenerator generator(wasm, stackPointer);
+ generator.generateRuntimeFunctions();
+
+ if (allowMemoryGrowth) {
+ generator.generateMemoryGrowthFunction();
+ }
+
+ generator.generateDynCallThunks();
+
+ return generator.generateEmscriptenMetadata(staticBump, initializerFunctions);
+}
} // namespace wasm