mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-06-28 20:20:26 +00:00
Represent BufferSource and ArrayBufferView as ordinary IDL typedefs over their underlying union types, instead of special casing in the IDL generator. This allows the union conversion/return machinery handle these types consistently with other typedefs, which removes buffer specific paths from the IDL generator. This necessitates changing the WebIDL::BufferSource and WebIDL::ArrayBufferView classes as views over these variants. This replaces the old GC backed BufferableObject wrapper structure and provide convenience helpers to determine things such as the byte length, byte offset, backing buffer, and typed-array APIs.
146 lines
6.1 KiB
C++
146 lines
6.1 KiB
C++
/*
|
|
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
|
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibJS/Runtime/ArrayBuffer.h>
|
|
#include <LibJS/Runtime/Realm.h>
|
|
#include <LibJS/Runtime/VM.h>
|
|
#include <LibWeb/Bindings/Intrinsics.h>
|
|
#include <LibWeb/Bindings/Module.h>
|
|
#include <LibWeb/WebAssembly/Module.h>
|
|
#include <LibWeb/WebAssembly/WebAssembly.h>
|
|
#include <LibWeb/WebIDL/AbstractOperations.h>
|
|
#include <LibWeb/WebIDL/Buffers.h>
|
|
|
|
namespace Web::WebAssembly {
|
|
|
|
GC_DEFINE_ALLOCATOR(Module);
|
|
|
|
WebIDL::ExceptionOr<GC::Ref<Module>> Module::construct_impl(JS::Realm& realm, WebIDL::BufferSource bytes)
|
|
{
|
|
auto& vm = realm.vm();
|
|
|
|
auto stable_bytes_or_error = WebIDL::get_buffer_source_copy(bytes);
|
|
if (stable_bytes_or_error.is_error()) {
|
|
VERIFY(stable_bytes_or_error.error().code() == ENOMEM);
|
|
return vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory));
|
|
}
|
|
auto stable_bytes = stable_bytes_or_error.release_value();
|
|
|
|
auto compiled_module = TRY(Detail::compile_a_webassembly_module(vm, move(stable_bytes)));
|
|
return realm.create<Module>(realm, move(compiled_module));
|
|
}
|
|
|
|
// https://webassembly.github.io/threads/js-api/index.html#dom-module-imports
|
|
WebIDL::ExceptionOr<Vector<ModuleImportDescriptor>> Module::imports(JS::VM&, GC::Ref<Module> module_object)
|
|
{
|
|
// 1. Let module be moduleObject.[[Module]].
|
|
// 2. Let imports be « ».
|
|
Vector<ModuleImportDescriptor> import_objects;
|
|
|
|
// 3. For each (moduleName, name, type) of module_imports(module),
|
|
auto& imports = module_object->m_compiled_module->module->import_section().imports();
|
|
import_objects.ensure_capacity(imports.size());
|
|
for (auto& import : imports) {
|
|
if (import.description().has<Wasm::TagType>()) {
|
|
dbgln("Not yet implemented: importing tags");
|
|
continue;
|
|
}
|
|
|
|
// 3.1. Let kind be the string value of the extern type type.
|
|
auto const kind = import.description().visit(
|
|
[](Wasm::TypeIndex) { return Bindings::ImportExportKind::Function; },
|
|
[](Wasm::TableType) { return Bindings::ImportExportKind::Table; },
|
|
[](Wasm::MemoryType) { return Bindings::ImportExportKind::Memory; },
|
|
[](Wasm::GlobalType) { return Bindings::ImportExportKind::Global; },
|
|
[](Wasm::FunctionType) { return Bindings::ImportExportKind::Function; },
|
|
[](Wasm::TagType) -> Bindings::ImportExportKind { TODO(); });
|
|
|
|
// 3.2. Let obj be «[ "module" → moduleName, "name" → name, "kind" → kind ]».
|
|
ModuleImportDescriptor descriptor {
|
|
.module = String::from_utf8_with_replacement_character(import.module()),
|
|
.name = String::from_utf8_with_replacement_character(import.name()),
|
|
.kind = kind,
|
|
};
|
|
|
|
// 3.3. Append obj to imports.
|
|
import_objects.append(move(descriptor));
|
|
}
|
|
// 4. Return imports.
|
|
return import_objects;
|
|
}
|
|
|
|
// https://webassembly.github.io/threads/js-api/index.html#dom-module-exports
|
|
WebIDL::ExceptionOr<Vector<ModuleExportDescriptor>> Module::exports(JS::VM&, GC::Ref<Module> module_object)
|
|
{
|
|
// 1. Let module be moduleObject.[[Module]].
|
|
// 2. Let exports be « ».
|
|
Vector<ModuleExportDescriptor> export_objects;
|
|
|
|
// 3. For each (name, type) of module_exports(module),
|
|
auto& exports = module_object->m_compiled_module->module->export_section().entries();
|
|
export_objects.ensure_capacity(exports.size());
|
|
for (auto& entry : exports) {
|
|
if (entry.description().has<Wasm::TagIndex>()) {
|
|
dbgln("Not yet implemented: exporting tags");
|
|
continue;
|
|
}
|
|
|
|
// 3.1. Let kind be the string value of the extern type type.
|
|
auto const kind = entry.description().visit(
|
|
[](Wasm::FunctionIndex) { return Bindings::ImportExportKind::Function; },
|
|
[](Wasm::TableIndex) { return Bindings::ImportExportKind::Table; },
|
|
[](Wasm::MemoryIndex) { return Bindings::ImportExportKind::Memory; },
|
|
[](Wasm::GlobalIndex) { return Bindings::ImportExportKind::Global; },
|
|
[](Wasm::TagIndex) -> Bindings::ImportExportKind { TODO(); });
|
|
// 3.2. Let obj be «[ "name" → name, "kind" → kind ]».
|
|
ModuleExportDescriptor descriptor {
|
|
.name = String::from_utf8_with_replacement_character(entry.name()),
|
|
.kind = kind,
|
|
};
|
|
// 3.3. Append obj to exports.
|
|
export_objects.append(move(descriptor));
|
|
}
|
|
// 4. Return exports.
|
|
return export_objects;
|
|
}
|
|
|
|
// https://webassembly.github.io/threads/js-api/index.html#dom-module-customsections
|
|
WebIDL::ExceptionOr<GC::RootVector<GC::Ref<JS::ArrayBuffer>>> Module::custom_sections(JS::VM&, GC::Ref<Module> module_object, String section_name)
|
|
{
|
|
// 1. Let bytes be moduleObject.[[Bytes]].
|
|
// 2. Let customSections be « ».
|
|
GC::RootVector<GC::Ref<JS::ArrayBuffer>> array_buffers;
|
|
|
|
// 3. For each custom section customSection of bytes, interpreted according to the module grammar,
|
|
auto& custom_sections = module_object->m_compiled_module->module->custom_sections();
|
|
for (auto& section : custom_sections) {
|
|
// 3.1. Let name be the name of customSection, decoded as UTF-8.
|
|
// 3.2. Assert: name is not failure (moduleObject.[[Module]] is valid).
|
|
auto name = MUST(String::from_utf8(section.name().bytes()));
|
|
// 3.3. If name equals sectionName as string values,
|
|
if (section_name == name) {
|
|
// 3.3.1. Append a new ArrayBuffer containing a copy of the bytes in bytes for the range matched by this customsec production to customSections.
|
|
array_buffers.append(JS::ArrayBuffer::create(module_object->realm(), section.contents()));
|
|
}
|
|
}
|
|
// 4. Return customSections.
|
|
return array_buffers;
|
|
}
|
|
|
|
Module::Module(JS::Realm& realm, NonnullRefPtr<Detail::CompiledWebAssemblyModule> compiled_module)
|
|
: Bindings::PlatformObject(realm)
|
|
, m_compiled_module(move(compiled_module))
|
|
{
|
|
}
|
|
|
|
void Module::initialize(JS::Realm& realm)
|
|
{
|
|
WEB_SET_PROTOTYPE_FOR_INTERFACE_WITH_CUSTOM_NAME(Module, WebAssembly.Module);
|
|
Base::initialize(realm);
|
|
}
|
|
|
|
}
|