diff options
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r-- | src/wasm-interpreter.h | 136 |
1 files changed, 111 insertions, 25 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 9558a3c38..37cf7a7a6 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -510,10 +510,11 @@ public: }; // Execute an constant expression in a global init or memory offset -class ConstantExpressionRunner : public ExpressionRunner<ConstantExpressionRunner> { - std::map<Name, Literal>& globals; +template<typename GlobalManager> +class ConstantExpressionRunner : public ExpressionRunner<ConstantExpressionRunner<GlobalManager>> { + GlobalManager& globals; public: - ConstantExpressionRunner(std::map<Name, Literal>& globals) : globals(globals) {} + ConstantExpressionRunner(GlobalManager& globals) : globals(globals) {} Flow visitLoop(Loop* curr) { WASM_UNREACHABLE(); } Flow visitCall(Call* curr) { WASM_UNREACHABLE(); } @@ -538,7 +539,8 @@ public: // To call into the interpreter, use callExport. // -class ModuleInstance { +template<typename GlobalManager, typename SubType> +class ModuleInstanceBase { public: // // You need to implement one of these to create a concrete interpreter. The @@ -546,32 +548,104 @@ public: // an imported function or accessing memory. // struct ExternalInterface { - virtual void init(Module& wasm, ModuleInstance& instance) {} - virtual void importGlobals(std::map<Name, Literal>& globals, Module& wasm) = 0; + virtual void init(Module& wasm, SubType& instance) {} + virtual void importGlobals(GlobalManager& globals, Module& wasm) = 0; virtual Literal callImport(Import* import, LiteralList& arguments) = 0; - virtual Literal callTable(Index index, LiteralList& arguments, WasmType result, ModuleInstance& instance) = 0; - virtual Literal load(Load* load, Address addr) = 0; - virtual void store(Store* store, Address addr, Literal value) = 0; + virtual Literal callTable(Index index, LiteralList& arguments, WasmType result, SubType& instance) = 0; virtual void growMemory(Address oldSize, Address newSize) = 0; virtual void trap(const char* why) = 0; + + // the default impls for load and store switch on the sizes. you can either + // customize load/store, or the sub-functions which they call + virtual Literal load(Load* load, Address addr) { + switch (load->type) { + case i32: { + switch (load->bytes) { + case 1: return load->signed_ ? Literal((int32_t)load8s(addr)) : Literal((int32_t)load8u(addr)); + case 2: return load->signed_ ? Literal((int32_t)load16s(addr)) : Literal((int32_t)load16u(addr)); + case 4: return load->signed_ ? Literal((int32_t)load32s(addr)) : Literal((int32_t)load32u(addr)); + default: WASM_UNREACHABLE(); + } + break; + } + case i64: { + switch (load->bytes) { + case 1: return load->signed_ ? Literal((int64_t)load8s(addr)) : Literal((int64_t)load8u(addr)); + case 2: return load->signed_ ? Literal((int64_t)load16s(addr)) : Literal((int64_t)load16u(addr)); + case 4: return load->signed_ ? Literal((int64_t)load32s(addr)) : Literal((int64_t)load32u(addr)); + case 8: return load->signed_ ? Literal((int64_t)load64s(addr)) : Literal((int64_t)load64u(addr)); + default: WASM_UNREACHABLE(); + } + break; + } + case f32: return Literal(load32u(addr)).castToF32(); + case f64: return Literal(load64u(addr)).castToF64(); + default: WASM_UNREACHABLE(); + } + } + virtual void store(Store* store, Address addr, Literal value) { + switch (store->valueType) { + case i32: { + switch (store->bytes) { + case 1: store8(addr, value.geti32()); break; + case 2: store16(addr, value.geti32()); break; + case 4: store32(addr, value.geti32()); break; + default: WASM_UNREACHABLE(); + } + break; + } + case i64: { + switch (store->bytes) { + case 1: store8(addr, value.geti64()); break; + case 2: store16(addr, value.geti64()); break; + case 4: store32(addr, value.geti64()); break; + case 8: store64(addr, value.geti64()); break; + default: WASM_UNREACHABLE(); + } + break; + } + // write floats carefully, ensuring all bits reach memory + case f32: store32(addr, value.reinterpreti32()); break; + case f64: store64(addr, value.reinterpreti64()); break; + default: WASM_UNREACHABLE(); + } + } + + virtual int8_t load8s(Address addr) { WASM_UNREACHABLE(); } + virtual uint8_t load8u(Address addr) { WASM_UNREACHABLE(); } + virtual int16_t load16s(Address addr) { WASM_UNREACHABLE(); } + virtual uint16_t load16u(Address addr) { WASM_UNREACHABLE(); } + virtual int32_t load32s(Address addr) { WASM_UNREACHABLE(); } + virtual uint32_t load32u(Address addr) { WASM_UNREACHABLE(); } + virtual int64_t load64s(Address addr) { WASM_UNREACHABLE(); } + virtual uint64_t load64u(Address addr) { WASM_UNREACHABLE(); } + + virtual void store8(Address addr, int8_t value) { WASM_UNREACHABLE(); } + virtual void store16(Address addr, int16_t value) { WASM_UNREACHABLE(); } + virtual void store32(Address addr, int32_t value) { WASM_UNREACHABLE(); } + virtual void store64(Address addr, int64_t value) { WASM_UNREACHABLE(); } }; + SubType* self() { + return static_cast<SubType*>(this); + } + Module& wasm; // Values of globals - std::map<Name, Literal> globals; + GlobalManager globals; - ModuleInstance(Module& wasm, ExternalInterface* externalInterface) : wasm(wasm), externalInterface(externalInterface) { + ModuleInstanceBase(Module& wasm, ExternalInterface* externalInterface) : wasm(wasm), externalInterface(externalInterface) { // import globals from the outside externalInterface->importGlobals(globals, wasm); // prepare memory memorySize = wasm.memory.initial; // generate internal (non-imported) globals for (auto& global : wasm.globals) { - globals[global->name] = ConstantExpressionRunner(globals).visit(global->init).value; + globals[global->name] = ConstantExpressionRunner<GlobalManager>(globals).visit(global->init).value; } // initialize the rest of the external interface - externalInterface->init(wasm, *this); + externalInterface->init(wasm, *self()); // run start, if present if (wasm.start.is()) { LiteralList arguments; @@ -586,6 +660,11 @@ public: return callFunction(export_->value, arguments); } + Literal callExport(Name name) { + LiteralList arguments; + return callExport(name, arguments); + } + // get an exported global Literal getExport(Name name) { Export *export_ = wasm.getExportOrNull(name); @@ -660,17 +739,17 @@ public: // Executes expresions with concrete runtime info, the function and module at runtime class RuntimeExpressionRunner : public ExpressionRunner<RuntimeExpressionRunner> { - ModuleInstance& instance; + ModuleInstanceBase& instance; FunctionScope& scope; public: - RuntimeExpressionRunner(ModuleInstance& instance, FunctionScope& scope) : instance(instance), scope(scope) {} + RuntimeExpressionRunner(ModuleInstanceBase& instance, FunctionScope& scope) : instance(instance), scope(scope) {} Flow generateArguments(const ExpressionList& operands, LiteralList& arguments) { NOTE_ENTER_("generateArguments"); arguments.reserve(operands.size()); for (auto expression : operands) { - Flow flow = visit(expression); + Flow flow = this->visit(expression); if (flow.breaking()) return flow; NOTE_EVAL1(flow.value); arguments.push_back(flow.value); @@ -702,10 +781,10 @@ public: LiteralList arguments; Flow flow = generateArguments(curr->operands, arguments); if (flow.breaking()) return flow; - Flow target = visit(curr->target); + Flow target = this->visit(curr->target); if (target.breaking()) return target; Index index = target.value.geti32(); - return instance.externalInterface->callTable(index, arguments, curr->type, instance); + return instance.externalInterface->callTable(index, arguments, curr->type, *instance.self()); } Flow visitGetLocal(GetLocal *curr) { @@ -718,7 +797,7 @@ public: Flow visitSetLocal(SetLocal *curr) { NOTE_ENTER("SetLocal"); auto index = curr->index; - Flow flow = visit(curr->value); + Flow flow = this->visit(curr->value); if (flow.breaking()) return flow; NOTE_EVAL1(index); NOTE_EVAL1(flow.value); @@ -738,7 +817,7 @@ public: Flow visitSetGlobal(SetGlobal *curr) { NOTE_ENTER("SetGlobal"); auto name = curr->name; - Flow flow = visit(curr->value); + Flow flow = this->visit(curr->value); if (flow.breaking()) return flow; NOTE_EVAL1(name); NOTE_EVAL1(flow.value); @@ -748,7 +827,7 @@ public: Flow visitLoad(Load *curr) { NOTE_ENTER("Load"); - Flow flow = visit(curr->ptr); + Flow flow = this->visit(curr->ptr); if (flow.breaking()) return flow; NOTE_EVAL1(flow); auto addr = instance.getFinalAddress(curr, flow.value); @@ -759,9 +838,9 @@ public: } Flow visitStore(Store *curr) { NOTE_ENTER("Store"); - Flow ptr = visit(curr->ptr); + Flow ptr = this->visit(curr->ptr); if (ptr.breaking()) return ptr; - Flow value = visit(curr->value); + Flow value = this->visit(curr->value); if (value.breaking()) return value; auto addr = instance.getFinalAddress(curr, ptr.value); NOTE_EVAL1(addr); @@ -777,7 +856,7 @@ public: case CurrentMemory: return Literal(int32_t(instance.memorySize)); case GrowMemory: { auto fail = Literal(int32_t(-1)); - Flow flow = visit(curr->operands[0]); + Flow flow = this->visit(curr->operands[0]); if (flow.breaking()) return flow; int32_t ret = instance.memorySize; uint32_t delta = flow.value.geti32(); @@ -840,7 +919,7 @@ public: return ret; } -private: +protected: Address memorySize; // in pages @@ -866,6 +945,13 @@ private: ExternalInterface* externalInterface; }; +// The default ModuleInstance uses a trivial global manager +typedef std::map<Name, Literal> TrivialGlobalManager; +class ModuleInstance : public ModuleInstanceBase<TrivialGlobalManager, ModuleInstance> { +public: + ModuleInstance(Module& wasm, ExternalInterface* externalInterface) : ModuleInstanceBase(wasm, externalInterface) {} +}; + } // namespace wasm #endif // wasm_wasm_interpreter_h |