summaryrefslogtreecommitdiff
path: root/src/wasm2js.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm2js.h')
-rw-r--r--src/wasm2js.h88
1 files changed, 63 insertions, 25 deletions
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 7bc356bea..84c65b189 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -126,7 +126,7 @@ public:
bool emscripten = false;
};
- Wasm2JSBuilder(Flags f) : flags(f) {}
+ Wasm2JSBuilder(Flags f, PassOptions options) : flags(f), options(options) {}
Ref processWasm(Module* wasm, Name funcName = ASM_FUNC);
Ref processFunction(Module* wasm, Function* func, bool standalone=false);
@@ -136,7 +136,7 @@ public:
// The second pass on an expression: process it fully, generating
// JS
- Ref processFunctionBody(Module* m, Function* func);
+ Ref processFunctionBody(Module* m, Function* func, bool standalone);
// Get a temp var.
IString getTemp(Type type, Function* func) {
@@ -225,6 +225,7 @@ public:
private:
Flags flags;
+ PassOptions options;
// How many temp vars we need
std::vector<size_t> temps; // type => num temps
@@ -238,6 +239,11 @@ private:
size_t tableSize;
+ // If a function is callable from outside, we'll need to cast the inputs
+ // and our return value. Otherwise, internally, casts are only needed
+ // on operations.
+ std::unordered_set<Name> functionsCallableFromOutside;
+
void addBasics(Ref ast);
void addFunctionImport(Ref ast, Function* import);
void addGlobalImport(Ref ast, Global* import);
@@ -252,6 +258,18 @@ private:
};
Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
+ // Scan the wasm for important things.
+ for (auto& exp : wasm->exports) {
+ if (exp->kind == ExternalKind::Function) {
+ functionsCallableFromOutside.insert(exp->value);
+ }
+ }
+ for (auto& segment : wasm->table.segments) {
+ for (auto name : segment.data) {
+ functionsCallableFromOutside.insert(name);
+ }
+ }
+
// Ensure the scratch memory helpers.
// If later on they aren't needed, we'll clean them up.
ABI::wasm2js::ensureScratchMemoryHelpers(wasm);
@@ -645,26 +663,29 @@ Ref Wasm2JSBuilder::processFunction(Module* m, Function* func, bool standaloneFu
temps.resize(std::max(i32, std::max(f32, f64)) + 1);
temps[i32] = temps[f32] = temps[f64] = 0;
// arguments
+ bool needCoercions = options.optimizeLevel == 0 || standaloneFunction || functionsCallableFromOutside.count(func->name);
for (Index i = 0; i < func->getNumParams(); i++) {
IString name = fromName(func->getLocalNameOrGeneric(i), NameScope::Local);
ValueBuilder::appendArgumentToFunction(ret, name);
- ret[3]->push_back(
- ValueBuilder::makeStatement(
- ValueBuilder::makeBinary(
- ValueBuilder::makeName(name), SET,
- makeAsmCoercion(
- ValueBuilder::makeName(name),
- wasmToAsmType(func->getLocalType(i))
+ if (needCoercions) {
+ ret[3]->push_back(
+ ValueBuilder::makeStatement(
+ ValueBuilder::makeBinary(
+ ValueBuilder::makeName(name), SET,
+ makeAsmCoercion(
+ ValueBuilder::makeName(name),
+ wasmToAsmType(func->getLocalType(i))
+ )
)
)
- )
- );
+ );
+ }
}
Ref theVar = ValueBuilder::makeVar();
size_t theVarIndex = ret[3]->size();
ret[3]->push_back(theVar);
// body
- flattenAppend(ret, processFunctionBody(m, func));
+ flattenAppend(ret, processFunctionBody(m, func, standaloneFunction));
// vars, including new temp vars
for (Index i = func->getVarIndexBase(); i < func->getNumLocals(); i++) {
ValueBuilder::appendToVar(
@@ -683,15 +704,17 @@ Ref Wasm2JSBuilder::processFunction(Module* m, Function* func, bool standaloneFu
return ret;
}
-Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func) {
+Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standaloneFunction) {
struct ExpressionProcessor : public Visitor<ExpressionProcessor, Ref> {
Wasm2JSBuilder* parent;
IString result; // TODO: remove
Function* func;
Module* module;
+ bool standaloneFunction;
MixedArena allocator;
- ExpressionProcessor(Wasm2JSBuilder* parent, Module* m, Function* func)
- : parent(parent), func(func), module(m) {}
+
+ ExpressionProcessor(Wasm2JSBuilder* parent, Module* m, Function* func, bool standaloneFunction)
+ : parent(parent), func(func), module(m), standaloneFunction(standaloneFunction) {}
// A scoped temporary variable.
struct ScopedTemp {
@@ -847,12 +870,19 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func) {
Ref visitCall(Call* curr) {
Ref theCall = ValueBuilder::makeCall(fromName(curr->target, NameScope::Top));
+ // For wasm => wasm calls, we don't need coercions. TODO: even imports might be safe?
+ bool needCoercions = parent->options.optimizeLevel == 0 || standaloneFunction || module->getFunction(curr->target)->imported();
for (auto operand : curr->operands) {
- theCall[2]->push_back(
- makeAsmCoercion(visit(operand, EXPRESSION_RESULT),
- wasmToAsmType(operand->type)));
+ auto value = visit(operand, EXPRESSION_RESULT);
+ if (needCoercions) {
+ value = makeAsmCoercion(value, wasmToAsmType(operand->type));
+ }
+ theCall[2]->push_back(value);
+ }
+ if (needCoercions) {
+ theCall = makeAsmCoercion(theCall, wasmToAsmType(curr->type));
}
- return makeAsmCoercion(theCall, wasmToAsmType(curr->type));
+ return theCall;
}
Ref visitCallIndirect(CallIndirect* curr) {
@@ -992,7 +1022,14 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func) {
abort();
}
}
- return makeAsmCoercion(ret, wasmToAsmType(curr->type));
+ // Coercions are not actually needed, as if the user reads beyond valid memory, it's
+ // undefined behavior anyhow, and so we don't care much about slowness of undefined
+ // values etc.
+ bool needCoercions = parent->options.optimizeLevel == 0 || standaloneFunction;
+ if (needCoercions) {
+ ret = makeAsmCoercion(ret, wasmToAsmType(curr->type));
+ }
+ return ret;
}
Ref visitStore(Store* curr) {
@@ -1521,10 +1558,11 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func) {
if (!curr->value) {
return ValueBuilder::makeReturn(Ref());
}
- Ref val = makeAsmCoercion(
- visit(curr->value, EXPRESSION_RESULT),
- wasmToAsmType(curr->value->type)
- );
+ Ref val = visit(curr->value, EXPRESSION_RESULT);
+ bool needCoercion = parent->options.optimizeLevel == 0 || standaloneFunction || parent->functionsCallableFromOutside.count(func->name);
+ if (needCoercion) {
+ val = makeAsmCoercion(val, wasmToAsmType(curr->value->type));
+ }
return ValueBuilder::makeReturn(val);
}
@@ -1564,7 +1602,7 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func) {
}
};
- return ExpressionProcessor(this, m, func).visit(func->body, NO_RESULT);
+ return ExpressionProcessor(this, m, func, standaloneFunction).visit(func->body, NO_RESULT);
}
void Wasm2JSBuilder::addMemoryGrowthFuncs(Ref ast, Module* wasm) {