1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:37:46 +00:00

LibJS: Setup host hooks and have promise jobs work out the realm

This allows the host of LibJS (notably LibWeb in this case) to override
certain functions such as HostEnqueuePromiseJob, so it can do it's own
thing in certain situations. Notably, LibWeb will override
HostEnqueuePromiseJob to put promise jobs on the microtask queue.

This also makes promise jobs use AK::Function instead of
JS::NativeFunction. This removes the need to go through a JavaScript
function and it more closely matches the spec's idea of "abstract
closures"
This commit is contained in:
Luke Wilde 2022-02-06 03:46:45 +00:00 committed by Linus Groh
parent 5aacec65ab
commit 4c1c6ef91c
12 changed files with 202 additions and 172 deletions

View file

@ -129,15 +129,15 @@ Promise::ResolvingFunctions Promise::create_resolving_functions()
// 13. Let thenJobCallback be HostMakeJobCallback(thenAction).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / PromiseResolvingFunction]: Creating JobCallback for then action @ {}", &promise, &then_action.as_function());
auto then_job_callback = make_job_callback(then_action.as_function());
auto then_job_callback = vm.host_make_job_callback(then_action.as_function());
// 14. Let job be NewPromiseResolveThenableJob(promise, resolution, thenJobCallback).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / PromiseResolvingFunction]: Creating PromiseResolveThenableJob for thenable {}", &promise, resolution);
auto* job = PromiseResolveThenableJob::create(global_object, promise, resolution, then_job_callback);
auto [job, realm] = create_promise_resolve_thenable_job(global_object, promise, resolution, move(then_job_callback));
// 15. Perform HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / PromiseResolvingFunction]: Enqueuing job @ {}", &promise, job);
vm.enqueue_promise_job(*job);
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / PromiseResolvingFunction]: Enqueuing job @ {} in realm {}", &promise, &job, realm);
vm.host_enqueue_promise_job(move(job), realm);
// 16. Return undefined.
return js_undefined();
@ -230,7 +230,7 @@ Value Promise::reject(Value reason)
// 7. If promise.[[PromiseIsHandled]] is false, perform HostPromiseRejectionTracker(promise, "reject").
if (!m_is_handled)
vm.promise_rejection_tracker(*this, RejectionOperation::Reject);
vm.host_promise_rejection_tracker(*this, RejectionOperation::Reject);
// 8. Return TriggerPromiseReactions(reactions, reason).
trigger_reactions();
@ -252,11 +252,11 @@ void Promise::trigger_reactions() const
for (auto& reaction : reactions) {
// a. Let job be NewPromiseReactionJob(reaction, argument).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / trigger_reactions()]: Creating PromiseReactionJob for PromiseReaction @ {} with argument {}", this, &reaction, m_result);
auto* job = PromiseReactionJob::create(global_object(), *reaction, m_result);
auto [job, realm] = create_promise_reaction_job(global_object(), *reaction, m_result);
// b. Perform HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / trigger_reactions()]: Enqueuing job @ {}", this, job);
vm.enqueue_promise_job(*job);
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / trigger_reactions()]: Enqueuing job @ {} in realm {}", this, &job, realm);
vm.host_enqueue_promise_job(move(job), realm);
}
if constexpr (PROMISE_DEBUG) {
@ -284,7 +284,7 @@ Value Promise::perform_then(Value on_fulfilled, Value on_rejected, Optional<Prom
if (on_fulfilled.is_function()) {
// a. Let onFulfilledJobCallback be HostMakeJobCallback(onFulfilled).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: Creating JobCallback for on_fulfilled function @ {}", this, &on_fulfilled.as_function());
on_fulfilled_job_callback = make_job_callback(on_fulfilled.as_function());
on_fulfilled_job_callback = vm.host_make_job_callback(on_fulfilled.as_function());
}
// 5. If IsCallable(onRejected) is false, then
@ -295,14 +295,14 @@ Value Promise::perform_then(Value on_fulfilled, Value on_rejected, Optional<Prom
if (on_rejected.is_function()) {
// a. Let onRejectedJobCallback be HostMakeJobCallback(onRejected).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: Creating JobCallback for on_rejected function @ {}", this, &on_rejected.as_function());
on_rejected_job_callback = make_job_callback(on_rejected.as_function());
on_rejected_job_callback = vm.host_make_job_callback(on_rejected.as_function());
}
// 7. Let fulfillReaction be the PromiseReaction { [[Capability]]: resultCapability, [[Type]]: Fulfill, [[Handler]]: onFulfilledJobCallback }.
auto* fulfill_reaction = PromiseReaction::create(vm, PromiseReaction::Type::Fulfill, result_capability, on_fulfilled_job_callback);
auto* fulfill_reaction = PromiseReaction::create(vm, PromiseReaction::Type::Fulfill, result_capability, move(on_fulfilled_job_callback));
// 8. Let rejectReaction be the PromiseReaction { [[Capability]]: resultCapability, [[Type]]: Reject, [[Handler]]: onRejectedJobCallback }.
auto* reject_reaction = PromiseReaction::create(vm, PromiseReaction::Type::Reject, result_capability, on_rejected_job_callback);
auto* reject_reaction = PromiseReaction::create(vm, PromiseReaction::Type::Reject, result_capability, move(on_rejected_job_callback));
switch (m_state) {
// 9. If promise.[[PromiseState]] is pending, then
@ -322,11 +322,11 @@ Value Promise::perform_then(Value on_fulfilled, Value on_rejected, Optional<Prom
// b. Let fulfillJob be NewPromiseReactionJob(fulfillReaction, value).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: State is State::Fulfilled, creating PromiseReactionJob for PromiseReaction @ {} with argument {}", this, fulfill_reaction, value);
auto* fulfill_job = PromiseReactionJob::create(global_object(), *fulfill_reaction, value);
auto [fulfill_job, realm] = create_promise_reaction_job(global_object(), *fulfill_reaction, value);
// c. Perform HostEnqueuePromiseJob(fulfillJob.[[Job]], fulfillJob.[[Realm]]).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: Enqueuing job @ {}", this, fulfill_job);
vm.enqueue_promise_job(*fulfill_job);
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: Enqueuing job @ {} in realm {}", this, &fulfill_job, realm);
vm.host_enqueue_promise_job(move(fulfill_job), realm);
break;
}
// 11. Else,
@ -338,15 +338,15 @@ Value Promise::perform_then(Value on_fulfilled, Value on_rejected, Optional<Prom
// c. If promise.[[PromiseIsHandled]] is false, perform HostPromiseRejectionTracker(promise, "handle").
if (!m_is_handled)
vm.promise_rejection_tracker(*this, RejectionOperation::Handle);
vm.host_promise_rejection_tracker(*this, RejectionOperation::Handle);
// d. Let rejectJob be NewPromiseReactionJob(rejectReaction, reason).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: State is State::Rejected, creating PromiseReactionJob for PromiseReaction @ {} with argument {}", this, reject_reaction, reason);
auto* reject_job = PromiseReactionJob::create(global_object(), *reject_reaction, reason);
auto [reject_job, realm] = create_promise_reaction_job(global_object(), *reject_reaction, reason);
// e. Perform HostEnqueuePromiseJob(rejectJob.[[Job]], rejectJob.[[Realm]]).
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: Enqueuing job @ {}", this, reject_job);
vm.enqueue_promise_job(*reject_job);
dbgln_if(PROMISE_DEBUG, "[Promise @ {} / perform_then()]: Enqueuing job @ {} in realm {}", this, &reject_job, realm);
vm.host_enqueue_promise_job(move(reject_job), realm);
break;
}
default: