1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 12:55:09 +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:
Linus Groh 2022-10-02 12:11:30 +01:00
parent 0585029c30
commit fc9d587e39
29 changed files with 243 additions and 217 deletions

View file

@ -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.