| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 11:19:45 +04:30
										 |  |  | #include "WebAssemblyInstanceObject.h"
 | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  | #include "WebAssemblyMemoryPrototype.h"
 | 
					
						
							| 
									
										
										
										
											2021-07-01 15:14:05 +04:30
										 |  |  | #include "WebAssemblyModuleConstructor.h"
 | 
					
						
							|  |  |  | #include "WebAssemblyModuleObject.h"
 | 
					
						
							|  |  |  | #include "WebAssemblyModulePrototype.h"
 | 
					
						
							| 
									
										
										
										
											2021-09-04 04:40:57 +04:30
										 |  |  | #include "WebAssemblyTableObject.h"
 | 
					
						
							|  |  |  | #include "WebAssemblyTablePrototype.h"
 | 
					
						
							| 
									
										
										
										
											2023-01-25 20:19:05 +01:00
										 |  |  | #include <AK/MemoryStream.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-17 21:42:56 +04:30
										 |  |  | #include <AK/ScopeGuard.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | #include <LibJS/Runtime/Array.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/ArrayBuffer.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/BigInt.h>
 | 
					
						
							| 
									
										
										
										
											2021-07-01 15:14:05 +04:30
										 |  |  | #include <LibJS/Runtime/DataView.h>
 | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  | #include <LibJS/Runtime/ThrowableStringBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | #include <LibJS/Runtime/TypedArray.h>
 | 
					
						
							|  |  |  | #include <LibWasm/AbstractMachine/Interpreter.h>
 | 
					
						
							| 
									
										
										
										
											2021-11-08 03:06:30 +03:30
										 |  |  | #include <LibWasm/AbstractMachine/Validator.h>
 | 
					
						
							| 
									
										
										
										
											2022-09-25 18:05:03 -06:00
										 |  |  | #include <LibWeb/Bindings/Intrinsics.h>
 | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  | #include <LibWeb/WebAssembly/WebAssemblyInstanceConstructor.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | #include <LibWeb/WebAssembly/WebAssemblyObject.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Web::Bindings { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  | WebAssemblyObject::WebAssemblyObject(JS::Realm& realm) | 
					
						
							| 
									
										
										
										
											2022-12-14 12:17:58 +01:00
										 |  |  |     : Object(ConstructWithPrototypeTag::Tag, *realm.intrinsics().object_prototype()) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-07-15 00:00:45 +04:30
										 |  |  |     s_abstract_machine.enable_instruction_count_limit(); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-28 12:33:35 -05:00
										 |  |  | JS::ThrowCompletionOr<void> WebAssemblyObject::initialize(JS::Realm& realm) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-28 12:33:35 -05:00
										 |  |  |     MUST_OR_THROW_OOM(Object::initialize(realm)); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-06 02:15:08 +03:00
										 |  |  |     u8 attr = JS::Attribute::Configurable | JS::Attribute::Writable | JS::Attribute::Enumerable; | 
					
						
							| 
									
										
										
										
											2022-08-22 21:47:35 +01:00
										 |  |  |     define_native_function(realm, "validate", validate, 1, attr); | 
					
						
							|  |  |  |     define_native_function(realm, "compile", compile, 1, attr); | 
					
						
							|  |  |  |     define_native_function(realm, "instantiate", instantiate, 1, attr); | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 17:49:06 -05:00
										 |  |  |     auto& memory_constructor = Bindings::ensure_web_constructor<WebAssemblyMemoryPrototype>(realm, "WebAssembly.Memory"sv); | 
					
						
							| 
									
										
										
										
											2021-07-06 02:15:08 +03:00
										 |  |  |     define_direct_property("Memory", &memory_constructor, JS::Attribute::Writable | JS::Attribute::Configurable); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 17:49:06 -05:00
										 |  |  |     auto& instance_constructor = Bindings::ensure_web_constructor<WebAssemblyInstancePrototype>(realm, "WebAssembly.Instance"sv); | 
					
						
							| 
									
										
										
										
											2021-07-06 02:15:08 +03:00
										 |  |  |     define_direct_property("Instance", &instance_constructor, JS::Attribute::Writable | JS::Attribute::Configurable); | 
					
						
							| 
									
										
										
										
											2021-07-01 15:14:05 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 17:49:06 -05:00
										 |  |  |     auto& module_constructor = Bindings::ensure_web_constructor<WebAssemblyModulePrototype>(realm, "WebAssembly.Module"sv); | 
					
						
							| 
									
										
										
										
											2021-07-06 02:15:08 +03:00
										 |  |  |     define_direct_property("Module", &module_constructor, JS::Attribute::Writable | JS::Attribute::Configurable); | 
					
						
							| 
									
										
										
										
											2021-09-04 04:40:57 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 17:49:06 -05:00
										 |  |  |     auto& table_constructor = Bindings::ensure_web_constructor<WebAssemblyTablePrototype>(realm, "WebAssembly.Table"sv); | 
					
						
							| 
									
										
										
										
											2021-09-04 04:40:57 +04:30
										 |  |  |     define_direct_property("Table", &table_constructor, JS::Attribute::Writable | JS::Attribute::Configurable); | 
					
						
							| 
									
										
										
										
											2023-01-28 12:33:35 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NonnullOwnPtrVector<WebAssemblyObject::CompiledWebAssemblyModule> WebAssemblyObject::s_compiled_modules; | 
					
						
							|  |  |  | NonnullOwnPtrVector<Wasm::ModuleInstance> WebAssemblyObject::s_instantiated_modules; | 
					
						
							| 
									
										
										
										
											2021-06-21 04:12:15 +04:30
										 |  |  | Vector<WebAssemblyObject::ModuleCache> WebAssemblyObject::s_module_caches; | 
					
						
							|  |  |  | WebAssemblyObject::GlobalModuleCache WebAssemblyObject::s_global_cache; | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | Wasm::AbstractMachine WebAssemblyObject::s_abstract_machine; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-21 04:12:15 +04:30
										 |  |  | void WebAssemblyObject::visit_edges(Visitor& visitor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Base::visit_edges(visitor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& entry : s_global_cache.function_instances) | 
					
						
							|  |  |  |         visitor.visit(entry.value); | 
					
						
							|  |  |  |     for (auto& module_cache : s_module_caches) { | 
					
						
							|  |  |  |         for (auto& entry : module_cache.function_instances) | 
					
						
							|  |  |  |             visitor.visit(entry.value); | 
					
						
							|  |  |  |         for (auto& entry : module_cache.memory_instances) | 
					
						
							|  |  |  |             visitor.visit(entry.value); | 
					
						
							| 
									
										
										
										
											2022-11-20 06:51:24 +03:30
										 |  |  |         for (auto& entry : module_cache.table_instances) | 
					
						
							|  |  |  |             visitor.visit(entry.value); | 
					
						
							| 
									
										
										
										
											2021-06-21 04:12:15 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-31 16:55:06 +02:00
										 |  |  | JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::validate) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-11-08 03:06:30 +03:30
										 |  |  |     // 1. Let stableBytes be a copy of the bytes held by the buffer bytes.
 | 
					
						
							|  |  |  |     // Note: There's no need to copy the bytes here as the buffer data cannot change while we're compiling the module.
 | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |     auto buffer = TRY(vm.argument(0).to_object(vm)); | 
					
						
							| 
									
										
										
										
											2021-11-08 03:06:30 +03:30
										 |  |  | 
 | 
					
						
							|  |  |  |     // 2. Compile stableBytes as a WebAssembly module and store the results as module.
 | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |     auto maybe_module = parse_module(vm, buffer); | 
					
						
							| 
									
										
										
										
											2021-11-08 03:06:30 +03:30
										 |  |  | 
 | 
					
						
							|  |  |  |     // 3. If module is error, return false.
 | 
					
						
							|  |  |  |     if (maybe_module.is_error()) | 
					
						
							|  |  |  |         return JS::Value(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Drop the module from the cache, we're never going to refer to it.
 | 
					
						
							|  |  |  |     ScopeGuard drop_from_cache { | 
					
						
							|  |  |  |         [&] { | 
					
						
							| 
									
										
										
										
											2021-12-02 12:54:34 +00:00
										 |  |  |             (void)s_compiled_modules.take_last(); | 
					
						
							| 
									
										
										
										
											2021-11-08 03:06:30 +03:30
										 |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 3 continued - our "compile" step is lazy with validation, explicitly do the validation.
 | 
					
						
							|  |  |  |     if (s_abstract_machine.validate(s_compiled_modules[maybe_module.value()].module).is_error()) | 
					
						
							|  |  |  |         return JS::Value(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 4. Return true.
 | 
					
						
							|  |  |  |     return JS::Value(true); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  | JS::ThrowCompletionOr<size_t> parse_module(JS::VM& vm, JS::Object* buffer_object) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-07-01 15:14:05 +04:30
										 |  |  |     ReadonlyBytes data; | 
					
						
							|  |  |  |     if (is<JS::ArrayBuffer>(buffer_object)) { | 
					
						
							|  |  |  |         auto& buffer = static_cast<JS::ArrayBuffer&>(*buffer_object); | 
					
						
							|  |  |  |         data = buffer.buffer(); | 
					
						
							|  |  |  |     } else if (is<JS::TypedArrayBase>(buffer_object)) { | 
					
						
							|  |  |  |         auto& buffer = static_cast<JS::TypedArrayBase&>(*buffer_object); | 
					
						
							|  |  |  |         data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), buffer.byte_length()); | 
					
						
							|  |  |  |     } else if (is<JS::DataView>(buffer_object)) { | 
					
						
							|  |  |  |         auto& buffer = static_cast<JS::DataView&>(*buffer_object); | 
					
						
							|  |  |  |         data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), buffer.byte_length()); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |         return vm.throw_completion<JS::TypeError>("Not a BufferSource"sv); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-30 11:05:43 +01:00
										 |  |  |     FixedMemoryStream stream { data }; | 
					
						
							|  |  |  |     auto module_result = Wasm::Module::parse(stream); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     if (module_result.is_error()) { | 
					
						
							|  |  |  |         // FIXME: Throw CompileError instead.
 | 
					
						
							| 
									
										
										
										
											2022-12-06 01:12:49 +00:00
										 |  |  |         return vm.throw_completion<JS::TypeError>(Wasm::parse_error_to_deprecated_string(module_result.error())); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-08 03:06:30 +03:30
										 |  |  |     if (auto validation_result = WebAssemblyObject::s_abstract_machine.validate(module_result.value()); validation_result.is_error()) { | 
					
						
							|  |  |  |         // FIXME: Throw CompileError instead.
 | 
					
						
							| 
									
										
										
										
											2022-08-16 20:33:17 +01:00
										 |  |  |         return vm.throw_completion<JS::TypeError>(validation_result.error().error_string); | 
					
						
							| 
									
										
										
										
											2021-11-08 03:06:30 +03:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     WebAssemblyObject::s_compiled_modules.append(make<WebAssemblyObject::CompiledWebAssemblyModule>(module_result.release_value())); | 
					
						
							|  |  |  |     return WebAssemblyObject::s_compiled_modules.size() - 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-31 16:55:06 +02:00
										 |  |  | JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::compile) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-22 11:48:08 +01:00
										 |  |  |     auto& realm = *vm.current_realm(); | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     // FIXME: This shouldn't block!
 | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |     auto buffer_or_error = vm.argument(0).to_object(vm); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     JS::Value rejection_value; | 
					
						
							| 
									
										
										
										
											2022-02-07 15:14:31 +01:00
										 |  |  |     if (buffer_or_error.is_error()) | 
					
						
							| 
									
										
										
										
											2021-12-28 17:42:14 +01:00
										 |  |  |         rejection_value = *buffer_or_error.throw_completion().value(); | 
					
						
							| 
									
										
										
										
											2022-02-07 15:14:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  |     auto promise = JS::Promise::create(realm); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     if (!rejection_value.is_empty()) { | 
					
						
							|  |  |  |         promise->reject(rejection_value); | 
					
						
							|  |  |  |         return promise; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-10-12 19:24:57 +01:00
										 |  |  |     auto* buffer = buffer_or_error.release_value(); | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |     auto result = parse_module(vm, buffer); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     if (result.is_error()) | 
					
						
							| 
									
										
										
										
											2021-12-28 17:42:14 +01:00
										 |  |  |         promise->reject(*result.release_error().value()); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2023-01-28 13:39:44 -05:00
										 |  |  |         promise->fulfill(MUST_OR_THROW_OOM(vm.heap().allocate<WebAssemblyModuleObject>(realm, realm, result.release_value()))); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     return promise; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  | JS::ThrowCompletionOr<size_t> WebAssemblyObject::instantiate_module(JS::VM& vm, Wasm::Module const& module) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |     Wasm::Linker linker { module }; | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |     HashMap<Wasm::Linker::Name, Wasm::ExternValue> resolved_imports; | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     auto import_argument = vm.argument(1); | 
					
						
							|  |  |  |     if (!import_argument.is_undefined()) { | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         auto* import_object = TRY(import_argument.to_object(vm)); | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |         dbgln("Trying to resolve stuff because import object was specified"); | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  |         for (Wasm::Linker::Name const& import_name : linker.unresolved_imports()) { | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |             dbgln("Trying to resolve {}::{}", import_name.module, import_name.name); | 
					
						
							| 
									
										
										
										
											2021-10-02 23:52:27 +01:00
										 |  |  |             auto value_or_error = import_object->get(import_name.module); | 
					
						
							|  |  |  |             if (value_or_error.is_error()) | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2021-10-02 23:52:27 +01:00
										 |  |  |             auto value = value_or_error.release_value(); | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |             auto object_or_error = value.to_object(vm); | 
					
						
							| 
									
										
										
										
											2021-10-12 19:24:57 +01:00
										 |  |  |             if (object_or_error.is_error()) | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2021-10-12 19:24:57 +01:00
										 |  |  |             auto* object = object_or_error.release_value(); | 
					
						
							| 
									
										
										
										
											2021-10-02 23:52:27 +01:00
										 |  |  |             auto import_or_error = object->get(import_name.name); | 
					
						
							|  |  |  |             if (import_or_error.is_error()) | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2021-10-02 23:52:27 +01:00
										 |  |  |             auto import_ = import_or_error.release_value(); | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |             TRY(import_name.type.visit( | 
					
						
							|  |  |  |                 [&](Wasm::TypeIndex index) -> JS::ThrowCompletionOr<void> { | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                     dbgln("Trying to resolve a function {}::{}, type index {}", import_name.module, import_name.name, index.value()); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |                     auto& type = module.type(index); | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                     // FIXME: IsCallable()
 | 
					
						
							|  |  |  |                     if (!import_.is_function()) | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                         return {}; | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                     auto& function = import_.as_function(); | 
					
						
							|  |  |  |                     // FIXME: If this is a function created by create_native_function(),
 | 
					
						
							|  |  |  |                     //        just extract its address and resolve to that.
 | 
					
						
							|  |  |  |                     Wasm::HostFunction host_function { | 
					
						
							|  |  |  |                         [&](auto&, auto& arguments) -> Wasm::Result { | 
					
						
							| 
									
										
										
										
											2022-02-09 10:06:40 +00:00
										 |  |  |                             JS::MarkedVector<JS::Value> argument_values { vm.heap() }; | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                             for (auto& entry : arguments) | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |                                 argument_values.append(to_js_value(vm, entry)); | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-21 19:24:32 +01:00
										 |  |  |                             auto result_or_error = JS::call(vm, function, JS::js_undefined(), move(argument_values)); | 
					
						
							| 
									
										
										
										
											2021-09-23 20:56:28 +03:00
										 |  |  |                             if (result_or_error.is_error()) { | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                                 return Wasm::Trap(); | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                             if (type.results().is_empty()) | 
					
						
							|  |  |  |                                 return Wasm::Result { Vector<Wasm::Value> {} }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             if (type.results().size() == 1) { | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |                                 auto value_or_error = to_webassembly_value(vm, result_or_error.release_value(), type.results().first()); | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                                 if (value_or_error.is_error()) | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                                     return Wasm::Trap {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                                 return Wasm::Result { Vector<Wasm::Value> { value_or_error.release_value() } }; | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             // FIXME: Multiple returns
 | 
					
						
							|  |  |  |                             TODO(); | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         type | 
					
						
							|  |  |  |                     }; | 
					
						
							|  |  |  |                     auto address = s_abstract_machine.store().allocate(move(host_function)); | 
					
						
							|  |  |  |                     dbgln("Resolved to {}", address->value()); | 
					
						
							|  |  |  |                     // FIXME: LinkError instead.
 | 
					
						
							|  |  |  |                     VERIFY(address.has_value()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     resolved_imports.set(import_name, Wasm::ExternValue { Wasm::FunctionAddress { *address } }); | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                     return {}; | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                 [&](Wasm::GlobalType const& type) -> JS::ThrowCompletionOr<void> { | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                     Optional<Wasm::GlobalAddress> address; | 
					
						
							|  |  |  |                     // https://webassembly.github.io/spec/js-api/#read-the-imports step 5.1
 | 
					
						
							|  |  |  |                     if (import_.is_number() || import_.is_bigint()) { | 
					
						
							|  |  |  |                         if (import_.is_number() && type.type().kind() == Wasm::ValueType::I64) { | 
					
						
							|  |  |  |                             // FIXME: Throw a LinkError instead.
 | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |                             return vm.throw_completion<JS::TypeError>("LinkError: Import resolution attempted to cast a Number to a BigInteger"sv); | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                         } | 
					
						
							|  |  |  |                         if (import_.is_bigint() && type.type().kind() != Wasm::ValueType::I64) { | 
					
						
							|  |  |  |                             // FIXME: Throw a LinkError instead.
 | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |                             return vm.throw_completion<JS::TypeError>("LinkError: Import resolution attempted to cast a BigInteger to a Number"sv); | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                         } | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |                         auto cast_value = TRY(to_webassembly_value(vm, import_, type.type())); | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                         address = s_abstract_machine.store().allocate({ type.type(), false }, cast_value); | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                     } else { | 
					
						
							|  |  |  |                         // FIXME: https://webassembly.github.io/spec/js-api/#read-the-imports step 5.2
 | 
					
						
							|  |  |  |                         //        if v implements Global
 | 
					
						
							|  |  |  |                         //            let globaladdr be v.[[Global]]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         // FIXME: Throw a LinkError instead
 | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |                         return vm.throw_completion<JS::TypeError>("LinkError: Invalid value for global type"sv); | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     resolved_imports.set(import_name, Wasm::ExternValue { *address }); | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                     return {}; | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                 [&](Wasm::MemoryType const&) -> JS::ThrowCompletionOr<void> { | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                     if (!import_.is_object() || !is<WebAssemblyMemoryObject>(import_.as_object())) { | 
					
						
							|  |  |  |                         // FIXME: Throw a LinkError instead
 | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |                         return vm.throw_completion<JS::TypeError>("LinkError: Expected an instance of WebAssembly.Memory for a memory import"sv); | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                     } | 
					
						
							|  |  |  |                     auto address = static_cast<WebAssemblyMemoryObject const&>(import_.as_object()).address(); | 
					
						
							|  |  |  |                     resolved_imports.set(import_name, Wasm::ExternValue { address }); | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                     return {}; | 
					
						
							| 
									
										
										
										
											2021-06-21 08:42:58 +04:30
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                 [&](Wasm::TableType const&) -> JS::ThrowCompletionOr<void> { | 
					
						
							| 
									
										
										
										
											2021-09-04 04:40:57 +04:30
										 |  |  |                     if (!import_.is_object() || !is<WebAssemblyTableObject>(import_.as_object())) { | 
					
						
							|  |  |  |                         // FIXME: Throw a LinkError instead
 | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |                         return vm.throw_completion<JS::TypeError>("LinkError: Expected an instance of WebAssembly.Table for a table import"sv); | 
					
						
							| 
									
										
										
										
											2021-09-04 04:40:57 +04:30
										 |  |  |                     } | 
					
						
							|  |  |  |                     auto address = static_cast<WebAssemblyTableObject const&>(import_.as_object()).address(); | 
					
						
							|  |  |  |                     resolved_imports.set(import_name, Wasm::ExternValue { address }); | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                     return {}; | 
					
						
							| 
									
										
										
										
											2021-09-04 04:40:57 +04:30
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  |                 [&](auto const&) -> JS::ThrowCompletionOr<void> { | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |                     // FIXME: Implement these.
 | 
					
						
							| 
									
										
										
										
											2021-05-17 21:42:56 +04:30
										 |  |  |                     dbgln("Unimplemented import of non-function attempted"); | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |                     return vm.throw_completion<JS::TypeError>("LinkError: Not Implemented"sv); | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |                 })); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |     linker.link(resolved_imports); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     auto link_result = linker.finish(); | 
					
						
							|  |  |  |     if (link_result.is_error()) { | 
					
						
							|  |  |  |         // FIXME: Throw a LinkError.
 | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |         JS::ThrowableStringBuilder builder(vm); | 
					
						
							|  |  |  |         MUST_OR_THROW_OOM(builder.append("LinkError: Missing "sv)); | 
					
						
							|  |  |  |         MUST_OR_THROW_OOM(builder.join(' ', link_result.error().missing_imports)); | 
					
						
							|  |  |  |         return vm.throw_completion<JS::TypeError>(MUST_OR_THROW_OOM(builder.to_string())); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |     auto instance_result = s_abstract_machine.instantiate(module, link_result.release_value()); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     if (instance_result.is_error()) { | 
					
						
							| 
									
										
										
										
											2021-05-17 12:29:44 +04:30
										 |  |  |         // FIXME: Throw a LinkError instead.
 | 
					
						
							| 
									
										
										
										
											2022-08-16 20:33:17 +01:00
										 |  |  |         return vm.throw_completion<JS::TypeError>(instance_result.error().error); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s_instantiated_modules.append(instance_result.release_value()); | 
					
						
							| 
									
										
										
										
											2021-06-21 04:12:15 +04:30
										 |  |  |     s_module_caches.empend(); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |     return s_instantiated_modules.size() - 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-31 16:55:06 +02:00
										 |  |  | JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::instantiate) | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-22 11:48:08 +01:00
										 |  |  |     auto& realm = *vm.current_realm(); | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |     // FIXME: This shouldn't block!
 | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |     auto buffer_or_error = vm.argument(0).to_object(vm); | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  |     auto promise = JS::Promise::create(realm); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |     bool should_return_module = false; | 
					
						
							| 
									
										
										
										
											2021-10-12 19:24:57 +01:00
										 |  |  |     if (buffer_or_error.is_error()) { | 
					
						
							| 
									
										
										
										
											2021-12-28 17:42:14 +01:00
										 |  |  |         auto rejection_value = *buffer_or_error.throw_completion().value(); | 
					
						
							| 
									
										
										
										
											2021-10-12 19:24:57 +01:00
										 |  |  |         promise->reject(rejection_value); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |         return promise; | 
					
						
							| 
									
										
										
										
											2021-10-12 19:24:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     auto* buffer = buffer_or_error.release_value(); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  |     Wasm::Module const* module { nullptr }; | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |     if (is<JS::ArrayBuffer>(buffer) || is<JS::TypedArrayBase>(buffer)) { | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |         auto result = parse_module(vm, buffer); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |         if (result.is_error()) { | 
					
						
							| 
									
										
										
										
											2021-12-28 17:42:14 +01:00
										 |  |  |             promise->reject(*result.release_error().value()); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |             return promise; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |         module = &WebAssemblyObject::s_compiled_modules.at(result.release_value()).module; | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |         should_return_module = true; | 
					
						
							|  |  |  |     } else if (is<WebAssemblyModuleObject>(buffer)) { | 
					
						
							|  |  |  |         module = &static_cast<WebAssemblyModuleObject*>(buffer)->module(); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |         auto error = JS::TypeError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted("{} is not an ArrayBuffer or a Module", buffer->class_name()))); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |         promise->reject(error); | 
					
						
							|  |  |  |         return promise; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     VERIFY(module); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |     auto result = instantiate_module(vm, *module); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |     if (result.is_error()) { | 
					
						
							| 
									
										
										
										
											2021-12-28 17:42:14 +01:00
										 |  |  |         promise->reject(*result.release_error().value()); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-01-28 13:39:44 -05:00
										 |  |  |         auto instance_object = MUST_OR_THROW_OOM(vm.heap().allocate<WebAssemblyInstanceObject>(realm, realm, result.release_value())); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |         if (should_return_module) { | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  |             auto object = JS::Object::create(realm, nullptr); | 
					
						
							| 
									
										
										
										
											2023-01-28 13:39:44 -05:00
										 |  |  |             object->define_direct_property("module", MUST_OR_THROW_OOM(vm.heap().allocate<WebAssemblyModuleObject>(realm, realm, s_compiled_modules.size() - 1)), JS::default_attributes); | 
					
						
							| 
									
										
										
										
											2021-07-06 01:15:50 +03:00
										 |  |  |             object->define_direct_property("instance", instance_object, JS::default_attributes); | 
					
						
							| 
									
										
										
										
											2021-07-01 13:41:15 +04:30
										 |  |  |             promise->fulfill(object); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             promise->fulfill(instance_object); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     return promise; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  | JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |     auto& realm = *vm.current_realm(); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     switch (wasm_value.type().kind()) { | 
					
						
							|  |  |  |     case Wasm::ValueType::I64: | 
					
						
							| 
									
										
										
										
											2023-01-28 13:39:44 -05:00
										 |  |  |         return realm.heap().allocate<JS::BigInt>(realm, ::Crypto::SignedBigInteger { wasm_value.to<i64>().value() }).release_allocated_value_but_fixme_should_propagate_errors(); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     case Wasm::ValueType::I32: | 
					
						
							|  |  |  |         return JS::Value(wasm_value.to<i32>().value()); | 
					
						
							|  |  |  |     case Wasm::ValueType::F64: | 
					
						
							|  |  |  |         return JS::Value(wasm_value.to<double>().value()); | 
					
						
							| 
									
										
										
										
											2021-07-22 13:24:45 +04:30
										 |  |  |     case Wasm::ValueType::F32: | 
					
						
							|  |  |  |         return JS::Value(static_cast<double>(wasm_value.to<float>().value())); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     case Wasm::ValueType::FunctionReference: | 
					
						
							|  |  |  |         // FIXME: What's the name of a function reference that isn't exported?
 | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |         return create_native_function(vm, wasm_value.to<Wasm::Reference::Func>().value().address, "FIXME_IHaveNoIdeaWhatThisShouldBeCalled"); | 
					
						
							| 
									
										
										
										
											2021-06-01 09:48:36 +04:30
										 |  |  |     case Wasm::ValueType::NullFunctionReference: | 
					
						
							|  |  |  |         return JS::js_null(); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     case Wasm::ValueType::ExternReference: | 
					
						
							| 
									
										
										
										
											2021-06-01 09:48:36 +04:30
										 |  |  |     case Wasm::ValueType::NullExternReference: | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |         TODO(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  | JS::ThrowCompletionOr<Wasm::Value> to_webassembly_value(JS::VM& vm, JS::Value value, Wasm::ValueType const& type) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-30 20:02:55 +03:00
										 |  |  |     static ::Crypto::SignedBigInteger two_64 = "1"_sbigint.shift_left(64); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (type.kind()) { | 
					
						
							|  |  |  |     case Wasm::ValueType::I64: { | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         auto bigint = TRY(value.to_bigint(vm)); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |         auto value = bigint->big_integer().divided_by(two_64).remainder; | 
					
						
							| 
									
										
										
										
											2021-07-22 13:25:57 +04:30
										 |  |  |         VERIFY(value.unsigned_value().trimmed_length() <= 2); | 
					
						
							|  |  |  |         i64 integer = static_cast<i64>(value.unsigned_value().to_u64()); | 
					
						
							|  |  |  |         if (value.is_negative()) | 
					
						
							|  |  |  |             integer = -integer; | 
					
						
							|  |  |  |         return Wasm::Value { integer }; | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     } | 
					
						
							|  |  |  |     case Wasm::ValueType::I32: { | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         auto _i32 = TRY(value.to_i32(vm)); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |         return Wasm::Value { static_cast<i32>(_i32) }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case Wasm::ValueType::F64: { | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         auto number = TRY(value.to_double(vm)); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |         return Wasm::Value { static_cast<double>(number) }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case Wasm::ValueType::F32: { | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         auto number = TRY(value.to_double(vm)); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |         return Wasm::Value { static_cast<float>(number) }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case Wasm::ValueType::FunctionReference: | 
					
						
							| 
									
										
										
										
											2021-09-04 04:40:57 +04:30
										 |  |  |     case Wasm::ValueType::NullFunctionReference: { | 
					
						
							|  |  |  |         if (value.is_null()) | 
					
						
							|  |  |  |             return Wasm::Value { Wasm::ValueType(Wasm::ValueType::NullExternReference), 0ull }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (value.is_function()) { | 
					
						
							|  |  |  |             auto& function = value.as_function(); | 
					
						
							|  |  |  |             for (auto& entry : WebAssemblyObject::s_global_cache.function_instances) { | 
					
						
							|  |  |  |                 if (entry.value == &function) | 
					
						
							|  |  |  |                     return Wasm::Value { Wasm::Reference { Wasm::Reference::Func { entry.key } } }; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 20:33:17 +01:00
										 |  |  |         return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Exported function"); | 
					
						
							| 
									
										
										
										
											2021-09-04 04:40:57 +04:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |     case Wasm::ValueType::ExternReference: | 
					
						
							| 
									
										
										
										
											2021-06-01 09:48:36 +04:30
										 |  |  |     case Wasm::ValueType::NullExternReference: | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |         TODO(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 18:02:33 +00:00
										 |  |  | JS::NativeFunction* create_native_function(JS::VM& vm, Wasm::FunctionAddress address, DeprecatedString const& name) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |     auto& realm = *vm.current_realm(); | 
					
						
							| 
									
										
										
										
											2021-06-13 21:33:10 +04:30
										 |  |  |     Optional<Wasm::FunctionType> type; | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  |     WebAssemblyObject::s_abstract_machine.store().get(address)->visit([&](auto const& value) { type = value.type(); }); | 
					
						
							| 
									
										
										
										
											2021-06-21 04:12:15 +04:30
										 |  |  |     if (auto entry = WebAssemblyObject::s_global_cache.function_instances.get(address); entry.has_value()) | 
					
						
							|  |  |  |         return *entry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto function = JS::NativeFunction::create( | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  |         realm, | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |         name, | 
					
						
							| 
									
										
										
										
											2022-08-22 11:48:08 +01:00
										 |  |  |         [address, type = type.release_value()](JS::VM& vm) -> JS::ThrowCompletionOr<JS::Value> { | 
					
						
							|  |  |  |             auto& realm = *vm.current_realm(); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |             Vector<Wasm::Value> values; | 
					
						
							| 
									
										
										
										
											2021-06-13 21:33:10 +04:30
										 |  |  |             values.ensure_capacity(type.parameters().size()); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |             // Grab as many values as needed and convert them.
 | 
					
						
							|  |  |  |             size_t index = 0; | 
					
						
							| 
									
										
										
										
											2021-10-31 16:53:51 +02:00
										 |  |  |             for (auto& type : type.parameters()) | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |                 values.append(TRY(to_webassembly_value(vm, vm.argument(index++), type))); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |             auto result = WebAssemblyObject::s_abstract_machine.invoke(address, move(values)); | 
					
						
							|  |  |  |             // FIXME: Use the convoluted mapping of errors defined in the spec.
 | 
					
						
							| 
									
										
										
										
											2021-10-19 22:53:27 +03:00
										 |  |  |             if (result.is_trap()) | 
					
						
							| 
									
										
										
										
											2023-02-16 14:09:11 -05:00
										 |  |  |                 return vm.throw_completion<JS::TypeError>(TRY_OR_THROW_OOM(vm, String::formatted("Wasm execution trapped (WIP): {}", result.trap().reason))); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |             if (result.values().is_empty()) | 
					
						
							|  |  |  |                 return JS::js_undefined(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (result.values().size() == 1) | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |                 return to_js_value(vm, result.values().first()); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |             Vector<JS::Value> result_values; | 
					
						
							|  |  |  |             for (auto& entry : result.values()) | 
					
						
							| 
									
										
										
										
											2022-08-21 21:16:30 +01:00
										 |  |  |                 result_values.append(to_js_value(vm, entry)); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  |             return JS::Value(JS::Array::create_from(realm, result_values)); | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2021-06-21 04:12:15 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |     WebAssemblyObject::s_global_cache.function_instances.set(address, function); | 
					
						
							|  |  |  |     return function; | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  | WebAssemblyMemoryObject::WebAssemblyMemoryObject(JS::Realm& realm, Wasm::MemoryAddress address) | 
					
						
							| 
									
										
										
										
											2023-01-09 17:49:06 -05:00
										 |  |  |     : Object(ConstructWithPrototypeTag::Tag, Bindings::ensure_web_prototype<WebAssemblyMemoryPrototype>(realm, "WebAssembly.Memory")) | 
					
						
							| 
									
										
										
										
											2021-05-17 21:42:56 +04:30
										 |  |  |     , m_address(address) | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-05-17 21:42:56 +04:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-17 00:16:44 +04:30
										 |  |  | } |