diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm.cpp | 147 | ||||
-rw-r--r-- | src/istring.h | 4 | ||||
-rw-r--r-- | src/wasm-interpreter.cpp | 95 | ||||
-rw-r--r-- | src/wasm.h | 151 |
4 files changed, 250 insertions, 147 deletions
diff --git a/src/asm2wasm.cpp b/src/asm2wasm.cpp index d6a521ca1..bdbef2d78 100644 --- a/src/asm2wasm.cpp +++ b/src/asm2wasm.cpp @@ -47,153 +47,6 @@ static void abort_on(std::string why, IString element) { abort(); } -// -// Simple WebAssembly optimizer, improves common patterns we get in asm2wasm. -// Operates in-place. -// - -struct WasmWalker { - wasm::Arena* allocator; // use an existing allocator, or null if no allocations - - WasmWalker() : allocator(nullptr) {} - WasmWalker(wasm::Arena* allocator) : allocator(allocator) {} - - // Each method receives an AST pointer, and it is replaced with what is returned. - virtual Expression* walkBlock(Block *curr) { return curr; }; - virtual Expression* walkIf(If *curr) { return curr; }; - virtual Expression* walkLoop(Loop *curr) { return curr; }; - virtual Expression* walkLabel(Label *curr) { return curr; }; - virtual Expression* walkBreak(Break *curr) { return curr; }; - virtual Expression* walkSwitch(Switch *curr) { return curr; }; - virtual Expression* walkCall(Call *curr) { return curr; }; - virtual Expression* walkCallImport(CallImport *curr) { return curr; }; - virtual Expression* walkCallIndirect(CallIndirect *curr) { return curr; }; - virtual Expression* walkGetLocal(GetLocal *curr) { return curr; }; - virtual Expression* walkSetLocal(SetLocal *curr) { return curr; }; - virtual Expression* walkLoad(Load *curr) { return curr; }; - virtual Expression* walkStore(Store *curr) { return curr; }; - virtual Expression* walkConst(Const *curr) { return curr; }; - virtual Expression* walkUnary(Unary *curr) { return curr; }; - virtual Expression* walkBinary(Binary *curr) { return curr; }; - virtual Expression* walkCompare(Compare *curr) { return curr; }; - virtual Expression* walkConvert(Convert *curr) { return curr; }; - virtual Expression* walkHost(Host *curr) { return curr; }; - virtual Expression* walkNop(Nop *curr) { return curr; }; - - // children-first - Expression *walk(Expression *curr) { - if (!curr) return curr; - - if (Block *cast = dynamic_cast<Block*>(curr)) { - ExpressionList& list = cast->list; - for (size_t z = 0; z < list.size(); z++) { - list[z] = walk(list[z]); - } - return walkBlock(cast); - } - if (If *cast = dynamic_cast<If*>(curr)) { - cast->condition = walk(cast->condition); - cast->ifTrue = walk(cast->ifTrue); - cast->ifFalse = walk(cast->ifFalse); - return walkIf(cast); - } - if (Loop *cast = dynamic_cast<Loop*>(curr)) { - cast->body = walk(cast->body); - return walkLoop(cast); - } - if (Label *cast = dynamic_cast<Label*>(curr)) { - return walkLabel(cast); - } - if (Break *cast = dynamic_cast<Break*>(curr)) { - cast->condition = walk(cast->condition); - cast->value = walk(cast->value); - return walkBreak(cast); - } - if (Switch *cast = dynamic_cast<Switch*>(curr)) { - cast->value = walk(cast->value); - for (auto& curr : cast->cases) { - curr.body = walk(curr.body); - } - cast->default_ = walk(cast->default_); - return walkSwitch(cast); - } - if (Call *cast = dynamic_cast<Call*>(curr)) { - ExpressionList& list = cast->operands; - for (size_t z = 0; z < list.size(); z++) { - list[z] = walk(list[z]); - } - return walkCall(cast); - } - if (CallImport *cast = dynamic_cast<CallImport*>(curr)) { - ExpressionList& list = cast->operands; - for (size_t z = 0; z < list.size(); z++) { - list[z] = walk(list[z]); - } - return walkCallImport(cast); - } - if (CallIndirect *cast = dynamic_cast<CallIndirect*>(curr)) { - cast->target = walk(cast->target); - ExpressionList& list = cast->operands; - for (size_t z = 0; z < list.size(); z++) { - list[z] = walk(list[z]); - } - return walkCallIndirect(cast); - } - if (GetLocal *cast = dynamic_cast<GetLocal*>(curr)) { - return walkGetLocal(cast); - } - if (SetLocal *cast = dynamic_cast<SetLocal*>(curr)) { - cast->value = walk(cast->value); - return walkSetLocal(cast); - } - if (Load *cast = dynamic_cast<Load*>(curr)) { - cast->ptr = walk(cast->ptr); - return walkLoad(cast); - } - if (Store *cast = dynamic_cast<Store*>(curr)) { - cast->ptr = walk(cast->ptr); - cast->value = walk(cast->value); - return walkStore(cast); - } - if (Const *cast = dynamic_cast<Const*>(curr)) { - return walkConst(cast); - } - if (Unary *cast = dynamic_cast<Unary*>(curr)) { - cast->value = walk(cast->value); - return walkUnary(cast); - } - if (Binary *cast = dynamic_cast<Binary*>(curr)) { - cast->left = walk(cast->left); - cast->right = walk(cast->right); - return walkBinary(cast); - } - if (Compare *cast = dynamic_cast<Compare*>(curr)) { - cast->left = walk(cast->left); - cast->right = walk(cast->right); - return walkCompare(cast); - } - if (Convert *cast = dynamic_cast<Convert*>(curr)) { - cast->value = walk(cast->value); - return walkConvert(cast); - } - if (Host *cast = dynamic_cast<Host*>(curr)) { - ExpressionList& list = cast->operands; - for (size_t z = 0; z < list.size(); z++) { - list[z] = walk(list[z]); - } - return walkHost(cast); - } - if (Nop *cast = dynamic_cast<Nop*>(curr)) { - return walkNop(cast); - } - abort(); - } - - void startWalk(Function *func) { - func->body = walk(func->body); - } -}; - // useful when we need to see our parent, in an asm.js expression stack struct AstStackHelper { static std::vector<Ref> astStack; diff --git a/src/istring.h b/src/istring.h index 3a66465d0..921e04487 100644 --- a/src/istring.h +++ b/src/istring.h @@ -68,6 +68,10 @@ struct IString { str = s.str; } + void clear() { + str = nullptr; + } + bool operator==(const IString& other) const { //assert((str == other.str) == !strcmp(str, other.str)); return str == other.str; // fast! diff --git a/src/wasm-interpreter.cpp b/src/wasm-interpreter.cpp new file mode 100644 index 000000000..8e1294624 --- /dev/null +++ b/src/wasm-interpreter.cpp @@ -0,0 +1,95 @@ + +// Simple WebAssembly interpreter, designed to be embeddable in JavaScript, so it +// can function as a polyfill. + +#include "wasm.h" + +namespace wasm { + +// An instance of a WebAssembly module +class ModuleInstance { +public: + ModuleInstance(Module& wasm) : wasm(wasm) { + for (auto function : wasm.functions) { + functions[function->name] = function; + } + } + + Literal callFunction(const char *name) { + return callFunction(IString(name)); + } + + Literal callFunction(IString name) { + // Stuff that flows around during executing expressions: a literal, or a change in control flow + class Flow : public Literal { + public: + IString breakTo; // if non-null, a break is going on + }; + + // Execute a statement + class ExpressionRunner : public WasmVisitor<Flow> { + virtual Flow visitBlock(Block *curr) { + Flow flow; + for (auto expression : curr->list) { + flow = visit(expression); + if (flow.breakTo) { + if (flow.breakTo == curr->name) { + flow.breakTo.clear(); + } + return flow; + } + } + return flow; + } + virtual Flow visitIf(If *curr) { + } + virtual Flow visitLoop(Loop *curr) { + } + virtual Flow visitLabel(Label *curr) { + } + virtual Flow visitBreak(Break *curr) { + } + virtual Flow visitSwitch(Switch *curr) { + } + virtual Flow visitCall(Call *curr) { + } + virtual Flow visitCallImport(CallImport *curr) { + } + virtual Flow visitCallIndirect(CallIndirect *curr) { + } + virtual Flow visitGetLocal(GetLocal *curr) { + } + virtual Flow visitSetLocal(SetLocal *curr) { + } + virtual Flow visitLoad(Load *curr) { + } + virtual Flow visitStore(Store *curr) { + } + virtual Flow visitConst(Const *curr) { + } + virtual Flow visitUnary(Unary *curr) { + } + virtual Flow visitBinary(Binary *curr) { + } + virtual Flow visitCompare(Compare *curr) { + } + virtual Flow visitConvert(Convert *curr) { + } + virtual Flow visitHost(Host *curr) { + } + virtual Flow visitNop(Nop *curr) { + } + }; + + return ExpressionRunner().visit(functions[name]->body); + } + +private: + Module& wasm; + + std::map<IString, Function*> functions; + +}; + +} // namespace wasm + diff --git a/src/wasm.h b/src/wasm.h index d13eb0795..290fc5d47 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -2,6 +2,9 @@ // WebAssembly representation and processing library // +#ifndef __wasm_h__ +#define __wasm_h__ + #include <cassert> #include <cstddef> #include <cstdint> @@ -796,5 +799,153 @@ public: } }; +// +// Simple WebAssembly AST walker +// + +struct WasmWalker { + wasm::Arena* allocator; // use an existing allocator, or null if no allocations + + WasmWalker() : allocator(nullptr) {} + WasmWalker(wasm::Arena* allocator) : allocator(allocator) {} + + // Each method receives an AST pointer, and it is replaced with what is returned. + virtual Expression* walkBlock(Block *curr) { return curr; }; + virtual Expression* walkIf(If *curr) { return curr; }; + virtual Expression* walkLoop(Loop *curr) { return curr; }; + virtual Expression* walkLabel(Label *curr) { return curr; }; + virtual Expression* walkBreak(Break *curr) { return curr; }; + virtual Expression* walkSwitch(Switch *curr) { return curr; }; + virtual Expression* walkCall(Call *curr) { return curr; }; + virtual Expression* walkCallImport(CallImport *curr) { return curr; }; + virtual Expression* walkCallIndirect(CallIndirect *curr) { return curr; }; + virtual Expression* walkGetLocal(GetLocal *curr) { return curr; }; + virtual Expression* walkSetLocal(SetLocal *curr) { return curr; }; + virtual Expression* walkLoad(Load *curr) { return curr; }; + virtual Expression* walkStore(Store *curr) { return curr; }; + virtual Expression* walkConst(Const *curr) { return curr; }; + virtual Expression* walkUnary(Unary *curr) { return curr; }; + virtual Expression* walkBinary(Binary *curr) { return curr; }; + virtual Expression* walkCompare(Compare *curr) { return curr; }; + virtual Expression* walkConvert(Convert *curr) { return curr; }; + virtual Expression* walkHost(Host *curr) { return curr; }; + virtual Expression* walkNop(Nop *curr) { return curr; }; + + // children-first + Expression *walk(Expression *curr) { + if (!curr) return curr; + + if (Block *cast = dynamic_cast<Block*>(curr)) { + ExpressionList& list = cast->list; + for (size_t z = 0; z < list.size(); z++) { + list[z] = walk(list[z]); + } + return walkBlock(cast); + } + if (If *cast = dynamic_cast<If*>(curr)) { + cast->condition = walk(cast->condition); + cast->ifTrue = walk(cast->ifTrue); + cast->ifFalse = walk(cast->ifFalse); + return walkIf(cast); + } + if (Loop *cast = dynamic_cast<Loop*>(curr)) { + cast->body = walk(cast->body); + return walkLoop(cast); + } + if (Label *cast = dynamic_cast<Label*>(curr)) { + return walkLabel(cast); + } + if (Break *cast = dynamic_cast<Break*>(curr)) { + cast->condition = walk(cast->condition); + cast->value = walk(cast->value); + return walkBreak(cast); + } + if (Switch *cast = dynamic_cast<Switch*>(curr)) { + cast->value = walk(cast->value); + for (auto& curr : cast->cases) { + curr.body = walk(curr.body); + } + cast->default_ = walk(cast->default_); + return walkSwitch(cast); + } + if (Call *cast = dynamic_cast<Call*>(curr)) { + ExpressionList& list = cast->operands; + for (size_t z = 0; z < list.size(); z++) { + list[z] = walk(list[z]); + } + return walkCall(cast); + } + if (CallImport *cast = dynamic_cast<CallImport*>(curr)) { + ExpressionList& list = cast->operands; + for (size_t z = 0; z < list.size(); z++) { + list[z] = walk(list[z]); + } + return walkCallImport(cast); + } + if (CallIndirect *cast = dynamic_cast<CallIndirect*>(curr)) { + cast->target = walk(cast->target); + ExpressionList& list = cast->operands; + for (size_t z = 0; z < list.size(); z++) { + list[z] = walk(list[z]); + } + return walkCallIndirect(cast); + } + if (GetLocal *cast = dynamic_cast<GetLocal*>(curr)) { + return walkGetLocal(cast); + } + if (SetLocal *cast = dynamic_cast<SetLocal*>(curr)) { + cast->value = walk(cast->value); + return walkSetLocal(cast); + } + if (Load *cast = dynamic_cast<Load*>(curr)) { + cast->ptr = walk(cast->ptr); + return walkLoad(cast); + } + if (Store *cast = dynamic_cast<Store*>(curr)) { + cast->ptr = walk(cast->ptr); + cast->value = walk(cast->value); + return walkStore(cast); + } + if (Const *cast = dynamic_cast<Const*>(curr)) { + return walkConst(cast); + } + if (Unary *cast = dynamic_cast<Unary*>(curr)) { + cast->value = walk(cast->value); + return walkUnary(cast); + } + if (Binary *cast = dynamic_cast<Binary*>(curr)) { + cast->left = walk(cast->left); + cast->right = walk(cast->right); + return walkBinary(cast); + } + if (Compare *cast = dynamic_cast<Compare*>(curr)) { + cast->left = walk(cast->left); + cast->right = walk(cast->right); + return walkCompare(cast); + } + if (Convert *cast = dynamic_cast<Convert*>(curr)) { + cast->value = walk(cast->value); + return walkConvert(cast); + } + if (Host *cast = dynamic_cast<Host*>(curr)) { + ExpressionList& list = cast->operands; + for (size_t z = 0; z < list.size(); z++) { + list[z] = walk(list[z]); + } + return walkHost(cast); + } + if (Nop *cast = dynamic_cast<Nop*>(curr)) { + return walkNop(cast); + } + abort(); + } + + void startWalk(Function *func) { + func->body = walk(func->body); + } +}; + } // namespace wasm +#endif // __wasm_h__ + |