LibWeb: Refactor WebAssembly API to use spec-defined promise AOs

This commit is contained in:
Andrew Kaster 2024-10-26 14:09:25 -06:00 committed by Andrew Kaster
parent 3504370281
commit ba6dcd7521
Notes: github-actions[bot] 2024-11-01 17:43:26 +00:00
6 changed files with 278 additions and 142 deletions

View file

@ -2,15 +2,51 @@
ArrayBuffer
-------------
Hello from wasm!!!!!!
FIXME: Run test for Uint8Array. Not running due to flakiness.
FIXME: Run test for Uint8ClampedArray. Not running due to flakiness.
FIXME: Run test for Uint16Array. Not running due to flakiness.
FIXME: Run test for Uint32Array. Not running due to flakiness.
FIXME: Run test for Int8Array. Not running due to flakiness.
FIXME: Run test for Int16Array. Not running due to flakiness.
FIXME: Run test for Float32Array. Not running due to flakiness.
FIXME: Run test for Float64Array. Not running due to flakiness.
FIXME: Run test for BigUint64Array. Not running due to flakiness.
FIXME: Run test for BigInt64Array. Not running due to flakiness.
FIXME: Run test for DataView. Not running due to flakiness.
FIXME: Run test for WebAssembly.Module. Not running due to flakiness.
-------------
Uint8Array
-------------
Hello from wasm!!!!!!
-------------
Uint8ClampedArray
-------------
Hello from wasm!!!!!!
-------------
Uint16Array
-------------
Hello from wasm!!!!!!
-------------
Uint32Array
-------------
Hello from wasm!!!!!!
-------------
Int8Array
-------------
Hello from wasm!!!!!!
-------------
Int16Array
-------------
Hello from wasm!!!!!!
-------------
Float32Array
-------------
Hello from wasm!!!!!!
-------------
Float64Array
-------------
Hello from wasm!!!!!!
-------------
BigUint64Array
-------------
Hello from wasm!!!!!!
-------------
BigInt64Array
-------------
Hello from wasm!!!!!!
-------------
DataView
-------------
Hello from wasm!!!!!!
-------------
WebAssembly.Module
-------------
Hello from wasm!!!!!!

View file

@ -9,13 +9,8 @@
cachedTextDecoder.decode();
let cachedUint8Memory0 = null;
function getUint8Memory0() {
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8Memory0;
return new Uint8Array(wasm.memory.buffer);
}
function getStringFromWasm0(ptr, len) {
@ -58,24 +53,30 @@
]).buffer;
const BUFFER_SOURCES = [
{ constructor: Uint8Array, flaky: true },
{ constructor: Uint8ClampedArray, flaky: true },
{ constructor: Uint16Array, flaky: true },
{ constructor: Uint32Array, flaky: true },
{ constructor: Int8Array, flaky: true },
{ constructor: Int16Array, flaky: true },
{ constructor: Float32Array, flaky: true },
{ constructor: Float64Array, flaky: true },
{ constructor: BigUint64Array, flaky: true },
{ constructor: BigInt64Array, flaky: true },
{ constructor: DataView, flaky: true },
{ constructor: Uint8Array},
{ constructor: Uint8ClampedArray },
{ constructor: Uint16Array },
{ constructor: Uint32Array },
{ constructor: Int8Array },
{ constructor: Int16Array },
{ constructor: Float32Array },
{ constructor: Float64Array },
{ constructor: BigUint64Array },
{ constructor: BigInt64Array },
{ constructor: DataView },
];
async function runTest(buffer) {
println("-------------")
println(buffer.constructor.name);
println("-------------")
const module = await WebAssembly.instantiate(buffer, exports);
const module = await WebAssembly.instantiate(buffer, exports).catch(e => {
println(`FIXME: Failed to instantiate with ${buffer.constructor.name}: ${e.name}: ${e.message}`);
return Promise.resolve();
});
if (!module) {
return Promise.resolve();
}
wasm = module.instance?.exports ?? module.exports;
try {
wasm.greet();
@ -87,23 +88,16 @@
await runTest(arrayBuffer);
for (const { constructor, flaky } of BUFFER_SOURCES) {
if (!flaky) {
await runTest(new constructor(arrayBuffer));
} else {
// The flakiness is the runtime either trapping with a RangeError, or the printed string being complete garbage,
// which more prominently happens with DataView and the arrays bigger than u8. However, the RangeError flake is
// still possible with u8.
println(`FIXME: Run test for ${constructor.name}. Not running due to flakiness.`);
}
for (const { constructor } of BUFFER_SOURCES) {
await runTest(new constructor(arrayBuffer));
}
if (false) {
const compiledModule = await WebAssembly.compile(arrayBuffer);
const compiledModule = await WebAssembly.compile(arrayBuffer).catch(() => {
println(`FIXME: Failed to compile with ArrayBuffer`);
return Promise.resolve()
});
if (compiledModule) {
await runTest(compiledModule);
} else {
// Same issues as above.
println(`FIXME: Run test for WebAssembly.Module. Not running due to flakiness.`);
}
done();

View file

@ -21,14 +21,13 @@ namespace Web::WebAssembly {
JS_DEFINE_ALLOCATOR(Instance);
WebIDL::ExceptionOr<JS::NonnullGCPtr<Instance>> Instance::construct_impl(JS::Realm& realm, Module& module, Optional<JS::Handle<JS::Object>>& import_object)
WebIDL::ExceptionOr<JS::NonnullGCPtr<Instance>> Instance::construct_impl(JS::Realm& realm, Module& module, Optional<JS::Handle<JS::Object>>& import_object_handle)
{
// FIXME: Implement the importObject parameter.
(void)import_object;
JS::GCPtr<JS::Object> import_object = import_object_handle.has_value() ? import_object_handle.value().ptr() : nullptr;
auto& vm = realm.vm();
auto module_instance = TRY(Detail::instantiate_module(vm, module.compiled_module()->module));
auto module_instance = TRY(Detail::instantiate_module(vm, module.compiled_module()->module, import_object));
return vm.heap().allocate<Instance>(realm, realm, move(module_instance));
}

View file

@ -11,6 +11,7 @@
#include <LibWeb/Bindings/ModulePrototype.h>
#include <LibWeb/WebAssembly/Module.h>
#include <LibWeb/WebAssembly/WebAssembly.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::WebAssembly {
@ -21,7 +22,14 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Module>> Module::construct_impl(JS::Realm&
{
auto& vm = realm.vm();
auto compiled_module = TRY(Detail::parse_module(vm, bytes->raw_object()));
auto stable_bytes_or_error = WebIDL::get_buffer_source_copy(bytes->raw_object());
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 vm.heap().allocate<Module>(realm, realm, move(compiled_module));
}

View file

@ -19,17 +19,23 @@
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/VM.h>
#include <LibWasm/AbstractMachine/Validator.h>
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/WebAssembly/Instance.h>
#include <LibWeb/WebAssembly/Memory.h>
#include <LibWeb/WebAssembly/Module.h>
#include <LibWeb/WebAssembly/Table.h>
#include <LibWeb/WebAssembly/WebAssembly.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/Promise.h>
namespace Web::WebAssembly {
static JS::NonnullGCPtr<WebIDL::Promise> asynchronously_compile_webassembly_module(JS::VM&, ByteBuffer, HTML::Task::Source = HTML::Task::Source::Unspecified);
static JS::NonnullGCPtr<WebIDL::Promise> instantiate_promise_of_module(JS::VM&, JS::NonnullGCPtr<WebIDL::Promise>, JS::GCPtr<JS::Object> import_object);
static JS::NonnullGCPtr<WebIDL::Promise> asynchronously_instantiate_webassembly_module(JS::VM&, JS::NonnullGCPtr<Module>, JS::GCPtr<JS::Object> import_object);
namespace Detail {
HashMap<JS::GCPtr<JS::Object>, WebAssemblyCache> s_caches;
@ -62,21 +68,19 @@ void finalize(JS::Object& object)
bool validate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes)
{
// 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.
auto stable_bytes = WebIDL::get_buffer_source_copy(*bytes->raw_object());
if (stable_bytes.is_error()) {
VERIFY(stable_bytes.error().code() == ENOMEM);
return false;
}
// 2. Compile stableBytes as a WebAssembly module and store the results as module.
auto module_or_error = Detail::parse_module(vm, bytes->raw_object());
auto module_or_error = Detail::compile_a_webassembly_module(vm, stable_bytes.release_value());
// 3. If module is error, return false.
if (module_or_error.is_error())
return false;
// 3 continued - our "compile" step is lazy with validation, explicitly do the validation.
auto compiled_module = module_or_error.release_value();
auto& cache = Detail::get_cache(*vm.current_realm());
if (cache.abstract_machine().validate(compiled_module->module).is_error())
return false;
// 4. Return true.
return true;
}
@ -86,87 +90,54 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> compile(JS::VM& vm, JS::H
{
auto& realm = *vm.current_realm();
// FIXME: This shouldn't block!
auto compiled_module_or_error = Detail::parse_module(vm, bytes->raw_object());
auto promise = WebIDL::create_promise(realm);
if (compiled_module_or_error.is_error()) {
WebIDL::reject_promise(realm, promise, compiled_module_or_error.error_value());
} else {
auto module_object = vm.heap().allocate<Module>(realm, realm, compiled_module_or_error.release_value());
WebIDL::resolve_promise(realm, promise, module_object);
// 1. Let stableBytes be a copy of the bytes held by the buffer bytes.
auto stable_bytes = WebIDL::get_buffer_source_copy(*bytes->raw_object());
if (stable_bytes.is_error()) {
VERIFY(stable_bytes.error().code() == ENOMEM);
return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
}
return promise;
// 2. Asynchronously compile a WebAssembly module from stableBytes and return the result.
return asynchronously_compile_webassembly_module(vm, stable_bytes.release_value());
}
// https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object)
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object_handle)
{
// FIXME: Implement the importObject parameter.
(void)import_object;
auto& realm = *vm.current_realm();
// FIXME: This shouldn't block!
auto compiled_module_or_error = Detail::parse_module(vm, bytes->raw_object());
auto promise = WebIDL::create_promise(realm);
if (compiled_module_or_error.is_error()) {
WebIDL::reject_promise(realm, promise, compiled_module_or_error.error_value());
return promise;
// 1. Let stableBytes be a copy of the bytes held by the buffer bytes.
auto stable_bytes = WebIDL::get_buffer_source_copy(*bytes->raw_object());
if (stable_bytes.is_error()) {
VERIFY(stable_bytes.error().code() == ENOMEM);
return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
}
auto compiled_module = compiled_module_or_error.release_value();
auto result = Detail::instantiate_module(vm, compiled_module->module);
// 2. Asynchronously compile a WebAssembly module from stableBytes and let promiseOfModule be the result.
auto promise_of_module = asynchronously_compile_webassembly_module(vm, stable_bytes.release_value());
if (result.is_error()) {
WebIDL::reject_promise(realm, promise, result.error_value());
} else {
auto module_object = vm.heap().allocate<Module>(realm, realm, move(compiled_module));
auto instance_object = vm.heap().allocate<Instance>(realm, realm, result.release_value());
auto object = JS::Object::create(realm, nullptr);
object->define_direct_property("module", module_object, JS::default_attributes);
object->define_direct_property("instance", instance_object, JS::default_attributes);
WebIDL::resolve_promise(realm, promise, object);
}
return promise;
// 3. Instantiate promiseOfModule with imports importObject and return the result.
JS::GCPtr<JS::Object> const import_object = import_object_handle.has_value() ? import_object_handle.value().ptr() : nullptr;
return instantiate_promise_of_module(vm, promise_of_module, import_object);
}
// https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate-moduleobject-importobject
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM& vm, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object)
{
// FIXME: Implement the importObject parameter.
(void)import_object;
auto& realm = *vm.current_realm();
auto promise = WebIDL::create_promise(realm);
// FIXME: This shouldn't block!
auto const& compiled_module = module_object.compiled_module();
auto result = Detail::instantiate_module(vm, compiled_module->module);
if (result.is_error()) {
WebIDL::reject_promise(realm, promise, result.error_value());
} else {
auto instance_object = vm.heap().allocate<Instance>(realm, realm, result.release_value());
WebIDL::resolve_promise(realm, promise, instance_object);
}
return promise;
// 1. Asynchronously instantiate the WebAssembly module moduleObject importing importObject, and return the result.
JS::NonnullGCPtr<Module> module { const_cast<Module&>(module_object) };
JS::GCPtr<JS::Object> const imports = import_object.has_value() ? import_object.value().ptr() : nullptr;
return asynchronously_instantiate_webassembly_module(vm, module, imports);
}
namespace Detail {
JS::ThrowCompletionOr<NonnullOwnPtr<Wasm::ModuleInstance>> instantiate_module(JS::VM& vm, Wasm::Module const& module)
JS::ThrowCompletionOr<NonnullOwnPtr<Wasm::ModuleInstance>> instantiate_module(JS::VM& vm, Wasm::Module const& module, JS::GCPtr<JS::Object> import_object)
{
Wasm::Linker linker { module };
HashMap<Wasm::Linker::Name, Wasm::ExternValue> resolved_imports;
auto import_argument = vm.argument(1);
auto& cache = get_cache(*vm.current_realm());
if (!import_argument.is_undefined()) {
auto import_object = TRY(import_argument.to_object(vm));
if (import_object) {
dbgln_if(LIBWEB_WASM_DEBUG, "Trying to resolve stuff because import object was specified");
for (Wasm::Linker::Name const& import_name : linker.unresolved_imports()) {
dbgln_if(LIBWEB_WASM_DEBUG, "Trying to resolve {}::{}", import_name.module, import_name.name);
@ -309,32 +280,10 @@ JS::ThrowCompletionOr<NonnullOwnPtr<Wasm::ModuleInstance>> instantiate_module(JS
return instance_result.release_value();
}
JS::ThrowCompletionOr<NonnullRefPtr<CompiledWebAssemblyModule>> parse_module(JS::VM& vm, JS::Object* buffer_object)
// // https://webassembly.github.io/spec/js-api/#compile-a-webassembly-module
JS::ThrowCompletionOr<NonnullRefPtr<CompiledWebAssemblyModule>> compile_a_webassembly_module(JS::VM& vm, ByteBuffer data)
{
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);
auto typed_array_record = JS::make_typed_array_with_buffer_witness_record(buffer, JS::ArrayBuffer::Order::SeqCst);
if (JS::is_typed_array_out_of_bounds(typed_array_record))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::BufferOutOfBounds, "TypedArray"sv);
data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), JS::typed_array_byte_length(typed_array_record));
} else if (is<JS::DataView>(buffer_object)) {
auto& buffer = static_cast<JS::DataView&>(*buffer_object);
auto view_record = JS::make_data_view_with_buffer_witness_record(buffer, JS::ArrayBuffer::Order::SeqCst);
if (JS::is_view_out_of_bounds(view_record))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::BufferOutOfBounds, "DataView"sv);
data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), JS::get_view_byte_length(view_record));
} else {
return vm.throw_completion<JS::TypeError>("Not a BufferSource"sv);
}
FixedMemoryStream stream { data };
FixedMemoryStream stream { data.bytes() };
auto module_result = Wasm::Module::parse(stream);
if (module_result.is_error()) {
// FIXME: Throw CompileError instead.
@ -525,4 +474,154 @@ JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value, Wasm::ValueType type)
}
// https://webassembly.github.io/spec/js-api/#asynchronously-compile-a-webassembly-module
JS::NonnullGCPtr<WebIDL::Promise> asynchronously_compile_webassembly_module(JS::VM& vm, ByteBuffer bytes, HTML::Task::Source task_source)
{
auto& realm = *vm.current_realm();
// 1. Let promise be a new Promise.
auto promise = WebIDL::create_promise(realm);
// 2. Run the following steps in parallel:
Platform::EventLoopPlugin::the().deferred_invoke([&vm, bytes = move(bytes), promise, task_source]() mutable {
HTML::TemporaryExecutionContext context(HTML::relevant_settings_object(*promise->promise()), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
// 1. Compile the WebAssembly module bytes and store the result as module.
auto module_or_error = Detail::compile_a_webassembly_module(vm, move(bytes));
// 2. Queue a task to perform the following steps. If taskSource was provided, queue the task on that task source.
HTML::queue_a_task(task_source, nullptr, nullptr, JS::create_heap_function(vm.heap(), [&vm, promise, module_or_error = move(module_or_error)]() mutable {
HTML::TemporaryExecutionContext context(HTML::relevant_settings_object(*promise->promise()), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
auto& realm = HTML::relevant_realm(*promise->promise());
// 1. If module is error, reject promise with a CompileError exception.
if (module_or_error.is_error()) {
WebIDL::reject_promise(realm, promise, module_or_error.error_value());
}
// 2. Otherwise,
else {
// 1. Construct a WebAssembly module object from module and bytes, and let moduleObject be the result.
// FIXME: Save bytes to the Module instance instead of moving into compile_a_webassembly_module
auto module_object = vm.heap().allocate<Module>(realm, realm, module_or_error.release_value());
// 2. Resolve promise with moduleObject.
WebIDL::resolve_promise(*vm.current_realm(), promise, module_object);
}
}));
});
// 3. Return promise.
return promise;
}
// https://webassembly.github.io/spec/js-api/#asynchronously-instantiate-a-webassembly-module
JS::NonnullGCPtr<WebIDL::Promise> asynchronously_instantiate_webassembly_module(JS::VM& vm, JS::NonnullGCPtr<Module> module_object, JS::GCPtr<JS::Object> import_object)
{
auto& realm = *vm.current_realm();
// 1. Let promise be a new promise.
auto promise = WebIDL::create_promise(realm);
// 2. Let module be moduleObject.[[Module]].
auto module = module_object->compiled_module();
// 3. Read the imports of module with imports importObject, and let imports be the result.
// If this operation throws an exception, catch it, reject promise with the exception, and return promise.
// Note: We do this at the same time as instantiation in instantiate_module.
// 4. Run the following steps in parallel:
// 1. Queue a task to perform the following steps: Note: Implementation-specific work may be performed here.
HTML::queue_a_task(HTML::Task::Source::Unspecified, nullptr, nullptr, JS::create_heap_function(vm.heap(), [&vm, promise, module, import_object]() {
HTML::TemporaryExecutionContext context(HTML::relevant_settings_object(*promise->promise()), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
auto& realm = HTML::relevant_realm(*promise->promise());
// 1. Instantiate the core of a WebAssembly module module with imports, and let instance be the result.
// If this throws an exception, catch it, reject promise with the exception, and terminate these substeps.
auto result = Detail::instantiate_module(vm, module->module, import_object);
if (result.is_error()) {
WebIDL::reject_promise(realm, promise, result.error_value());
return;
}
auto instance = result.release_value();
// 2. Let instanceObject be a new Instance.
// 3. Initialize instanceObject from module and instance. If this throws an exception, catch it, reject promise with the exception, and terminate these substeps.
// FIXME: Investigate whether we are doing all the proper steps for "initialize an instance object"
auto instance_object = vm.heap().allocate<Instance>(realm, realm, move(instance));
// 4. Resolve promise with instanceObject.
WebIDL::resolve_promise(realm, promise, instance_object);
}));
// 5. Return promise.
return promise;
}
// https://webassembly.github.io/spec/js-api/#instantiate-a-promise-of-a-module
JS::NonnullGCPtr<WebIDL::Promise> instantiate_promise_of_module(JS::VM& vm, JS::NonnullGCPtr<WebIDL::Promise> promise_of_module, JS::GCPtr<JS::Object> import_object)
{
auto& realm = *vm.current_realm();
// 1. Let promise be a new Promise.
auto promise = WebIDL::create_promise(realm);
// FIXME: Spec should use react to promise here instead of separate upon fulfillment and upon rejection steps
// 2. Upon fulfillment of promiseOfModule with value module:
auto fulfillment_steps = JS::create_heap_function(vm.heap(), [&vm, promise, import_object](JS::Value module_value) -> WebIDL::ExceptionOr<JS::Value> {
VERIFY(module_value.is_object() && is<Module>(module_value.as_object()));
auto module = JS::NonnullGCPtr { static_cast<Module&>(module_value.as_object()) };
// 1. Instantiate the WebAssembly module module importing importObject, and let innerPromise be the result.
auto inner_promise = asynchronously_instantiate_webassembly_module(vm, module, import_object);
// 2. Upon fulfillment of innerPromise with value instance.
auto instantiate_fulfillment_steps = JS::create_heap_function(vm.heap(), [promise, module](JS::Value instance_value) -> WebIDL::ExceptionOr<JS::Value> {
auto& realm = HTML::relevant_realm(*promise->promise());
VERIFY(instance_value.is_object() && is<Instance>(instance_value.as_object()));
auto instance = JS::NonnullGCPtr { static_cast<Instance&>(instance_value.as_object()) };
// 1. Let result be the WebAssemblyInstantiatedSource value «[ "module" → module, "instance" → instance ]».
auto result = JS::Object::create(realm, nullptr);
result->define_direct_property("module", module, JS::default_attributes);
result->define_direct_property("instance", instance, JS::default_attributes);
// 2. Resolve promise with result.
WebIDL::resolve_promise(realm, promise, result);
return JS::js_undefined();
});
// 3. Upon rejection of innerPromise with reason reason.
auto instantiate_rejection_steps = JS::create_heap_function(vm.heap(), [promise](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
auto& realm = HTML::relevant_realm(*promise->promise());
// 1. Reject promise with reason.
WebIDL::reject_promise(realm, promise, reason);
return JS::js_undefined();
});
WebIDL::react_to_promise(inner_promise, instantiate_fulfillment_steps, instantiate_rejection_steps);
return JS::js_undefined();
});
// 3. Upon rejection of promiseOfModule with reason reason:
auto rejection_steps = JS::create_heap_function(vm.heap(), [promise](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
auto& realm = HTML::relevant_realm(*promise->promise());
// 1. Reject promise with reason.
WebIDL::reject_promise(realm, promise, reason);
return JS::js_undefined();
});
WebIDL::react_to_promise(promise_of_module, fulfillment_steps, rejection_steps);
// 4. Return promise.
return promise;
}
}

View file

@ -62,8 +62,8 @@ private:
WebAssemblyCache& get_cache(JS::Realm&);
JS::ThrowCompletionOr<NonnullOwnPtr<Wasm::ModuleInstance>> instantiate_module(JS::VM&, Wasm::Module const&);
JS::ThrowCompletionOr<NonnullRefPtr<CompiledWebAssemblyModule>> parse_module(JS::VM&, JS::Object* buffer);
JS::ThrowCompletionOr<NonnullOwnPtr<Wasm::ModuleInstance>> instantiate_module(JS::VM&, Wasm::Module const&, JS::GCPtr<JS::Object> import_object);
JS::ThrowCompletionOr<NonnullRefPtr<CompiledWebAssemblyModule>> compile_a_webassembly_module(JS::VM&, ByteBuffer);
JS::NativeFunction* create_native_function(JS::VM&, Wasm::FunctionAddress address, ByteString const& name, Instance* instance = nullptr);
JS::ThrowCompletionOr<Wasm::Value> to_webassembly_value(JS::VM&, JS::Value value, Wasm::ValueType const& type);
Wasm::Value default_webassembly_value(JS::VM&, Wasm::ValueType type);