LibJS: Coerce empty completion to "undefined" early in Interpreter

Instead of always checking if we're about to return an empty completion
value in Interpreter::run_executable(), we now coerce empty completions
to the undefined value earlier instead.

This simplifies the most common path through run_executable(), giving us
a small speedup.
This commit is contained in:
Andreas Kling 2025-10-31 21:10:51 +01:00 committed by Andreas Kling
parent 75d49c4b55
commit 6f9d297c3c
2 changed files with 8 additions and 6 deletions

View File

@ -380,7 +380,10 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
handle_End: { handle_End: {
auto& instruction = *reinterpret_cast<Op::End const*>(&bytecode[program_counter]); auto& instruction = *reinterpret_cast<Op::End const*>(&bytecode[program_counter]);
reg(Register::return_value()) = get(instruction.value()); auto value = get(instruction.value());
if (value.is_special_empty_value())
value = js_undefined();
reg(Register::return_value()) = value;
return; return;
} }
@ -489,7 +492,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
auto& unwind_context = unwind_contexts.last(); auto& unwind_context = unwind_contexts.last();
VERIFY(unwind_context.executable == &current_executable()); VERIFY(unwind_context.executable == &current_executable());
reg(Register::saved_return_value()) = reg(Register::return_value()); reg(Register::saved_return_value()) = reg(Register::return_value());
reg(Register::return_value()) = js_special_empty_value(); reg(Register::return_value()) = js_undefined();
program_counter = finalizer.value(); program_counter = finalizer.value();
// the unwind_context will be pop'ed when entering the finally block // the unwind_context will be pop'ed when entering the finally block
goto start; goto start;
@ -752,10 +755,7 @@ ThrowCompletionOr<Value> Interpreter::run_executable(ExecutionContext& context,
if (!exception.is_special_empty_value()) [[unlikely]] if (!exception.is_special_empty_value()) [[unlikely]]
return throw_completion(exception); return throw_completion(exception);
auto return_value = reg(Register::return_value()); return reg(Register::return_value());
if (return_value.is_special_empty_value())
return_value = js_undefined();
return return_value;
} }
void Interpreter::enter_unwind_context() void Interpreter::enter_unwind_context()

View File

@ -58,6 +58,8 @@ public:
Value do_yield(Value value, Optional<Label> continuation); Value do_yield(Value value, Optional<Label> continuation);
void do_return(Value value) void do_return(Value value)
{ {
if (value.is_special_empty_value())
value = js_undefined();
reg(Register::return_value()) = value; reg(Register::return_value()) = value;
reg(Register::exception()) = js_special_empty_value(); reg(Register::exception()) = js_special_empty_value();
} }