mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibWasm+LibWeb: Allow tables to have externrefs in the JS API
This commit is contained in:
parent
fc83653f3c
commit
4e7d3026d2
Notes:
github-actions[bot]
2024-08-18 21:36:13 +00:00
Author: https://github.com/dzfrias Commit: https://github.com/LadybirdBrowser/ladybird/commit/4e7d3026d24 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1105 Reviewed-by: https://github.com/alimpfard
8 changed files with 56 additions and 13 deletions
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue