mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-30 08:41:15 +00:00
LibWeb: Cache the WebAssembly objects that we hand out to JS
The spec requires this behaviour, and it's generally faster to do this instead of re-resolving and re-creating the instances anyway.
This commit is contained in:
parent
a256997064
commit
e523e530fc
Notes:
sideshowbarker
2024-07-18 11:57:13 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/e523e530fcc Pull-request: https://github.com/SerenityOS/serenity/pull/8180 Reviewed-by: https://github.com/linusg
|
@ -35,8 +35,24 @@ void WebAssemblyObject::initialize(JS::GlobalObject& global_object)
|
||||||
|
|
||||||
NonnullOwnPtrVector<WebAssemblyObject::CompiledWebAssemblyModule> WebAssemblyObject::s_compiled_modules;
|
NonnullOwnPtrVector<WebAssemblyObject::CompiledWebAssemblyModule> WebAssemblyObject::s_compiled_modules;
|
||||||
NonnullOwnPtrVector<Wasm::ModuleInstance> WebAssemblyObject::s_instantiated_modules;
|
NonnullOwnPtrVector<Wasm::ModuleInstance> WebAssemblyObject::s_instantiated_modules;
|
||||||
|
Vector<WebAssemblyObject::ModuleCache> WebAssemblyObject::s_module_caches;
|
||||||
|
WebAssemblyObject::GlobalModuleCache WebAssemblyObject::s_global_cache;
|
||||||
Wasm::AbstractMachine WebAssemblyObject::s_abstract_machine;
|
Wasm::AbstractMachine WebAssemblyObject::s_abstract_machine;
|
||||||
|
|
||||||
|
void WebAssemblyObject::visit_edges(Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
|
||||||
|
for (auto& entry : s_global_cache.function_instances)
|
||||||
|
visitor.visit(entry.value);
|
||||||
|
for (auto& module_cache : s_module_caches) {
|
||||||
|
for (auto& entry : module_cache.function_instances)
|
||||||
|
visitor.visit(entry.value);
|
||||||
|
for (auto& entry : module_cache.memory_instances)
|
||||||
|
visitor.visit(entry.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::validate)
|
JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::validate)
|
||||||
{
|
{
|
||||||
// FIXME: Implement this once module validation is implemented in LibWasm.
|
// FIXME: Implement this once module validation is implemented in LibWasm.
|
||||||
|
@ -231,6 +247,7 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::instantiate)
|
||||||
}
|
}
|
||||||
|
|
||||||
s_instantiated_modules.append(instance_result.release_value());
|
s_instantiated_modules.append(instance_result.release_value());
|
||||||
|
s_module_caches.empend();
|
||||||
promise->fulfill(vm.heap().allocate<WebAssemblyInstanceObject>(global_object, global_object, s_instantiated_modules.size() - 1));
|
promise->fulfill(vm.heap().allocate<WebAssemblyInstanceObject>(global_object, global_object, s_instantiated_modules.size() - 1));
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
@ -318,8 +335,10 @@ JS::NativeFunction* create_native_function(Wasm::FunctionAddress address, String
|
||||||
{
|
{
|
||||||
Optional<Wasm::FunctionType> type;
|
Optional<Wasm::FunctionType> type;
|
||||||
WebAssemblyObject::s_abstract_machine.store().get(address)->visit([&](const auto& value) { type = value.type(); });
|
WebAssemblyObject::s_abstract_machine.store().get(address)->visit([&](const auto& value) { type = value.type(); });
|
||||||
// FIXME: Cache these.
|
if (auto entry = WebAssemblyObject::s_global_cache.function_instances.get(address); entry.has_value())
|
||||||
return JS::NativeFunction::create(
|
return *entry;
|
||||||
|
|
||||||
|
auto function = JS::NativeFunction::create(
|
||||||
global_object,
|
global_object,
|
||||||
name,
|
name,
|
||||||
[address, type = type.release_value()](JS::VM& vm, JS::GlobalObject& global_object) -> JS::Value {
|
[address, type = type.release_value()](JS::VM& vm, JS::GlobalObject& global_object) -> JS::Value {
|
||||||
|
@ -355,6 +374,9 @@ JS::NativeFunction* create_native_function(Wasm::FunctionAddress address, String
|
||||||
|
|
||||||
return JS::Array::create_from(global_object, result_values);
|
return JS::Array::create_from(global_object, result_values);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
WebAssemblyObject::s_global_cache.function_instances.set(address, function);
|
||||||
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebAssemblyInstanceObject::initialize(JS::GlobalObject& global_object)
|
void WebAssemblyInstanceObject::initialize(JS::GlobalObject& global_object)
|
||||||
|
@ -364,16 +386,24 @@ void WebAssemblyInstanceObject::initialize(JS::GlobalObject& global_object)
|
||||||
VERIFY(!m_exports_object);
|
VERIFY(!m_exports_object);
|
||||||
m_exports_object = JS::Object::create(global_object, nullptr);
|
m_exports_object = JS::Object::create(global_object, nullptr);
|
||||||
auto& instance = this->instance();
|
auto& instance = this->instance();
|
||||||
|
auto& cache = this->cache();
|
||||||
for (auto& export_ : instance.exports()) {
|
for (auto& export_ : instance.exports()) {
|
||||||
export_.value().visit(
|
export_.value().visit(
|
||||||
[&](const Wasm::FunctionAddress& address) {
|
[&](const Wasm::FunctionAddress& address) {
|
||||||
auto function = create_native_function(address, export_.name(), global_object);
|
auto object = cache.function_instances.get(address);
|
||||||
m_exports_object->define_property(export_.name(), function);
|
if (!object.has_value()) {
|
||||||
|
object = create_native_function(address, export_.name(), global_object);
|
||||||
|
cache.function_instances.set(address, *object);
|
||||||
|
}
|
||||||
|
m_exports_object->define_property(export_.name(), *object);
|
||||||
},
|
},
|
||||||
[&](const Wasm::MemoryAddress& address) {
|
[&](const Wasm::MemoryAddress& address) {
|
||||||
// FIXME: Cache this.
|
auto object = cache.memory_instances.get(address);
|
||||||
auto memory = heap().allocate<WebAssemblyMemoryObject>(global_object, global_object, address);
|
if (!object.has_value()) {
|
||||||
m_exports_object->define_property(export_.name(), memory);
|
object = heap().allocate<WebAssemblyMemoryObject>(global_object, global_object, address);
|
||||||
|
cache.memory_instances.set(address, *object);
|
||||||
|
}
|
||||||
|
m_exports_object->define_property(export_.name(), *object);
|
||||||
},
|
},
|
||||||
[&](const auto&) {
|
[&](const auto&) {
|
||||||
// FIXME: Implement other exports!
|
// FIXME: Implement other exports!
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
namespace Web::Bindings {
|
namespace Web::Bindings {
|
||||||
|
|
||||||
|
class WebAssemblyMemoryObject;
|
||||||
|
|
||||||
class WebAssemblyObject final : public JS::Object {
|
class WebAssemblyObject final : public JS::Object {
|
||||||
JS_OBJECT(WebAssemblyObject, JS::Object);
|
JS_OBJECT(WebAssemblyObject, JS::Object);
|
||||||
|
|
||||||
|
@ -21,6 +23,8 @@ public:
|
||||||
virtual void initialize(JS::GlobalObject&) override;
|
virtual void initialize(JS::GlobalObject&) override;
|
||||||
virtual ~WebAssemblyObject() override = default;
|
virtual ~WebAssemblyObject() override = default;
|
||||||
|
|
||||||
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
struct CompiledWebAssemblyModule {
|
struct CompiledWebAssemblyModule {
|
||||||
explicit CompiledWebAssemblyModule(Wasm::Module&& module)
|
explicit CompiledWebAssemblyModule(Wasm::Module&& module)
|
||||||
: module(move(module))
|
: module(move(module))
|
||||||
|
@ -34,8 +38,18 @@ public:
|
||||||
// but the module needs to stick around while its instance is alive
|
// but the module needs to stick around while its instance is alive
|
||||||
// so ideally this would be a refcounted object, shared between
|
// so ideally this would be a refcounted object, shared between
|
||||||
// WebAssemblyModuleObject's and WebAssemblyInstantiatedModuleObject's.
|
// WebAssemblyModuleObject's and WebAssemblyInstantiatedModuleObject's.
|
||||||
|
struct ModuleCache {
|
||||||
|
HashMap<Wasm::FunctionAddress, JS::Function*> function_instances;
|
||||||
|
HashMap<Wasm::MemoryAddress, WebAssemblyMemoryObject*> memory_instances;
|
||||||
|
};
|
||||||
|
struct GlobalModuleCache {
|
||||||
|
HashMap<Wasm::FunctionAddress, JS::NativeFunction*> function_instances;
|
||||||
|
};
|
||||||
|
|
||||||
static NonnullOwnPtrVector<CompiledWebAssemblyModule> s_compiled_modules;
|
static NonnullOwnPtrVector<CompiledWebAssemblyModule> s_compiled_modules;
|
||||||
static NonnullOwnPtrVector<Wasm::ModuleInstance> s_instantiated_modules;
|
static NonnullOwnPtrVector<Wasm::ModuleInstance> s_instantiated_modules;
|
||||||
|
static Vector<ModuleCache> s_module_caches;
|
||||||
|
static GlobalModuleCache s_global_cache;
|
||||||
|
|
||||||
static Wasm::AbstractMachine s_abstract_machine;
|
static Wasm::AbstractMachine s_abstract_machine;
|
||||||
|
|
||||||
|
@ -69,6 +83,7 @@ public:
|
||||||
|
|
||||||
size_t index() const { return m_index; }
|
size_t index() const { return m_index; }
|
||||||
Wasm::ModuleInstance& instance() const { return WebAssemblyObject::s_instantiated_modules.at(m_index); }
|
Wasm::ModuleInstance& instance() const { return WebAssemblyObject::s_instantiated_modules.at(m_index); }
|
||||||
|
auto& cache() { return WebAssemblyObject::s_module_caches.at(m_index); }
|
||||||
|
|
||||||
void visit_edges(Cell::Visitor&) override;
|
void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue