mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-21 16:58:58 +00:00
LibWeb: Implement resizable ArrayBuffers for Wasm memories
This commit adds the toResizableBuffer() and toFixedLengthBuffer() methods to WebAssembly.Memory. This includes the necessary hook to HostResizeArrayBuffer. Some modifications to function signatures in LibWeb/WebAssembly/Memory.h were also made (changing the return type from WebIDL::ExceptionOr to JS::ThrowCompletionOr) to allow the use of some code in the aforementioned hook. Note: the hook for HostGrowSharedArrayBuffer isn't implemented, since LibJS doesn't seem to have complete support for growable SharedArrayBuffers; the relevant methods/getters don't even exist on the prototype, let alone HostGrowSharedArrayBuffer! This should help pass the WebAssembly.Memory WPT tests included in Interop 2025, except those pertaining to growable SharedArrayBuffers.
This commit is contained in:
parent
826eb68ecd
commit
d0d5bffb2d
Notes:
github-actions[bot]
2025-08-23 06:27:40 +00:00
Author: https://github.com/CountBleck
Commit: d0d5bffb2d
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5889
Reviewed-by: https://github.com/alimpfard ✅
6 changed files with 246 additions and 6 deletions
|
@ -50,6 +50,7 @@
|
||||||
#include <LibWeb/HTML/WorkletGlobalScope.h>
|
#include <LibWeb/HTML/WorkletGlobalScope.h>
|
||||||
#include <LibWeb/Platform/EventLoopPlugin.h>
|
#include <LibWeb/Platform/EventLoopPlugin.h>
|
||||||
#include <LibWeb/ServiceWorker/ServiceWorkerGlobalScope.h>
|
#include <LibWeb/ServiceWorker/ServiceWorkerGlobalScope.h>
|
||||||
|
#include <LibWeb/WebAssembly/WebAssembly.h>
|
||||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||||
|
|
||||||
namespace Web::Bindings {
|
namespace Web::Bindings {
|
||||||
|
@ -690,6 +691,14 @@ void initialize_main_thread_vm(AgentType type)
|
||||||
s_main_thread_vm->host_unrecognized_date_string = [](StringView date) {
|
s_main_thread_vm->host_unrecognized_date_string = [](StringView date) {
|
||||||
dbgln("Unable to parse date string: \"{}\"", date);
|
dbgln("Unable to parse date string: \"{}\"", date);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
s_main_thread_vm->host_resize_array_buffer = [default_host_resize_array_buffer = move(s_main_thread_vm->host_resize_array_buffer)](JS::ArrayBuffer& buffer, size_t new_byte_length) -> JS::ThrowCompletionOr<JS::HandledByHost> {
|
||||||
|
auto wasm_handled = TRY(WebAssembly::Detail::host_resize_array_buffer(*s_main_thread_vm, buffer, new_byte_length));
|
||||||
|
if (wasm_handled == JS::HandledByHost::Handled)
|
||||||
|
return JS::HandledByHost::Handled;
|
||||||
|
|
||||||
|
return default_host_resize_array_buffer(buffer, new_byte_length);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::VM& main_thread_vm()
|
JS::VM& main_thread_vm()
|
||||||
|
|
|
@ -89,7 +89,7 @@ void Memory::visit_edges(Visitor& visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/js-api/#dom-memory-grow
|
// https://webassembly.github.io/spec/js-api/#dom-memory-grow
|
||||||
WebIDL::ExceptionOr<u32> Memory::grow(u32 delta)
|
JS::ThrowCompletionOr<u32> Memory::grow(u32 delta)
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
|
|
||||||
|
@ -106,6 +106,91 @@ WebIDL::ExceptionOr<u32> Memory::grow(u32 delta)
|
||||||
return previous_size;
|
return previous_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://webassembly.github.io/threads/js-api/index.html#dom-memory-tofixedlengthbuffer
|
||||||
|
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> Memory::to_fixed_length_buffer()
|
||||||
|
{
|
||||||
|
auto& vm = this->vm();
|
||||||
|
|
||||||
|
// 1. Let buffer be this.[[BufferObject]].
|
||||||
|
// 2. Let memaddr be this.[[Memory]].
|
||||||
|
// 3. If IsSharedArrayBuffer(buffer) is false,
|
||||||
|
if (m_shared == Shared::No) {
|
||||||
|
// 1. If IsFixedLengthArrayBuffer(buffer) is true, return buffer.
|
||||||
|
if (m_buffer->is_fixed_length())
|
||||||
|
return GC::Ref(*m_buffer);
|
||||||
|
|
||||||
|
// 2. Otherwise,
|
||||||
|
// 1. Let fixedBuffer be the result of creating a fixed length memory buffer from memaddr.
|
||||||
|
auto fixed_buffer = create_a_fixed_length_memory_buffer(vm, realm(), m_address, m_shared);
|
||||||
|
|
||||||
|
// 2. Perform ! DetachArrayBuffer(buffer, "WebAssembly.Memory").
|
||||||
|
MUST(JS::detach_array_buffer(vm, *m_buffer, JS::PrimitiveString::create(vm, "WebAssembly.Memory"_string)));
|
||||||
|
|
||||||
|
// 3. Set this.[[BufferObject]] to fixedBuffer.
|
||||||
|
m_buffer = fixed_buffer;
|
||||||
|
|
||||||
|
// 4. Return fixedBuffer.
|
||||||
|
return fixed_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Otherwise,
|
||||||
|
// 1. Let map be the surrounding agent's associated Memory object cache.
|
||||||
|
auto& cache = Detail::get_cache(realm());
|
||||||
|
|
||||||
|
// 2. Assert: map[memaddr] exists.
|
||||||
|
// 3. Let newMemory be map[memaddr].
|
||||||
|
auto new_memory = cache.get_memory_instance(m_address);
|
||||||
|
VERIFY(new_memory.has_value());
|
||||||
|
|
||||||
|
// 4. Let newBufferObject be newMemory.[[BufferObject]].
|
||||||
|
auto new_buffer_object = new_memory.value()->m_buffer;
|
||||||
|
|
||||||
|
// 5. Set this.[[BufferObject]] to newBufferObject.
|
||||||
|
m_buffer = new_buffer_object;
|
||||||
|
|
||||||
|
// 6. Return newBufferObject.
|
||||||
|
return GC::Ref(*new_buffer_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://webassembly.github.io/spec/js-api/#dom-memory-toresizablebuffer
|
||||||
|
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> Memory::to_resizable_buffer()
|
||||||
|
{
|
||||||
|
auto& vm = this->vm();
|
||||||
|
|
||||||
|
// 1. Let buffer be this.[[BufferObject]].
|
||||||
|
// 2. If IsFixedLengthArrayBuffer(buffer) is false, return buffer.
|
||||||
|
if (!m_buffer->is_fixed_length())
|
||||||
|
return GC::Ref(*m_buffer);
|
||||||
|
|
||||||
|
// 3. Let memaddr be this.[[Memory]].
|
||||||
|
// 4. Let store be the surrounding agent’s associated store.
|
||||||
|
auto& store = Detail::get_cache(realm()).abstract_machine().store();
|
||||||
|
|
||||||
|
// 5. Let memtype be mem_type(store, memaddr).
|
||||||
|
auto mem_type = store.get(m_address)->type();
|
||||||
|
|
||||||
|
// 6. If memtype has a max,
|
||||||
|
// 1. Let maxsize be the max value in memtype.
|
||||||
|
// 7. Otherwise,
|
||||||
|
// 1. Let maxsize be 65536 × 65536.
|
||||||
|
size_t max_size = mem_type.limits().max().value_or(65536) * Wasm::Constants::page_size;
|
||||||
|
|
||||||
|
// 8. Let resizableBuffer be the result of creating a resizable memory buffer from memaddr and maxsize.
|
||||||
|
auto resizable_buffer = TRY(create_a_resizable_memory_buffer(vm, realm(), m_address, m_shared, max_size));
|
||||||
|
|
||||||
|
// https://webassembly.github.io/threads/js-api/index.html#dom-memory-toresizablebuffer
|
||||||
|
// 5. If IsSharedArrayBuffer(buffer) is false,
|
||||||
|
// 9. Perform ! DetachArrayBuffer(buffer, "WebAssembly.Memory").
|
||||||
|
if (!m_buffer->is_shared_array_buffer())
|
||||||
|
MUST(JS::detach_array_buffer(vm, *m_buffer, JS::PrimitiveString::create(vm, "WebAssembly.Memory"_string)));
|
||||||
|
|
||||||
|
// 10. Set this.[[BufferObject]] to resizableBuffer.
|
||||||
|
m_buffer = resizable_buffer;
|
||||||
|
|
||||||
|
// 11. Return resizeableBuffer.
|
||||||
|
return resizable_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/js-api/#refresh-the-memory-buffer
|
// https://webassembly.github.io/spec/js-api/#refresh-the-memory-buffer
|
||||||
void Memory::refresh_the_memory_buffer(JS::VM& vm, JS::Realm& realm, Wasm::MemoryAddress address)
|
void Memory::refresh_the_memory_buffer(JS::VM& vm, JS::Realm& realm, Wasm::MemoryAddress address)
|
||||||
{
|
{
|
||||||
|
@ -130,15 +215,45 @@ void Memory::refresh_the_memory_buffer(JS::VM& vm, JS::Realm& realm, Wasm::Memor
|
||||||
|
|
||||||
// 2. Let newBuffer be the result of creating a fixed length memory buffer from memaddr.
|
// 2. Let newBuffer be the result of creating a fixed length memory buffer from memaddr.
|
||||||
// 3. Set memory.[[BufferObject]] to newBuffer.
|
// 3. Set memory.[[BufferObject]] to newBuffer.
|
||||||
}
|
buffer = create_a_fixed_length_memory_buffer(vm, realm, address, memory.value()->m_shared);
|
||||||
|
} else {
|
||||||
|
// 1. Let block be a Data Block which is identified with the underlying memory of memaddr.
|
||||||
|
auto& bytes = cache.abstract_machine().store().get(address)->data();
|
||||||
|
|
||||||
buffer = create_a_fixed_length_memory_buffer(vm, realm, address, memory.value()->m_shared);
|
// 2. Set buffer.[[ArrayBufferData]] to block.
|
||||||
|
// 3. Set buffer.[[ArrayBufferByteLength]] to the length of block.
|
||||||
|
buffer->set_data_block({ JS::DataBlock::UnownedFixedLengthByteBuffer(&bytes) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/js-api/#dom-memory-buffer
|
// https://webassembly.github.io/threads/js-api/#dom-memory-buffer
|
||||||
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> Memory::buffer() const
|
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> Memory::buffer() const
|
||||||
{
|
{
|
||||||
return GC::Ref(*m_buffer);
|
// 1. Let memaddr be this.[[Memory]].
|
||||||
|
// 2. Let block be a Data Block which is identified with the underlying memory of memaddr.
|
||||||
|
// 3. If block is a Shared Data Block,
|
||||||
|
if (m_shared == Shared::Yes) {
|
||||||
|
// 1. Let map be the surrounding agent's associated Memory object cache.
|
||||||
|
// 2. Assert: map[memaddr] exists.
|
||||||
|
// 3. Let newMemory be map[memaddr].
|
||||||
|
auto& cache = Detail::get_cache(realm());
|
||||||
|
auto new_memory = cache.get_memory_instance(m_address);
|
||||||
|
VERIFY(new_memory.has_value());
|
||||||
|
|
||||||
|
// 4. Let newBufferObject be newMemory.[[BufferObject]].
|
||||||
|
auto new_buffer_object = new_memory.value()->m_buffer;
|
||||||
|
|
||||||
|
// 5. Set this.[[BufferObject]] to newBufferObject.
|
||||||
|
m_buffer = new_buffer_object;
|
||||||
|
|
||||||
|
// 6. Return newBufferObject.
|
||||||
|
return GC::Ref(*new_buffer_object);
|
||||||
|
}
|
||||||
|
// 4. Otherwise,
|
||||||
|
else {
|
||||||
|
// 1. Return this.[[BufferObject]].
|
||||||
|
return GC::Ref(*m_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/js-api/#create-a-fixed-length-memory-buffer
|
// https://webassembly.github.io/spec/js-api/#create-a-fixed-length-memory-buffer
|
||||||
|
@ -173,4 +288,62 @@ GC::Ref<JS::ArrayBuffer> Memory::create_a_fixed_length_memory_buffer(JS::VM& vm,
|
||||||
return GC::Ref(*array_buffer);
|
return GC::Ref(*array_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://webassembly.github.io/spec/js-api/#create-a-resizable-memory-buffer
|
||||||
|
JS::ThrowCompletionOr<GC::Ref<JS::ArrayBuffer>> Memory::create_a_resizable_memory_buffer(JS::VM& vm, JS::Realm& realm, Wasm::MemoryAddress address, Shared shared, size_t max_size)
|
||||||
|
{
|
||||||
|
auto& context = Detail::get_cache(realm);
|
||||||
|
auto* memory = context.abstract_machine().store().get(address);
|
||||||
|
VERIFY(memory);
|
||||||
|
|
||||||
|
// 3. If maxsize > (65536 × 65536),
|
||||||
|
if (max_size > (65536 * Wasm::Constants::page_size)) {
|
||||||
|
// 1. Throw a RangeError exception.
|
||||||
|
return vm.throw_completion<JS::RangeError>("Maximum memory length exceeds 65536 * 65536 bytes"sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://webassembly.github.io/threads/js-api/index.html#create-a-resizable-memory-buffer
|
||||||
|
// 5. If share is shared,
|
||||||
|
if (shared == Shared::Yes) {
|
||||||
|
// 1. Let block be a Shared Data Block which is identified with the underlying memory of memaddr.
|
||||||
|
// 2. Let buffer be a new SharedArrayBuffer with the internal slots [[ArrayBufferData]], [[ArrayBufferByteLength]], and [[ArrayBufferMaxByteLength]].
|
||||||
|
// 3. Set buffer.[[ArrayBufferData]] to block.
|
||||||
|
auto buffer = JS::ArrayBuffer::create(realm, &memory->data());
|
||||||
|
|
||||||
|
// AD-HOC: The threads proposal uses the memory type's minimum for both shared and
|
||||||
|
// non-shared memories, but the upstream spec uses the memory instance's current
|
||||||
|
// size. We assume the upstream spec is correct for both cases.
|
||||||
|
// 4. Set buffer.[[ArrayBufferByteLength]] to min.
|
||||||
|
VERIFY(buffer->byte_length() == memory->size());
|
||||||
|
|
||||||
|
// 5. Set buffer.[[ArrayBufferMaxByteLength]] to maxsize.
|
||||||
|
buffer->set_max_byte_length(max_size);
|
||||||
|
|
||||||
|
// 6. Perform ! SetIntegrityLevel(buffer, "frozen").
|
||||||
|
MUST(buffer->set_integrity_level(IntegrityLevel::Frozen));
|
||||||
|
|
||||||
|
// 7. Return buffer.
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
// 6. Otherwise,
|
||||||
|
else {
|
||||||
|
// 1. Let block be a Data Block which is identified with the underlying memory of memaddr.
|
||||||
|
// 4. Let buffer be a new ArrayBuffer with the internal slots [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferMaxByteLength]], and [[ArrayBufferDetachKey]].
|
||||||
|
// 5. Set buffer.[[ArrayBufferData]] to block.
|
||||||
|
auto buffer = JS::ArrayBuffer::create(realm, &memory->data());
|
||||||
|
|
||||||
|
// 2. Let length be the length of block.
|
||||||
|
// 6. Set buffer.[[ArrayBufferByteLength]] to length.
|
||||||
|
VERIFY(buffer->byte_length() == memory->size());
|
||||||
|
|
||||||
|
// 7. Set buffer.[[ArrayBufferMaxByteLength]] to maxsize.
|
||||||
|
buffer->set_max_byte_length(max_size);
|
||||||
|
|
||||||
|
// 8. Set buffer.[[ArrayBufferDetachKey]] to "WebAssembly.Memory".
|
||||||
|
buffer->set_detach_key(JS::PrimitiveString::create(vm, "WebAssembly.Memory"_string));
|
||||||
|
|
||||||
|
// 9. Return buffer.
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,14 @@ class Memory : public Bindings::PlatformObject {
|
||||||
public:
|
public:
|
||||||
static WebIDL::ExceptionOr<GC::Ref<Memory>> construct_impl(JS::Realm&, MemoryDescriptor& descriptor);
|
static WebIDL::ExceptionOr<GC::Ref<Memory>> construct_impl(JS::Realm&, MemoryDescriptor& descriptor);
|
||||||
|
|
||||||
WebIDL::ExceptionOr<u32> grow(u32 delta);
|
JS::ThrowCompletionOr<u32> grow(u32 delta);
|
||||||
|
|
||||||
|
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> to_fixed_length_buffer();
|
||||||
|
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> to_resizable_buffer();
|
||||||
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> buffer() const;
|
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> buffer() const;
|
||||||
|
|
||||||
Wasm::MemoryAddress address() const { return m_address; }
|
Wasm::MemoryAddress address() const { return m_address; }
|
||||||
|
GC::Ptr<JS::ArrayBuffer> buffer_object() const { return m_buffer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Memory(JS::Realm&, Wasm::MemoryAddress, Shared shared);
|
Memory(JS::Realm&, Wasm::MemoryAddress, Shared shared);
|
||||||
|
@ -48,6 +52,7 @@ private:
|
||||||
|
|
||||||
static void refresh_the_memory_buffer(JS::VM&, JS::Realm&, Wasm::MemoryAddress);
|
static void refresh_the_memory_buffer(JS::VM&, JS::Realm&, Wasm::MemoryAddress);
|
||||||
static GC::Ref<JS::ArrayBuffer> create_a_fixed_length_memory_buffer(JS::VM&, JS::Realm&, Wasm::MemoryAddress, Shared shared);
|
static GC::Ref<JS::ArrayBuffer> create_a_fixed_length_memory_buffer(JS::VM&, JS::Realm&, Wasm::MemoryAddress, Shared shared);
|
||||||
|
static JS::ThrowCompletionOr<GC::Ref<JS::ArrayBuffer>> create_a_resizable_memory_buffer(JS::VM&, JS::Realm&, Wasm::MemoryAddress, Shared shared, size_t max_size);
|
||||||
|
|
||||||
Wasm::MemoryAddress m_address;
|
Wasm::MemoryAddress m_address;
|
||||||
Shared m_shared { Shared::No };
|
Shared m_shared { Shared::No };
|
||||||
|
|
|
@ -12,5 +12,7 @@ interface Memory {
|
||||||
|
|
||||||
unsigned long grow([EnforceRange] unsigned long delta);
|
unsigned long grow([EnforceRange] unsigned long delta);
|
||||||
|
|
||||||
|
ArrayBuffer toFixedLengthBuffer();
|
||||||
|
ArrayBuffer toResizableBuffer();
|
||||||
readonly attribute ArrayBuffer buffer;
|
readonly attribute ArrayBuffer buffer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -438,6 +438,56 @@ JS::ThrowCompletionOr<NonnullRefPtr<CompiledWebAssemblyModule>> compile_a_webass
|
||||||
return compiled_module;
|
return compiled_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS::ThrowCompletionOr<JS::HandledByHost> host_resize_array_buffer(JS::VM& vm, JS::ArrayBuffer& buffer, size_t new_length)
|
||||||
|
{
|
||||||
|
// 1. If buffer.[[ArrayBufferDetachKey]] is "WebAssembly.Memory",
|
||||||
|
auto detach_key = buffer.detach_key();
|
||||||
|
if (detach_key.is_string() && detach_key.as_string() == JS::PrimitiveString::create(vm, "WebAssembly.Memory"_string)) {
|
||||||
|
// 1. Let map be the surrounding agent's associated Memory object cache.
|
||||||
|
auto const& map = get_cache(*vm.current_realm()).memory_instances();
|
||||||
|
|
||||||
|
// 3. For each memaddr → mem in map,
|
||||||
|
bool seen = false;
|
||||||
|
for (auto [address, memory] : map) {
|
||||||
|
auto buffer_object = memory->buffer_object();
|
||||||
|
// 1. If SameValue(mem.[[BufferObject]], buffer) is true,
|
||||||
|
if (buffer_object.ptr() == &buffer) {
|
||||||
|
// 2. Assert: buffer is the [[BufferObject]] of exactly one value in map.
|
||||||
|
VERIFY(!seen);
|
||||||
|
seen = true;
|
||||||
|
|
||||||
|
// 1. Assert: buffer.[[ArrayBufferByteLength]] modulo 65536 is 0.
|
||||||
|
VERIFY(buffer.byte_length() % Wasm::Constants::page_size == 0);
|
||||||
|
|
||||||
|
// 2. Let lengthDelta be newLength - buffer.[[ArrayBufferByteLength]].
|
||||||
|
auto length_delta = new_length - buffer.byte_length();
|
||||||
|
|
||||||
|
// 3. If lengthDelta < 0 or lengthDelta modulo 65536 is not 0,
|
||||||
|
if (new_length < buffer.byte_length() || length_delta % Wasm::Constants::page_size != 0) {
|
||||||
|
// 1. Throw a RangeError exception.
|
||||||
|
return vm.throw_completion<JS::RangeError>("WebAssembly.Memory buffers must be resized by a multiple of the page size"sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Let delta be lengthDelta ÷ 65536.
|
||||||
|
auto delta = length_delta / Wasm::Constants::page_size;
|
||||||
|
|
||||||
|
// 5. Grow the memory buffer associated with memaddr by delta.
|
||||||
|
// FIXME: "Grow the memory buffer" is a separate algorithm from the Memory#grow() method.
|
||||||
|
TRY(memory->grow(delta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Assert: buffer is the [[BufferObject]] of exactly one value in map.
|
||||||
|
VERIFY(seen);
|
||||||
|
|
||||||
|
// 4. Return handled.
|
||||||
|
return JS::HandledByHost::Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Otherwise, return unhandled.
|
||||||
|
return JS::HandledByHost::Unhandled;
|
||||||
|
}
|
||||||
|
|
||||||
GC_DEFINE_ALLOCATOR(ExportedWasmFunction);
|
GC_DEFINE_ALLOCATOR(ExportedWasmFunction);
|
||||||
|
|
||||||
GC::Ref<ExportedWasmFunction> ExportedWasmFunction::create(JS::Realm& realm, Utf16FlyString name, Function<JS::ThrowCompletionOr<JS::Value>(JS::VM&)> behavior, Wasm::FunctionAddress exported_address)
|
GC::Ref<ExportedWasmFunction> ExportedWasmFunction::create(JS::Realm& realm, Utf16FlyString name, Function<JS::ThrowCompletionOr<JS::Value>(JS::VM&)> behavior, Wasm::FunctionAddress exported_address)
|
||||||
|
|
|
@ -107,6 +107,7 @@ JS::ThrowCompletionOr<Wasm::Value> to_webassembly_value(JS::VM&, JS::Value value
|
||||||
Wasm::Value default_webassembly_value(JS::VM&, Wasm::ValueType type);
|
Wasm::Value default_webassembly_value(JS::VM&, Wasm::ValueType type);
|
||||||
JS::Value to_js_value(JS::VM&, Wasm::Value& wasm_value, Wasm::ValueType type);
|
JS::Value to_js_value(JS::VM&, Wasm::Value& wasm_value, Wasm::ValueType type);
|
||||||
JS::ThrowCompletionOr<void> host_ensure_can_compile_wasm_bytes(JS::VM&);
|
JS::ThrowCompletionOr<void> host_ensure_can_compile_wasm_bytes(JS::VM&);
|
||||||
|
JS::ThrowCompletionOr<JS::HandledByHost> host_resize_array_buffer(JS::VM&, JS::ArrayBuffer&, size_t);
|
||||||
|
|
||||||
extern HashMap<GC::Ptr<JS::Object>, WebAssemblyCache> s_caches;
|
extern HashMap<GC::Ptr<JS::Object>, WebAssemblyCache> s_caches;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue