mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 21:48:11 +00:00
LibWasm: Make Frame a value type as well
This means stack operations will no longer do extra allocations.
This commit is contained in:
parent
73eb0785e0
commit
bc936a5fac
6 changed files with 53 additions and 54 deletions
|
@ -107,15 +107,15 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex
|
||||||
|
|
||||||
module.for_each_section_of_type<GlobalSection>([&](auto& global_section) {
|
module.for_each_section_of_type<GlobalSection>([&](auto& global_section) {
|
||||||
for (auto& entry : global_section.entries()) {
|
for (auto& entry : global_section.entries()) {
|
||||||
auto frame = make<Frame>(
|
|
||||||
auxiliary_instance,
|
|
||||||
Vector<Value> {},
|
|
||||||
entry.expression(),
|
|
||||||
1);
|
|
||||||
Configuration config { m_store };
|
Configuration config { m_store };
|
||||||
config.pre_interpret_hook = &pre_interpret_hook;
|
config.pre_interpret_hook = &pre_interpret_hook;
|
||||||
config.post_interpret_hook = &post_interpret_hook;
|
config.post_interpret_hook = &post_interpret_hook;
|
||||||
config.set_frame(move(frame));
|
config.set_frame(Frame {
|
||||||
|
auxiliary_instance,
|
||||||
|
Vector<Value> {},
|
||||||
|
entry.expression(),
|
||||||
|
1,
|
||||||
|
});
|
||||||
auto result = config.execute();
|
auto result = config.execute();
|
||||||
// What if this traps?
|
// What if this traps?
|
||||||
if (result.is_trap())
|
if (result.is_trap())
|
||||||
|
@ -139,15 +139,15 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex
|
||||||
for (auto& segment : data_section.data()) {
|
for (auto& segment : data_section.data()) {
|
||||||
segment.value().visit(
|
segment.value().visit(
|
||||||
[&](const DataSection::Data::Active& data) {
|
[&](const DataSection::Data::Active& data) {
|
||||||
auto frame = make<Frame>(
|
|
||||||
main_module_instance,
|
|
||||||
Vector<Value> {},
|
|
||||||
data.offset,
|
|
||||||
1);
|
|
||||||
Configuration config { m_store };
|
Configuration config { m_store };
|
||||||
config.pre_interpret_hook = &pre_interpret_hook;
|
config.pre_interpret_hook = &pre_interpret_hook;
|
||||||
config.post_interpret_hook = &post_interpret_hook;
|
config.post_interpret_hook = &post_interpret_hook;
|
||||||
config.set_frame(move(frame));
|
config.set_frame(Frame {
|
||||||
|
main_module_instance,
|
||||||
|
Vector<Value> {},
|
||||||
|
data.offset,
|
||||||
|
1,
|
||||||
|
});
|
||||||
auto result = config.execute();
|
auto result = config.execute();
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
result.values().first().value().visit(
|
result.values().first().value().visit(
|
||||||
|
|
|
@ -392,8 +392,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class Frame {
|
class Frame {
|
||||||
AK_MAKE_NONCOPYABLE(Frame);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Frame(const ModuleInstance& module, Vector<Value> locals, const Expression& expression, size_t arity)
|
explicit Frame(const ModuleInstance& module, Vector<Value> locals, const Expression& expression, size_t arity)
|
||||||
: m_module(module)
|
: m_module(module)
|
||||||
|
@ -418,7 +416,7 @@ private:
|
||||||
|
|
||||||
class Stack {
|
class Stack {
|
||||||
public:
|
public:
|
||||||
using EntryType = Variant<Value, Label, NonnullOwnPtr<Frame>>;
|
using EntryType = Variant<Value, Label, Frame>;
|
||||||
Stack() = default;
|
Stack() = default;
|
||||||
|
|
||||||
[[nodiscard]] bool is_empty() const { return m_data.is_empty(); }
|
[[nodiscard]] bool is_empty() const { return m_data.is_empty(); }
|
||||||
|
@ -428,9 +426,10 @@ public:
|
||||||
|
|
||||||
auto size() const { return m_data.size(); }
|
auto size() const { return m_data.size(); }
|
||||||
auto& entries() const { return m_data; }
|
auto& entries() const { return m_data; }
|
||||||
|
auto& entries() { return m_data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<EntryType> m_data;
|
Vector<EntryType, 64> m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
using InstantiationResult = AK::Result<NonnullOwnPtr<ModuleInstance>, InstantiationError>;
|
using InstantiationResult = AK::Result<NonnullOwnPtr<ModuleInstance>, InstantiationError>;
|
||||||
|
|
|
@ -35,13 +35,12 @@ Result Configuration::call(FunctionAddress address, Vector<Value> arguments)
|
||||||
for (auto& type : wasm_function->code().locals())
|
for (auto& type : wasm_function->code().locals())
|
||||||
locals.empend(type, 0ull);
|
locals.empend(type, 0ull);
|
||||||
|
|
||||||
auto frame = make<Frame>(
|
set_frame(Frame {
|
||||||
wasm_function->module(),
|
wasm_function->module(),
|
||||||
move(locals),
|
move(locals),
|
||||||
wasm_function->code().body(),
|
wasm_function->code().body(),
|
||||||
wasm_function->type().results().size());
|
wasm_function->type().results().size(),
|
||||||
|
});
|
||||||
set_frame(move(frame));
|
|
||||||
return execute();
|
return execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +60,8 @@ Result Configuration::execute()
|
||||||
return Trap {};
|
return Trap {};
|
||||||
|
|
||||||
Vector<Value> results;
|
Vector<Value> results;
|
||||||
results.ensure_capacity(m_current_frame->arity());
|
results.ensure_capacity(frame().arity());
|
||||||
for (size_t i = 0; i < m_current_frame->arity(); ++i)
|
for (size_t i = 0; i < frame().arity(); ++i)
|
||||||
results.append(move(stack().pop().get<Value>()));
|
results.append(move(stack().pop().get<Value>()));
|
||||||
auto label = stack().pop();
|
auto label = stack().pop();
|
||||||
// ASSERT: label == current frame
|
// ASSERT: label == current frame
|
||||||
|
@ -83,9 +82,9 @@ void Configuration::dump_stack()
|
||||||
dbgln(" *{}", v.value());
|
dbgln(" *{}", v.value());
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[](const NonnullOwnPtr<Frame>& f) {
|
[](const Frame& f) {
|
||||||
dbgln(" frame({})", f->arity());
|
dbgln(" frame({})", f.arity());
|
||||||
for (auto& local : f->locals()) {
|
for (auto& local : f.locals()) {
|
||||||
local.value().visit([]<typename T>(const T& v) {
|
local.value().visit([]<typename T>(const T& v) {
|
||||||
if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
|
if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
|
||||||
dbgln(" {}", v);
|
dbgln(" {}", v);
|
||||||
|
|
|
@ -18,14 +18,15 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Label> nth_label(size_t);
|
Optional<Label> nth_label(size_t);
|
||||||
void set_frame(NonnullOwnPtr<Frame> frame)
|
void set_frame(Frame&& frame)
|
||||||
{
|
{
|
||||||
m_current_frame = frame.ptr();
|
m_current_frame_index = m_stack.size();
|
||||||
|
Label label(frame.arity(), frame.expression().instructions().size());
|
||||||
m_stack.push(move(frame));
|
m_stack.push(move(frame));
|
||||||
m_stack.push(Label(m_current_frame->arity(), m_current_frame->expression().instructions().size()));
|
m_stack.push(label);
|
||||||
}
|
}
|
||||||
auto& frame() const { return m_current_frame; }
|
auto& frame() const { return m_stack.entries()[m_current_frame_index].get<Frame>(); }
|
||||||
auto& frame() { return m_current_frame; }
|
auto& frame() { return m_stack.entries()[m_current_frame_index].get<Frame>(); }
|
||||||
auto& ip() const { return m_ip; }
|
auto& ip() const { return m_ip; }
|
||||||
auto& ip() { return m_ip; }
|
auto& ip() { return m_ip; }
|
||||||
auto& depth() const { return m_depth; }
|
auto& depth() const { return m_depth; }
|
||||||
|
@ -45,7 +46,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Store& m_store;
|
Store& m_store;
|
||||||
Frame* m_current_frame { nullptr };
|
size_t m_current_frame_index { 0 };
|
||||||
Stack m_stack;
|
Stack m_stack;
|
||||||
size_t m_depth { 0 };
|
size_t m_depth { 0 };
|
||||||
InstructionPointer m_ip;
|
InstructionPointer m_ip;
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace Wasm {
|
||||||
|
|
||||||
void Interpreter::interpret(Configuration& configuration)
|
void Interpreter::interpret(Configuration& configuration)
|
||||||
{
|
{
|
||||||
auto& instructions = configuration.frame()->expression().instructions();
|
auto& instructions = configuration.frame().expression().instructions();
|
||||||
auto max_ip_value = InstructionPointer { instructions.size() };
|
auto max_ip_value = InstructionPointer { instructions.size() };
|
||||||
auto& current_ip_value = configuration.ip();
|
auto& current_ip_value = configuration.ip();
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ void Interpreter::branch_to_label(Configuration& configuration, LabelIndex index
|
||||||
|
|
||||||
ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const Instruction& instruction, size_t size)
|
ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const Instruction& instruction, size_t size)
|
||||||
{
|
{
|
||||||
auto& address = configuration.frame()->module().memories().first();
|
auto& address = configuration.frame().module().memories().first();
|
||||||
auto memory = configuration.store().get(address);
|
auto memory = configuration.store().get(address);
|
||||||
if (!memory) {
|
if (!memory) {
|
||||||
m_do_trap = true;
|
m_do_trap = true;
|
||||||
|
@ -97,7 +97,7 @@ ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const
|
||||||
|
|
||||||
void Interpreter::store_to_memory(Configuration& configuration, const Instruction& instruction, ReadonlyBytes data)
|
void Interpreter::store_to_memory(Configuration& configuration, const Instruction& instruction, ReadonlyBytes data)
|
||||||
{
|
{
|
||||||
auto& address = configuration.frame()->module().memories().first();
|
auto& address = configuration.frame().module().memories().first();
|
||||||
auto memory = configuration.store().get(address);
|
auto memory = configuration.store().get(address);
|
||||||
TRAP_IF_NOT(memory);
|
TRAP_IF_NOT(memory);
|
||||||
auto& arg = instruction.arguments().get<Instruction::MemoryArgument>();
|
auto& arg = instruction.arguments().get<Instruction::MemoryArgument>();
|
||||||
|
@ -366,11 +366,11 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
case Instructions::nop.value():
|
case Instructions::nop.value():
|
||||||
return;
|
return;
|
||||||
case Instructions::local_get.value():
|
case Instructions::local_get.value():
|
||||||
configuration.stack().push(Value(configuration.frame()->locals()[instruction.arguments().get<LocalIndex>().value()]));
|
configuration.stack().push(Value(configuration.frame().locals()[instruction.arguments().get<LocalIndex>().value()]));
|
||||||
return;
|
return;
|
||||||
case Instructions::local_set.value(): {
|
case Instructions::local_set.value(): {
|
||||||
auto entry = configuration.stack().pop();
|
auto entry = configuration.stack().pop();
|
||||||
configuration.frame()->locals()[instruction.arguments().get<LocalIndex>().value()] = move(entry.get<Value>());
|
configuration.frame().locals()[instruction.arguments().get<LocalIndex>().value()] = move(entry.get<Value>());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case Instructions::i32_const.value():
|
case Instructions::i32_const.value():
|
||||||
|
@ -448,7 +448,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
}
|
}
|
||||||
case Instructions::return_.value(): {
|
case Instructions::return_.value(): {
|
||||||
Vector<Stack::EntryType> results;
|
Vector<Stack::EntryType> results;
|
||||||
auto& frame = *configuration.frame();
|
auto& frame = configuration.frame();
|
||||||
results.ensure_capacity(frame.arity());
|
results.ensure_capacity(frame.arity());
|
||||||
for (size_t i = 0; i < frame.arity(); ++i)
|
for (size_t i = 0; i < frame.arity(); ++i)
|
||||||
results.prepend(configuration.stack().pop());
|
results.prepend(configuration.stack().pop());
|
||||||
|
@ -460,7 +460,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
last_label = entry.get<Label>();
|
last_label = entry.get<Label>();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (entry.has<NonnullOwnPtr<Frame>>()) {
|
if (entry.has<Frame>()) {
|
||||||
// Push the frame back
|
// Push the frame back
|
||||||
configuration.stack().push(move(entry));
|
configuration.stack().push(move(entry));
|
||||||
// Push its label back (if there is one)
|
// Push its label back (if there is one)
|
||||||
|
@ -475,7 +475,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
configuration.stack().push(move(result));
|
configuration.stack().push(move(result));
|
||||||
|
|
||||||
// Jump past the call/indirect instruction
|
// Jump past the call/indirect instruction
|
||||||
configuration.ip() = configuration.frame()->expression().instructions().size() - 1;
|
configuration.ip() = configuration.frame().expression().instructions().size() - 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case Instructions::br.value():
|
case Instructions::br.value():
|
||||||
|
@ -489,14 +489,14 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case Instructions::call.value(): {
|
case Instructions::call.value(): {
|
||||||
auto index = instruction.arguments().get<FunctionIndex>();
|
auto index = instruction.arguments().get<FunctionIndex>();
|
||||||
auto address = configuration.frame()->module().functions()[index.value()];
|
auto address = configuration.frame().module().functions()[index.value()];
|
||||||
dbgln_if(WASM_TRACE_DEBUG, "call({})", address.value());
|
dbgln_if(WASM_TRACE_DEBUG, "call({})", address.value());
|
||||||
call_address(configuration, address);
|
call_address(configuration, address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case Instructions::call_indirect.value(): {
|
case Instructions::call_indirect.value(): {
|
||||||
auto& args = instruction.arguments().get<Instruction::IndirectCallArgs>();
|
auto& args = instruction.arguments().get<Instruction::IndirectCallArgs>();
|
||||||
auto table_address = configuration.frame()->module().tables()[args.table.value()];
|
auto table_address = configuration.frame().module().tables()[args.table.value()];
|
||||||
auto table_instance = configuration.store().get(table_address);
|
auto table_instance = configuration.store().get(table_address);
|
||||||
auto index = configuration.stack().pop().get<Value>().to<i32>();
|
auto index = configuration.stack().pop().get<Value>().to<i32>();
|
||||||
TRAP_IF_NOT(index.has_value());
|
TRAP_IF_NOT(index.has_value());
|
||||||
|
@ -565,15 +565,15 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
case Instructions::local_tee.value(): {
|
case Instructions::local_tee.value(): {
|
||||||
auto value = configuration.stack().peek().get<Value>();
|
auto value = configuration.stack().peek().get<Value>();
|
||||||
auto local_index = instruction.arguments().get<LocalIndex>();
|
auto local_index = instruction.arguments().get<LocalIndex>();
|
||||||
TRAP_IF_NOT(configuration.frame()->locals().size() > local_index.value());
|
TRAP_IF_NOT(configuration.frame().locals().size() > local_index.value());
|
||||||
dbgln_if(WASM_TRACE_DEBUG, "stack:peek -> locals({})", local_index.value());
|
dbgln_if(WASM_TRACE_DEBUG, "stack:peek -> locals({})", local_index.value());
|
||||||
configuration.frame()->locals()[local_index.value()] = move(value);
|
configuration.frame().locals()[local_index.value()] = move(value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case Instructions::global_get.value(): {
|
case Instructions::global_get.value(): {
|
||||||
auto global_index = instruction.arguments().get<GlobalIndex>();
|
auto global_index = instruction.arguments().get<GlobalIndex>();
|
||||||
TRAP_IF_NOT(configuration.frame()->module().globals().size() > global_index.value());
|
TRAP_IF_NOT(configuration.frame().module().globals().size() > global_index.value());
|
||||||
auto address = configuration.frame()->module().globals()[global_index.value()];
|
auto address = configuration.frame().module().globals()[global_index.value()];
|
||||||
dbgln_if(WASM_TRACE_DEBUG, "global({}) -> stack", address.value());
|
dbgln_if(WASM_TRACE_DEBUG, "global({}) -> stack", address.value());
|
||||||
auto global = configuration.store().get(address);
|
auto global = configuration.store().get(address);
|
||||||
configuration.stack().push(Value(global->value()));
|
configuration.stack().push(Value(global->value()));
|
||||||
|
@ -581,8 +581,8 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
}
|
}
|
||||||
case Instructions::global_set.value(): {
|
case Instructions::global_set.value(): {
|
||||||
auto global_index = instruction.arguments().get<GlobalIndex>();
|
auto global_index = instruction.arguments().get<GlobalIndex>();
|
||||||
TRAP_IF_NOT(configuration.frame()->module().globals().size() > global_index.value());
|
TRAP_IF_NOT(configuration.frame().module().globals().size() > global_index.value());
|
||||||
auto address = configuration.frame()->module().globals()[global_index.value()];
|
auto address = configuration.frame().module().globals()[global_index.value()];
|
||||||
auto value = configuration.stack().pop().get<Value>();
|
auto value = configuration.stack().pop().get<Value>();
|
||||||
dbgln_if(WASM_TRACE_DEBUG, "stack -> global({})", address.value());
|
dbgln_if(WASM_TRACE_DEBUG, "stack -> global({})", address.value());
|
||||||
auto global = configuration.store().get(address);
|
auto global = configuration.store().get(address);
|
||||||
|
@ -590,7 +590,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case Instructions::memory_size.value(): {
|
case Instructions::memory_size.value(): {
|
||||||
auto address = configuration.frame()->module().memories()[0];
|
auto address = configuration.frame().module().memories()[0];
|
||||||
auto instance = configuration.store().get(address);
|
auto instance = configuration.store().get(address);
|
||||||
auto pages = instance->size() / Constants::page_size;
|
auto pages = instance->size() / Constants::page_size;
|
||||||
dbgln_if(WASM_TRACE_DEBUG, "memory.size -> stack({})", pages);
|
dbgln_if(WASM_TRACE_DEBUG, "memory.size -> stack({})", pages);
|
||||||
|
@ -598,7 +598,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case Instructions::memory_grow.value(): {
|
case Instructions::memory_grow.value(): {
|
||||||
auto address = configuration.frame()->module().memories()[0];
|
auto address = configuration.frame().module().memories()[0];
|
||||||
auto instance = configuration.store().get(address);
|
auto instance = configuration.store().get(address);
|
||||||
i32 old_pages = instance->size() / Constants::page_size;
|
i32 old_pages = instance->size() / Constants::page_size;
|
||||||
auto new_pages = configuration.stack().pop().get<Value>().to<i32>();
|
auto new_pages = configuration.stack().pop().get<Value>().to<i32>();
|
||||||
|
|
|
@ -155,10 +155,10 @@ static bool pre_interpret_hook(Wasm::Configuration& config, Wasm::InstructionPoi
|
||||||
Optional<Wasm::FunctionAddress> address;
|
Optional<Wasm::FunctionAddress> address;
|
||||||
auto index = args[1].to_uint<u64>();
|
auto index = args[1].to_uint<u64>();
|
||||||
if (index.has_value()) {
|
if (index.has_value()) {
|
||||||
address = config.frame()->module().functions()[index.value()];
|
address = config.frame().module().functions()[index.value()];
|
||||||
} else {
|
} else {
|
||||||
auto& name = args[1];
|
auto& name = args[1];
|
||||||
for (auto& export_ : config.frame()->module().exports()) {
|
for (auto& export_ : config.frame().module().exports()) {
|
||||||
if (export_.name() == name) {
|
if (export_.name() == name) {
|
||||||
if (auto addr = export_.value().get_pointer<Wasm::FunctionAddress>()) {
|
if (auto addr = export_.value().get_pointer<Wasm::FunctionAddress>()) {
|
||||||
address = *addr;
|
address = *addr;
|
||||||
|
@ -437,12 +437,12 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
Wasm::Configuration config { machine.store() };
|
Wasm::Configuration config { machine.store() };
|
||||||
auto frame = make<Wasm::Frame>(
|
config.set_frame(Wasm::Frame {
|
||||||
*module_instance,
|
*module_instance,
|
||||||
Vector<Wasm::Value> {},
|
Vector<Wasm::Value> {},
|
||||||
instance->get<Wasm::WasmFunction>().code().body(),
|
instance->get<Wasm::WasmFunction>().code().body(),
|
||||||
1);
|
1,
|
||||||
config.set_frame(move(frame));
|
});
|
||||||
const Wasm::Instruction instr { Wasm::Instructions::nop };
|
const Wasm::Instruction instr { Wasm::Instructions::nop };
|
||||||
Wasm::InstructionPointer ip { 0 };
|
Wasm::InstructionPointer ip { 0 };
|
||||||
g_continue = false;
|
g_continue = false;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue