summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWasm/AbstractMachine
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2023-02-25 11:15:11 +0330
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2023-02-26 10:54:23 +0330
commit6b50f232426742fcf9e71420c37bf4831bca2e31 (patch)
treebb6a8545d01d0e60e7b5274d835e97d772dcf4d9 /Userland/Libraries/LibWasm/AbstractMachine
parent1c3050245ea7660bec230c397ca1046bdf083bd2 (diff)
downloadserenity-6b50f232426742fcf9e71420c37bf4831bca2e31.zip
LibWasm+LibWeb: Sneak a JS::Completion into Wasm::Result
Imported functions in Wasm may throw JS exceptions, and we need to preserve these exceptions so we can pass them to the calling JS code. This also adds a `assert_wasm_result()` API to Result for cases where only Wasm traps or values are expected (e.g. internal uses) to avoid making LibWasm (pointlessly) handle JS exceptions that will never show up in reality.
Diffstat (limited to 'Userland/Libraries/LibWasm/AbstractMachine')
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp8
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h54
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp9
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h16
4 files changed, 75 insertions, 12 deletions
diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp
index ddc8cc4538..d3d962b8ce 100644
--- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp
+++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp
@@ -175,7 +175,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
entry.expression(),
1,
});
- auto result = config.execute(interpreter);
+ auto result = config.execute(interpreter).assert_wasm_result();
if (result.is_trap())
instantiation_result = InstantiationError { DeprecatedString::formatted("Global value construction trapped: {}", result.trap().reason) };
else
@@ -202,7 +202,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
entry,
entry.instructions().size(),
});
- auto result = config.execute(interpreter);
+ auto result = config.execute(interpreter).assert_wasm_result();
if (result.is_trap()) {
instantiation_result = InstantiationError { DeprecatedString::formatted("Element construction trapped: {}", result.trap().reason) };
return IterationDecision::Continue;
@@ -255,7 +255,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
active_ptr->expression,
1,
});
- auto result = config.execute(interpreter);
+ auto result = config.execute(interpreter).assert_wasm_result();
if (result.is_trap()) {
instantiation_result = InstantiationError { DeprecatedString::formatted("Element section initialisation trapped: {}", result.trap().reason) };
return IterationDecision::Break;
@@ -315,7 +315,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
data.offset,
1,
});
- auto result = config.execute(interpreter);
+ auto result = config.execute(interpreter).assert_wasm_result();
if (result.is_trap()) {
instantiation_result = InstantiationError { DeprecatedString::formatted("Data section initialisation trapped: {}", result.trap().reason) };
return;
diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h
index d94c541826..b08120ffd2 100644
--- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h
+++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h
@@ -13,6 +13,9 @@
#include <AK/Result.h>
#include <LibWasm/Types.h>
+// NOTE: Special case for Wasm::Result.
+#include <LibJS/Runtime/Completion.h>
+
namespace Wasm {
class Configuration;
@@ -171,6 +174,35 @@ struct Trap {
DeprecatedString reason;
};
+// A variant of Result that does not include external reasons for error (JS::Completion, for now).
+class PureResult {
+public:
+ explicit PureResult(Vector<Value> values)
+ : m_result(move(values))
+ {
+ }
+
+ PureResult(Trap trap)
+ : m_result(move(trap))
+ {
+ }
+
+ auto is_trap() const { return m_result.has<Trap>(); }
+ auto& values() const { return m_result.get<Vector<Value>>(); }
+ auto& values() { return m_result.get<Vector<Value>>(); }
+ auto& trap() const { return m_result.get<Trap>(); }
+ auto& trap() { return m_result.get<Trap>(); }
+
+private:
+ friend class Result;
+ explicit PureResult(Variant<Vector<Value>, Trap>&& result)
+ : m_result(move(result))
+ {
+ }
+
+ Variant<Vector<Value>, Trap> m_result;
+};
+
class Result {
public:
explicit Result(Vector<Value> values)
@@ -183,14 +215,34 @@ public:
{
}
+ Result(JS::Completion completion)
+ : m_result(move(completion))
+ {
+ VERIFY(m_result.get<JS::Completion>().is_abrupt());
+ }
+
+ Result(PureResult&& result)
+ : m_result(result.m_result.downcast<decltype(m_result)>())
+ {
+ }
+
auto is_trap() const { return m_result.has<Trap>(); }
+ auto is_completion() const { return m_result.has<JS::Completion>(); }
auto& values() const { return m_result.get<Vector<Value>>(); }
auto& values() { return m_result.get<Vector<Value>>(); }
auto& trap() const { return m_result.get<Trap>(); }
auto& trap() { return m_result.get<Trap>(); }
+ auto& completion() { return m_result.get<JS::Completion>(); }
+ auto& completion() const { return m_result.get<JS::Completion>(); }
+
+ PureResult assert_wasm_result() &&
+ {
+ VERIFY(!is_completion());
+ return PureResult(move(m_result).downcast<Vector<Value>, Trap>());
+ }
private:
- Variant<Vector<Value>, Trap> m_result;
+ Variant<Vector<Value>, Trap, JS::Completion> m_result;
};
using ExternValue = Variant<FunctionAddress, TableAddress, MemoryAddress, GlobalAddress>;
diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp
index 2e11c1ccf1..ee5baaaf17 100644
--- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp
+++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp
@@ -34,7 +34,7 @@ namespace Wasm {
void BytecodeInterpreter::interpret(Configuration& configuration)
{
- m_trap.clear();
+ m_trap = Empty {};
auto& instructions = configuration.frame().expression().instructions();
auto max_ip_value = InstructionPointer { instructions.size() };
auto& current_ip_value = configuration.ip();
@@ -51,7 +51,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration)
auto& instruction = instructions[current_ip_value.value()];
auto old_ip = current_ip_value;
interpret(configuration, current_ip_value, instruction);
- if (m_trap.has_value())
+ if (did_trap())
return;
if (current_ip_value == old_ip) // If no jump occurred
++current_ip_value;
@@ -140,6 +140,11 @@ void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd
return;
}
+ if (result.is_completion()) {
+ m_trap = move(result.completion());
+ return;
+ }
+
configuration.stack().entries().ensure_capacity(configuration.stack().size() + result.values().size());
for (auto& entry : result.values().in_reverse())
configuration.stack().entries().unchecked_append(move(entry));
diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h
index 55ffc1eeec..9cb1385d30 100644
--- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h
+++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h
@@ -15,9 +15,15 @@ namespace Wasm {
struct BytecodeInterpreter : public Interpreter {
virtual void interpret(Configuration&) override;
virtual ~BytecodeInterpreter() override = default;
- virtual bool did_trap() const override { return m_trap.has_value(); }
- virtual DeprecatedString trap_reason() const override { return m_trap.value().reason; }
- virtual void clear_trap() override { m_trap.clear(); }
+ virtual bool did_trap() const override { return !m_trap.has<Empty>(); }
+ virtual DeprecatedString trap_reason() const override
+ {
+ return m_trap.visit(
+ [](Empty) -> DeprecatedString { VERIFY_NOT_REACHED(); },
+ [](Trap const& trap) { return trap.reason; },
+ [](JS::Completion const& completion) { return completion.value()->to_string_without_side_effects().release_value().to_deprecated_string(); });
+ }
+ virtual void clear_trap() override { m_trap = Empty {}; }
struct CallFrameHandle {
explicit CallFrameHandle(BytecodeInterpreter& interpreter, Configuration& configuration)
@@ -62,10 +68,10 @@ protected:
{
if (!value)
m_trap = Trap { reason };
- return m_trap.has_value();
+ return !m_trap.has<Empty>();
}
- Optional<Trap> m_trap;
+ Variant<Trap, JS::Completion, Empty> m_trap;
StackInfo m_stack_info;
};