1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:28:12 +00:00

LibJS: Remove implicit wrapping/unwrapping of completion records

This is an editorial change in the ECMA-262 spec, with similar changes
in some proposals.

See:
- 7575f74
- df899eb
- 9eb5a12
- c81f527
This commit is contained in:
Linus Groh 2022-05-02 20:54:39 +02:00
parent 15f32379bb
commit 9f3f3b0864
88 changed files with 792 additions and 735 deletions

View file

@ -26,11 +26,11 @@ ThrowCompletionOr<void> CyclicModule::link(VM& vm)
// 2. Let stack be a new empty List.
Vector<Module*> stack;
// 3. Let result be InnerModuleLinking(module, stack, 0).
auto inner_module_linked_or_error = inner_module_linking(vm, stack, 0);
// 3. Let result be Completion(InnerModuleLinking(module, stack, 0)).
auto result = inner_module_linking(vm, stack, 0);
// 4. If result is an abrupt completion, then
if (inner_module_linked_or_error.is_error()) {
if (result.is_throw_completion()) {
// a. For each Cyclic Module Record m of stack, do
for (auto* module : stack) {
if (is<CyclicModule>(module)) {
@ -46,7 +46,7 @@ ThrowCompletionOr<void> CyclicModule::link(VM& vm)
VERIFY(m_status == ModuleStatus::Unlinked);
// c. Return result.
return inner_module_linked_or_error.release_error();
return result.release_error();
}
// 5. Assert: module.[[Status]] is linked, evaluating-async, or evaluated.
@ -54,8 +54,7 @@ ThrowCompletionOr<void> CyclicModule::link(VM& vm)
// 6. Assert: stack is empty.
VERIFY(stack.is_empty());
// 7. Return undefined.
// Note: We return void since the result of this is never used.
// 7. Return unused.
return {};
}
@ -130,7 +129,7 @@ ThrowCompletionOr<u32> CyclicModule::inner_module_linking(VM& vm, Vector<Module*
}
// 10. Perform ? module.InitializeEnvironment().
(void)TRY(initialize_environment(vm));
TRY(initialize_environment(vm));
// 11. Assert: module occurs exactly once in stack.
size_t count = 0;
@ -204,7 +203,7 @@ ThrowCompletionOr<Promise*> CyclicModule::evaluate(VM& vm)
// 7. Set module.[[TopLevelCapability]] to capability.
m_top_level_capability = MUST(new_promise_capability(global_object, global_object.promise_constructor()));
// 8. Let result be InnerModuleEvaluation(module, stack, 0).
// 8. Let result be Completion(InnerModuleEvaluation(module, stack, 0)).
auto result = inner_module_evaluation(vm, stack, 0);
// 9. If result is an abrupt completion, then
@ -273,7 +272,7 @@ ThrowCompletionOr<u32> CyclicModule::inner_module_evaluation(VM& vm, Vector<Modu
if (!m_evaluation_error.is_error())
return index;
// b. Otherwise, return module.[[EvaluationError]].
// b. Otherwise, return ? module.[[EvaluationError]].
return m_evaluation_error.throw_completion();
}
@ -336,7 +335,7 @@ ThrowCompletionOr<u32> CyclicModule::inner_module_evaluation(VM& vm, Vector<Modu
// 2. Assert: requiredModule.[[Status]] is evaluating-async or evaluated.
VERIFY(cyclic_module->m_status == ModuleStatus::EvaluatingAsync || cyclic_module->m_status == ModuleStatus::Evaluated);
// 3. If requiredModule.[[EvaluationError]] is not empty, return requiredModule.[[EvaluationError]].
// 3. If requiredModule.[[EvaluationError]] is not empty, return ? requiredModule.[[EvaluationError]].
if (cyclic_module->m_evaluation_error.is_error())
return cyclic_module->m_evaluation_error.throw_completion();
}
@ -361,13 +360,13 @@ ThrowCompletionOr<u32> CyclicModule::inner_module_evaluation(VM& vm, Vector<Modu
m_async_evaluation = true;
// c. NOTE: The order in which module records have their [[AsyncEvaluation]] fields transition to true is significant. (See 16.2.1.5.2.4.)
// d. If module.[[PendingAsyncDependencies]] is 0, perform ! ExecuteAsyncModule(module).
// d. If module.[[PendingAsyncDependencies]] is 0, perform ExecuteAsyncModule(module).
if (m_pending_async_dependencies.value() == 0)
MUST(execute_async_module(vm));
execute_async_module(vm);
}
// 13. Otherwise, perform ? module.ExecuteModule().
else {
(void)TRY(execute_module(vm));
TRY(execute_module(vm));
}
// 14. Assert: module occurs exactly once in stack.
@ -417,24 +416,22 @@ ThrowCompletionOr<u32> CyclicModule::inner_module_evaluation(VM& vm, Vector<Modu
return index;
}
Completion CyclicModule::initialize_environment(VM&)
ThrowCompletionOr<void> CyclicModule::initialize_environment(VM&)
{
// 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.
VERIFY_NOT_REACHED();
return normal_completion({});
}
Completion CyclicModule::execute_module(VM&, Optional<PromiseCapability>)
ThrowCompletionOr<void> CyclicModule::execute_module(VM&, Optional<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.
VERIFY_NOT_REACHED();
return js_undefined();
}
// 16.2.1.5.2.2 ExecuteAsyncModule ( module ), https://tc39.es/ecma262/#sec-execute-async-module
ThrowCompletionOr<void> CyclicModule::execute_async_module(VM& vm)
void CyclicModule::execute_async_module(VM& vm)
{
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] executing async module {}", filename());
// 1. Assert: module.[[Status]] is evaluating or evaluating-async.
@ -449,43 +446,43 @@ ThrowCompletionOr<void> CyclicModule::execute_async_module(VM& vm)
// 4. Let fulfilledClosure be a new Abstract Closure with no parameters that captures module and performs the following steps when called:
auto fulfilled_closure = [&](VM& vm, GlobalObject&) -> ThrowCompletionOr<Value> {
// a. Perform ! AsyncModuleExecutionFulfilled(module).
MUST(async_module_execution_fulfilled(vm));
// a. Perform AsyncModuleExecutionFulfilled(module).
async_module_execution_fulfilled(vm);
// b. Return undefined.
return js_undefined();
};
// 5. Let onFulfilled be ! CreateBuiltinFunction(fulfilledClosure, 0, "", « »).
// 5. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 0, "", « »).
auto* on_fulfilled = NativeFunction::create(global_object, move(fulfilled_closure), 0, "");
// 6. Let rejectedClosure be a new Abstract Closure with parameters (error) that captures module and performs the following steps when called:
auto rejected_closure = [&](VM& vm, GlobalObject&) -> ThrowCompletionOr<Value> {
auto error = vm.argument(0);
// a. Perform ! AsyncModuleExecutionRejected(module, error).
MUST(async_module_execution_rejected(vm, error));
// a. Perform AsyncModuleExecutionRejected(module, error).
async_module_execution_rejected(vm, error);
// b. Return undefined.
return js_undefined();
};
// 7. Let onRejected be ! CreateBuiltinFunction(rejectedClosure, 0, "", « »).
// 7. Let onRejected be CreateBuiltinFunction(rejectedClosure, 0, "", « »).
auto* on_rejected = NativeFunction::create(global_object, move(rejected_closure), 0, "");
VERIFY(is<Promise>(*capability.promise));
// 8. Perform ! PerformPromiseThen(capability.[[Promise]], onFulfilled, onRejected).
// 8. Perform PerformPromiseThen(capability.[[Promise]], onFulfilled, onRejected).
static_cast<Promise*>(capability.promise)->perform_then(on_fulfilled, on_rejected, {});
// 9. Perform ! module.ExecuteModule(capability).
(void)MUST(execute_module(vm, capability));
MUST(execute_module(vm, capability));
return {};
// 10. Return unused.
}
// 16.2.1.5.2.3 GatherAvailableAncestors ( module, execList ), https://tc39.es/ecma262/#sec-gather-available-ancestors
ThrowCompletionOr<void> CyclicModule::gather_available_ancestors(Vector<CyclicModule*>& exec_list)
void CyclicModule::gather_available_ancestors(Vector<CyclicModule*>& exec_list)
{
// 1. For each Cyclic Module Record m of module.[[AsyncParentModules]], do
for (auto* module : m_async_parent_modules) {
@ -511,25 +508,26 @@ ThrowCompletionOr<void> CyclicModule::gather_available_ancestors(Vector<CyclicMo
// 1. Append m to execList.
exec_list.append(module);
// 2. If m.[[HasTLA]] is false, perform ! GatherAvailableAncestors(m, execList).
// 2. If m.[[HasTLA]] is false, perform GatherAvailableAncestors(m, execList).
if (!module->m_has_top_level_await)
MUST(module->gather_available_ancestors(exec_list));
module->gather_available_ancestors(exec_list);
}
}
}
return {};
// 2. Return unused.
}
// 16.2.1.5.2.4 AsyncModuleExecutionFulfilled ( module ), https://tc39.es/ecma262/#sec-async-module-execution-fulfilled
ThrowCompletionOr<void> CyclicModule::async_module_execution_fulfilled(VM& vm)
void CyclicModule::async_module_execution_fulfilled(VM& vm)
{
// 1. If module.[[Status]] is evaluated, then
if (m_status == ModuleStatus::Evaluated) {
// a. Assert: module.[[EvaluationError]] is not empty.
VERIFY(m_evaluation_error.is_error());
// b. Return.
return {};
// b. Return unused.
return;
}
// 2. Assert: module.[[Status]] is evaluating-async.
@ -560,8 +558,8 @@ ThrowCompletionOr<void> CyclicModule::async_module_execution_fulfilled(VM& vm)
// 8. Let execList be a new empty List.
Vector<CyclicModule*> exec_list;
// 9. Perform ! GatherAvailableAncestors(module, execList).
MUST(gather_available_ancestors(exec_list));
// 9. Perform GatherAvailableAncestors(module, execList).
gather_available_ancestors(exec_list);
// 10. Let sortedExecList be a List whose elements are the elements of execList, in the order in which they had their [[AsyncEvaluation]] fields set to true in InnerModuleEvaluation.
// FIXME: Sort the list. To do this we need to use more than an Optional<bool> to track [[AsyncEvaluation]].
@ -578,8 +576,8 @@ ThrowCompletionOr<void> CyclicModule::async_module_execution_fulfilled(VM& vm)
}
// b. Else if m.[[HasTLA]] is true, then
else if (module->m_has_top_level_await) {
// i. Perform ! ExecuteAsyncModule(m).
MUST(module->execute_async_module(vm));
// i. Perform ExecuteAsyncModule(m).
module->execute_async_module(vm);
}
// c. Else,
else {
@ -587,9 +585,9 @@ ThrowCompletionOr<void> CyclicModule::async_module_execution_fulfilled(VM& vm)
auto result = module->execute_module(vm);
// ii. If result is an abrupt completion, then
if (result.is_abrupt()) {
// 1. Perform ! AsyncModuleExecutionRejected(m, result.[[Value]]).
module->async_module_execution_rejected(vm, *result.value());
if (result.is_throw_completion()) {
// 1. Perform AsyncModuleExecutionRejected(m, result.[[Value]]).
module->async_module_execution_rejected(vm, *result.throw_completion().value());
}
// iii. Else,
else {
@ -608,18 +606,20 @@ ThrowCompletionOr<void> CyclicModule::async_module_execution_fulfilled(VM& vm)
}
}
}
return {};
// 13. Return unused.
}
// 16.2.1.5.2.5 AsyncModuleExecutionRejected ( module, error ), https://tc39.es/ecma262/#sec-async-module-execution-rejected
ThrowCompletionOr<void> CyclicModule::async_module_execution_rejected(VM& vm, Value error)
void CyclicModule::async_module_execution_rejected(VM& vm, Value error)
{
// 1. If module.[[Status]] is evaluated, then
if (m_status == ModuleStatus::Evaluated) {
// a. Assert: module.[[EvaluationError]] is not empty.
VERIFY(m_evaluation_error.is_error());
// b. Return.
return {};
// b. Return unused.
return;
}
// 2. Assert: module.[[Status]] is evaluating-async.
@ -640,8 +640,8 @@ ThrowCompletionOr<void> CyclicModule::async_module_execution_rejected(VM& vm, Va
// 7. For each Cyclic Module Record m of module.[[AsyncParentModules]], do
for (auto* module : m_async_parent_modules) {
// a. Perform ! AsyncModuleExecutionRejected(m, error).
MUST(module->async_module_execution_rejected(vm, error));
// a. Perform AsyncModuleExecutionRejected(m, error).
module->async_module_execution_rejected(vm, error);
}
// 8. If module.[[TopLevelCapability]] is not empty, then
@ -654,7 +654,7 @@ ThrowCompletionOr<void> CyclicModule::async_module_execution_rejected(VM& vm, Va
MUST(call(vm.current_realm()->global_object(), m_top_level_capability->reject, js_undefined(), error));
}
return {};
// 9. Return unused.
}
}