summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm2wasm.h129
-rw-r--r--src/passes/Print.cpp2
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp57
-rw-r--r--src/tools/asm2wasm.cpp15
-rw-r--r--src/wasm-emscripten.cpp4
-rw-r--r--src/wasm-emscripten.h2
6 files changed, 143 insertions, 66 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 5e751327b..8688edb87 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -742,6 +742,64 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
Ref body = asmFunction[3];
assert(body[0][0] == STRING && (body[0][1]->getIString() == IString("use asm") || body[0][1]->getIString() == IString("almost asm")));
+ // extra functions that we add, that are not from the compiled code. we need
+ // to make sure to optimize them normally (OptimizingIncrementalModuleBuilder
+ // does that on the fly for compiled code)
+ std::vector<Function*> extraSupportFunctions;
+
+ // first, add the memory elements. we do this before the main compile+optimize
+ // since the optimizer should see the memory
+
+ // apply memory growth, if relevant
+ if (preprocessor.memoryGrowth) {
+ EmscriptenGlueGenerator generator(wasm);
+ auto* func = generator.generateMemoryGrowthFunction();
+ extraSupportFunctions.push_back(func);
+ wasm.memory.max = Memory::kMaxSize;
+ }
+
+ // import memory
+ auto memoryImport = make_unique<Import>();
+ memoryImport->name = MEMORY;
+ memoryImport->module = ENV;
+ memoryImport->base = MEMORY;
+ memoryImport->kind = ExternalKind::Memory;
+ wasm.memory.exists = true;
+ wasm.memory.imported = true;
+ wasm.addImport(memoryImport.release());
+
+ // import table
+ auto tableImport = make_unique<Import>();
+ tableImport->name = TABLE;
+ tableImport->module = ENV;
+ tableImport->base = TABLE;
+ tableImport->kind = ExternalKind::Table;
+ wasm.addImport(tableImport.release());
+ wasm.table.exists = true;
+ wasm.table.imported = true;
+
+ // Import memory offset, if not already there
+ {
+ auto* import = new Import;
+ import->name = Name("memoryBase");
+ import->module = Name("env");
+ import->base = Name("memoryBase");
+ import->kind = ExternalKind::Global;
+ import->globalType = i32;
+ wasm.addImport(import);
+ }
+
+ // Import table offset, if not already there
+ {
+ auto* import = new Import;
+ import->name = Name("tableBase");
+ import->module = Name("env");
+ import->base = Name("tableBase");
+ import->kind = ExternalKind::Global;
+ import->globalType = i32;
+ wasm.addImport(import);
+ }
+
auto addImport = [&](IString name, Ref imported, WasmType type) {
assert(imported[0] == DOT);
Ref module = imported[1];
@@ -846,7 +904,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
}
}
}
- auto import = new Import();
+ auto import = make_unique<Import>();
import->name = name;
import->module = moduleName;
import->base = imported[2]->getIString();
@@ -877,7 +935,12 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
} else {
import->kind = ExternalKind::Function;
}
- wasm.addImport(import);
+ // we may have already created an import for this manually
+ if ((name == "tableBase" || name == "memoryBase") &&
+ (wasm.getImportOrNull(import->base) || wasm.getGlobalOrNull(import->base))) {
+ return;
+ }
+ wasm.addImport(import.release());
};
IString Int8Array, Int16Array, Int32Array, UInt8Array, UInt16Array, UInt32Array, Float32Array, Float64Array;
@@ -915,6 +978,9 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
auto* func = pair.second;
passRunner.runFunction(func);
}
+ for (auto* func : extraSupportFunctions) {
+ passRunner.runFunction(func);
+ }
}, debug, false /* do not validate globally yet */);
}
@@ -1352,65 +1418,6 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
wasm.removeImport(EMSCRIPTEN_DEBUGINFO);
}
- // apply memory growth, if relevant
- if (preprocessor.memoryGrowth) {
- EmscriptenGlueGenerator generator(wasm);
- generator.generateMemoryGrowthFunction();
- wasm.memory.max = Memory::kMaxSize;
- }
-
-#if 0
- // export memory
- auto memoryExport = make_unique<Export>();
- memoryExport->name = MEMORY;
- memoryExport->value = Name::fromInt(0);
- memoryExport->kind = ExternalKind::Memory;
- wasm.addExport(memoryExport.release());
-#else
- // import memory
- auto memoryImport = make_unique<Import>();
- memoryImport->name = MEMORY;
- memoryImport->module = ENV;
- memoryImport->base = MEMORY;
- memoryImport->kind = ExternalKind::Memory;
- wasm.memory.exists = true;
- wasm.memory.imported = true;
- wasm.addImport(memoryImport.release());
-
- // import table
- auto tableImport = make_unique<Import>();
- tableImport->name = TABLE;
- tableImport->module = ENV;
- tableImport->base = TABLE;
- tableImport->kind = ExternalKind::Table;
- wasm.addImport(tableImport.release());
- wasm.table.exists = true;
- wasm.table.imported = true;
-
- // Import memory offset, if not already there
- if (!wasm.getImportOrNull("memoryBase") && !wasm.getGlobalOrNull("memoryBase")) {
- auto* import = new Import;
- import->name = Name("memoryBase");
- import->module = Name("env");
- import->base = Name("memoryBase");
- import->kind = ExternalKind::Global;
- import->globalType = i32;
- wasm.addImport(import);
- }
-
- // Import table offset, if not already there
- if (!wasm.getImportOrNull("tableBase") && !wasm.getGlobalOrNull("tableBase")) {
- auto* import = new Import;
- import->name = Name("tableBase");
- import->module = Name("env");
- import->base = Name("tableBase");
- import->kind = ExternalKind::Global;
- import->globalType = i32;
- wasm.addImport(import);
- }
-
-#endif
-
if (udivmoddi4.is() && getTempRet0.is()) {
// generate a wasm-optimized __udivmoddi4 method, which we can do much more efficiently in wasm
// we can only do this if we know getTempRet0 as well since we use it to figure out which minified global is tempRet0
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index cfdfc09dd..7651414e0 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -735,6 +735,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
o << " anyfunc)";
}
void visitTable(Table *curr) {
+ if (!curr->exists) return;
// if table wasn't imported, declare it
if (!curr->imported) {
doIndent(o, indent);
@@ -764,6 +765,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
o << ")";
}
void visitMemory(Memory* curr) {
+ if (!curr->exists) return;
// if memory wasn't imported, declare it
if (!curr->imported) {
doIndent(o, indent);
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index 8bf2f9c9a..13caaccc9 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -43,6 +43,8 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
Module* module;
std::vector<ModuleElement> queue;
std::set<ModuleElement> reachable;
+ bool usesMemory = false;
+ bool usesTable = false;
ReachabilityAnalyzer(Module* module, const std::vector<ModuleElement>& roots) : module(module) {
queue = roots;
@@ -86,6 +88,9 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
queue.emplace_back(ModuleElementKind::Function, curr->target);
}
}
+ void visitCallIndirect(CallIndirect* curr) {
+ usesTable = true;
+ }
void visitGetGlobal(GetGlobal* curr) {
if (reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) == 0) {
@@ -97,6 +102,30 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
queue.emplace_back(ModuleElementKind::Global, curr->name);
}
}
+
+ void visitLoad(Load* curr) {
+ usesMemory = true;
+ }
+ void visitStore(Store* curr) {
+ usesMemory = true;
+ }
+ void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+ usesMemory = true;
+ }
+ void visitAtomicRMW(AtomicRMW* curr) {
+ usesMemory = true;
+ }
+ void visitAtomicWait(AtomicWait* curr) {
+ usesMemory = true;
+ }
+ void visitAtomicWake(AtomicWake* curr) {
+ usesMemory = true;
+ }
+ void visitHost(Host* curr) {
+ if (curr->op == CurrentMemory || curr->op == GrowMemory) {
+ usesMemory = true;
+ }
+ }
};
// Finds function type usage
@@ -136,11 +165,17 @@ struct RemoveUnusedModuleElements : public Pass {
roots.emplace_back(ModuleElementKind::Function, module->start);
}
// Exports are roots.
+ bool exportsMemory = false;
+ bool exportsTable = false;
for (auto& curr : module->exports) {
if (curr->kind == ExternalKind::Function) {
roots.emplace_back(ModuleElementKind::Function, curr->value);
} else if (curr->kind == ExternalKind::Global) {
roots.emplace_back(ModuleElementKind::Global, curr->value);
+ } else if (curr->kind == ExternalKind::Memory) {
+ exportsMemory = true;
+ } else if (curr->kind == ExternalKind::Table) {
+ exportsTable = true;
}
}
// For now, all functions that can be called indirectly are marked as roots.
@@ -176,6 +211,28 @@ struct RemoveUnusedModuleElements : public Pass {
}), v.end());
}
module->updateMaps();
+ // Handle the memory and table
+ if (!exportsMemory && !analyzer.usesMemory && module->memory.segments.empty()) {
+ module->memory.exists = false;
+ module->memory.imported = false;
+ module->memory.initial = 0;
+ module->memory.max = 0;
+ removeImport(ExternalKind::Memory, module);
+ }
+ if (!exportsTable && !analyzer.usesTable && module->table.segments.empty()) {
+ module->table.exists = false;
+ module->table.imported = false;
+ module->table.initial = 0;
+ module->table.max = 0;
+ removeImport(ExternalKind::Table, module);
+ }
+ }
+
+ void removeImport(ExternalKind kind, Module* module) {
+ auto& v = module->imports;
+ v.erase(std::remove_if(v.begin(), v.end(), [&](const std::unique_ptr<Import>& curr) {
+ return curr->kind == kind;
+ }), v.end());
}
void optimizeFunctionTypes(Module* module) {
diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp
index 3f70e0388..75a2c4d15 100644
--- a/src/tools/asm2wasm.cpp
+++ b/src/tools/asm2wasm.cpp
@@ -159,11 +159,12 @@ int main(int argc, const char *argv[]) {
if (options.debug) std::cerr << "wasming..." << std::endl;
Module wasm;
+
+ // set up memory
wasm.memory.initial = wasm.memory.max = totalMemory / Memory::kPageSize;
- Asm2WasmBuilder asm2wasm(wasm, pre, options.debug, trapMode, options.passOptions, legalizeJavaScriptFFI, options.runningDefaultOptimizationPasses(), wasmOnly);
- asm2wasm.processAsm(asmjs);
- // import mem init file, if provided
+ // import mem init file, if provided (do this before compiling the module,
+ // since the optimizer should see the memory segments)
const auto &memInit = options.extra.find("mem init");
if (memInit != options.extra.end()) {
auto filename = memInit->second.c_str();
@@ -177,6 +178,14 @@ int main(int argc, const char *argv[]) {
init = Builder(wasm).makeConst(Literal(int32_t(atoi(memBase->second.c_str()))));
}
wasm.memory.segments.emplace_back(init, data);
+ }
+
+ // compile the code
+ Asm2WasmBuilder asm2wasm(wasm, pre, options.debug, trapMode, options.passOptions, legalizeJavaScriptFFI, options.runningDefaultOptimizationPasses(), wasmOnly);
+ asm2wasm.processAsm(asmjs);
+
+ // finalize the imported mem init
+ if (memInit != options.extra.end()) {
if (options.runningDefaultOptimizationPasses()) {
PassRunner runner(&wasm);
runner.setFeatures(options.features);
diff --git a/src/wasm-emscripten.cpp b/src/wasm-emscripten.cpp
index 6961fc75f..a07254061 100644
--- a/src/wasm-emscripten.cpp
+++ b/src/wasm-emscripten.cpp
@@ -122,7 +122,7 @@ void EmscriptenGlueGenerator::generateRuntimeFunctions() {
generateStackRestoreFunction();
}
-void EmscriptenGlueGenerator::generateMemoryGrowthFunction() {
+Function* EmscriptenGlueGenerator::generateMemoryGrowthFunction() {
Name name(GROW_WASM_MEMORY);
std::vector<NameType> params { { NEW_SIZE, i32 } };
Function* growFunction = builder.makeFunction(
@@ -135,6 +135,8 @@ void EmscriptenGlueGenerator::generateMemoryGrowthFunction() {
);
addExportedFunction(wasm, growFunction);
+
+ return growFunction;
}
static bool hasI64ResultOrParam(FunctionType* ft) {
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
index 90a7d9a86..0a0f88574 100644
--- a/src/wasm-emscripten.h
+++ b/src/wasm-emscripten.h
@@ -32,7 +32,7 @@ public:
stackPointerOffset(stackPointerOffset) { }
void generateRuntimeFunctions();
- void generateMemoryGrowthFunction();
+ Function* generateMemoryGrowthFunction();
// Create thunks for use with emscripten Runtime.dynCall. Creates one for each
// signature in the indirect function table.