From 321db0159e8d004ef963bb4aa6b23990df1cc304 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Thu, 1 Jul 2021 15:14:05 +0430 Subject: [PATCH] LibWeb: Add the WebAssembly.Module constructor --- Userland/Libraries/LibWeb/CMakeLists.txt | 2 + .../WebAssemblyInstanceConstructor.cpp | 1 + .../WebAssemblyModuleConstructor.cpp | 61 +++++++++++++++++++ .../WebAssemblyModuleConstructor.h | 28 +++++++++ .../WebAssembly/WebAssemblyModuleObject.cpp | 18 ++++++ .../WebAssembly/WebAssemblyModuleObject.h | 31 ++++++++++ .../WebAssembly/WebAssemblyModulePrototype.h | 28 +++++++++ .../LibWeb/WebAssembly/WebAssemblyObject.cpp | 39 +++++++----- .../LibWeb/WebAssembly/WebAssemblyObject.h | 15 +---- 9 files changed, 193 insertions(+), 30 deletions(-) create mode 100644 Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleConstructor.cpp create mode 100644 Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleConstructor.h create mode 100644 Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleObject.cpp create mode 100644 Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleObject.h create mode 100644 Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModulePrototype.h diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 9e53c09f6d..03b0cfac54 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -227,6 +227,8 @@ set(SOURCES WebAssembly/WebAssemblyInstanceObjectPrototype.cpp WebAssembly/WebAssemblyMemoryConstructor.cpp WebAssembly/WebAssemblyMemoryPrototype.cpp + WebAssembly/WebAssemblyModuleConstructor.cpp + WebAssembly/WebAssemblyModuleObject.cpp WebAssembly/WebAssemblyObject.cpp WebContentClient.cpp XHR/EventNames.cpp diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyInstanceConstructor.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyInstanceConstructor.cpp index 5dafdd35ac..7ec16d6862 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyInstanceConstructor.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyInstanceConstructor.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace Web::Bindings { diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleConstructor.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleConstructor.cpp new file mode 100644 index 0000000000..f787f63ea7 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleConstructor.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021, Ali Mohammad Pur + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Web::Bindings { + +WebAssemblyModuleConstructor::WebAssemblyModuleConstructor(JS::GlobalObject& global_object) + : NativeFunction(*global_object.function_prototype()) +{ +} + +WebAssemblyModuleConstructor::~WebAssemblyModuleConstructor() +{ +} + +JS::Value WebAssemblyModuleConstructor::call() +{ + vm().throw_exception(global_object(), JS::ErrorType::ConstructorWithoutNew, "WebAssemblyModule"); + return {}; +} + +JS::Value WebAssemblyModuleConstructor::construct(FunctionObject&) +{ + auto& vm = this->vm(); + auto& global_object = this->global_object(); + + auto buffer_object = vm.argument(0).to_object(global_object); + if (vm.exception()) + return {}; + + auto result = parse_module(global_object, buffer_object); + if (result.is_error()) { + vm.throw_exception(global_object, result.error()); + return {}; + } + + return heap().allocate(global_object, global_object, result.release_value()); +} + +void WebAssemblyModuleConstructor::initialize(JS::GlobalObject& global_object) +{ + auto& vm = this->vm(); + auto& window = static_cast(global_object); + + NativeFunction::initialize(global_object); + define_property(vm.names.prototype, &window.ensure_web_prototype("WebAssemblyModulePrototype")); + define_property(vm.names.length, JS::Value(1), JS::Attribute::Configurable); +} + +} diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleConstructor.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleConstructor.h new file mode 100644 index 0000000000..9df31c2a2a --- /dev/null +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleConstructor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021, Ali Mohammad Pur + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::Bindings { + +class WebAssemblyModuleConstructor : public JS::NativeFunction { + JS_OBJECT(WebAssemblyModuleConstructor, JS::NativeFunction); + +public: + explicit WebAssemblyModuleConstructor(JS::GlobalObject&); + virtual void initialize(JS::GlobalObject&) override; + virtual ~WebAssemblyModuleConstructor() override; + + virtual JS::Value call() override; + virtual JS::Value construct(JS::FunctionObject& new_target) override; + +private: + virtual bool has_constructor() const override { return true; } +}; + +} diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleObject.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleObject.cpp new file mode 100644 index 0000000000..27e5340197 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleObject.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021, Ali Mohammad Pur + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "WebAssemblyModulePrototype.h" +#include + +namespace Web::Bindings { + +WebAssemblyModuleObject::WebAssemblyModuleObject(JS::GlobalObject& global_object, size_t index) + : Object(static_cast(global_object).ensure_web_prototype("WebAssemblyModulePrototype")) + , m_index(index) +{ +} + +} diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleObject.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleObject.h new file mode 100644 index 0000000000..b865fab521 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModuleObject.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021, Ali Mohammad Pur + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Web::Bindings { + +class WebAssemblyModuleObject final : public JS::Object { + JS_OBJECT(WebAssemblyModuleObject, Object); + +public: + explicit WebAssemblyModuleObject(JS::GlobalObject&, size_t index); + virtual ~WebAssemblyModuleObject() override = default; + + size_t index() const { return m_index; } + const Wasm::Module& module() const { return WebAssemblyObject::s_compiled_modules.at(m_index).module; } + +private: + size_t m_index { 0 }; +}; + +} diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModulePrototype.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModulePrototype.h new file mode 100644 index 0000000000..d0b6b953fe --- /dev/null +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyModulePrototype.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021, Ali Mohammad Pur + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "WebAssemblyModuleConstructor.h" +#include +#include +#include +#include +#include + +namespace Web::Bindings { + +class WebAssemblyModulePrototype final : public JS::Object { + JS_OBJECT(WebAssemblyModulePrototype, JS::Object); + +public: + explicit WebAssemblyModulePrototype(JS::GlobalObject& global_object) + : JS::Object(global_object) + { + } +}; + +} diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp index 065697534d..c21dd3daf6 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp @@ -6,10 +6,14 @@ #include "WebAssemblyInstanceObject.h" #include "WebAssemblyMemoryPrototype.h" +#include "WebAssemblyModuleConstructor.h" +#include "WebAssemblyModuleObject.h" +#include "WebAssemblyModulePrototype.h" #include #include #include #include +#include #include #include #include @@ -45,6 +49,12 @@ void WebAssemblyObject::initialize(JS::GlobalObject& global_object) auto& instance_prototype = window.ensure_web_prototype("WebAssemblyInstancePrototype"); instance_prototype.define_property(vm.names.constructor, &instance_constructor, JS::Attribute::Writable | JS::Attribute::Configurable); define_property("Instance", &instance_constructor); + + auto& module_constructor = window.ensure_web_constructor("WebAssembly.Module"); + module_constructor.define_property(vm.names.name, js_string(vm, "WebAssembly.Module"), JS::Attribute::Configurable); + auto& module_prototype = window.ensure_web_prototype("WebAssemblyModulePrototype"); + module_prototype.define_property(vm.names.constructor, &module_constructor, JS::Attribute::Writable | JS::Attribute::Configurable); + define_property("Module", &module_constructor); } NonnullOwnPtrVector WebAssemblyObject::s_compiled_modules; @@ -74,20 +84,23 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::validate) return JS::Value { true }; } -static Result parse_module(JS::GlobalObject& global_object, JS::Object* buffer) +Result parse_module(JS::GlobalObject& global_object, JS::Object* buffer_object) { - ByteBuffer* bytes; - if (is(buffer)) { - auto array_buffer = static_cast(buffer); - bytes = &array_buffer->buffer(); - } else if (is(buffer)) { - auto array = static_cast(buffer); - bytes = &array->viewed_array_buffer()->buffer(); + ReadonlyBytes data; + if (is(buffer_object)) { + auto& buffer = static_cast(*buffer_object); + data = buffer.buffer(); + } else if (is(buffer_object)) { + auto& buffer = static_cast(*buffer_object); + data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), buffer.byte_length()); + } else if (is(buffer_object)) { + auto& buffer = static_cast(*buffer_object); + data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), buffer.byte_length()); } else { - auto error = JS::TypeError::create(global_object, String::formatted("{} is not an ArrayBuffer", buffer->class_name())); + auto error = JS::TypeError::create(global_object, "Not a BufferSource"); return JS::Value { error }; } - InputMemoryStream stream { *bytes }; + InputMemoryStream stream { data }; auto module_result = Wasm::Module::parse(stream); ScopeGuard drain_errors { [&] { @@ -325,12 +338,6 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::instantiate) return promise; } -WebAssemblyModuleObject::WebAssemblyModuleObject(JS::GlobalObject& global_object, size_t index) - : Object(*global_object.object_prototype()) - , m_index(index) -{ -} - JS::Value to_js_value(Wasm::Value& wasm_value, JS::GlobalObject& global_object) { switch (wasm_value.type().kind()) { diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h index 4713f25b1d..2c0eae4349 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h @@ -14,6 +14,7 @@ namespace Web::Bindings { class WebAssemblyMemoryObject; +Result parse_module(JS::GlobalObject& global_object, JS::Object* buffer); JS::NativeFunction* create_native_function(Wasm::FunctionAddress address, String name, JS::GlobalObject& global_object); JS::Value to_js_value(Wasm::Value& wasm_value, JS::GlobalObject& global_object); Optional to_webassembly_value(JS::Value value, const Wasm::ValueType& type, JS::GlobalObject& global_object); @@ -64,20 +65,6 @@ private: JS_DECLARE_NATIVE_FUNCTION(instantiate); }; -class WebAssemblyModuleObject final : public JS::Object { - JS_OBJECT(WebAssemblyModuleObject, JS::Object); - -public: - explicit WebAssemblyModuleObject(JS::GlobalObject&, size_t index); - virtual ~WebAssemblyModuleObject() override = default; - - size_t index() const { return m_index; } - const Wasm::Module& module() const { return WebAssemblyObject::s_compiled_modules.at(m_index).module; } - -private: - size_t m_index { 0 }; -}; - class WebAssemblyMemoryObject final : public JS::Object { JS_OBJECT(WebAssemblyMemoryObject, JS::Object);