mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 14:48:14 +00:00
LibWasm: Make Interpreter a virtual interface
This allows multiply different kinds of interpreters to be used by the runtime; currently a BytecodeInterpreter and a DebuggerBytecodeInterpreter is provided.
This commit is contained in:
parent
f91fa79fc5
commit
c5df55a8a2
7 changed files with 86 additions and 66 deletions
|
@ -29,7 +29,7 @@ namespace Wasm {
|
|||
} \
|
||||
} while (false)
|
||||
|
||||
void Interpreter::interpret(Configuration& configuration)
|
||||
void BytecodeInterpreter::interpret(Configuration& configuration)
|
||||
{
|
||||
auto& instructions = configuration.frame().expression().instructions();
|
||||
auto max_ip_value = InstructionPointer { instructions.size() };
|
||||
|
@ -46,7 +46,7 @@ void Interpreter::interpret(Configuration& configuration)
|
|||
}
|
||||
}
|
||||
|
||||
void Interpreter::branch_to_label(Configuration& configuration, LabelIndex index)
|
||||
void BytecodeInterpreter::branch_to_label(Configuration& configuration, LabelIndex index)
|
||||
{
|
||||
dbgln_if(WASM_TRACE_DEBUG, "Branch to label with index {}...", index.value());
|
||||
auto label = configuration.nth_label(index.value());
|
||||
|
@ -71,7 +71,7 @@ void Interpreter::branch_to_label(Configuration& configuration, LabelIndex index
|
|||
configuration.ip() = label->continuation();
|
||||
}
|
||||
|
||||
ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const Instruction& instruction, size_t size)
|
||||
ReadonlyBytes BytecodeInterpreter::load_from_memory(Configuration& configuration, const Instruction& instruction, size_t size)
|
||||
{
|
||||
auto& address = configuration.frame().module().memories().first();
|
||||
auto memory = configuration.store().get(address);
|
||||
|
@ -95,7 +95,7 @@ ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const
|
|||
return memory->data().bytes().slice(instance_address, size);
|
||||
}
|
||||
|
||||
void Interpreter::store_to_memory(Configuration& configuration, const Instruction& instruction, ReadonlyBytes data)
|
||||
void BytecodeInterpreter::store_to_memory(Configuration& configuration, const Instruction& instruction, ReadonlyBytes data)
|
||||
{
|
||||
auto& address = configuration.frame().module().memories().first();
|
||||
auto memory = configuration.store().get(address);
|
||||
|
@ -113,7 +113,7 @@ void Interpreter::store_to_memory(Configuration& configuration, const Instructio
|
|||
data.copy_to(memory->data().bytes().slice(instance_address, data.size()));
|
||||
}
|
||||
|
||||
void Interpreter::call_address(Configuration& configuration, FunctionAddress address)
|
||||
void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAddress address)
|
||||
{
|
||||
auto instance = configuration.store().get(address);
|
||||
TRAP_IF_NOT(instance);
|
||||
|
@ -129,7 +129,7 @@ void Interpreter::call_address(Configuration& configuration, FunctionAddress add
|
|||
Result result { Trap {} };
|
||||
{
|
||||
Configuration::CallFrameHandle handle { configuration };
|
||||
result = configuration.call(address, move(args));
|
||||
result = configuration.call(*this, address, move(args));
|
||||
}
|
||||
|
||||
if (result.is_trap()) {
|
||||
|
@ -215,7 +215,7 @@ void Interpreter::call_address(Configuration& configuration, FunctionAddress add
|
|||
} while (false)
|
||||
|
||||
template<typename T>
|
||||
T Interpreter::read_value(ReadonlyBytes data)
|
||||
T BytecodeInterpreter::read_value(ReadonlyBytes data)
|
||||
{
|
||||
T value;
|
||||
InputMemoryStream stream { data };
|
||||
|
@ -226,7 +226,7 @@ T Interpreter::read_value(ReadonlyBytes data)
|
|||
}
|
||||
|
||||
template<>
|
||||
float Interpreter::read_value<float>(ReadonlyBytes data)
|
||||
float BytecodeInterpreter::read_value<float>(ReadonlyBytes data)
|
||||
{
|
||||
InputMemoryStream stream { data };
|
||||
LittleEndian<u32> raw_value;
|
||||
|
@ -237,7 +237,7 @@ float Interpreter::read_value<float>(ReadonlyBytes data)
|
|||
}
|
||||
|
||||
template<>
|
||||
double Interpreter::read_value<double>(ReadonlyBytes data)
|
||||
double BytecodeInterpreter::read_value<double>(ReadonlyBytes data)
|
||||
{
|
||||
InputMemoryStream stream { data };
|
||||
LittleEndian<u64> raw_value;
|
||||
|
@ -282,7 +282,7 @@ struct ConvertToRaw<double> {
|
|||
};
|
||||
|
||||
template<typename V, typename T>
|
||||
MakeSigned<T> Interpreter::checked_signed_truncate(V value)
|
||||
MakeSigned<T> BytecodeInterpreter::checked_signed_truncate(V value)
|
||||
{
|
||||
if (isnan(value) || isinf(value)) { // "undefined", let's just trap.
|
||||
m_do_trap = true;
|
||||
|
@ -305,7 +305,7 @@ MakeSigned<T> Interpreter::checked_signed_truncate(V value)
|
|||
}
|
||||
|
||||
template<typename V, typename T>
|
||||
MakeUnsigned<T> Interpreter::checked_unsigned_truncate(V value)
|
||||
MakeUnsigned<T> BytecodeInterpreter::checked_unsigned_truncate(V value)
|
||||
{
|
||||
if (isnan(value) || isinf(value)) { // "undefined", let's just trap.
|
||||
m_do_trap = true;
|
||||
|
@ -326,7 +326,7 @@ MakeUnsigned<T> Interpreter::checked_unsigned_truncate(V value)
|
|||
return true;
|
||||
}
|
||||
|
||||
Vector<Value> Interpreter::pop_values(Configuration& configuration, size_t count)
|
||||
Vector<Value> BytecodeInterpreter::pop_values(Configuration& configuration, size_t count)
|
||||
{
|
||||
Vector<Value> results;
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
|
@ -339,28 +339,10 @@ Vector<Value> Interpreter::pop_values(Configuration& configuration, size_t count
|
|||
return results;
|
||||
}
|
||||
|
||||
void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip, const Instruction& instruction)
|
||||
void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPointer& ip, const Instruction& instruction)
|
||||
{
|
||||
dbgln_if(WASM_TRACE_DEBUG, "Executing instruction {} at ip {}", instruction_name(instruction.opcode()), ip.value());
|
||||
|
||||
if (pre_interpret_hook && *pre_interpret_hook) {
|
||||
auto result = pre_interpret_hook->operator()(configuration, ip, instruction);
|
||||
if (!result) {
|
||||
m_do_trap = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ScopeGuard guard { [&] {
|
||||
if (post_interpret_hook && *post_interpret_hook) {
|
||||
auto result = post_interpret_hook->operator()(configuration, ip, instruction, *this);
|
||||
if (!result) {
|
||||
m_do_trap = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} };
|
||||
|
||||
switch (instruction.opcode().value()) {
|
||||
case Instructions::unreachable.value():
|
||||
m_do_trap = true;
|
||||
|
@ -912,4 +894,28 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerBytecodeInterpreter::interpret(Configuration& configuration, InstructionPointer& ip, const Instruction& instruction)
|
||||
{
|
||||
if (pre_interpret_hook) {
|
||||
auto result = pre_interpret_hook(configuration, ip, instruction);
|
||||
if (!result) {
|
||||
m_do_trap = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ScopeGuard guard { [&] {
|
||||
if (post_interpret_hook) {
|
||||
auto result = post_interpret_hook(configuration, ip, instruction, *this);
|
||||
if (!result) {
|
||||
m_do_trap = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} };
|
||||
|
||||
BytecodeInterpreter::interpret(configuration, ip, instruction);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue