diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm.h | 15 | ||||
-rw-r--r-- | src/passes/CoalesceLocals.cpp | 14 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 41 |
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 |