From 57de5056b68feaf3f572ac91f07dff4b2e044367 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Sun, 14 Nov 2021 12:20:49 +0000 Subject: [PATCH] LibJS: Convert push_execution_context() to ThrowCompletionOr --- Userland/Libraries/LibJS/Bytecode/Interpreter.cpp | 3 +-- Userland/Libraries/LibJS/Interpreter.cpp | 3 +-- Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp | 2 +- Userland/Libraries/LibJS/Runtime/Completion.cpp | 4 ++-- .../Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp | 8 ++++---- Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp | 2 +- Userland/Libraries/LibJS/Runtime/NativeFunction.cpp | 4 ++-- Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp | 4 ++-- Userland/Libraries/LibJS/Runtime/VM.cpp | 3 ++- Userland/Libraries/LibJS/Runtime/VM.h | 8 ++++---- 10 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index e89536dbee..ab704b4985 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -57,8 +57,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e execution_context.realm = &m_realm; // FIXME: How do we know if we're in strict mode? Maybe the Bytecode::Block should know this? // execution_context.is_strict_mode = ???; - vm().push_execution_context(execution_context, global_object()); - VERIFY(!vm().exception()); + MUST(vm().push_execution_context(execution_context, global_object())); } auto block = entry_point ?: &executable.basic_blocks.first(); diff --git a/Userland/Libraries/LibJS/Interpreter.cpp b/Userland/Libraries/LibJS/Interpreter.cpp index 27220abdda..5ad5f5c48c 100644 --- a/Userland/Libraries/LibJS/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Interpreter.cpp @@ -58,8 +58,7 @@ void Interpreter::run(GlobalObject& global_object, const Program& program) execution_context.variable_environment = &realm().global_environment(); execution_context.realm = &realm(); execution_context.is_strict_mode = program.is_strict_mode(); - vm.push_execution_context(execution_context, global_object); - VERIFY(!vm.exception()); + MUST(vm.push_execution_context(execution_context, global_object)); auto value = program.execute(*this, global_object); vm.set_last_value(Badge {}, value.value_or(js_undefined())); diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index 3e290b5b1b..1c88573851 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -525,7 +525,7 @@ ThrowCompletionOr perform_eval(Value x, GlobalObject& caller_realm, Calle eval_context.variable_environment = variable_environment; eval_context.lexical_environment = lexical_environment; eval_context.private_environment = private_environment; - vm.push_execution_context(eval_context, eval_realm->global_object()); + TRY(vm.push_execution_context(eval_context, eval_realm->global_object())); ScopeGuard pop_guard = [&] { vm.pop_execution_context(); diff --git a/Userland/Libraries/LibJS/Runtime/Completion.cpp b/Userland/Libraries/LibJS/Runtime/Completion.cpp index 09d9a7002b..df29a93ab9 100644 --- a/Userland/Libraries/LibJS/Runtime/Completion.cpp +++ b/Userland/Libraries/LibJS/Runtime/Completion.cpp @@ -51,7 +51,7 @@ ThrowCompletionOr await(GlobalObject& global_object, Value value) result = vm.argument(0); // c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context. - vm.push_execution_context(async_context, global_object); + TRY(vm.push_execution_context(async_context, global_object)); // d. Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it. // e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context. @@ -75,7 +75,7 @@ ThrowCompletionOr await(GlobalObject& global_object, Value value) result = vm.argument(0); // c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context. - vm.push_execution_context(async_context, global_object); + TRY(vm.push_execution_context(async_context, global_object)); // d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that suspended it. // e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context. diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index cd305680fb..94e1a6a6c2 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -597,9 +597,7 @@ ThrowCompletionOr ECMAScriptFunctionObject::prepare_for_ordinary_call(Exec // FIXME: We don't have this concept yet. // 12. Push calleeContext onto the execution context stack; calleeContext is now the running execution context. - vm.push_execution_context(callee_context, global_object()); - if (auto* exception = vm.exception()) - return throw_completion(exception->value()); + TRY(vm.push_execution_context(callee_context, global_object())); // 13. NOTE: Any exception objects produced after this point are associated with calleeRealm. // 14. Return calleeContext. (See NOTE above about how contexts are allocated on the C++ stack.) @@ -729,7 +727,9 @@ void ECMAScriptFunctionObject::async_block_start(PromiseCapability const& promis }); // 4. Push asyncContext onto the execution context stack; asyncContext is now the running execution context. - vm.push_execution_context(async_context, global_object()); + auto push_result = vm.push_execution_context(async_context, global_object()); + if (push_result.is_error()) + return; // 5. Resume the suspended evaluation of asyncContext. Let result be the value returned by the resumed computation. auto result = vm.call(*execution_steps, async_context.this_value.is_empty() ? js_undefined() : async_context.this_value); diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp index 417bc69e00..e145f9422c 100644 --- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp @@ -92,7 +92,7 @@ ThrowCompletionOr GeneratorObject::next_impl(VM& vm, GlobalObject& global bytecode_interpreter->enter_frame(m_frame); // Temporarily switch to the captured execution context - vm.push_execution_context(m_execution_context, global_object); + TRY(vm.push_execution_context(m_execution_context, global_object)); // Pretend that 'yield' returned the passed value, or threw if (value_to_throw.has_value()) { diff --git a/Userland/Libraries/LibJS/Runtime/NativeFunction.cpp b/Userland/Libraries/LibJS/Runtime/NativeFunction.cpp index 8034f98eea..cd719737ec 100644 --- a/Userland/Libraries/LibJS/Runtime/NativeFunction.cpp +++ b/Userland/Libraries/LibJS/Runtime/NativeFunction.cpp @@ -104,7 +104,7 @@ ThrowCompletionOr NativeFunction::internal_call(Value this_argument, Mark // -------------------------------------------------------------------------- // 9. Push calleeContext onto the execution context stack; calleeContext is now the running execution context. - vm.push_execution_context(callee_context, global_object); + TRY(vm.push_execution_context(callee_context, global_object)); // 10. Let result be the Completion Record that is the result of evaluating F in a manner that conforms to the specification of F. thisArgument is the this value, argumentsList provides the named parameters, and the NewTarget value is undefined. auto result = call(); @@ -168,7 +168,7 @@ ThrowCompletionOr NativeFunction::internal_construct(MarkedValueList ar // -------------------------------------------------------------------------- // 9. Push calleeContext onto the execution context stack; calleeContext is now the running execution context. - vm.push_execution_context(callee_context, global_object); + TRY(vm.push_execution_context(callee_context, global_object)); // 10. Let result be the Completion Record that is the result of evaluating F in a manner that conforms to the specification of F. The this value is uninitialized, argumentsList provides the named parameters, and newTarget provides the NewTarget value. auto result = construct(new_target); diff --git a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp index 278081b526..9e547c4568 100644 --- a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp +++ b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp @@ -105,7 +105,7 @@ ThrowCompletionOr perform_shadow_realm_eval(GlobalObject& global_object, eval_context.is_strict_mode = strict_eval; // 18. Push evalContext onto the execution context stack; evalContext is now the running execution context. - vm.push_execution_context(eval_context, eval_realm.global_object()); + TRY(vm.push_execution_context(eval_context, eval_realm.global_object())); // 19. Let result be EvalDeclarationInstantiation(body, varEnv, lexEnv, null, strictEval). auto eval_result = eval_declaration_instantiation(vm, eval_realm.global_object(), program, variable_environment, lexical_environment, nullptr, strict_eval); @@ -168,7 +168,7 @@ ThrowCompletionOr shadow_realm_import_value(GlobalObject& global_object, // NOTE: We don't support this concept yet. // 9. Push evalContext onto the execution context stack; evalContext is now the running execution context. - vm.push_execution_context(eval_context, eval_realm.global_object()); + TRY(vm.push_execution_context(eval_context, eval_realm.global_object())); // 10. Perform ! HostImportModuleDynamically(null, specifierString, innerCapability). // FIXME: We don't have this yet. We generally have very little support for modules and imports. diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index c288c3a830..e668e2b512 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -535,7 +535,8 @@ void VM::run_queued_promise_jobs() if (m_execution_context_stack.is_empty()) { static FlyString promise_execution_context_name = "(promise execution context)"; execution_context.function_name = promise_execution_context_name; - push_execution_context(execution_context, job->global_object()); + // FIXME: Propagate potential failure + MUST(push_execution_context(execution_context, job->global_object())); pushed_execution_context = true; } diff --git a/Userland/Libraries/LibJS/Runtime/VM.h b/Userland/Libraries/LibJS/Runtime/VM.h index d54184dddc..2330273c60 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.h +++ b/Userland/Libraries/LibJS/Runtime/VM.h @@ -98,14 +98,14 @@ public: #endif } - void push_execution_context(ExecutionContext& context, GlobalObject& global_object) + ThrowCompletionOr push_execution_context(ExecutionContext& context, GlobalObject& global_object) { VERIFY(!exception()); // Ensure we got some stack space left, so the next function call doesn't kill us. if (did_reach_stack_space_limit()) - throw_exception(global_object, ErrorType::CallStackSizeExceeded); - else - m_execution_context_stack.append(&context); + return throw_completion(global_object, ErrorType::CallStackSizeExceeded); + m_execution_context_stack.append(&context); + return {}; } void pop_execution_context()