diff options
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime')
18 files changed, 187 insertions, 157 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp index 1b3aa73bc4..e8899b7c63 100644 --- a/Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp @@ -38,15 +38,15 @@ static Object* async_from_sync_iterator_continuation(VM& vm, Object& result, Pro // 1. NOTE: Because promiseCapability is derived from the intrinsic %Promise%, the calls to promiseCapability.[[Reject]] entailed by the use IfAbruptRejectPromise below are guaranteed not to throw. // 2. Let done be Completion(IteratorComplete(result)). // 3. IfAbruptRejectPromise(done, promiseCapability). - auto done = TRY_OR_MUST_REJECT(vm, promise_capability, iterator_complete(vm, result)); + auto done = TRY_OR_MUST_REJECT(vm, &promise_capability, iterator_complete(vm, result)); // 4. Let value be Completion(IteratorValue(result)). // 5. IfAbruptRejectPromise(value, promiseCapability). - auto value = TRY_OR_MUST_REJECT(vm, promise_capability, iterator_value(vm, result)); + auto value = TRY_OR_MUST_REJECT(vm, &promise_capability, iterator_value(vm, result)); // 6. Let valueWrapper be PromiseResolve(%Promise%, value). // 7. IfAbruptRejectPromise(valueWrapper, promiseCapability). - auto value_wrapper = TRY_OR_MUST_REJECT(vm, promise_capability, promise_resolve(vm, *realm.intrinsics().promise_constructor(), value)); + auto value_wrapper = TRY_OR_MUST_REJECT(vm, &promise_capability, promise_resolve(vm, *realm.intrinsics().promise_constructor(), value)); // 8. Let unwrap be a new Abstract Closure with parameters (value) that captures done and performs the following steps when called: auto unwrap = [done](VM& vm) -> ThrowCompletionOr<Value> { @@ -59,10 +59,10 @@ static Object* async_from_sync_iterator_continuation(VM& vm, Object& result, Pro auto* on_fulfilled = NativeFunction::create(realm, move(unwrap), 1, ""); // 11. Perform PerformPromiseThen(valueWrapper, onFulfilled, undefined, promiseCapability). - verify_cast<Promise>(value_wrapper)->perform_then(move(on_fulfilled), js_undefined(), promise_capability); + verify_cast<Promise>(value_wrapper)->perform_then(move(on_fulfilled), js_undefined(), &promise_capability); // 12. Return promiseCapability.[[Promise]]. - return promise_capability.promise; + return promise_capability.promise(); } // 27.1.4.2.1 %AsyncFromSyncIteratorPrototype%.next ( [ value ] ), https://tc39.es/ecma262/#sec-%asyncfromsynciteratorprototype%.next @@ -118,10 +118,10 @@ JS_DEFINE_NATIVE_FUNCTION(AsyncFromSyncIteratorPrototype::return_) auto* iter_result = create_iterator_result_object(vm, vm.argument(0), true); // b. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »). - MUST(call(vm, *promise_capability.resolve, js_undefined(), iter_result)); + MUST(call(vm, *promise_capability->resolve(), js_undefined(), iter_result)); // c. Return promiseCapability.[[Promise]]. - return promise_capability.promise; + return promise_capability->promise(); } // 8. If value is present, then @@ -137,9 +137,9 @@ JS_DEFINE_NATIVE_FUNCTION(AsyncFromSyncIteratorPrototype::return_) if (!result.is_object()) { auto* error = TypeError::create(realm, String::formatted(ErrorType::NotAnObject.message(), "SyncIteratorReturnResult")); // a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »). - MUST(call(vm, *promise_capability.reject, js_undefined(), error)); + MUST(call(vm, *promise_capability->reject(), js_undefined(), error)); // b. Return promiseCapability.[[Promise]]. - return promise_capability.promise; + return promise_capability->promise(); } // 12. Return AsyncFromSyncIteratorContinuation(result, promiseCapability). @@ -168,9 +168,9 @@ JS_DEFINE_NATIVE_FUNCTION(AsyncFromSyncIteratorPrototype::throw_) // 7. If throw is undefined, then if (throw_method == nullptr) { // a. Perform ! Call(promiseCapability.[[Reject]], undefined, « value »). - MUST(call(vm, *promise_capability.reject, js_undefined(), vm.argument(0))); + MUST(call(vm, *promise_capability->reject(), js_undefined(), vm.argument(0))); // b. Return promiseCapability.[[Promise]]. - return promise_capability.promise; + return promise_capability->promise(); } // 8. If value is present, then // a. Let result be Completion(Call(throw, syncIterator, « value »)). @@ -185,10 +185,10 @@ JS_DEFINE_NATIVE_FUNCTION(AsyncFromSyncIteratorPrototype::throw_) if (!result.is_object()) { auto* error = TypeError::create(realm, String::formatted(ErrorType::NotAnObject.message(), "SyncIteratorThrowResult")); // a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »). - MUST(call(vm, *promise_capability.reject, js_undefined(), error)); + MUST(call(vm, *promise_capability->reject(), js_undefined(), error)); // b. Return promiseCapability.[[Promise]]. - return promise_capability.promise; + return promise_capability->promise(); } // 12. Return AsyncFromSyncIteratorContinuation(result, promiseCapability). diff --git a/Userland/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp b/Userland/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp index d6977d61a9..4226026f88 100644 --- a/Userland/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp +++ b/Userland/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp @@ -59,7 +59,8 @@ ThrowCompletionOr<Value> AsyncFunctionDriverWrapper::react_to_async_task_complet if (TRY(result.get(vm, vm.names.done)).to_boolean()) return promise; - return promise->perform_then(m_on_fulfillment, m_on_rejection, PromiseCapability { promise, m_on_fulfillment, m_on_rejection }); + auto promise_capability = PromiseCapability::create(vm, promise, m_on_fulfillment, m_on_rejection); + return promise->perform_then(m_on_fulfillment, m_on_rejection, promise_capability); } void AsyncFunctionDriverWrapper::visit_edges(Cell::Visitor& visitor) diff --git a/Userland/Libraries/LibJS/Runtime/AsyncGenerator.cpp b/Userland/Libraries/LibJS/Runtime/AsyncGenerator.cpp index db83d52a25..f3eb5a3be5 100644 --- a/Userland/Libraries/LibJS/Runtime/AsyncGenerator.cpp +++ b/Userland/Libraries/LibJS/Runtime/AsyncGenerator.cpp @@ -21,9 +21,7 @@ void AsyncGenerator::visit_edges(Cell::Visitor& visitor) for (auto const& request : m_async_generator_queue) { if (request.completion.value().has_value()) visitor.visit(*request.completion.value()); - visitor.visit(request.capability.promise); - visitor.visit(request.capability.reject); - visitor.visit(request.capability.resolve); + visitor.visit(request.capability); } } diff --git a/Userland/Libraries/LibJS/Runtime/AsyncGeneratorRequest.h b/Userland/Libraries/LibJS/Runtime/AsyncGeneratorRequest.h index ddfd38857b..7be045fab0 100644 --- a/Userland/Libraries/LibJS/Runtime/AsyncGeneratorRequest.h +++ b/Userland/Libraries/LibJS/Runtime/AsyncGeneratorRequest.h @@ -13,8 +13,8 @@ namespace JS { // 27.6.3.1 AsyncGeneratorRequest Records, https://tc39.es/ecma262/#sec-asyncgeneratorrequest-records struct AsyncGeneratorRequest { - Completion completion; // [[Completion]] - PromiseCapability capability; // [[Capability]] + Completion completion; // [[Completion]] + NonnullGCPtr<PromiseCapability> capability; // [[Capability]] }; } diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 1341da4f49..5fd32e9cae 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -743,12 +743,12 @@ void async_block_start(VM& vm, NonnullRefPtr<Statement> const& async_body, Promi // d. If result.[[Type]] is normal, then if (result.type() == Completion::Type::Normal) { // i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »). - MUST(call(vm, promise_capability.resolve, js_undefined(), js_undefined())); + MUST(call(vm, *promise_capability.resolve(), js_undefined(), js_undefined())); } // e. Else if result.[[Type]] is return, then else if (result.type() == Completion::Type::Return) { // i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « result.[[Value]] »). - MUST(call(vm, promise_capability.resolve, js_undefined(), *result.value())); + MUST(call(vm, *promise_capability.resolve(), js_undefined(), *result.value())); } // f. Else, else { @@ -756,7 +756,7 @@ void async_block_start(VM& vm, NonnullRefPtr<Statement> const& async_body, Promi VERIFY(result.type() == Completion::Type::Throw); // ii. Perform ! Call(promiseCapability.[[Reject]], undefined, « result.[[Value]] »). - MUST(call(vm, promise_capability.reject, js_undefined(), *result.value())); + MUST(call(vm, *promise_capability.reject(), js_undefined(), *result.value())); } // g. Return unused. // NOTE: We don't support returning an empty/optional/unused value here. @@ -877,7 +877,7 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body() // 3. If declResult is an abrupt completion, then if (declaration_result.is_throw_completion()) { // a. Perform ! Call(promiseCapability.[[Reject]], undefined, « declResult.[[Value]] »). - MUST(call(vm, promise_capability.reject, js_undefined(), *declaration_result.throw_completion().value())); + MUST(call(vm, *promise_capability->reject(), js_undefined(), *declaration_result.throw_completion().value())); } // 4. Else, else { @@ -886,7 +886,7 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body() } // 5. Return Completion Record { [[Type]]: return, [[Value]]: promiseCapability.[[Promise]], [[Target]]: empty }. - return Completion { Completion::Type::Return, promise_capability.promise, {} }; + return Completion { Completion::Type::Return, promise_capability->promise(), {} }; } } VERIFY_NOT_REACHED(); diff --git a/Userland/Libraries/LibJS/Runtime/Promise.cpp b/Userland/Libraries/LibJS/Runtime/Promise.cpp index 40637f2151..5d688babdf 100644 --- a/Userland/Libraries/LibJS/Runtime/Promise.cpp +++ b/Userland/Libraries/LibJS/Runtime/Promise.cpp @@ -36,10 +36,10 @@ ThrowCompletionOr<Object*> promise_resolve(VM& vm, Object& constructor, Value va auto promise_capability = TRY(new_promise_capability(vm, &constructor)); // 3. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »). - (void)TRY(call(vm, *promise_capability.resolve, js_undefined(), value)); + (void)TRY(call(vm, *promise_capability->resolve(), js_undefined(), value)); // 4. Return promiseCapability.[[Promise]]. - return promise_capability.promise; + return promise_capability->promise().ptr(); } Promise* Promise::create(Realm& realm) @@ -288,7 +288,7 @@ void Promise::trigger_reactions() const } // 27.2.5.4.1 PerformPromiseThen ( promise, onFulfilled, onRejected [ , resultCapability ] ), https://tc39.es/ecma262/#sec-performpromisethen -Value Promise::perform_then(Value on_fulfilled, Value on_rejected, Optional<PromiseCapability> result_capability) +Value Promise::perform_then(Value on_fulfilled, Value on_rejected, GCPtr<PromiseCapability> result_capability) { auto& vm = this->vm(); @@ -377,7 +377,7 @@ Value Promise::perform_then(Value on_fulfilled, Value on_rejected, Optional<Prom m_is_handled = true; // 13. If resultCapability is undefined, then - if (!result_capability.has_value()) { + if (result_capability == nullptr) { // a. Return undefined. dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: No result PromiseCapability, returning undefined", this); return js_undefined(); @@ -385,9 +385,8 @@ Value Promise::perform_then(Value on_fulfilled, Value on_rejected, Optional<Prom // 14. Else, // a. Return resultCapability.[[Promise]]. - auto* promise = result_capability.value().promise; - dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: Returning Promise @ {} from result PromiseCapability @ {}", this, promise, &result_capability.value()); - return promise; + dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: Returning Promise @ {} from result PromiseCapability @ {}", this, result_capability->promise().ptr(), result_capability.ptr()); + return result_capability->promise(); } void Promise::visit_edges(Cell::Visitor& visitor) diff --git a/Userland/Libraries/LibJS/Runtime/Promise.h b/Userland/Libraries/LibJS/Runtime/Promise.h index 82692393dc..790e3482e4 100644 --- a/Userland/Libraries/LibJS/Runtime/Promise.h +++ b/Userland/Libraries/LibJS/Runtime/Promise.h @@ -42,7 +42,7 @@ public: void fulfill(Value value); void reject(Value reason); - Value perform_then(Value on_fulfilled, Value on_rejected, Optional<PromiseCapability> result_capability); + Value perform_then(Value on_fulfilled, Value on_rejected, GCPtr<PromiseCapability> result_capability); bool is_handled() const { return m_is_handled; } void set_is_handled() { m_is_handled = true; } diff --git a/Userland/Libraries/LibJS/Runtime/PromiseCapability.cpp b/Userland/Libraries/LibJS/Runtime/PromiseCapability.cpp index b75cf4093c..5c56801c0a 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseCapability.cpp +++ b/Userland/Libraries/LibJS/Runtime/PromiseCapability.cpp @@ -11,8 +11,27 @@ namespace JS { +NonnullGCPtr<PromiseCapability> PromiseCapability::create(VM& vm, GCPtr<Object> promise, GCPtr<FunctionObject> resolve, GCPtr<FunctionObject> reject) +{ + return NonnullGCPtr { *vm.heap().allocate_without_realm<PromiseCapability>(promise, resolve, reject) }; +} + +PromiseCapability::PromiseCapability(GCPtr<Object> promise, GCPtr<FunctionObject> resolve, GCPtr<FunctionObject> reject) + : m_promise(promise) + , m_resolve(resolve) + , m_reject(reject) +{ +} + +void PromiseCapability::visit_edges(Cell::Visitor& visitor) +{ + visitor.visit(m_promise); + visitor.visit(m_resolve); + visitor.visit(m_reject); +} + // 27.2.1.5 NewPromiseCapability ( C ), https://tc39.es/ecma262/#sec-newpromisecapability -ThrowCompletionOr<PromiseCapability> new_promise_capability(VM& vm, Value constructor) +ThrowCompletionOr<NonnullGCPtr<PromiseCapability>> new_promise_capability(VM& vm, Value constructor) { auto& realm = *vm.current_realm(); @@ -70,11 +89,11 @@ ThrowCompletionOr<PromiseCapability> new_promise_capability(VM& vm, Value constr // 9. Set promiseCapability.[[Promise]] to promise. // 10. Return promiseCapability. - return PromiseCapability { + return PromiseCapability::create( + vm, promise, &promise_capability_functions.resolve.as_function(), - &promise_capability_functions.reject.as_function(), - }; + &promise_capability_functions.reject.as_function()); } } diff --git a/Userland/Libraries/LibJS/Runtime/PromiseCapability.h b/Userland/Libraries/LibJS/Runtime/PromiseCapability.h index 12d88b542f..c2cee43deb 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseCapability.h +++ b/Userland/Libraries/LibJS/Runtime/PromiseCapability.h @@ -13,27 +13,48 @@ namespace JS { // 27.2.1.1 PromiseCapability Records, https://tc39.es/ecma262/#sec-promisecapability-records -struct PromiseCapability { - Object* promise { nullptr }; - FunctionObject* resolve { nullptr }; - FunctionObject* reject { nullptr }; +class PromiseCapability final : public Cell { + JS_CELL(PromiseCapability, Cell); + +public: + static NonnullGCPtr<PromiseCapability> create(VM& vm, GCPtr<Object> promise, GCPtr<FunctionObject> resolve, GCPtr<FunctionObject> reject); + + virtual ~PromiseCapability() = default; + + [[nodiscard]] GCPtr<Object> promise() const { return m_promise; } + void set_promise(NonnullGCPtr<Object> promise) { m_promise = promise; } + + [[nodiscard]] GCPtr<FunctionObject> resolve() const { return m_resolve; } + void set_resolve(NonnullGCPtr<FunctionObject> resolve) { m_resolve = resolve; } + + [[nodiscard]] GCPtr<FunctionObject> reject() const { return m_reject; } + void set_reject(NonnullGCPtr<FunctionObject> reject) { m_reject = reject; } + +private: + PromiseCapability(GCPtr<Object>, GCPtr<FunctionObject>, GCPtr<FunctionObject>); + + virtual void visit_edges(Visitor&) override; + + GCPtr<Object> m_promise; + GCPtr<FunctionObject> m_resolve; + GCPtr<FunctionObject> m_reject; }; // 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise -#define __TRY_OR_REJECT(vm, capability, expression, CALL_CHECK) \ - ({ \ - auto _temporary_try_or_reject_result = (expression); \ - /* 1. If value is an abrupt completion, then */ \ - if (_temporary_try_or_reject_result.is_error()) { \ - /* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \ - CALL_CHECK(JS::call(vm, *capability.reject, js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \ - \ - /* b. Return capability.[[Promise]]. */ \ - return capability.promise; \ - } \ - \ - /* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \ - _temporary_try_or_reject_result.release_value(); \ +#define __TRY_OR_REJECT(vm, capability, expression, CALL_CHECK) \ + ({ \ + auto _temporary_try_or_reject_result = (expression); \ + /* 1. If value is an abrupt completion, then */ \ + if (_temporary_try_or_reject_result.is_error()) { \ + /* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \ + CALL_CHECK(JS::call(vm, *(capability)->reject(), js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \ + \ + /* b. Return capability.[[Promise]]. */ \ + return (capability)->promise(); \ + } \ + \ + /* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \ + _temporary_try_or_reject_result.release_value(); \ }) #define TRY_OR_REJECT(vm, capability, expression) \ @@ -43,23 +64,23 @@ struct PromiseCapability { __TRY_OR_REJECT(vm, capability, expression, MUST) // 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise -#define TRY_OR_REJECT_WITH_VALUE(vm, capability, expression) \ - ({ \ - auto _temporary_try_or_reject_result = (expression); \ - /* 1. If value is an abrupt completion, then */ \ - if (_temporary_try_or_reject_result.is_error()) { \ - /* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \ - TRY(JS::call(vm, *capability.reject, js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \ - \ - /* b. Return capability.[[Promise]]. */ \ - return Value { capability.promise }; \ - } \ - \ - /* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \ - _temporary_try_or_reject_result.release_value(); \ +#define TRY_OR_REJECT_WITH_VALUE(vm, capability, expression) \ + ({ \ + auto _temporary_try_or_reject_result = (expression); \ + /* 1. If value is an abrupt completion, then */ \ + if (_temporary_try_or_reject_result.is_error()) { \ + /* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \ + TRY(JS::call(vm, *(capability)->reject(), js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \ + \ + /* b. Return capability.[[Promise]]. */ \ + return Value { (capability)->promise() }; \ + } \ + \ + /* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \ + _temporary_try_or_reject_result.release_value(); \ }) // 27.2.1.5 NewPromiseCapability ( C ), https://tc39.es/ecma262/#sec-newpromisecapability -ThrowCompletionOr<PromiseCapability> new_promise_capability(VM& vm, Value constructor); +ThrowCompletionOr<NonnullGCPtr<PromiseCapability>> new_promise_capability(VM& vm, Value constructor); } diff --git a/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp b/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp index 2aead988f0..65fed311f1 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp @@ -39,7 +39,7 @@ static ThrowCompletionOr<Value> get_promise_resolve(VM& vm, Value constructor) using EndOfElementsCallback = Function<ThrowCompletionOr<Value>(PromiseValueList&)>; using InvokeElementFunctionCallback = Function<ThrowCompletionOr<Value>(PromiseValueList&, RemainingElements&, Value, size_t)>; -static ThrowCompletionOr<Value> perform_promise_common(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve, EndOfElementsCallback end_of_list, InvokeElementFunctionCallback invoke_element_function) +static ThrowCompletionOr<Value> perform_promise_common(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve, EndOfElementsCallback end_of_list, InvokeElementFunctionCallback invoke_element_function) { VERIFY(constructor.is_constructor()); VERIFY(promise_resolve.is_function()); @@ -79,7 +79,7 @@ static ThrowCompletionOr<Value> perform_promise_common(VM& vm, Iterator& iterato } // iv. Return resultCapability.[[Promise]]. - return result_capability.promise; + return result_capability.promise(); } // e. Let nextValue be Completion(IteratorValue(next)). @@ -113,7 +113,7 @@ static ThrowCompletionOr<Value> perform_promise_common(VM& vm, Iterator& iterato } // 27.2.4.1.2 PerformPromiseAll ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseall -static ThrowCompletionOr<Value> perform_promise_all(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve) +static ThrowCompletionOr<Value> perform_promise_all(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve) { auto& realm = *vm.current_realm(); @@ -124,10 +124,10 @@ static ThrowCompletionOr<Value> perform_promise_all(VM& vm, Iterator& iterator_r auto* values_array = Array::create_from(realm, values.values()); // 2. Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »). - TRY(call(vm, *result_capability.resolve, js_undefined(), values_array)); + TRY(call(vm, *result_capability.resolve(), js_undefined(), values_array)); // iv. Return resultCapability.[[Promise]]. - return Value(result_capability.promise); + return result_capability.promise(); }, [&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) { // j. Let steps be the algorithm steps defined in Promise.all Resolve Element Functions. @@ -142,12 +142,12 @@ static ThrowCompletionOr<Value> perform_promise_all(VM& vm, Iterator& iterator_r on_fulfilled->define_direct_property(vm.names.name, js_string(vm, String::empty()), Attribute::Configurable); // s. Perform ? Invoke(nextPromise, "then", « onFulfilled, resultCapability.[[Reject]] »). - return next_promise.invoke(vm, vm.names.then, on_fulfilled, result_capability.reject); + return next_promise.invoke(vm, vm.names.then, on_fulfilled, result_capability.reject()); }); } // 27.2.4.2.1 PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseallsettled -static ThrowCompletionOr<Value> perform_promise_all_settled(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve) +static ThrowCompletionOr<Value> perform_promise_all_settled(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve) { auto& realm = *vm.current_realm(); @@ -156,9 +156,9 @@ static ThrowCompletionOr<Value> perform_promise_all_settled(VM& vm, Iterator& it [&](PromiseValueList& values) -> ThrowCompletionOr<Value> { auto* values_array = Array::create_from(realm, values.values()); - TRY(call(vm, *result_capability.resolve, js_undefined(), values_array)); + TRY(call(vm, *result_capability.resolve(), js_undefined(), values_array)); - return Value(result_capability.promise); + return result_capability.promise(); }, [&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) { // j. Let stepsFulfilled be the algorithm steps defined in Promise.allSettled Resolve Element Functions. @@ -190,7 +190,7 @@ static ThrowCompletionOr<Value> perform_promise_all_settled(VM& vm, Iterator& it } // 27.2.4.3.1 PerformPromiseAny ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseany -static ThrowCompletionOr<Value> perform_promise_any(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve) +static ThrowCompletionOr<Value> perform_promise_any(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve) { auto& realm = *vm.current_realm(); @@ -220,22 +220,22 @@ static ThrowCompletionOr<Value> perform_promise_any(VM& vm, Iterator& iterator_r on_rejected->define_direct_property(vm.names.name, js_string(vm, String::empty()), Attribute::Configurable); // s. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], onRejected »). - return next_promise.invoke(vm, vm.names.then, result_capability.resolve, on_rejected); + return next_promise.invoke(vm, vm.names.then, result_capability.resolve(), on_rejected); }); } // 27.2.4.5.1 PerformPromiseRace ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiserace -static ThrowCompletionOr<Value> perform_promise_race(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve) +static ThrowCompletionOr<Value> perform_promise_race(VM& vm, Iterator& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve) { return perform_promise_common( vm, iterator_record, constructor, result_capability, promise_resolve, [&](PromiseValueList&) -> ThrowCompletionOr<Value> { // ii. Return resultCapability.[[Promise]]. - return Value(result_capability.promise); + return result_capability.promise(); }, [&](PromiseValueList&, RemainingElements&, Value next_promise, size_t) { // i. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »). - return next_promise.invoke(vm, vm.names.then, result_capability.resolve, result_capability.reject); + return next_promise.invoke(vm, vm.names.then, result_capability.resolve(), result_capability.reject()); }); } @@ -456,10 +456,10 @@ JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::reject) auto promise_capability = TRY(new_promise_capability(vm, constructor)); // 3. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »). - [[maybe_unused]] auto result = TRY(JS::call(vm, *promise_capability.reject, js_undefined(), reason)); + [[maybe_unused]] auto result = TRY(JS::call(vm, *promise_capability->reject(), js_undefined(), reason)); // 4. Return promiseCapability.[[Promise]]. - return promise_capability.promise; + return promise_capability->promise(); } // 27.2.4.7 Promise.resolve ( x ), https://tc39.es/ecma262/#sec-promise.resolve diff --git a/Userland/Libraries/LibJS/Runtime/PromiseJobs.cpp b/Userland/Libraries/LibJS/Runtime/PromiseJobs.cpp index a31ed65060..1eb425d476 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseJobs.cpp +++ b/Userland/Libraries/LibJS/Runtime/PromiseJobs.cpp @@ -20,7 +20,7 @@ namespace JS { static ThrowCompletionOr<Value> run_reaction_job(VM& vm, PromiseReaction& reaction, Value argument) { // a. Let promiseCapability be reaction.[[Capability]]. - auto& promise_capability = reaction.capability(); + auto promise_capability = reaction.capability(); // b. Let type be reaction.[[Type]]. auto type = reaction.type(); @@ -58,7 +58,7 @@ static ThrowCompletionOr<Value> run_reaction_job(VM& vm, PromiseReaction& reacti } // f. If promiseCapability is undefined, then - if (!promise_capability.has_value()) { + if (promise_capability == nullptr) { // i. Assert: handlerResult is not an abrupt completion. VERIFY(!handler_result.is_abrupt()); @@ -74,15 +74,15 @@ static ThrowCompletionOr<Value> run_reaction_job(VM& vm, PromiseReaction& reacti // h. If handlerResult is an abrupt completion, then if (handler_result.is_abrupt()) { // i. Return ? Call(promiseCapability.[[Reject]], undefined, « handlerResult.[[Value]] »). - auto* reject_function = promise_capability.value().reject; - dbgln_if(PROMISE_DEBUG, "run_reaction_job: Calling PromiseCapability's reject function @ {}", reject_function); + auto reject_function = promise_capability->reject(); + dbgln_if(PROMISE_DEBUG, "run_reaction_job: Calling PromiseCapability's reject function @ {}", reject_function.ptr()); return call(vm, *reject_function, js_undefined(), *handler_result.value()); } // i. Else, else { // i. Return ? Call(promiseCapability.[[Resolve]], undefined, « handlerResult.[[Value]] »). - auto* resolve_function = promise_capability.value().resolve; - dbgln_if(PROMISE_DEBUG, "[PromiseReactionJob]: Calling PromiseCapability's resolve function @ {}", resolve_function); + auto resolve_function = promise_capability->resolve(); + dbgln_if(PROMISE_DEBUG, "[PromiseReactionJob]: Calling PromiseCapability's resolve function @ {}", resolve_function.ptr()); return call(vm, *resolve_function, js_undefined(), *handler_result.value()); } } @@ -165,9 +165,8 @@ PromiseJob create_promise_resolve_thenable_job(VM& vm, Promise& promise_to_resol VERIFY(then_realm); // 1. Let job be a new Job Abstract Closure with no parameters that captures promiseToResolve, thenable, and then and performs the following steps when called: - // See PromiseResolveThenableJob::call() for "the following steps". - // NOTE: This is done out of order, since `then` is moved into the lambda and `then` would be invalid if it was done at the start. - auto job = [&vm, promise_to_resolve = make_handle(&promise_to_resolve), thenable = make_handle(thenable), then = move(then)]() mutable { + // See run_resolve_thenable_job() for "the following steps". + auto job = [&vm, promise_to_resolve = make_handle(promise_to_resolve), thenable = make_handle(thenable), then = move(then)]() mutable { return run_resolve_thenable_job(vm, *promise_to_resolve.cell(), thenable.value(), then); }; diff --git a/Userland/Libraries/LibJS/Runtime/PromiseReaction.cpp b/Userland/Libraries/LibJS/Runtime/PromiseReaction.cpp index a6f2e392e0..abe81da6f2 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseReaction.cpp +++ b/Userland/Libraries/LibJS/Runtime/PromiseReaction.cpp @@ -10,14 +10,14 @@ namespace JS { -PromiseReaction* PromiseReaction::create(VM& vm, Type type, Optional<PromiseCapability> capability, Optional<JobCallback> handler) +PromiseReaction* PromiseReaction::create(VM& vm, Type type, GCPtr<PromiseCapability> capability, Optional<JobCallback> handler) { - return vm.heap().allocate_without_realm<PromiseReaction>(type, move(capability), move(handler)); + return vm.heap().allocate_without_realm<PromiseReaction>(type, capability, move(handler)); } -PromiseReaction::PromiseReaction(Type type, Optional<PromiseCapability> capability, Optional<JobCallback> handler) +PromiseReaction::PromiseReaction(Type type, GCPtr<PromiseCapability> capability, Optional<JobCallback> handler) : m_type(type) - , m_capability(move(capability)) + , m_capability(capability) , m_handler(move(handler)) { } @@ -25,12 +25,7 @@ PromiseReaction::PromiseReaction(Type type, Optional<PromiseCapability> capabili void PromiseReaction::visit_edges(Cell::Visitor& visitor) { Cell::visit_edges(visitor); - if (m_capability.has_value()) { - auto& capability = m_capability.value(); - visitor.visit(capability.promise); - visitor.visit(capability.resolve); - visitor.visit(capability.reject); - } + visitor.visit(m_capability); } } diff --git a/Userland/Libraries/LibJS/Runtime/PromiseReaction.h b/Userland/Libraries/LibJS/Runtime/PromiseReaction.h index 58d6dd63af..ef913c80c7 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseReaction.h +++ b/Userland/Libraries/LibJS/Runtime/PromiseReaction.h @@ -23,23 +23,23 @@ public: Reject, }; - static PromiseReaction* create(VM& vm, Type type, Optional<PromiseCapability> capability, Optional<JobCallback> handler); + static PromiseReaction* create(VM& vm, Type type, GCPtr<PromiseCapability> capability, Optional<JobCallback> handler); virtual ~PromiseReaction() = default; Type type() const { return m_type; } - Optional<PromiseCapability> const& capability() const { return m_capability; } + GCPtr<PromiseCapability> capability() const { return m_capability; } Optional<JobCallback>& handler() { return m_handler; } Optional<JobCallback> const& handler() const { return m_handler; } private: - PromiseReaction(Type type, Optional<PromiseCapability> capability, Optional<JobCallback> handler); + PromiseReaction(Type type, GCPtr<PromiseCapability> capability, Optional<JobCallback> handler); virtual void visit_edges(Visitor&) override; Type m_type; - Optional<PromiseCapability> m_capability; + GCPtr<PromiseCapability> m_capability; Optional<JobCallback> m_handler; }; diff --git a/Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.cpp b/Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.cpp index a967474cd3..35824d5d37 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.cpp +++ b/Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.cpp @@ -20,11 +20,11 @@ void PromiseValueList::visit_edges(Visitor& visitor) visitor.visit(val); } -PromiseResolvingElementFunction::PromiseResolvingElementFunction(size_t index, PromiseValueList& values, PromiseCapability capability, RemainingElements& remaining_elements, Object& prototype) +PromiseResolvingElementFunction::PromiseResolvingElementFunction(size_t index, PromiseValueList& values, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements, Object& prototype) : NativeFunction(prototype) , m_index(index) , m_values(values) - , m_capability(move(capability)) + , m_capability(capability) , m_remaining_elements(remaining_elements) { } @@ -49,19 +49,17 @@ void PromiseResolvingElementFunction::visit_edges(Cell::Visitor& visitor) Base::visit_edges(visitor); visitor.visit(&m_values); - visitor.visit(m_capability.promise); - visitor.visit(m_capability.resolve); - visitor.visit(m_capability.reject); + visitor.visit(m_capability); visitor.visit(&m_remaining_elements); } -PromiseAllResolveElementFunction* PromiseAllResolveElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, PromiseCapability capability, RemainingElements& remaining_elements) +PromiseAllResolveElementFunction* PromiseAllResolveElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements) { return realm.heap().allocate<PromiseAllResolveElementFunction>(realm, index, values, capability, remaining_elements, *realm.intrinsics().function_prototype()); } -PromiseAllResolveElementFunction::PromiseAllResolveElementFunction(size_t index, PromiseValueList& values, PromiseCapability capability, RemainingElements& remaining_elements, Object& prototype) - : PromiseResolvingElementFunction(index, values, move(capability), remaining_elements, prototype) +PromiseAllResolveElementFunction::PromiseAllResolveElementFunction(size_t index, PromiseValueList& values, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements, Object& prototype) + : PromiseResolvingElementFunction(index, values, capability, remaining_elements, prototype) { } @@ -80,20 +78,20 @@ ThrowCompletionOr<Value> PromiseAllResolveElementFunction::resolve_element() auto* values_array = Array::create_from(realm, m_values.values()); // b. Return ? Call(promiseCapability.[[Resolve]], undefined, « valuesArray »). - return JS::call(vm, *m_capability.resolve, js_undefined(), values_array); + return JS::call(vm, *m_capability->resolve(), js_undefined(), values_array); } // 11. Return undefined. return js_undefined(); } -PromiseAllSettledResolveElementFunction* PromiseAllSettledResolveElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, PromiseCapability capability, RemainingElements& remaining_elements) +PromiseAllSettledResolveElementFunction* PromiseAllSettledResolveElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements) { return realm.heap().allocate<PromiseAllSettledResolveElementFunction>(realm, index, values, capability, remaining_elements, *realm.intrinsics().function_prototype()); } -PromiseAllSettledResolveElementFunction::PromiseAllSettledResolveElementFunction(size_t index, PromiseValueList& values, PromiseCapability capability, RemainingElements& remaining_elements, Object& prototype) - : PromiseResolvingElementFunction(index, values, move(capability), remaining_elements, prototype) +PromiseAllSettledResolveElementFunction::PromiseAllSettledResolveElementFunction(size_t index, PromiseValueList& values, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements, Object& prototype) + : PromiseResolvingElementFunction(index, values, capability, remaining_elements, prototype) { } @@ -121,20 +119,20 @@ ThrowCompletionOr<Value> PromiseAllSettledResolveElementFunction::resolve_elemen auto* values_array = Array::create_from(realm, m_values.values()); // b. Return ? Call(promiseCapability.[[Resolve]], undefined, « valuesArray »). - return JS::call(vm, *m_capability.resolve, js_undefined(), values_array); + return JS::call(vm, *m_capability->resolve(), js_undefined(), values_array); } // 15. Return undefined. return js_undefined(); } -PromiseAllSettledRejectElementFunction* PromiseAllSettledRejectElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, PromiseCapability capability, RemainingElements& remaining_elements) +PromiseAllSettledRejectElementFunction* PromiseAllSettledRejectElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements) { return realm.heap().allocate<PromiseAllSettledRejectElementFunction>(realm, index, values, capability, remaining_elements, *realm.intrinsics().function_prototype()); } -PromiseAllSettledRejectElementFunction::PromiseAllSettledRejectElementFunction(size_t index, PromiseValueList& values, PromiseCapability capability, RemainingElements& remaining_elements, Object& prototype) - : PromiseResolvingElementFunction(index, values, move(capability), remaining_elements, prototype) +PromiseAllSettledRejectElementFunction::PromiseAllSettledRejectElementFunction(size_t index, PromiseValueList& values, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements, Object& prototype) + : PromiseResolvingElementFunction(index, values, capability, remaining_elements, prototype) { } @@ -162,20 +160,20 @@ ThrowCompletionOr<Value> PromiseAllSettledRejectElementFunction::resolve_element auto* values_array = Array::create_from(realm, m_values.values()); // b. Return ? Call(promiseCapability.[[Resolve]], undefined, « valuesArray »). - return JS::call(vm, *m_capability.resolve, js_undefined(), values_array); + return JS::call(vm, *m_capability->resolve(), js_undefined(), values_array); } // 15. Return undefined. return js_undefined(); } -PromiseAnyRejectElementFunction* PromiseAnyRejectElementFunction::create(Realm& realm, size_t index, PromiseValueList& errors, PromiseCapability capability, RemainingElements& remaining_elements) +PromiseAnyRejectElementFunction* PromiseAnyRejectElementFunction::create(Realm& realm, size_t index, PromiseValueList& errors, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements) { return realm.heap().allocate<PromiseAnyRejectElementFunction>(realm, index, errors, capability, remaining_elements, *realm.intrinsics().function_prototype()); } -PromiseAnyRejectElementFunction::PromiseAnyRejectElementFunction(size_t index, PromiseValueList& errors, PromiseCapability capability, RemainingElements& remaining_elements, Object& prototype) - : PromiseResolvingElementFunction(index, errors, move(capability), remaining_elements, prototype) +PromiseAnyRejectElementFunction::PromiseAnyRejectElementFunction(size_t index, PromiseValueList& errors, NonnullGCPtr<PromiseCapability> capability, RemainingElements& remaining_elements, Object& prototype) + : PromiseResolvingElementFunction(index, errors, capability, remaining_elements, prototype) { } @@ -198,7 +196,7 @@ ThrowCompletionOr<Value> PromiseAnyRejectElementFunction::resolve_element() MUST(error->define_property_or_throw(vm.names.errors, { .value = errors_array, .writable = true, .enumerable = false, .configurable = true })); // c. Return ? Call(promiseCapability.[[Reject]], undefined, « error »). - return JS::call(vm, *m_capability.reject, js_undefined(), error); + return JS::call(vm, *m_capability->reject(), js_undefined(), error); } return js_undefined(); diff --git a/Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.h b/Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.h index 62cb018009..bbfeff46ad 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.h +++ b/Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.h @@ -51,13 +51,13 @@ public: virtual ThrowCompletionOr<Value> call() override; protected: - explicit PromiseResolvingElementFunction(size_t, PromiseValueList&, PromiseCapability, RemainingElements&, Object& prototype); + explicit PromiseResolvingElementFunction(size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&, Object& prototype); virtual ThrowCompletionOr<Value> resolve_element() = 0; size_t m_index { 0 }; PromiseValueList& m_values; - PromiseCapability m_capability; + NonnullGCPtr<PromiseCapability> m_capability; RemainingElements& m_remaining_elements; private: @@ -71,12 +71,12 @@ class PromiseAllResolveElementFunction final : public PromiseResolvingElementFun JS_OBJECT(PromiseResolvingFunction, NativeFunction); public: - static PromiseAllResolveElementFunction* create(Realm&, size_t, PromiseValueList&, PromiseCapability, RemainingElements&); + static PromiseAllResolveElementFunction* create(Realm&, size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&); virtual ~PromiseAllResolveElementFunction() override = default; private: - explicit PromiseAllResolveElementFunction(size_t, PromiseValueList&, PromiseCapability, RemainingElements&, Object& prototype); + explicit PromiseAllResolveElementFunction(size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&, Object& prototype); virtual ThrowCompletionOr<Value> resolve_element() override; }; @@ -86,12 +86,12 @@ class PromiseAllSettledResolveElementFunction final : public PromiseResolvingEle JS_OBJECT(PromiseResolvingFunction, NativeFunction); public: - static PromiseAllSettledResolveElementFunction* create(Realm&, size_t, PromiseValueList&, PromiseCapability, RemainingElements&); + static PromiseAllSettledResolveElementFunction* create(Realm&, size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&); virtual ~PromiseAllSettledResolveElementFunction() override = default; private: - explicit PromiseAllSettledResolveElementFunction(size_t, PromiseValueList&, PromiseCapability, RemainingElements&, Object& prototype); + explicit PromiseAllSettledResolveElementFunction(size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&, Object& prototype); virtual ThrowCompletionOr<Value> resolve_element() override; }; @@ -101,12 +101,12 @@ class PromiseAllSettledRejectElementFunction final : public PromiseResolvingElem JS_OBJECT(PromiseResolvingFunction, PromiseResolvingElementFunction); public: - static PromiseAllSettledRejectElementFunction* create(Realm&, size_t, PromiseValueList&, PromiseCapability, RemainingElements&); + static PromiseAllSettledRejectElementFunction* create(Realm&, size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&); virtual ~PromiseAllSettledRejectElementFunction() override = default; private: - explicit PromiseAllSettledRejectElementFunction(size_t, PromiseValueList&, PromiseCapability, RemainingElements&, Object& prototype); + explicit PromiseAllSettledRejectElementFunction(size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&, Object& prototype); virtual ThrowCompletionOr<Value> resolve_element() override; }; @@ -116,12 +116,12 @@ class PromiseAnyRejectElementFunction final : public PromiseResolvingElementFunc JS_OBJECT(PromiseResolvingFunction, PromiseResolvingElementFunction); public: - static PromiseAnyRejectElementFunction* create(Realm&, size_t, PromiseValueList&, PromiseCapability, RemainingElements&); + static PromiseAnyRejectElementFunction* create(Realm&, size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&); virtual ~PromiseAnyRejectElementFunction() override = default; private: - explicit PromiseAnyRejectElementFunction(size_t, PromiseValueList&, PromiseCapability, RemainingElements&, Object& prototype); + explicit PromiseAnyRejectElementFunction(size_t, PromiseValueList&, NonnullGCPtr<PromiseCapability>, RemainingElements&, Object& prototype); virtual ThrowCompletionOr<Value> resolve_element() override; }; diff --git a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp index 74b4cad7f4..cf85dd83b1 100644 --- a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp +++ b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp @@ -276,7 +276,7 @@ ThrowCompletionOr<Value> shadow_realm_import_value(VM& vm, String specifier_stri }); // 13. Return PerformPromiseThen(innerCapability.[[Promise]], onFulfilled, callerRealm.[[Intrinsics]].[[%ThrowTypeError%]], promiseCapability). - return verify_cast<Promise>(inner_capability.promise)->perform_then(on_fulfilled, throw_type_error, promise_capability); + return verify_cast<Promise>(inner_capability->promise().ptr())->perform_then(on_fulfilled, throw_type_error, promise_capability); } // 3.1.5 GetWrappedValue ( callerRealm: a Realm Record, value: unknown, ), https://tc39.es/proposal-shadowrealm/#sec-getwrappedvalue diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index 1b15a1571d..40a17de1c1 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -70,7 +70,7 @@ VM::VM(OwnPtr<CustomData> custom_data) return resolve_imported_module(move(referencing_script_or_module), specifier); }; - host_import_module_dynamically = [&](ScriptOrModule, ModuleRequest const&, PromiseCapability promise_capability) { + host_import_module_dynamically = [&](ScriptOrModule, ModuleRequest const&, PromiseCapability const& promise_capability) { // By default, we throw on dynamic imports this is to prevent arbitrary file access by scripts. VERIFY(current_realm()); auto& realm = *current_realm(); @@ -85,11 +85,11 @@ VM::VM(OwnPtr<CustomData> custom_data) NativeFunction::create(realm, "", [](auto&) -> ThrowCompletionOr<Value> { VERIFY_NOT_REACHED(); }), - NativeFunction::create(realm, "", [reject = make_handle(promise_capability.reject)](auto& vm) -> ThrowCompletionOr<Value> { + NativeFunction::create(realm, "", [&promise_capability](auto& vm) -> ThrowCompletionOr<Value> { auto error = vm.argument(0); // a. Perform ! Call(promiseCapability.[[Reject]], undefined, « error »). - MUST(call(vm, reject.cell(), js_undefined(), error)); + MUST(call(vm, *promise_capability.reject(), js_undefined(), error)); // b. Return undefined. return js_undefined(); @@ -97,7 +97,7 @@ VM::VM(OwnPtr<CustomData> custom_data) {}); }; - host_finish_dynamic_import = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier, PromiseCapability promise_capability, Promise* promise) { + host_finish_dynamic_import = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier, PromiseCapability const& promise_capability, Promise* promise) { return finish_dynamic_import(move(referencing_script_or_module), specifier, promise_capability, promise); }; @@ -146,7 +146,7 @@ VM::VM(OwnPtr<CustomData> custom_data) void VM::enable_default_host_import_module_dynamically_hook() { - host_import_module_dynamically = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier, PromiseCapability promise_capability) { + host_import_module_dynamically = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier, PromiseCapability const& promise_capability) { return import_module_dynamically(move(referencing_script_or_module), specifier, promise_capability); }; } @@ -976,7 +976,7 @@ ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModu } // 16.2.1.8 HostImportModuleDynamically ( referencingScriptOrModule, specifier, promiseCapability ), https://tc39.es/ecma262/#sec-hostimportmoduledynamically -void VM::import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability promise_capability) +void VM::import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability) { auto& realm = *current_realm(); @@ -995,7 +995,7 @@ void VM::import_module_dynamically(ScriptOrModule referencing_script_or_module, auto* promise = Promise::create(realm); ScopeGuard finish_dynamic_import = [&] { - host_finish_dynamic_import(referencing_script_or_module, move(module_request), promise_capability, promise); + host_finish_dynamic_import(referencing_script_or_module, module_request, promise_capability, promise); }; // Generally within ECMA262 we always get a referencing_script_or_moulde. However, ShadowRealm gives an explicit null. @@ -1034,14 +1034,14 @@ void VM::import_module_dynamically(ScriptOrModule referencing_script_or_module, } // 16.2.1.9 FinishDynamicImport ( referencingScriptOrModule, specifier, promiseCapability, innerPromise ), https://tc39.es/ecma262/#sec-finishdynamicimport -void VM::finish_dynamic_import(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability promise_capability, Promise* inner_promise) +void VM::finish_dynamic_import(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability, Promise* inner_promise) { dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] finish_dynamic_import on {}", module_request.module_specifier); auto& realm = *current_realm(); // 1. Let fulfilledClosure be a new Abstract Closure with parameters (result) that captures referencingScriptOrModule, specifier, and promiseCapability and performs the following steps when called: - auto fulfilled_closure = [referencing_script_or_module, module_request = move(module_request), resolve_function = make_handle(promise_capability.resolve), reject_function = make_handle(promise_capability.reject)](VM& vm) -> ThrowCompletionOr<Value> { + auto fulfilled_closure = [referencing_script_or_module = move(referencing_script_or_module), module_request = move(module_request), &promise_capability](VM& vm) -> ThrowCompletionOr<Value> { auto result = vm.argument(0); // a. Assert: result is undefined. VERIFY(result.is_undefined()); @@ -1057,12 +1057,12 @@ void VM::finish_dynamic_import(ScriptOrModule referencing_script_or_module, Modu // e. If namespace is an abrupt completion, then if (namespace_.is_throw_completion()) { // i. Perform ! Call(promiseCapability.[[Reject]], undefined, « namespace.[[Value]] »). - MUST(call(vm, reject_function.cell(), js_undefined(), *namespace_.throw_completion().value())); + MUST(call(vm, *promise_capability.reject(), js_undefined(), *namespace_.throw_completion().value())); } // f. Else, else { // i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « namespace.[[Value]] »). - MUST(call(vm, resolve_function.cell(), js_undefined(), namespace_.release_value())); + MUST(call(vm, *promise_capability.resolve(), js_undefined(), namespace_.release_value())); } // g. Return unused. // NOTE: We don't support returning an empty/optional/unused value here. @@ -1073,10 +1073,10 @@ void VM::finish_dynamic_import(ScriptOrModule referencing_script_or_module, Modu auto* on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 0, ""); // 3. Let rejectedClosure be a new Abstract Closure with parameters (error) that captures promiseCapability and performs the following steps when called: - auto rejected_closure = [rejected_function = make_handle(promise_capability.reject)](VM& vm) -> ThrowCompletionOr<Value> { + auto rejected_closure = [&promise_capability](VM& vm) -> ThrowCompletionOr<Value> { auto error = vm.argument(0); // a. Perform ! Call(promiseCapability.[[Reject]], undefined, « error »). - MUST(call(vm, rejected_function.cell(), js_undefined(), error)); + MUST(call(vm, *promise_capability.reject(), js_undefined(), error)); // b. Return unused. // NOTE: We don't support returning an empty/optional/unused value here. diff --git a/Userland/Libraries/LibJS/Runtime/VM.h b/Userland/Libraries/LibJS/Runtime/VM.h index 5d037e8013..63e5a2e52c 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.h +++ b/Userland/Libraries/LibJS/Runtime/VM.h @@ -223,8 +223,8 @@ public: ScriptOrModule get_active_script_or_module() const; Function<ThrowCompletionOr<NonnullGCPtr<Module>>(ScriptOrModule, ModuleRequest const&)> host_resolve_imported_module; - Function<void(ScriptOrModule, ModuleRequest, PromiseCapability)> host_import_module_dynamically; - Function<void(ScriptOrModule, ModuleRequest const&, PromiseCapability, Promise*)> host_finish_dynamic_import; + Function<void(ScriptOrModule, ModuleRequest, PromiseCapability const&)> host_import_module_dynamically; + Function<void(ScriptOrModule, ModuleRequest const&, PromiseCapability const&, Promise*)> host_finish_dynamic_import; Function<HashMap<PropertyKey, Value>(SourceTextModule const&)> host_get_import_meta_properties; Function<void(Object*, SourceTextModule const&)> host_finalize_import_meta; @@ -250,8 +250,8 @@ private: ThrowCompletionOr<NonnullGCPtr<Module>> resolve_imported_module(ScriptOrModule referencing_script_or_module, ModuleRequest const& module_request); ThrowCompletionOr<void> link_and_eval_module(Module& module); - void import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability promise_capability); - void finish_dynamic_import(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability promise_capability, Promise* inner_promise); + void import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability); + void finish_dynamic_import(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability, Promise* inner_promise); HashMap<String, PrimitiveString*> m_string_cache; |