LibWasm+LibWeb: Allow tables to have externrefs in the JS API

This commit is contained in:
Diego Frias 2024-08-17 15:40:21 -07:00 committed by Ali Mohammad Pur
parent fc83653f3c
commit 4e7d3026d2
Notes: github-actions[bot] 2024-08-18 21:36:13 +00:00
8 changed files with 56 additions and 13 deletions

View file

@ -36,6 +36,9 @@ Optional<TableAddress> Store::allocate(TableType const& type)
{
TableAddress address { m_tables.size() };
Vector<Reference> 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;

View file

@ -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<typename T>

View file

@ -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 {

View file

@ -1040,7 +1040,7 @@ struct InvocationOf<impl> {
}
}
// Return value is errno, we have nothing to return.
return Wasm::Result { Vector<Value> { Value() } };
return Wasm::Result { Vector<Value> { Value(ValueType(ValueType::Kind::I32)) } };
},
FunctionType {
move(arguments_types),

View file

@ -31,8 +31,8 @@ static Wasm::ValueType table_kind_to_value_type(Bindings::TableKind kind)
static JS::ThrowCompletionOr<Wasm::Value> 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);
}

View file

@ -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<Wasm::Value> 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<Wasm::Value> to_webassembly_value(JS::VM& vm, JS::Value va
return vm.throw_completion<JS::TypeError>(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<JS::TypeError>("Cannot convert a vector value to a javascript value"sv);
}
@ -444,6 +455,7 @@ JS::ThrowCompletionOr<Wasm::Value> 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<Wasm::Reference>();
if (ref_.ref().has<Wasm::Reference::Null>())
return JS::js_null();
auto address = ref_.ref().get<Wasm::Reference::Extern>().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();
}

View file

@ -42,15 +42,19 @@ public:
void add_compiled_module(NonnullRefPtr<CompiledWebAssemblyModule> module) { m_compiled_modules.append(module); }
void add_function_instance(Wasm::FunctionAddress address, JS::GCPtr<JS::NativeFunction> function) { m_function_instances.set(address, function); }
void add_imported_object(JS::GCPtr<JS::Object> object) { m_imported_objects.set(object); }
void add_extern_value(Wasm::ExternAddress address, JS::Value value) { m_extern_values.set(address, value); }
Optional<JS::GCPtr<JS::NativeFunction>> get_function_instance(Wasm::FunctionAddress address) { return m_function_instances.get(address); }
Optional<JS::Value> get_extern_value(Wasm::ExternAddress address) { return m_extern_values.get(address); }
HashMap<Wasm::FunctionAddress, JS::GCPtr<JS::NativeFunction>> function_instances() const { return m_function_instances; }
HashMap<Wasm::ExternAddress, JS::Value> extern_values() const { return m_extern_values; }
HashTable<JS::GCPtr<JS::Object>> imported_objects() const { return m_imported_objects; }
Wasm::AbstractMachine& abstract_machine() { return m_abstract_machine; }
private:
HashMap<Wasm::FunctionAddress, JS::GCPtr<JS::NativeFunction>> m_function_instances;
HashMap<Wasm::ExternAddress, JS::Value> m_extern_values;
Vector<NonnullRefPtr<CompiledWebAssemblyModule>> m_compiled_modules;
HashTable<JS::GCPtr<JS::Object>> m_imported_objects;
Wasm::AbstractMachine m_abstract_machine;

View file

@ -726,8 +726,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
dbgln("[wasm runtime] Stub function {} was called with the following arguments: {}", name, argument_builder.to_byte_string());
Vector<Wasm::Value> 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<int> serenity_main(Main::Arguments arguments)
for (auto& param : instance->get<Wasm::WasmFunction>().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 {