diff options
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h | 15 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/WebAssembly/Memory.cpp | 41 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/WebAssembly/Memory.h | 4 |
3 files changed, 55 insertions, 5 deletions
diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index b08120ffd2..4229198994 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -398,7 +398,12 @@ public: auto& data() const { return m_data; } auto& data() { return m_data; } - bool grow(size_t size_to_grow) + enum class InhibitGrowCallback { + No, + Yes, + }; + + bool grow(size_t size_to_grow, InhibitGrowCallback inhibit_callback = InhibitGrowCallback::No) { if (size_to_grow == 0) return true; @@ -416,9 +421,17 @@ public: m_size = new_size; // The spec requires that we zero out everything on grow __builtin_memset(m_data.offset_pointer(previous_size), 0, size_to_grow); + + // NOTE: This exists because wasm-js-api wants to execute code after a successful grow, + // See [this issue](https://github.com/WebAssembly/spec/issues/1635) for more details. + if (inhibit_callback == InhibitGrowCallback::No && successful_grow_hook) + successful_grow_hook(); + return true; } + Function<void()> successful_grow_hook; + private: explicit MemoryInstance(MemoryType const& type) : m_type(type) diff --git a/Userland/Libraries/LibWeb/WebAssembly/Memory.cpp b/Userland/Libraries/LibWeb/WebAssembly/Memory.cpp index a07a1dc244..c7ff4a5121 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/Memory.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/Memory.cpp @@ -25,7 +25,12 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Memory>> Memory::construct_impl(JS::Realm& if (!address.has_value()) return vm.throw_completion<JS::TypeError>("Wasm Memory allocation failed"sv); - return MUST_OR_THROW_OOM(vm.heap().allocate<Memory>(realm, realm, *address)); + auto memory_object = MUST_OR_THROW_OOM(vm.heap().allocate<Memory>(realm, realm, *address)); + Detail::s_abstract_machine.store().get(*address)->successful_grow_hook = [memory_object] { + MUST(memory_object->reset_the_memory_buffer()); + }; + + return memory_object; } Memory::Memory(JS::Realm& realm, Wasm::MemoryAddress address) @@ -52,26 +57,54 @@ WebIDL::ExceptionOr<u32> Memory::grow(u32 delta) return vm.throw_completion<JS::RangeError>("Could not find the memory instance to grow"sv); auto previous_size = memory->size() / Wasm::Constants::page_size; - if (!memory->grow(delta * Wasm::Constants::page_size)) + if (!memory->grow(delta * Wasm::Constants::page_size, Wasm::MemoryInstance::InhibitGrowCallback::Yes)) return vm.throw_completion<JS::RangeError>("Memory.grow() grows past the stated limit of the memory instance"sv); + TRY(reset_the_memory_buffer()); + return previous_size; } +// https://webassembly.github.io/spec/js-api/#reset-the-memory-buffer +WebIDL::ExceptionOr<void> Memory::reset_the_memory_buffer() +{ + if (!m_buffer) + return {}; + + auto& vm = this->vm(); + auto& realm = *vm.current_realm(); + + MUST(JS::detach_array_buffer(vm, *m_buffer, MUST_OR_THROW_OOM(JS::PrimitiveString::create(vm, "WebAssembly.Memory"sv)))); + + auto buffer = TRY(create_a_memory_buffer(vm, realm, m_address)); + m_buffer = buffer; + + return {}; +} + // https://webassembly.github.io/spec/js-api/#dom-memory-buffer WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> Memory::buffer() const { auto& vm = this->vm(); auto& realm = *vm.current_realm(); - auto* memory = Detail::s_abstract_machine.store().get(address()); + if (!m_buffer) + m_buffer = TRY(create_a_memory_buffer(vm, realm, m_address)); + + return JS::NonnullGCPtr(*m_buffer); +} + +// https://webassembly.github.io/spec/js-api/#create-a-memory-buffer +WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> Memory::create_a_memory_buffer(JS::VM& vm, JS::Realm& realm, Wasm::MemoryAddress address) +{ + auto* memory = Detail::s_abstract_machine.store().get(address); if (!memory) return vm.throw_completion<JS::RangeError>("Could not find the memory instance"sv); auto array_buffer = JS::ArrayBuffer::create(realm, &memory->data()); array_buffer->set_detach_key(MUST_OR_THROW_OOM(JS::PrimitiveString::create(vm, "WebAssembly.Memory"sv))); - return array_buffer; + return JS::NonnullGCPtr(*array_buffer); } } diff --git a/Userland/Libraries/LibWeb/WebAssembly/Memory.h b/Userland/Libraries/LibWeb/WebAssembly/Memory.h index 5ead1b2f6c..f8b63ee960 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/Memory.h +++ b/Userland/Libraries/LibWeb/WebAssembly/Memory.h @@ -38,7 +38,11 @@ private: virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; + WebIDL::ExceptionOr<void> reset_the_memory_buffer(); + static WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> create_a_memory_buffer(JS::VM&, JS::Realm&, Wasm::MemoryAddress); + Wasm::MemoryAddress m_address; + mutable JS::GCPtr<JS::ArrayBuffer> m_buffer; }; } |