Skip to content

Commit 9b161a9

Browse files
authored
[Interpreter] Instance (#7343)
Adds an instance struct to encapsulate the runtime representation of a module, as seen in the [spec](https://webassembly.github.io/spec/core/exec/runtime.html#module-instances). Also adds an instantiate method, which runs the initialization expressions of globals in the module.
1 parent db9d68f commit 9b161a9

File tree

4 files changed

+169
-66
lines changed

4 files changed

+169
-66
lines changed

src/interpreter/interpreter.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,14 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
4747
ExpressionInterpreter(Interpreter& parent) : parent(parent) {}
4848

4949
WasmStore& store() { return InterpreterImpl::getStore(parent); }
50+
Frame& frame() { return store().callStack.back(); }
51+
Instance& instance() { return frame().instance; }
52+
5053
void push(Literal val) { store().push(val); }
5154
Literal pop() { return store().pop(); }
5255

5356
Flow visitNop(Nop* curr) { WASM_UNREACHABLE("TODO"); }
54-
Flow visitBlock(Block* curr) { WASM_UNREACHABLE("TODO"); }
57+
Flow visitBlock(Block* curr) { return {}; }
5558
Flow visitIf(If* curr) { WASM_UNREACHABLE("TODO"); }
5659
Flow visitLoop(Loop* curr) { WASM_UNREACHABLE("TODO"); }
5760
Flow visitBreak(Break* curr) { WASM_UNREACHABLE("TODO"); }
@@ -60,8 +63,14 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
6063
Flow visitCallIndirect(CallIndirect* curr) { WASM_UNREACHABLE("TODO"); }
6164
Flow visitLocalGet(LocalGet* curr) { WASM_UNREACHABLE("TODO"); }
6265
Flow visitLocalSet(LocalSet* curr) { WASM_UNREACHABLE("TODO"); }
63-
Flow visitGlobalGet(GlobalGet* curr) { WASM_UNREACHABLE("TODO"); }
64-
Flow visitGlobalSet(GlobalSet* curr) { WASM_UNREACHABLE("TODO"); }
66+
Flow visitGlobalGet(GlobalGet* curr) {
67+
push(instance().globalValues[curr->name]);
68+
return {};
69+
}
70+
Flow visitGlobalSet(GlobalSet* curr) {
71+
instance().globalValues[curr->name] = pop();
72+
return {};
73+
}
6574
Flow visitLoad(Load* curr) { WASM_UNREACHABLE("TODO"); }
6675
Flow visitStore(Store* curr) { WASM_UNREACHABLE("TODO"); }
6776
Flow visitAtomicRMW(AtomicRMW* curr) { WASM_UNREACHABLE("TODO"); }
@@ -272,13 +281,33 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
272281

273282
} // anonymous namespace
274283

275-
std::vector<Literal> Interpreter::run(Expression* root) {
276-
// Create a fresh store and execution frame, then run the expression to
277-
// completion.
278-
store = WasmStore();
279-
store.callStack.emplace_back();
280-
store.callStack.back().exprs = ExpressionIterator(root);
284+
Result<> Interpreter::addInstance(std::shared_ptr<Module> wasm) {
285+
return instantiate(store.instances.emplace_back(wasm));
286+
}
287+
288+
Result<> Interpreter::instantiate(Instance& instance) {
289+
for (auto& global : instance.wasm->globals) {
290+
store.callStack.emplace_back(instance, ExpressionIterator(global->init));
291+
auto results = run();
292+
assert(results.size() == 1);
293+
instance.globalValues[global->name] = results[0];
294+
}
295+
return Ok{};
296+
}
297+
298+
// This is a temporary convenience while stil using gTests to validate this
299+
// interpreter. Once spec tests can run, this shall be deleted.
300+
std::vector<Literal> Interpreter::runTest(Expression* root) {
301+
static std::shared_ptr<wasm::Module> dummyModule = std::make_shared<Module>();
302+
if (store.instances.empty()) {
303+
auto result = addInstance(dummyModule);
304+
}
305+
store.callStack.emplace_back(store.instances.back(),
306+
ExpressionIterator(root));
307+
return run();
308+
}
281309

310+
std::vector<Literal> Interpreter::run() {
282311
ExpressionInterpreter interpreter(*this);
283312
while (auto& it = store.callStack.back().exprs) {
284313
if (auto flow = interpreter.visit(*it)) {
@@ -288,7 +317,9 @@ std::vector<Literal> Interpreter::run(Expression* root) {
288317
}
289318
}
290319

291-
return store.callStack.back().valueStack;
320+
auto valueStack = store.callStack.back().valueStack;
321+
store.callStack.pop_back();
322+
return valueStack;
292323
}
293324

294325
} // namespace wasm

src/interpreter/interpreter.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,24 @@
1818
#define interpreter_interpreter_h
1919

2020
#include "store.h"
21+
#include "support/result.h"
2122

2223
namespace wasm {
2324

2425
class Interpreter {
2526
public:
2627
// TODO: Methods to instantiate modules.
2728
// TODO: Methods to run exported functions.
28-
std::vector<Literal> run(Expression* root);
29+
30+
Result<> addInstance(std::shared_ptr<Module> wasm);
31+
std::vector<Literal> runTest(Expression* root);
32+
std::vector<Literal> run();
2933

3034
private:
3135
interpreter::WasmStore store;
3236
friend class InterpreterImpl;
37+
38+
Result<> instantiate(interpreter::Instance& instance);
3339
};
3440

3541
} // namespace wasm

src/interpreter/store.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,28 @@
2222

2323
#include "expression-iterator.h"
2424
#include "literal.h"
25+
#include "support/result.h"
2526

2627
namespace wasm::interpreter {
2728

29+
// Contains the runtime representation of an instance of a Wasm module.
30+
struct Instance {
31+
std::shared_ptr<Module> wasm;
32+
std::unordered_map<Name, Literal> globalValues;
33+
34+
Instance(std::shared_ptr<Module> wasm) : wasm(std::move(wasm)){};
35+
};
36+
2837
// A frame of execution for a function call.
2938
struct Frame {
30-
// TODO: Reference to current instance to find referenced functions, globals,
31-
// tables, memories, etc.
32-
39+
Instance& instance;
3340
std::vector<Literal> locals;
3441
std::vector<Literal> valueStack;
3542
ExpressionIterator exprs;
3643

44+
Frame(Instance& instance, ExpressionIterator&& exprs)
45+
: instance(instance), exprs(std::move(exprs)){};
46+
3747
// TODO: Map loops to ExpressionIterators so we can branch backwards.
3848

3949
// Helpers to push and pop the current value stack.
@@ -55,6 +65,7 @@ struct WasmStore {
5565
// TODO: Storage for memories, tables, globals, heap objects, etc.
5666
// TODO: Map instances and import names to other instances to find imports.
5767
std::vector<Frame> callStack;
68+
std::vector<Instance> instances;
5869

5970
Frame& getFrame() {
6071
assert(!callStack.empty());

0 commit comments

Comments
 (0)