summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm2wasm.h15
-rw-r--r--src/passes/CoalesceLocals.cpp14
-rw-r--r--src/wasm-interpreter.h41
3 files changed, 46 insertions, 24 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 2c78df2c0..4231fcc9a 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -660,6 +660,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
// exports
Ref object = curr[1];
Ref contents = object[1];
+ std::map<Name, Export*> exported;
for (unsigned k = 0; k < contents->size(); k++) {
Ref pair = contents[k];
IString key = pair[0]->getIString();
@@ -675,10 +676,16 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
getTempRet0 = value;
}
assert(wasm.checkFunction(value));
- auto export_ = new Export;
- export_->name = key;
- export_->value = value;
- wasm.addExport(export_);
+ if (exported.count(key) > 0) {
+ // asm.js allows duplicate exports, but not wasm. use the last, like asm.js
+ exported[key]->value = value;
+ } else {
+ auto* export_ = new Export;
+ export_->name = key;
+ export_->value = value;
+ wasm.addExport(export_);
+ exported[key] = export_;
+ }
}
}
}
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp
index 39c480107..c36371ec0 100644
--- a/src/passes/CoalesceLocals.cpp
+++ b/src/passes/CoalesceLocals.cpp
@@ -183,7 +183,7 @@ struct CoalesceLocals : public WalkerPass<CFGWalker<CoalesceLocals, Visitor<Coal
void calculateInterferences();
- void calculateInterferences(LocalSet& locals);
+ void calculateInterferences(const LocalSet& locals);
// merge starts of a list of blocks, adding new interferences as necessary. return
// whether anything changed vs an old state (which indicates further processing is necessary).
@@ -282,8 +282,6 @@ void CoalesceLocals::flowLiveness() {
queue.insert(in);
}
}
- // live locals at the entry block include params, obviously, but also
- // vars, in which case the 0-init value is actually used.
#ifdef CFG_DEBUG
std::hash<std::vector<bool>> hasher;
std::cout << getFunction()->name << ": interference hash: " << hasher(*(std::vector<bool>*)&interferences) << "\n";
@@ -347,9 +345,17 @@ void CoalesceLocals::calculateInterferences() {
}
}
}
+ // Params have a value on entry, so mark them as live, as variables
+ // live at the entry expect their zero-init value.
+ LocalSet start = entry->contents.start;
+ auto numParams = getFunction()->getNumParams();
+ for (Index i = 0; i < numParams; i++) {
+ start.insert(i);
+ }
+ calculateInterferences(start);
}
-void CoalesceLocals::calculateInterferences(LocalSet& locals) {
+void CoalesceLocals::calculateInterferences(const LocalSet& locals) {
size_t size = locals.size();
for (size_t i = 0; i < size; i++) {
for (size_t j = i + 1; j < size; j++) {
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index b8f6554ec..0ee2aff78 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -46,7 +46,7 @@ enum {
maxCallDepth = 250
};
-// Stuff that flows around during executing expressions: a literal, or a change in control flow
+// Stuff that flows around during executing expressions: a literal, or a change in control flow.
class Flow {
public:
Flow() {}
@@ -125,23 +125,28 @@ public:
}
private:
+ // Keep a record of call depth, to guard against excessive recursion.
+ size_t callDepth;
- size_t callDepth = 0;
+ // Function name stack. We maintain this explicitly to allow printing of
+ // stack traces.
+ std::vector<Name> functionStack;
#ifdef WASM_INTERPRETER_DEBUG
int indent = 0;
#endif
- // Function stack. We maintain this explicitly to allow printing of
- // stack traces.
- std::vector<Name> functionStack;
-
- //
- // Calls a function. This can be used both internally (calls from
- // the interpreter to another method), or when you want to call into
- // the module.
- //
+ // Call a function, starting an invocation.
Literal callFunction(IString name, LiteralList& arguments) {
+ // if the last call ended in a jump up the stack, it might have left stuff for us to clean up here
+ callDepth = 0;
+ functionStack.clear();
+ return callFunctionInternal(name, arguments);
+ }
+
+private:
+ // Internal function call.
+ Literal callFunctionInternal(IString name, LiteralList& arguments) {
class FunctionScope {
public:
@@ -329,7 +334,7 @@ private:
LiteralList arguments;
Flow flow = generateArguments(curr->operands, arguments);
if (flow.breaking()) return flow;
- Flow ret = instance.callFunction(curr->target, arguments);
+ Flow ret = instance.callFunctionInternal(curr->target, arguments);
#ifdef WASM_INTERPRETER_DEBUG
std::cout << "(returned to " << scope.function->name << ")\n";
#endif
@@ -354,7 +359,7 @@ private:
LiteralList arguments;
Flow flow = generateArguments(curr->operands, arguments);
if (flow.breaking()) return flow;
- return instance.callFunction(name, arguments);
+ return instance.callFunctionInternal(name, arguments);
}
Flow visitGetLocal(GetLocal *curr) {
@@ -698,7 +703,9 @@ private:
};
if (callDepth > maxCallDepth) externalInterface->trap("stack limit");
+ auto previousCallDepth = callDepth;
callDepth++;
+ auto previousFunctionStackSize = functionStack.size();
functionStack.push_back(name);
Function *function = wasm.getFunction(name);
@@ -714,9 +721,11 @@ private:
Literal ret = flow.value;
if (function->result == none) ret = Literal();
assert(function->result == ret.type);
- callDepth--;
- assert(functionStack.back() == name);
- functionStack.pop_back();
+ callDepth = previousCallDepth; // may decrease more than one, if we jumped up the stack
+ // if we jumped up the stack, we also need to pop higher frames
+ while (functionStack.size() > previousFunctionStackSize) {
+ functionStack.pop_back();
+ }
#ifdef WASM_INTERPRETER_DEBUG
std::cout << "exiting " << function->name << " with " << ret << '\n';
#endif