mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-19 07:22:21 +00:00
LibWasm: Make traps hold on to externally-managed data
...instead of specially handling JS::Completion. This makes it possible for LibWeb/LibJS to have full control over how these things are made, stored, and visited (whenever). Fixes an issue where we couldn't roundtrip a JS exception through Wasm.
This commit is contained in:
parent
7b2a427430
commit
51bab5b186
Notes:
github-actions[bot]
2025-04-22 14:45:25 +00:00
Author: https://github.com/alimpfard
Commit: 51bab5b186
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4423
Reviewed-by: https://github.com/ADKaster ✅
11 changed files with 176 additions and 111 deletions
|
@ -42,7 +42,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration)
|
|||
while (current_ip_value < max_ip_value) {
|
||||
if (should_limit_instruction_count) {
|
||||
if (executed_instructions++ >= Constants::max_allowed_executed_instructions_per_call) [[unlikely]] {
|
||||
m_trap = Trap { "Exceeded maximum allowed number of instructions" };
|
||||
m_trap = Trap::from_string("Exceeded maximum allowed number of instructions");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ void BytecodeInterpreter::load_and_push(Configuration& configuration, Instructio
|
|||
auto base = entry.to<i32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + arg.offset;
|
||||
if (instance_address + sizeof(ReadType) > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
m_trap = Trap::from_string("Memory access out of bounds");
|
||||
dbgln("LibWasm: Memory access out of bounds (expected {} to be less than or equal to {})", instance_address + sizeof(ReadType), memory->size());
|
||||
return;
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ void BytecodeInterpreter::load_and_push_mxn(Configuration& configuration, Instru
|
|||
auto base = entry.to<i32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + arg.offset;
|
||||
if (instance_address + M * N / 8 > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
m_trap = Trap::from_string("Memory access out of bounds");
|
||||
dbgln("LibWasm: Memory access out of bounds (expected {} to be less than or equal to {})", instance_address + M * N / 8, memory->size());
|
||||
return;
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ void BytecodeInterpreter::load_and_push_lane_n(Configuration& configuration, Ins
|
|||
auto base = configuration.value_stack().take_last().to<u32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + memarg_and_lane.memory.offset;
|
||||
if (instance_address + N / 8 > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
m_trap = Trap::from_string("Memory access out of bounds");
|
||||
return;
|
||||
}
|
||||
auto slice = memory->data().bytes().slice(instance_address, N / 8);
|
||||
|
@ -149,7 +149,7 @@ void BytecodeInterpreter::load_and_push_zero_n(Configuration& configuration, Ins
|
|||
auto base = configuration.value_stack().take_last().to<u32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + memarg_and_lane.offset;
|
||||
if (instance_address + N / 8 > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
m_trap = Trap::from_string("Memory access out of bounds");
|
||||
return;
|
||||
}
|
||||
auto slice = memory->data().bytes().slice(instance_address, N / 8);
|
||||
|
@ -168,7 +168,7 @@ void BytecodeInterpreter::load_and_push_m_splat(Configuration& configuration, In
|
|||
auto base = entry.to<i32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + arg.offset;
|
||||
if (instance_address + M / 8 > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
m_trap = Trap::from_string("Memory access out of bounds");
|
||||
dbgln("LibWasm: Memory access out of bounds (expected {} to be less than or equal to {})", instance_address + M / 8, memory->size());
|
||||
return;
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd
|
|||
|
||||
configuration.value_stack().remove(configuration.value_stack().size() - span.size(), span.size());
|
||||
|
||||
Result result { Trap { ""sv } };
|
||||
Result result { Trap::from_string("") };
|
||||
if (instance->has<WasmFunction>()) {
|
||||
CallFrameHandle handle { *this, configuration };
|
||||
result = configuration.call(*this, address, move(args));
|
||||
|
@ -251,11 +251,6 @@ void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd
|
|||
return;
|
||||
}
|
||||
|
||||
if (result.is_completion()) {
|
||||
m_trap = move(result.completion());
|
||||
return;
|
||||
}
|
||||
|
||||
configuration.value_stack().ensure_capacity(configuration.value_stack().size() + result.values().size());
|
||||
for (auto& entry : result.values().in_reverse())
|
||||
configuration.value_stack().unchecked_append(entry);
|
||||
|
@ -361,7 +356,7 @@ void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruct
|
|||
Checked addition { instance_address };
|
||||
addition += data.size();
|
||||
if (addition.has_overflow() || addition.value() > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
m_trap = Trap::from_string("Memory access out of bounds");
|
||||
dbgln("LibWasm: Memory access out of bounds (expected 0 <= {} and {} <= {})", instance_address, instance_address + data.size(), memory->size());
|
||||
return;
|
||||
}
|
||||
|
@ -376,7 +371,7 @@ T BytecodeInterpreter::read_value(ReadonlyBytes data)
|
|||
auto value_or_error = stream.read_value<LittleEndian<T>>();
|
||||
if (value_or_error.is_error()) {
|
||||
dbgln("Read from {} failed", data.data());
|
||||
m_trap = Trap { "Read from memory failed" };
|
||||
m_trap = Trap::from_string("Read from memory failed");
|
||||
}
|
||||
return value_or_error.release_value();
|
||||
}
|
||||
|
@ -387,7 +382,7 @@ float BytecodeInterpreter::read_value<float>(ReadonlyBytes data)
|
|||
FixedMemoryStream stream { data };
|
||||
auto raw_value_or_error = stream.read_value<LittleEndian<u32>>();
|
||||
if (raw_value_or_error.is_error())
|
||||
m_trap = Trap { "Read from memory failed" };
|
||||
m_trap = Trap::from_string("Read from memory failed");
|
||||
auto raw_value = raw_value_or_error.release_value();
|
||||
return bit_cast<float>(static_cast<u32>(raw_value));
|
||||
}
|
||||
|
@ -398,7 +393,7 @@ double BytecodeInterpreter::read_value<double>(ReadonlyBytes data)
|
|||
FixedMemoryStream stream { data };
|
||||
auto raw_value_or_error = stream.read_value<LittleEndian<u64>>();
|
||||
if (raw_value_or_error.is_error())
|
||||
m_trap = Trap { "Read from memory failed" };
|
||||
m_trap = Trap::from_string("Read from memory failed");
|
||||
auto raw_value = raw_value_or_error.release_value();
|
||||
return bit_cast<double>(static_cast<u64>(raw_value));
|
||||
}
|
||||
|
@ -409,7 +404,7 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
|
||||
switch (instruction.opcode().value()) {
|
||||
case Instructions::unreachable.value():
|
||||
m_trap = Trap { "Unreachable" };
|
||||
m_trap = Trap::from_string("Unreachable");
|
||||
return;
|
||||
case Instructions::nop.value():
|
||||
return;
|
||||
|
@ -1659,7 +1654,7 @@ void DebuggerBytecodeInterpreter::interpret_instruction(Configuration& configura
|
|||
if (pre_interpret_hook) {
|
||||
auto result = pre_interpret_hook(configuration, ip, instruction);
|
||||
if (!result) {
|
||||
m_trap = Trap { "Trapped by user request" };
|
||||
m_trap = Trap::from_string("Trapped by user request");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1669,7 +1664,7 @@ void DebuggerBytecodeInterpreter::interpret_instruction(Configuration& configura
|
|||
if (post_interpret_hook) {
|
||||
auto result = post_interpret_hook(configuration, ip, instruction, *this);
|
||||
if (!result) {
|
||||
m_trap = Trap { "Trapped by user request" };
|
||||
m_trap = Trap::from_string("Trapped by user request");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue