summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2023-03-29 01:31:51 +0330
committerAndreas Kling <kling@serenityos.org>2023-03-29 07:16:37 +0200
commit64da05a96db1fabd400f7e424059f503de4e455d (patch)
tree3164fb84941f2fe032bd936761ceb1df2e8b246b /Userland/Libraries
parent14fb6372c354bd8e7a161ebac1ad49fc08d234f3 (diff)
downloadserenity-64da05a96db1fabd400f7e424059f503de4e455d.zip
LibWeb+LibWasm: Implement and use the "reset the Memory buffer" steps
This implements the memory object cache and its "reset on grow" semantics, as the web depends on the exact behaviour.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h15
-rw-r--r--Userland/Libraries/LibWeb/WebAssembly/Memory.cpp41
-rw-r--r--Userland/Libraries/LibWeb/WebAssembly/Memory.h4
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;
};
}