1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-10 12:17:35 +00:00

LibWasm: Replace memory write macros with templated functions

This commit is contained in:
Ali Mohammad Pur 2021-08-11 22:16:05 +04:30 committed by Andreas Kling
parent b6381f785d
commit 4060f18d7e
2 changed files with 78 additions and 76 deletions

View file

@ -111,29 +111,6 @@ void BytecodeInterpreter::load_and_push(Configuration& configuration, Instructio
configuration.stack().peek() = Value(static_cast<PushType>(read_value<ReadType>(slice)));
}
void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruction const& instruction, ReadonlyBytes data)
{
auto& address = configuration.frame().module().memories().first();
auto memory = configuration.store().get(address);
TRAP_IF_NOT(memory);
auto& arg = instruction.arguments().get<Instruction::MemoryArgument>();
TRAP_IF_NOT(!configuration.stack().is_empty());
auto entry = configuration.stack().pop();
TRAP_IF_NOT(entry.has<Value>());
auto base = entry.get<Value>().to<i32>();
TRAP_IF_NOT(base.has_value());
u64 instance_address = static_cast<u64>(bit_cast<u32>(base.value())) + arg.offset;
Checked addition { instance_address };
addition += data.size();
if (addition.has_overflow() || addition.value() > memory->size()) {
m_trap = Trap { "Memory access out of bounds" };
dbgln("LibWasm: Memory access out of bounds (expected 0 <= {} and {} <= {})", instance_address, instance_address + data.size(), memory->size());
return;
}
dbgln_if(WASM_TRACE_DEBUG, "tempoaray({}b) -> store({})", data.size(), instance_address);
data.copy_to(memory->data().bytes().slice(instance_address, data.size()));
}
void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAddress address)
{
TRAP_IF_NOT(m_stack_info.size_free() >= Constants::minimum_stack_space_to_keep_free);
@ -224,16 +201,73 @@ void BytecodeInterpreter::unary_operation(Configuration& configuration)
configuration.stack().peek() = Value(result);
}
#define POP_AND_STORE(pop_type, store_type) \
do { \
TRAP_IF_NOT(!configuration.stack().is_empty()); \
auto entry = configuration.stack().pop(); \
TRAP_IF_NOT(entry.has<Value>()); \
auto value = ConvertToRaw<store_type> {}(*entry.get<Value>().to<pop_type>()); \
dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> temporary({}b)", value, sizeof(store_type)); \
store_to_memory(configuration, instruction, { &value, sizeof(store_type) }); \
return; \
} while (false)
template<typename T>
struct ConvertToRaw {
T operator()(T value)
{
return LittleEndian<T>(value);
}
};
template<>
struct ConvertToRaw<float> {
u32 operator()(float value)
{
LittleEndian<u32> res;
ReadonlyBytes bytes { &value, sizeof(float) };
InputMemoryStream stream { bytes };
stream >> res;
VERIFY(!stream.has_any_error());
return static_cast<u32>(res);
}
};
template<>
struct ConvertToRaw<double> {
u64 operator()(double value)
{
LittleEndian<u64> res;
ReadonlyBytes bytes { &value, sizeof(double) };
InputMemoryStream stream { bytes };
stream >> res;
VERIFY(!stream.has_any_error());
return static_cast<u64>(res);
}
};
template<typename PopT, typename StoreT>
void BytecodeInterpreter::pop_and_store(Configuration& configuration, Instruction const& instruction)
{
TRAP_IF_NOT(!configuration.stack().is_empty());
auto entry = configuration.stack().pop();
TRAP_IF_NOT(entry.has<Value>());
auto value = ConvertToRaw<StoreT> {}(*entry.get<Value>().to<PopT>());
dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> temporary({}b)", value, sizeof(StoreT));
store_to_memory(configuration, instruction, { &value, sizeof(StoreT) });
}
void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruction const& instruction, ReadonlyBytes data)
{
auto& address = configuration.frame().module().memories().first();
auto memory = configuration.store().get(address);
TRAP_IF_NOT(memory);
auto& arg = instruction.arguments().get<Instruction::MemoryArgument>();
TRAP_IF_NOT(!configuration.stack().is_empty());
auto entry = configuration.stack().pop();
TRAP_IF_NOT(entry.has<Value>());
auto base = entry.get<Value>().to<i32>();
TRAP_IF_NOT(base.has_value());
u64 instance_address = static_cast<u64>(bit_cast<u32>(base.value())) + arg.offset;
Checked addition { instance_address };
addition += data.size();
if (addition.has_overflow() || addition.value() > memory->size()) {
m_trap = Trap { "Memory access out of bounds" };
dbgln("LibWasm: Memory access out of bounds (expected 0 <= {} and {} <= {})", instance_address, instance_address + data.size(), memory->size());
return;
}
dbgln_if(WASM_TRACE_DEBUG, "tempoaray({}b) -> store({})", data.size(), instance_address);
data.copy_to(memory->data().bytes().slice(instance_address, data.size()));
}
template<typename T>
T BytecodeInterpreter::read_value(ReadonlyBytes data)
@ -270,40 +304,6 @@ double BytecodeInterpreter::read_value<double>(ReadonlyBytes data)
return bit_cast<double>(static_cast<u64>(raw_value));
}
template<typename T>
struct ConvertToRaw {
T operator()(T value)
{
return LittleEndian<T>(value);
}
};
template<>
struct ConvertToRaw<float> {
u32 operator()(float value)
{
LittleEndian<u32> res;
ReadonlyBytes bytes { &value, sizeof(float) };
InputMemoryStream stream { bytes };
stream >> res;
VERIFY(!stream.has_any_error());
return static_cast<u32>(res);
}
};
template<>
struct ConvertToRaw<double> {
u64 operator()(double value)
{
LittleEndian<u64> res;
ReadonlyBytes bytes { &value, sizeof(double) };
InputMemoryStream stream { bytes };
stream >> res;
VERIFY(!stream.has_any_error());
return static_cast<u64>(res);
}
};
template<typename V, typename T>
MakeSigned<T> BytecodeInterpreter::checked_signed_truncate(V value)
{
@ -550,23 +550,23 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi
case Instructions::i64_load32_u.value():
return load_and_push<u32, i64>(configuration, instruction);
case Instructions::i32_store.value():
POP_AND_STORE(i32, i32);
return pop_and_store<i32, i32>(configuration, instruction);
case Instructions::i64_store.value():
POP_AND_STORE(i64, i64);
return pop_and_store<i64, i64>(configuration, instruction);
case Instructions::f32_store.value():
POP_AND_STORE(float, float);
return pop_and_store<float, float>(configuration, instruction);
case Instructions::f64_store.value():
POP_AND_STORE(double, double);
return pop_and_store<double, double>(configuration, instruction);
case Instructions::i32_store8.value():
POP_AND_STORE(i32, i8);
return pop_and_store<i32, i8>(configuration, instruction);
case Instructions::i32_store16.value():
POP_AND_STORE(i32, i16);
return pop_and_store<i32, i16>(configuration, instruction);
case Instructions::i64_store8.value():
POP_AND_STORE(i64, i8);
return pop_and_store<i64, i8>(configuration, instruction);
case Instructions::i64_store16.value():
POP_AND_STORE(i64, i16);
return pop_and_store<i64, i16>(configuration, instruction);
case Instructions::i64_store32.value():
POP_AND_STORE(i64, i32);
return pop_and_store<i64, i32>(configuration, instruction);
case Instructions::local_tee.value(): {
TRAP_IF_NOT(!configuration.stack().is_empty());
auto& entry = configuration.stack().peek();