summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibJS/AST.cpp14
-rw-r--r--Userland/Libraries/LibJS/CyclicModule.cpp30
-rw-r--r--Userland/Libraries/LibJS/CyclicModule.h24
-rw-r--r--Userland/Libraries/LibJS/Forward.h2
-rw-r--r--Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp26
-rw-r--r--Userland/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp3
-rw-r--r--Userland/Libraries/LibJS/Runtime/AsyncGenerator.cpp4
-rw-r--r--Userland/Libraries/LibJS/Runtime/AsyncGeneratorRequest.h4
-rw-r--r--Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp10
-rw-r--r--Userland/Libraries/LibJS/Runtime/Promise.cpp13
-rw-r--r--Userland/Libraries/LibJS/Runtime/Promise.h2
-rw-r--r--Userland/Libraries/LibJS/Runtime/PromiseCapability.cpp27
-rw-r--r--Userland/Libraries/LibJS/Runtime/PromiseCapability.h87
-rw-r--r--Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp32
-rw-r--r--Userland/Libraries/LibJS/Runtime/PromiseJobs.cpp17
-rw-r--r--Userland/Libraries/LibJS/Runtime/PromiseReaction.cpp15
-rw-r--r--Userland/Libraries/LibJS/Runtime/PromiseReaction.h8
-rw-r--r--Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.cpp40
-rw-r--r--Userland/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.h20
-rw-r--r--Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/VM.cpp26
-rw-r--r--Userland/Libraries/LibJS/Runtime/VM.h8
-rw-r--r--Userland/Libraries/LibJS/SourceTextModule.cpp10
-rw-r--r--Userland/Libraries/LibJS/SourceTextModule.h2
-rw-r--r--Userland/Libraries/LibWeb/Fetch/Body.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h2
-rw-r--r--Userland/Libraries/LibWeb/WebIDL/Promise.cpp22
-rw-r--r--Userland/Libraries/LibWeb/WebIDL/Promise.h6
29 files changed, 243 insertions, 217 deletions
diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp
index 3bd1a28376..cda5af2b97 100644
--- a/Userland/Libraries/LibJS/AST.cpp
+++ b/Userland/Libraries/LibJS/AST.cpp
@@ -3361,10 +3361,10 @@ Completion ImportCall::execute(Interpreter& interpreter) const
if (!options_value.is_object()) {
auto* error = TypeError::create(realm, String::formatted(ErrorType::NotAnObject.message(), "ImportOptions"));
// i. 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));
// ii. Return promiseCapability.[[Promise]].
- return Value { promise_capability.promise };
+ return Value { promise_capability->promise() };
}
// b. Let assertionsObj be Get(options, "assert").
@@ -3377,10 +3377,10 @@ Completion ImportCall::execute(Interpreter& interpreter) const
if (!assertion_object.is_object()) {
auto* error = TypeError::create(realm, String::formatted(ErrorType::NotAnObject.message(), "ImportOptionsAssertions"));
// 1. 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));
// 2. Return promiseCapability.[[Promise]].
- return Value { promise_capability.promise };
+ return Value { promise_capability->promise() };
}
// ii. Let keys be EnumerableOwnPropertyNames(assertionsObj, key).
@@ -3402,10 +3402,10 @@ Completion ImportCall::execute(Interpreter& interpreter) const
if (!value.is_string()) {
auto* error = TypeError::create(realm, String::formatted(ErrorType::NotAString.message(), "Import Assertion option value"));
// 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 Value { promise_capability.promise };
+ return Value { promise_capability->promise() };
}
// 4. If supportedAssertions contains key, then
@@ -3426,7 +3426,7 @@ Completion ImportCall::execute(Interpreter& interpreter) const
interpreter.vm().host_import_module_dynamically(referencing_script_or_module, move(request), promise_capability);
// 13. Return promiseCapability.[[Promise]].
- return Value { promise_capability.promise };
+ return Value { promise_capability->promise() };
}
// 13.2.3.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-literals-runtime-semantics-evaluation
diff --git a/Userland/Libraries/LibJS/CyclicModule.cpp b/Userland/Libraries/LibJS/CyclicModule.cpp
index b98d9c84bb..658889ab90 100644
--- a/Userland/Libraries/LibJS/CyclicModule.cpp
+++ b/Userland/Libraries/LibJS/CyclicModule.cpp
@@ -197,10 +197,9 @@ ThrowCompletionOr<Promise*> CyclicModule::evaluate(VM& vm)
}
// 4. If module.[[TopLevelCapability]] is not empty, then
- if (m_top_level_capability.has_value()) {
+ if (m_top_level_capability != nullptr) {
// a. Return module.[[TopLevelCapability]].[[Promise]].
- VERIFY(is<Promise>(*m_top_level_capability->promise));
- return static_cast<Promise*>(m_top_level_capability->promise);
+ return verify_cast<Promise>(m_top_level_capability->promise().ptr());
}
// 5. Let stack be a new empty List.
@@ -243,7 +242,7 @@ ThrowCompletionOr<Promise*> CyclicModule::evaluate(VM& vm)
VERIFY(m_evaluation_error.is_error() && same_value(*m_evaluation_error.throw_completion().value(), *result.throw_completion().value()));
// d. Perform ! Call(capability.[[Reject]], undefined, « result.[[Value]] »).
- MUST(call(vm, m_top_level_capability->reject, js_undefined(), *result.throw_completion().value()));
+ MUST(call(vm, *m_top_level_capability->reject(), js_undefined(), *result.throw_completion().value()));
}
// 10. Else,
else {
@@ -257,7 +256,7 @@ ThrowCompletionOr<Promise*> CyclicModule::evaluate(VM& vm)
// i. Assert: module.[[Status]] is evaluated.
VERIFY(m_status == ModuleStatus::Evaluated);
// ii. Perform ! Call(capability.[[Resolve]], undefined, « undefined »).
- MUST(call(vm, m_top_level_capability->resolve, js_undefined(), js_undefined()));
+ MUST(call(vm, *m_top_level_capability->resolve(), js_undefined(), js_undefined()));
}
// d. Assert: stack is empty.
@@ -265,8 +264,7 @@ ThrowCompletionOr<Promise*> CyclicModule::evaluate(VM& vm)
}
// 11. Return capability.[[Promise]].
- VERIFY(is<Promise>(*m_top_level_capability->promise));
- return static_cast<Promise*>(m_top_level_capability->promise);
+ return verify_cast<Promise>(m_top_level_capability->promise().ptr());
}
// 16.2.1.5.2.1 InnerModuleEvaluation ( module, stack, index ), https://tc39.es/ecma262/#sec-innermoduleevaluation
@@ -432,7 +430,7 @@ ThrowCompletionOr<void> CyclicModule::initialize_environment(VM&)
VERIFY_NOT_REACHED();
}
-ThrowCompletionOr<void> CyclicModule::execute_module(VM&, Optional<PromiseCapability>)
+ThrowCompletionOr<void> CyclicModule::execute_module(VM&, GCPtr<PromiseCapability>)
{
// Note: In ecma262 this is never called on a cyclic module only on SourceTextModules.
// So this check is to make sure we don't accidentally call this.
@@ -479,10 +477,8 @@ void CyclicModule::execute_async_module(VM& vm)
// 7. Let onRejected be CreateBuiltinFunction(rejectedClosure, 0, "", « »).
auto* on_rejected = NativeFunction::create(realm, move(rejected_closure), 0, "");
- VERIFY(is<Promise>(*capability.promise));
-
// 8. Perform PerformPromiseThen(capability.[[Promise]], onFulfilled, onRejected).
- static_cast<Promise*>(capability.promise)->perform_then(on_fulfilled, on_rejected, {});
+ verify_cast<Promise>(capability->promise().ptr())->perform_then(on_fulfilled, on_rejected, {});
// 9. Perform ! module.ExecuteModule(capability).
MUST(execute_module(vm, capability));
@@ -555,12 +551,12 @@ void CyclicModule::async_module_execution_fulfilled(VM& vm)
m_status = ModuleStatus::Evaluated;
// 7. If module.[[TopLevelCapability]] is not empty, then
- if (m_top_level_capability.has_value()) {
+ if (m_top_level_capability != nullptr) {
// a. Assert: module.[[CycleRoot]] is module.
VERIFY(m_cycle_root == this);
// b. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »).
- MUST(call(vm, m_top_level_capability->resolve, js_undefined(), js_undefined()));
+ MUST(call(vm, *m_top_level_capability->resolve(), js_undefined(), js_undefined()));
}
// 8. Let execList be a new empty List.
@@ -603,12 +599,12 @@ void CyclicModule::async_module_execution_fulfilled(VM& vm)
module->m_status = ModuleStatus::Evaluated;
// 2. If m.[[TopLevelCapability]] is not empty, then
- if (module->m_top_level_capability.has_value()) {
+ if (module->m_top_level_capability != nullptr) {
// a. Assert: m.[[CycleRoot]] is m.
VERIFY(module->m_cycle_root == module);
// b. Perform ! Call(m.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »).
- MUST(call(vm, module->m_top_level_capability->resolve, js_undefined(), js_undefined()));
+ MUST(call(vm, *module->m_top_level_capability->resolve(), js_undefined(), js_undefined()));
}
}
}
@@ -652,12 +648,12 @@ void CyclicModule::async_module_execution_rejected(VM& vm, Value error)
}
// 8. If module.[[TopLevelCapability]] is not empty, then
- if (m_top_level_capability.has_value()) {
+ if (m_top_level_capability != nullptr) {
// a. Assert: module.[[CycleRoot]] is module.
VERIFY(m_cycle_root == this);
// b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]], undefined, « error »).
- MUST(call(vm, m_top_level_capability->reject, js_undefined(), error));
+ MUST(call(vm, *m_top_level_capability->reject(), js_undefined(), error));
}
// 9. Return unused.
diff --git a/Userland/Libraries/LibJS/CyclicModule.h b/Userland/Libraries/LibJS/CyclicModule.h
index 00facbefcb..b610a678fc 100644
--- a/Userland/Libraries/LibJS/CyclicModule.h
+++ b/Userland/Libraries/LibJS/CyclicModule.h
@@ -42,24 +42,24 @@ protected:
virtual ThrowCompletionOr<u32> inner_module_evaluation(VM& vm, Vector<Module*>& stack, u32 index) override;
virtual ThrowCompletionOr<void> initialize_environment(VM& vm);
- virtual ThrowCompletionOr<void> execute_module(VM& vm, Optional<PromiseCapability> capability = {});
+ virtual ThrowCompletionOr<void> execute_module(VM& vm, GCPtr<PromiseCapability> capability = {});
void execute_async_module(VM& vm);
void gather_available_ancestors(Vector<CyclicModule*>& exec_list);
void async_module_execution_fulfilled(VM& vm);
void async_module_execution_rejected(VM& vm, Value error);
- ModuleStatus m_status { ModuleStatus::Unlinked }; // [[Status]]
- ThrowCompletionOr<void> m_evaluation_error; // [[EvaluationError]]
- Optional<u32> m_dfs_index; // [[DFSIndex]]
- Optional<u32> m_dfs_ancestor_index; // [[DFSAncestorIndex]]
- Vector<ModuleRequest> m_requested_modules; // [[RequestedModules]]
- CyclicModule* m_cycle_root { nullptr }; // [[CycleRoot]]
- bool m_has_top_level_await { false }; // [[HasTLA]]
- bool m_async_evaluation { false }; // [[AsyncEvaluation]]
- Optional<PromiseCapability> m_top_level_capability; // [[TopLevelCapability]]
- Vector<CyclicModule*> m_async_parent_modules; // [[AsyncParentModules]]
- Optional<u32> m_pending_async_dependencies; // [[PendingAsyncDependencies]]
+ ModuleStatus m_status { ModuleStatus::Unlinked }; // [[Status]]
+ ThrowCompletionOr<void> m_evaluation_error; // [[EvaluationError]]
+ Optional<u32> m_dfs_index; // [[DFSIndex]]
+ Optional<u32> m_dfs_ancestor_index; // [[DFSAncestorIndex]]
+ Vector<ModuleRequest> m_requested_modules; // [[RequestedModules]]
+ CyclicModule* m_cycle_root { nullptr }; // [[CycleRoot]]
+ bool m_has_top_level_await { false }; // [[HasTLA]]
+ bool m_async_evaluation { false }; // [[AsyncEvaluation]]
+ GCPtr<PromiseCapability> m_top_level_capability; // [[TopLevelCapability]]
+ Vector<CyclicModule*> m_async_parent_modules; // [[AsyncParentModules]]
+ Optional<u32> m_pending_async_dependencies; // [[PendingAsyncDependencies]]
};
}
diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h
index 7f1735dc42..9e2a6fda05 100644
--- a/Userland/Libraries/LibJS/Forward.h
+++ b/Userland/Libraries/LibJS/Forward.h
@@ -176,6 +176,7 @@ class Module;
class NativeFunction;
class ObjectEnvironment;
class PrimitiveString;
+class PromiseCapability;
class PromiseReaction;
class PropertyAttributes;
class PropertyDescriptor;
@@ -199,7 +200,6 @@ enum class DeclarationKind;
struct AlreadyResolved;
struct JobCallback;
struct ModuleRequest;
-struct PromiseCapability;
// Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype
class ProxyObject;
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;
diff --git a/Userland/Libraries/LibJS/SourceTextModule.cpp b/Userland/Libraries/LibJS/SourceTextModule.cpp
index c8c75b5bc0..3f2f1e9359 100644
--- a/Userland/Libraries/LibJS/SourceTextModule.cpp
+++ b/Userland/Libraries/LibJS/SourceTextModule.cpp
@@ -646,9 +646,9 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
}
// 16.2.1.6.5 ExecuteModule ( [ capability ] ), https://tc39.es/ecma262/#sec-source-text-module-record-execute-module
-ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, Optional<PromiseCapability> capability)
+ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, GCPtr<PromiseCapability> capability)
{
- dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] SourceTextModule::execute_module({}, capability has value: {})", filename(), capability.has_value());
+ dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] SourceTextModule::execute_module({}, PromiseCapability @ {})", filename(), capability.ptr());
// 1. Let moduleContext be a new ECMAScript code execution context.
ExecutionContext module_context { vm.heap() };
@@ -679,7 +679,7 @@ ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, Optional<Promis
// 9. If module.[[HasTLA]] is false, then
if (!m_has_top_level_await) {
// a. Assert: capability is not present.
- VERIFY(!capability.has_value());
+ VERIFY(capability == nullptr);
// b. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
TRY(vm.push_execution_context(module_context, {}));
@@ -701,10 +701,10 @@ ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, Optional<Promis
// 10. Else,
else {
// a. Assert: capability is a PromiseCapability Record.
- VERIFY(capability.has_value());
+ VERIFY(capability != nullptr);
// b. Perform AsyncBlockStart(capability, module.[[ECMAScriptCode]], moduleContext).
- async_block_start(vm, m_ecmascript_code, capability.value(), module_context);
+ async_block_start(vm, m_ecmascript_code, *capability, module_context);
}
// 11. Return unused.
diff --git a/Userland/Libraries/LibJS/SourceTextModule.h b/Userland/Libraries/LibJS/SourceTextModule.h
index 0519f8e771..2979b06d4a 100644
--- a/Userland/Libraries/LibJS/SourceTextModule.h
+++ b/Userland/Libraries/LibJS/SourceTextModule.h
@@ -34,7 +34,7 @@ public:
protected:
virtual ThrowCompletionOr<void> initialize_environment(VM& vm) override;
- virtual ThrowCompletionOr<void> execute_module(VM& vm, Optional<PromiseCapability> capability) override;
+ virtual ThrowCompletionOr<void> execute_module(VM& vm, GCPtr<PromiseCapability> capability) override;
private:
SourceTextModule(Realm&, StringView filename, bool has_top_level_await, NonnullRefPtr<Program> body, Vector<ModuleRequest> requested_modules,
diff --git a/Userland/Libraries/LibWeb/Fetch/Body.cpp b/Userland/Libraries/LibWeb/Fetch/Body.cpp
index 7cc9dbc285..03151faec4 100644
--- a/Userland/Libraries/LibWeb/Fetch/Body.cpp
+++ b/Userland/Libraries/LibWeb/Fetch/Body.cpp
@@ -147,7 +147,7 @@ JS::NonnullGCPtr<JS::Promise> consume_body(JS::Realm& realm, BodyMixin const& ob
// 1. If object is unusable, then return a promise rejected with a TypeError.
if (object.is_unusable()) {
auto promise_capability = WebIDL::create_rejected_promise(realm, JS::TypeError::create(realm, "Body is unusable"sv));
- return static_cast<JS::Promise&>(*promise_capability.promise);
+ return verify_cast<JS::Promise>(*promise_capability->promise().ptr());
}
// 2. Let promise be a promise resolved with an empty byte sequence.
diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp
index 7b08e08058..d4b5ded3ec 100644
--- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp
+++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp
@@ -40,7 +40,7 @@ WebIDL::ExceptionOr<Body> Body::clone() const
}
// https://fetch.spec.whatwg.org/#fully-reading-body-as-promise
-JS::PromiseCapability Body::fully_read_as_promise() const
+JS::NonnullGCPtr<JS::PromiseCapability> Body::fully_read_as_promise() const
{
auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm();
diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h
index 2d7a3221f2..3dbe155259 100644
--- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h
+++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h
@@ -31,7 +31,7 @@ public:
[[nodiscard]] WebIDL::ExceptionOr<Body> clone() const;
- [[nodiscard]] JS::PromiseCapability fully_read_as_promise() const;
+ [[nodiscard]] JS::NonnullGCPtr<JS::PromiseCapability> fully_read_as_promise() const;
private:
// https://fetch.spec.whatwg.org/#concept-body-stream
diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp
index ad726919e2..be8f9bfce0 100644
--- a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp
+++ b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp
@@ -15,7 +15,7 @@
namespace Web::WebIDL {
// https://webidl.spec.whatwg.org/#a-new-promise
-JS::PromiseCapability create_promise(JS::Realm& realm)
+JS::NonnullGCPtr<JS::PromiseCapability> create_promise(JS::Realm& realm)
{
auto& vm = realm.vm();
@@ -28,7 +28,7 @@ JS::PromiseCapability create_promise(JS::Realm& realm)
}
// https://webidl.spec.whatwg.org/#a-promise-resolved-with
-JS::PromiseCapability create_resolved_promise(JS::Realm& realm, JS::Value value)
+JS::NonnullGCPtr<JS::PromiseCapability> create_resolved_promise(JS::Realm& realm, JS::Value value)
{
auto& vm = realm.vm();
@@ -42,14 +42,14 @@ JS::PromiseCapability create_resolved_promise(JS::Realm& realm, JS::Value value)
auto promise_capability = MUST(JS::new_promise_capability(vm, constructor));
// 4. Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »).
- MUST(JS::call(vm, promise_capability.resolve, JS::js_undefined(), value));
+ MUST(JS::call(vm, *promise_capability->resolve(), JS::js_undefined(), value));
// 5. Return promiseCapability.
return promise_capability;
}
// https://webidl.spec.whatwg.org/#a-promise-rejected-with
-JS::PromiseCapability create_rejected_promise(JS::Realm& realm, JS::Value reason)
+JS::NonnullGCPtr<JS::PromiseCapability> create_rejected_promise(JS::Realm& realm, JS::Value reason)
{
auto& vm = realm.vm();
@@ -61,7 +61,7 @@ JS::PromiseCapability create_rejected_promise(JS::Realm& realm, JS::Value reason
auto promise_capability = MUST(JS::new_promise_capability(vm, constructor));
// 3. Perform ! Call(promiseCapability.[[Reject]], undefined, « r »).
- MUST(JS::call(vm, promise_capability.reject, JS::js_undefined(), reason));
+ MUST(JS::call(vm, *promise_capability->reject(), JS::js_undefined(), reason));
// 4. Return promiseCapability.
return promise_capability;
@@ -76,20 +76,20 @@ void resolve_promise(JS::VM& vm, JS::PromiseCapability const& promise_capability
// 2. Let value be the result of converting x to an ECMAScript value.
// 3. Perform ! Call(p.[[Resolve]], undefined, « value »).
- MUST(JS::call(vm, promise_capability.resolve, JS::js_undefined(), value));
+ MUST(JS::call(vm, *promise_capability.resolve(), JS::js_undefined(), value));
}
// https://webidl.spec.whatwg.org/#reject
void reject_promise(JS::VM& vm, JS::PromiseCapability const& promise_capability, JS::Value reason)
{
// 1. Perform ! Call(p.[[Reject]], undefined, « r »).
- MUST(JS::call(vm, promise_capability.reject, JS::js_undefined(), reason));
+ MUST(JS::call(vm, *promise_capability.reject(), JS::js_undefined(), reason));
}
// https://webidl.spec.whatwg.org/#dfn-perform-steps-once-promise-is-settled
JS::NonnullGCPtr<JS::Promise> react_to_promise(JS::PromiseCapability const& promise_capability, Optional<ReactionSteps> on_fulfilled_callback, Optional<ReactionSteps> on_rejected_callback)
{
- auto& realm = promise_capability.promise->shape().realm();
+ auto& realm = promise_capability.promise()->shape().realm();
auto& vm = realm.vm();
// 1. Let onFulfilledSteps be the following steps given argument V:
@@ -117,7 +117,7 @@ JS::NonnullGCPtr<JS::Promise> react_to_promise(JS::PromiseCapability const& prom
// 2. If there is a set of steps to be run if the promise was rejected, then let result be the result of performing them, given reason. Otherwise, let result be a promise rejected with reason.
auto result = on_rejected_callback.has_value()
? TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return (*on_rejected_callback)(reason); }))
- : WebIDL::create_rejected_promise(realm, reason).promise;
+ : WebIDL::create_rejected_promise(realm, reason)->promise();
// 3. Return result, converted to an ECMAScript value.
return result;
@@ -134,7 +134,7 @@ JS::NonnullGCPtr<JS::Promise> react_to_promise(JS::PromiseCapability const& prom
auto new_capability = MUST(JS::new_promise_capability(vm, constructor));
// 7. Return PerformPromiseThen(promise.[[Promise]], onFulfilled, onRejected, newCapability).
- auto* promise = static_cast<JS::Promise*>(promise_capability.promise);
+ auto* promise = verify_cast<JS::Promise>(promise_capability.promise().ptr());
auto value = promise->perform_then(on_fulfilled, on_rejected, new_capability);
return verify_cast<JS::Promise>(value.as_object());
}
@@ -172,7 +172,7 @@ JS::NonnullGCPtr<JS::Promise> upon_rejection(JS::PromiseCapability const& promis
void mark_promise_as_handled(JS::PromiseCapability const& promise_capability)
{
// To mark as handled a Promise<T> promise, set promise.[[Promise]].[[PromiseIsHandled]] to true.
- auto* promise = static_cast<JS::Promise*>(promise_capability.promise);
+ auto* promise = verify_cast<JS::Promise>(promise_capability.promise().ptr());
promise->set_is_handled();
}
diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.h b/Userland/Libraries/LibWeb/WebIDL/Promise.h
index 43a9336a45..0e221dc518 100644
--- a/Userland/Libraries/LibWeb/WebIDL/Promise.h
+++ b/Userland/Libraries/LibWeb/WebIDL/Promise.h
@@ -14,9 +14,9 @@ namespace Web::WebIDL {
using ReactionSteps = JS::SafeFunction<WebIDL::ExceptionOr<JS::Value>(JS::Value)>;
-JS::PromiseCapability create_promise(JS::Realm&);
-JS::PromiseCapability create_resolved_promise(JS::Realm&, JS::Value);
-JS::PromiseCapability create_rejected_promise(JS::Realm&, JS::Value);
+JS::NonnullGCPtr<JS::PromiseCapability> create_promise(JS::Realm&);
+JS::NonnullGCPtr<JS::PromiseCapability> create_resolved_promise(JS::Realm&, JS::Value);
+JS::NonnullGCPtr<JS::PromiseCapability> create_rejected_promise(JS::Realm&, JS::Value);
void resolve_promise(JS::VM&, JS::PromiseCapability const&, JS::Value = JS::js_undefined());
void reject_promise(JS::VM&, JS::PromiseCapability const&, JS::Value);
JS::NonnullGCPtr<JS::Promise> react_to_promise(JS::PromiseCapability const&, Optional<ReactionSteps> on_fulfilled_callback, Optional<ReactionSteps> on_rejected_callback);