mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 09:04:59 +00:00
LibJS: Make PromiseCapability GC-allocated
A struct with three raw pointers to other GC'd types is a pretty big liability, let's just turn this into a Cell itself. This comes with the additional benefit of being able to capture it in a lambda effortlessly, without having to create handles for individual members.
This commit is contained in:
parent
0585029c30
commit
fc9d587e39
29 changed files with 243 additions and 217 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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]]
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]]
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue