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.cpp139
1 files changed, 89 insertions, 50 deletions
diff --git a/src/wasm-emscripten.cpp b/src/wasm-emscripten.cpp
index a07254061..60bf5cce3 100644
--- a/src/wasm-emscripten.cpp
+++ b/src/wasm-emscripten.cpp
@@ -40,28 +40,39 @@ void addExportedFunction(Module& wasm, Function* function) {
wasm.addExport(export_);
}
-Load* EmscriptenGlueGenerator::generateLoadStackPointer() {
- Load* load = builder.makeLoad(
- /* bytes =*/ 4,
- /* signed =*/ false,
- /* offset =*/ stackPointerOffset,
- /* align =*/ 4,
- /* ptr =*/ builder.makeConst(Literal(0)),
- /* type =*/ i32
- );
- return load;
+Global* EmscriptenGlueGenerator::getStackPointerGlobal() {
+ // Assumption: first global is __stack_pointer
+ return wasm.globals[0].get();
}
-Store* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) {
- Store* store = builder.makeStore(
- /* bytes =*/ 4,
- /* offset =*/ stackPointerOffset,
- /* align =*/ 4,
- /* ptr =*/ builder.makeConst(Literal(0)),
- /* value =*/ value,
- /* type =*/ i32
- );
- return store;
+Expression* EmscriptenGlueGenerator::generateLoadStackPointer() {
+ if (!useStackPointerGlobal) {
+ return builder.makeLoad(
+ /* bytes =*/ 4,
+ /* signed =*/ false,
+ /* offset =*/ stackPointerOffset,
+ /* align =*/ 4,
+ /* ptr =*/ builder.makeConst(Literal(0)),
+ /* type =*/ i32
+ );
+ }
+ Global* stackPointer = getStackPointerGlobal();
+ return builder.makeGetGlobal(stackPointer->name, i32);
+}
+
+Expression* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) {
+ if (!useStackPointerGlobal) {
+ return builder.makeStore(
+ /* bytes =*/ 4,
+ /* offset =*/ stackPointerOffset,
+ /* align =*/ 4,
+ /* ptr =*/ builder.makeConst(Literal(0)),
+ /* value =*/ value,
+ /* type =*/ i32
+ );
+ }
+ Global* stackPointer = getStackPointerGlobal();
+ return builder.makeSetGlobal(stackPointer->name, value);
}
void EmscriptenGlueGenerator::generateStackSaveFunction() {
@@ -82,7 +93,7 @@ void EmscriptenGlueGenerator::generateStackAllocFunction() {
Function* function = builder.makeFunction(
name, std::move(params), i32, { { "1", i32 } }
);
- Load* loadStack = generateLoadStackPointer();
+ Expression* loadStack = generateLoadStackPointer();
GetLocal* getSizeArg = builder.makeGetLocal(0, i32);
Binary* sub = builder.makeBinary(SubInt32, loadStack, getSizeArg);
const static uint32_t bitAlignment = 16;
@@ -90,7 +101,7 @@ void EmscriptenGlueGenerator::generateStackAllocFunction() {
Const* subConst = builder.makeConst(Literal(~bitMask));
Binary* maskedSub = builder.makeBinary(AndInt32, sub, subConst);
SetLocal* teeStackLocal = builder.makeTeeLocal(1, maskedSub);
- Store* storeStack = generateStoreStackPointer(teeStackLocal);
+ Expression* storeStack = generateStoreStackPointer(teeStackLocal);
Block* block = builder.makeBlock();
block->list.push_back(storeStack);
@@ -109,7 +120,7 @@ void EmscriptenGlueGenerator::generateStackRestoreFunction() {
name, std::move(params), none, {}
);
GetLocal* getArg = builder.makeGetLocal(0, i32);
- Store* store = generateStoreStackPointer(getArg);
+ Expression* store = generateStoreStackPointer(getArg);
function->body = store;
@@ -147,21 +158,7 @@ static bool hasI64ResultOrParam(FunctionType* ft) {
return false;
}
-void removeImportsWithSubstring(Module& module, Name name) {
- std::vector<Name> toRemove;
- for (auto& import : module.imports) {
- if (import->name.hasSubstring(name)) {
- toRemove.push_back(import->name);
- }
- }
- for (auto importName : toRemove) {
- module.removeImport(importName);
- }
-}
-
void EmscriptenGlueGenerator::generateDynCallThunks() {
- removeImportsWithSubstring(wasm, EMSCRIPTEN_ASM_CONST); // we create _sig versions
-
std::unordered_set<std::string> sigs;
Builder builder(wasm);
std::vector<Name> tableSegmentData;
@@ -172,7 +169,12 @@ void EmscriptenGlueGenerator::generateDynCallThunks() {
if (indirectFunc == dummyFunction) {
continue;
}
- std::string sig(getSig(wasm.getFunction(indirectFunc)));
+ std::string sig;
+ if (auto import = wasm.getImportOrNull(indirectFunc)) {
+ sig = getSig(wasm.getFunctionType(import->functionType));
+ } else {
+ sig = getSig(wasm.getFunction(indirectFunc));
+ }
auto* funcType = ensureFunctionType(sig, &wasm);
if (hasI64ResultOrParam(funcType)) continue; // Can't export i64s on the web.
if (!sigs.insert(sig).second) continue; // Sig is already in the set
@@ -196,7 +198,7 @@ void EmscriptenGlueGenerator::generateDynCallThunks() {
struct AsmConstWalker : public PostWalker<AsmConstWalker> {
Module& wasm;
- std::unordered_map<Address, Address> segmentsByAddress; // address => segment index
+ std::vector<Address> segmentOffsets; // segment index => address offset
std::map<std::string, std::set<std::string>> sigsForCode;
std::map<std::string, Address> ids;
@@ -206,7 +208,7 @@ struct AsmConstWalker : public PostWalker<AsmConstWalker> {
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);
+ segmentOffsets.push_back(address);
}
}
@@ -214,6 +216,7 @@ struct AsmConstWalker : public PostWalker<AsmConstWalker> {
private:
std::string codeForConstAddr(Const* addrConst);
+ const char* stringAtAddr(Address adddress);
Literal idLiteralForCode(std::string code);
std::string asmConstSig(std::string baseSig);
Name nameForImportWithSig(std::string sig);
@@ -222,7 +225,8 @@ private:
};
void AsmConstWalker::visitCallImport(CallImport* curr) {
- if (curr->target.hasSubstring(EMSCRIPTEN_ASM_CONST)) {
+ Import* import = wasm.getImport(curr->target);
+ if (import->base.hasSubstring(EMSCRIPTEN_ASM_CONST)) {
auto arg = curr->operands[0]->cast<Const>();
auto code = codeForConstAddr(arg);
arg->value = idLiteralForCode(code);
@@ -241,13 +245,25 @@ void AsmConstWalker::visitCallImport(CallImport* curr) {
std::string AsmConstWalker::codeForConstAddr(Const* addrConst) {
auto address = addrConst->value.geti32();
- auto segmentIterator = segmentsByAddress.find(address);
- if (segmentIterator == segmentsByAddress.end()) {
- // If we can't find the segment corresponding with the address, then we omitted the segment and the address points to an empty string.
+ const char* str = stringAtAddr(address);
+ if (!str) {
+ // If we can't find the segment corresponding with the address, then we
+ // omitted the segment and the address points to an empty string.
return escape("");
}
- Address segmentIndex = segmentsByAddress[address];
- return escape(&wasm.memory.segments[segmentIndex].data[0]);
+ auto result = escape(str);
+ return result;
+}
+
+const char* AsmConstWalker::stringAtAddr(Address address) {
+ for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) {
+ Memory::Segment &segment = wasm.memory.segments[i];
+ Address offset = segmentOffsets[i];
+ if (address >= offset && address < offset + segment.data.size()) {
+ return &segment.data[address - offset];
+ }
+ }
+ return nullptr;
}
std::string AsmConstWalker::escape(const char *input) {
@@ -308,6 +324,31 @@ void AsmConstWalker::addImport(Name importName, std::string baseSig) {
wasm.addImport(import);
}
+AsmConstWalker fixEmAsmConstsAndReturnWalker(Module& wasm) {
+ // Collect imports to remove
+ // This would find our generated functions if we ran it later
+ std::vector<Name> toRemove;
+ for (auto& import : wasm.imports) {
+ if (import->base.hasSubstring(EMSCRIPTEN_ASM_CONST)) {
+ toRemove.push_back(import->name);
+ }
+ }
+
+ // Walk the module, generate _sig versions of EM_ASM functions
+ AsmConstWalker walker(wasm);
+ walker.walkModule(&wasm);
+
+ // Remove the base functions that we didn't generate
+ for (auto importName : toRemove) {
+ wasm.removeImport(importName);
+ }
+ return walker;
+}
+
+void EmscriptenGlueGenerator::fixEmAsmConsts() {
+ fixEmAsmConstsAndReturnWalker(wasm);
+}
+
template<class C>
void printSet(std::ostream& o, C& c) {
o << "[";
@@ -324,11 +365,9 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
Address staticBump,
std::vector<Name> const& initializerFunctions) {
std::stringstream meta;
- meta << ";; METADATA: { ";
+ meta << "{ ";
- // find asmConst calls, and emit their metadata
- AsmConstWalker walker(wasm);
- walker.walkModule(&wasm);
+ AsmConstWalker walker = fixEmAsmConstsAndReturnWalker(wasm);
// print
meta << "\"asmConsts\": {";