diff options
-rw-r--r-- | Tests/LibWasm/test-wasm.cpp | 9 | ||||
-rw-r--r-- | Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h | 20 | ||||
-rw-r--r-- | Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp | 25 | ||||
-rw-r--r-- | Userland/Libraries/LibWasm/Types.h | 8 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp | 5 | ||||
-rw-r--r-- | Userland/Utilities/wasm.cpp | 8 |
8 files changed, 73 insertions, 9 deletions
diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index 0ecd294ec6..ecd89f8932 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -190,6 +190,12 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) case Wasm::ValueType::Kind::ExternReference: arguments.append(Wasm::Value(Wasm::ExternAddress { static_cast<u64>(value) })); break; + case Wasm::ValueType::Kind::NullFunctionReference: + arguments.append(Wasm::Value(Wasm::Value::Null { Wasm::ValueType(Wasm::ValueType::Kind::FunctionReference) })); + break; + case Wasm::ValueType::Kind::NullExternReference: + arguments.append(Wasm::Value(Wasm::Value::Null { Wasm::ValueType(Wasm::ValueType::Kind::ExternReference) })); + break; } } @@ -206,6 +212,7 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) result.values().first().value().visit( [&](const auto& value) { return_value = JS::Value(static_cast<double>(value)); }, [&](const Wasm::FunctionAddress& index) { return_value = JS::Value(static_cast<double>(index.value())); }, - [&](const Wasm::ExternAddress& index) { return_value = JS::Value(static_cast<double>(index.value())); }); + [&](const Wasm::ExternAddress& index) { return_value = JS::Value(static_cast<double>(index.value())); }, + [&](const Wasm::Value::Null&) { return_value = JS::js_null(); }); return return_value; } diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 2daca7ab14..592c90223c 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -152,7 +152,8 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex result.values().first().value().visit( [&](const auto& value) { offset = value; }, [&](const FunctionAddress&) { instantiation_result = InstantiationError { "Data segment offset returned an address" }; }, - [&](const ExternAddress&) { instantiation_result = InstantiationError { "Data segment offset returned an address" }; }); + [&](const ExternAddress&) { instantiation_result = InstantiationError { "Data segment offset returned an address" }; }, + [&](const Value::Null&) { instantiation_result = InstantiationError { "Data segment offset returned a null reference" }; }); if (instantiation_result.has_value() && instantiation_result->is_error()) return; if (main_module_instance.memories().size() <= data.index.value()) { diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index 98db12d9ab..b7b49b664b 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -45,7 +45,11 @@ public: { } - using AnyValueType = Variant<i32, i64, float, double, FunctionAddress, ExternAddress>; + struct Null { + ValueType type; + }; + + using AnyValueType = Variant<i32, i64, float, double, FunctionAddress, ExternAddress, Null>; explicit Value(AnyValueType value) : m_value(move(value)) , m_type(ValueType::I32) @@ -62,6 +66,8 @@ public: m_type = ValueType { ValueType::FunctionReference }; else if (m_value.has<ExternAddress>()) m_type = ValueType { ValueType::ExternReference }; + else if (m_value.has<Null>()) + m_type = ValueType { m_value.get<Null>().type.kind() == ValueType::ExternReference ? ValueType::NullExternReference : ValueType::NullFunctionReference }; else VERIFY_NOT_REACHED(); } @@ -90,6 +96,14 @@ public: case ValueType::Kind::F64: m_value = bit_cast<double>(raw_value); break; + case ValueType::Kind::NullFunctionReference: + VERIFY(raw_value == 0); + m_value = Null { ValueType(ValueType::Kind::FunctionReference) }; + break; + case ValueType::Kind::NullExternReference: + VERIFY(raw_value == 0); + m_value = Null { ValueType(ValueType::Kind::ExternReference) }; + break; default: VERIFY_NOT_REACHED(); } @@ -139,6 +153,10 @@ public: [&](const ExternAddress& address) { if constexpr (IsSame<T, ExternAddress>) result = address; + }, + [&](const Null& null) { + if constexpr (IsSame<T, Null>) + result = null; }); return result; } diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp index 4a27fcbd49..fcfd14ddee 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp @@ -85,6 +85,8 @@ void Configuration::dump_stack() v.value().visit([]<typename T>(const T& v) { if constexpr (IsIntegral<T> || IsFloatingPoint<T>) dbgln(" {}", v); + else if constexpr (IsSame<Value::Null, T>) + dbgln(" *null"); else dbgln(" *{}", v.value()); }); @@ -95,6 +97,8 @@ void Configuration::dump_stack() local.value().visit([]<typename T>(const T& v) { if constexpr (IsIntegral<T> || IsFloatingPoint<T>) dbgln(" {}", v); + else if constexpr (IsSame<Value::Null, T>) + dbgln(" *null"); else dbgln(" *{}", v.value()); }); diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp index efeec9a304..dbce68e6e7 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp @@ -590,10 +590,29 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi } case Instructions::table_get.value(): case Instructions::table_set.value(): - case Instructions::ref_null.value(): - case Instructions::ref_func.value(): - case Instructions::ref_is_null.value(): goto unimplemented; + case Instructions::ref_null.value(): { + auto type = instruction.arguments().get<ValueType>(); + TRAP_IF_NOT(type.is_reference()); + configuration.stack().push(Value(Value::Null { type })); + return; + }; + case Instructions::ref_func.value(): { + auto index = instruction.arguments().get<FunctionIndex>().value(); + auto& functions = configuration.frame().module().functions(); + TRAP_IF_NOT(functions.size() > index); + auto address = functions[index]; + configuration.stack().push(Value(ValueType(ValueType::FunctionReference), address.value())); + return; + } + case Instructions::ref_is_null.value(): { + auto top = configuration.stack().peek().get_pointer<Value>(); + TRAP_IF_NOT(top); + TRAP_IF_NOT(top->type().is_reference()); + auto is_null = top->to<Value::Null>().has_value(); + configuration.stack().peek() = Value(ValueType(ValueType::I32), static_cast<u64>(is_null ? 1 : 0)); + return; + } case Instructions::drop.value(): configuration.stack().pop(); return; diff --git a/Userland/Libraries/LibWasm/Types.h b/Userland/Libraries/LibWasm/Types.h index 9134af6272..bb0299b38a 100644 --- a/Userland/Libraries/LibWasm/Types.h +++ b/Userland/Libraries/LibWasm/Types.h @@ -170,6 +170,8 @@ public: F64, FunctionReference, ExternReference, + NullFunctionReference, + NullExternReference, }; explicit ValueType(Kind kind) @@ -177,7 +179,7 @@ public: { } - auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference; } + auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference || m_kind == NullExternReference || m_kind == NullFunctionReference; } auto is_numeric() const { return !is_reference(); } auto kind() const { return m_kind; } @@ -198,6 +200,10 @@ public: return "funcref"; case ExternReference: return "externref"; + case NullFunctionReference: + return "ref.null externref"; + case NullExternReference: + return "ref.null funcref"; } VERIFY_NOT_REACHED(); } diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp index a8e8f82c8c..b4bd033dc4 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp @@ -262,7 +262,10 @@ JS::Value to_js_value(Wasm::Value& wasm_value, JS::GlobalObject& global_object) case Wasm::ValueType::FunctionReference: // FIXME: What's the name of a function reference that isn't exported? return create_native_function(wasm_value.to<Wasm::FunctionAddress>().value(), "FIXME_IHaveNoIdeaWhatThisShouldBeCalled", global_object); + case Wasm::ValueType::NullFunctionReference: + return JS::js_null(); case Wasm::ValueType::ExternReference: + case Wasm::ValueType::NullExternReference: TODO(); } VERIFY_NOT_REACHED(); @@ -304,6 +307,8 @@ Optional<Wasm::Value> to_webassembly_value(JS::Value value, const Wasm::ValueTyp } case Wasm::ValueType::FunctionReference: case Wasm::ValueType::ExternReference: + case Wasm::ValueType::NullFunctionReference: + case Wasm::ValueType::NullExternReference: TODO(); } diff --git a/Userland/Utilities/wasm.cpp b/Userland/Utilities/wasm.cpp index f9a2d97dc5..5b1d7f786d 100644 --- a/Userland/Utilities/wasm.cpp +++ b/Userland/Utilities/wasm.cpp @@ -202,9 +202,11 @@ static bool pre_interpret_hook(Wasm::Configuration& config, Wasm::InstructionPoi warnln("Returned:"); for (auto& value : result.values()) { auto str = value.value().visit( - [&](const auto& value) { + [&]<typename T>(const T& value) { if constexpr (requires { value.value(); }) return String::formatted(" -> addr{} ", value.value()); + else if constexpr (IsSame<Wasm::Value::Null, T>) + return String::formatted(" ->addr(null)"); else return String::formatted(" -> {} ", value); }); @@ -460,9 +462,11 @@ int main(int argc, char* argv[]) warnln("Returned:"); for (auto& value : result.values()) { value.value().visit( - [&](const auto& value) { + [&]<typename T>(const T& value) { if constexpr (requires { value.value(); }) out(" -> addr{} ", value.value()); + else if constexpr (IsSame<Wasm::Value::Null, T>) + out(" ->addr(null)"); else out(" -> {} ", value); }); |