diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index f3d5922ef9e..cecbce36246 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -36,6 +36,9 @@ Optional Store::allocate(TableType const& type) { TableAddress address { m_tables.size() }; Vector elements; + elements.ensure_capacity(type.limits().min()); + for (size_t i = 0; i < type.limits().min(); i++) + elements.append(Wasm::Reference { Wasm::Reference::Null { type.element_type() } }); elements.resize(type.limits().min()); m_tables.empend(TableInstance { type, move(elements) }); return address; diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index 0bab4898c80..3d807043914 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -74,9 +74,25 @@ private: class Value { public: - Value() + explicit Value(ValueType type) : m_value(u128()) { + switch (type.kind()) { + case ValueType::I32: + case ValueType::I64: + case ValueType::F32: + case ValueType::F64: + case ValueType::V128: + break; + case ValueType::FunctionReference: + // ref.null funcref + m_value = u128(0, 2); + break; + case ValueType::ExternReference: + // ref.null externref + m_value = u128(0, 3); + break; + } } template diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp index 28c8d91917a..fab66867ced 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp @@ -28,7 +28,7 @@ Result Configuration::call(Interpreter& interpreter, FunctionAddress address, Ve locals.ensure_capacity(locals.size() + wasm_function->code().func().locals().size()); for (auto& local : wasm_function->code().func().locals()) { for (size_t i = 0; i < local.n(); ++i) - locals.append(Value()); + locals.append(Value(local.type())); } set_frame(Frame { diff --git a/Userland/Libraries/LibWasm/WASI/Wasi.cpp b/Userland/Libraries/LibWasm/WASI/Wasi.cpp index f77c5e74b47..6d2f8341f5c 100644 --- a/Userland/Libraries/LibWasm/WASI/Wasi.cpp +++ b/Userland/Libraries/LibWasm/WASI/Wasi.cpp @@ -1040,7 +1040,7 @@ struct InvocationOf { } } // Return value is errno, we have nothing to return. - return Wasm::Result { Vector { Value() } }; + return Wasm::Result { Vector { Value(ValueType(ValueType::Kind::I32)) } }; }, FunctionType { move(arguments_types), diff --git a/Userland/Libraries/LibWeb/WebAssembly/Table.cpp b/Userland/Libraries/LibWeb/WebAssembly/Table.cpp index 50941c8739d..2d0b86b1832 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/Table.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/Table.cpp @@ -31,8 +31,8 @@ static Wasm::ValueType table_kind_to_value_type(Bindings::TableKind kind) static JS::ThrowCompletionOr value_to_reference(JS::VM& vm, JS::Value value, Wasm::ValueType const& reference_type) { - if (value.is_undefined()) - return Wasm::Value(); + if (value.is_undefined() && reference_type.kind() != Wasm::ValueType::Kind::ExternReference) + return Wasm::Value(reference_type); return Detail::to_webassembly_value(vm, value, reference_type); } diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index 94901a5c1df..7d6644743db 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -46,6 +46,7 @@ void visit_edges(JS::Object& object, JS::Cell::Visitor& visitor) auto& cache = maybe_cache.release_value(); visitor.visit(cache.function_instances()); visitor.visit(cache.imported_objects()); + visitor.visit(cache.extern_values()); } } @@ -422,7 +423,7 @@ JS::ThrowCompletionOr to_webassembly_value(JS::VM& vm, JS::Value va } case Wasm::ValueType::FunctionReference: { if (value.is_null()) - return Wasm::Value(); + return Wasm::Value(Wasm::ValueType { Wasm::ValueType::Kind::FunctionReference }); if (value.is_function()) { auto& function = value.as_function(); @@ -435,8 +436,18 @@ JS::ThrowCompletionOr to_webassembly_value(JS::VM& vm, JS::Value va return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "Exported function"); } - case Wasm::ValueType::ExternReference: - TODO(); + case Wasm::ValueType::ExternReference: { + if (value.is_null()) + return Wasm::Value(Wasm::ValueType { Wasm::ValueType::Kind::ExternReference }); + auto& cache = get_cache(*vm.current_realm()); + for (auto& entry : cache.extern_values()) { + if (entry.value == value) + return Wasm::Value { Wasm::Reference { Wasm::Reference::Extern { entry.key } } }; + } + Wasm::ExternAddress extern_addr = cache.extern_values().size(); + cache.add_extern_value(extern_addr, value); + return Wasm::Value { Wasm::Reference { Wasm::Reference::Extern { extern_addr } } }; + } case Wasm::ValueType::V128: return vm.throw_completion("Cannot convert a vector value to a javascript value"sv); } @@ -444,6 +455,7 @@ JS::ThrowCompletionOr to_webassembly_value(JS::VM& vm, JS::Value va VERIFY_NOT_REACHED(); } +// https://webassembly.github.io/spec/js-api/#tojsvalue JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value, Wasm::ValueType type) { auto& realm = *vm.current_realm(); @@ -473,9 +485,17 @@ JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value, Wasm::ValueType type) }); return create_native_function(vm, address, name); } + case Wasm::ValueType::ExternReference: { + auto ref_ = wasm_value.to(); + if (ref_.ref().has()) + return JS::js_null(); + auto address = ref_.ref().get().address; + auto& cache = get_cache(realm); + auto value = cache.get_extern_value(address); + return value.release_value(); + } case Wasm::ValueType::V128: - case Wasm::ValueType::ExternReference: - TODO(); + VERIFY_NOT_REACHED(); } VERIFY_NOT_REACHED(); } diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h index 78bbf3a6f5a..2ed611cfe04 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h @@ -42,15 +42,19 @@ public: void add_compiled_module(NonnullRefPtr module) { m_compiled_modules.append(module); } void add_function_instance(Wasm::FunctionAddress address, JS::GCPtr function) { m_function_instances.set(address, function); } void add_imported_object(JS::GCPtr object) { m_imported_objects.set(object); } + void add_extern_value(Wasm::ExternAddress address, JS::Value value) { m_extern_values.set(address, value); } Optional> get_function_instance(Wasm::FunctionAddress address) { return m_function_instances.get(address); } + Optional get_extern_value(Wasm::ExternAddress address) { return m_extern_values.get(address); } HashMap> function_instances() const { return m_function_instances; } + HashMap extern_values() const { return m_extern_values; } HashTable> imported_objects() const { return m_imported_objects; } Wasm::AbstractMachine& abstract_machine() { return m_abstract_machine; } private: HashMap> m_function_instances; + HashMap m_extern_values; Vector> m_compiled_modules; HashTable> m_imported_objects; Wasm::AbstractMachine m_abstract_machine; diff --git a/Userland/Utilities/wasm.cpp b/Userland/Utilities/wasm.cpp index 9e374eb6823..246051628e8 100644 --- a/Userland/Utilities/wasm.cpp +++ b/Userland/Utilities/wasm.cpp @@ -726,8 +726,8 @@ ErrorOr serenity_main(Main::Arguments arguments) dbgln("[wasm runtime] Stub function {} was called with the following arguments: {}", name, argument_builder.to_byte_string()); Vector result; result.ensure_capacity(type.results().size()); - for (size_t i = 0; i < type.results().size(); ++i) - result.append(Wasm::Value()); + for (auto expect_result : type.results()) + result.append(Wasm::Value(expect_result)); return Wasm::Result { move(result) }; }, type, @@ -818,7 +818,7 @@ ErrorOr serenity_main(Main::Arguments arguments) for (auto& param : instance->get().type().parameters()) { if (values_to_push.is_empty()) { - values.append(Wasm::Value()); + values.append(Wasm::Value(param)); } else if (param == values_to_push.last().type) { values.append(values_to_push.take_last().value); } else {