Skip to content

Commit a7d13b1

Browse files
committed
LibJS: Move all per-frame state from Interpreter to ExecutionContext
This simplifies function entry/exit and lets us just walk away from the used ExecutionContext instead of resetting a bunch of its state when returning control to the caller.
1 parent 59ce6c9 commit a7d13b1

File tree

3 files changed

+36
-39
lines changed

3 files changed

+36
-39
lines changed

Libraries/LibJS/Bytecode/Interpreter.cpp

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,12 @@ Interpreter::~Interpreter()
167167

168168
ALWAYS_INLINE Value Interpreter::get(Operand op) const
169169
{
170-
return m_registers_and_constants_and_locals_arguments.data()[op.index()];
170+
return m_running_execution_context->registers_and_constants_and_locals_arguments.data()[op.index()];
171171
}
172172

173173
ALWAYS_INLINE void Interpreter::set(Operand op, Value value)
174174
{
175-
m_registers_and_constants_and_locals_arguments.data()[op.index()] = value;
175+
m_running_execution_context->registers_and_constants_and_locals_arguments.data()[op.index()] = value;
176176
}
177177

178178
ALWAYS_INLINE Value Interpreter::do_yield(Value value, Optional<Label> continuation)
@@ -308,7 +308,7 @@ ThrowCompletionOr<Value> Interpreter::run(SourceTextModule& module)
308308
NEVER_INLINE Interpreter::HandleExceptionResponse Interpreter::handle_exception(u32& program_counter, Value exception)
309309
{
310310
reg(Register::exception()) = exception;
311-
m_scheduled_jump = {};
311+
m_running_execution_context->scheduled_jump = {};
312312
auto handlers = current_executable().exception_handlers_for_offset(program_counter);
313313
if (!handlers.has_value()) {
314314
return HandleExceptionResponse::ExitFromExecutable;
@@ -318,7 +318,7 @@ NEVER_INLINE Interpreter::HandleExceptionResponse Interpreter::handle_exception(
318318

319319
VERIFY(!running_execution_context().unwind_contexts.is_empty());
320320
auto& unwind_context = running_execution_context().unwind_contexts.last();
321-
VERIFY(unwind_context.executable == m_current_executable);
321+
VERIFY(unwind_context.executable == &current_executable());
322322

323323
if (handler.has_value()) {
324324
program_counter = handler.value();
@@ -492,7 +492,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
492492
if (auto finalizer = handlers.value().finalizer_offset; finalizer.has_value()) {
493493
VERIFY(!running_execution_context.unwind_contexts.is_empty());
494494
auto& unwind_context = running_execution_context.unwind_contexts.last();
495-
VERIFY(unwind_context.executable == m_current_executable);
495+
VERIFY(unwind_context.executable == &current_executable());
496496
reg(Register::saved_return_value()) = reg(Register::return_value());
497497
reg(Register::return_value()) = js_special_empty_value();
498498
program_counter = finalizer.value();
@@ -503,21 +503,21 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
503503
return;
504504
}
505505
auto const old_scheduled_jump = running_execution_context.previously_scheduled_jumps.take_last();
506-
if (m_scheduled_jump.has_value()) {
507-
program_counter = m_scheduled_jump.value();
508-
m_scheduled_jump = {};
506+
if (m_running_execution_context->scheduled_jump.has_value()) {
507+
program_counter = m_running_execution_context->scheduled_jump.value();
508+
m_running_execution_context->scheduled_jump = {};
509509
} else {
510510
program_counter = instruction.resume_target().address();
511511
// set the scheduled jump to the old value if we continue
512512
// where we left it
513-
m_scheduled_jump = old_scheduled_jump;
513+
m_running_execution_context->scheduled_jump = old_scheduled_jump;
514514
}
515515
goto start;
516516
}
517517

518518
handle_ScheduleJump: {
519519
auto& instruction = *reinterpret_cast<Op::ScheduleJump const*>(&bytecode[program_counter]);
520-
m_scheduled_jump = instruction.target().address();
520+
m_running_execution_context->scheduled_jump = instruction.target().address();
521521
auto finalizer = executable.exception_handlers_for_offset(program_counter).value().finalizer_offset;
522522
VERIFY(finalizer.has_value());
523523
program_counter = finalizer.value();
@@ -704,26 +704,24 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
704704

705705
Utf16FlyString const& Interpreter::get_identifier(IdentifierTableIndex index) const
706706
{
707-
return m_identifier_table.data()[index.value];
707+
return m_running_execution_context->identifier_table.data()[index.value];
708708
}
709709

710710
Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& executable, Optional<size_t> entry_point, Value initial_accumulator_value)
711711
{
712712
dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter will run unit {:p}", &executable);
713713

714-
TemporaryChange restore_executable { m_current_executable, GC::Ptr { executable } };
715-
TemporaryChange restore_saved_jump { m_scheduled_jump, Optional<size_t> {} };
716-
TemporaryChange restore_realm { m_realm, GC::Ptr { vm().current_realm() } };
717-
TemporaryChange restore_global_object { m_global_object, GC::Ptr { m_realm->global_object() } };
718-
TemporaryChange restore_global_declarative_environment { m_global_declarative_environment, GC::Ptr { m_realm->global_environment().declarative_record() } };
719-
TemporaryChange restore_identifier_table { m_identifier_table, executable.identifier_table->identifiers() };
720-
721714
auto& running_execution_context = vm().running_execution_context();
715+
TemporaryChange restore_running_execution_context { m_running_execution_context, &running_execution_context };
716+
717+
running_execution_context.global_object = realm().global_object();
718+
running_execution_context.global_declarative_environment = realm().global_environment().declarative_record();
719+
running_execution_context.identifier_table = executable.identifier_table->identifiers();
720+
722721
u32 registers_and_constants_and_locals_count = executable.number_of_registers + executable.constants.size() + executable.local_variable_names.size();
723722
VERIFY(registers_and_constants_and_locals_count <= running_execution_context.registers_and_constants_and_locals_and_arguments_span().size());
724723

725-
TemporaryChange restore_running_execution_context { m_running_execution_context, &running_execution_context };
726-
TemporaryChange restore_registers_and_constants_and_locals { m_registers_and_constants_and_locals_arguments, running_execution_context.registers_and_constants_and_locals_and_arguments_span() };
724+
running_execution_context.registers_and_constants_and_locals_arguments = running_execution_context.registers_and_constants_and_locals_and_arguments_span();
727725

728726
reg(Register::accumulator()) = initial_accumulator_value;
729727
reg(Register::return_value()) = js_special_empty_value();
@@ -773,10 +771,10 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe
773771
void Interpreter::enter_unwind_context()
774772
{
775773
running_execution_context().unwind_contexts.empend(
776-
m_current_executable,
774+
current_executable(),
777775
running_execution_context().lexical_environment);
778-
running_execution_context().previously_scheduled_jumps.append(m_scheduled_jump);
779-
m_scheduled_jump = {};
776+
running_execution_context().previously_scheduled_jumps.append(m_running_execution_context->scheduled_jump);
777+
m_running_execution_context->scheduled_jump = {};
780778
}
781779

782780
void Interpreter::leave_unwind_context()
@@ -797,13 +795,13 @@ void Interpreter::catch_exception(Operand dst)
797795

798796
void Interpreter::restore_scheduled_jump()
799797
{
800-
m_scheduled_jump = running_execution_context().previously_scheduled_jumps.take_last();
798+
m_running_execution_context->scheduled_jump = running_execution_context().previously_scheduled_jumps.take_last();
801799
}
802800

803801
void Interpreter::leave_finally()
804802
{
805803
reg(Register::exception()) = js_special_empty_value();
806-
m_scheduled_jump = running_execution_context().previously_scheduled_jumps.take_last();
804+
m_running_execution_context->scheduled_jump = running_execution_context().previously_scheduled_jumps.take_last();
807805
}
808806

809807
void Interpreter::enter_object_environment(Object& object)

Libraries/LibJS/Bytecode/Interpreter.h

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class JS_API Interpreter {
2525
explicit Interpreter(VM&);
2626
~Interpreter();
2727

28-
[[nodiscard]] Realm& realm() { return *m_realm; }
29-
[[nodiscard]] Object& global_object() { return *m_global_object; }
30-
[[nodiscard]] DeclarativeEnvironment& global_declarative_environment() { return *m_global_declarative_environment; }
28+
[[nodiscard]] Realm& realm() { return *m_running_execution_context->realm; }
29+
[[nodiscard]] Object& global_object() { return *m_running_execution_context->global_object; }
30+
[[nodiscard]] DeclarativeEnvironment& global_declarative_environment() { return *m_running_execution_context->global_declarative_environment; }
3131
VM& vm() { return m_vm; }
3232
VM const& vm() const { return m_vm; }
3333

@@ -50,11 +50,11 @@ class JS_API Interpreter {
5050
ALWAYS_INLINE Value& saved_return_value() { return reg(Register::saved_return_value()); }
5151
Value& reg(Register const& r)
5252
{
53-
return m_registers_and_constants_and_locals_arguments.data()[r.index()];
53+
return m_running_execution_context->registers_and_constants_and_locals_arguments.data()[r.index()];
5454
}
5555
Value reg(Register const& r) const
5656
{
57-
return m_registers_and_constants_and_locals_arguments.data()[r.index()];
57+
return m_running_execution_context->registers_and_constants_and_locals_arguments.data()[r.index()];
5858
}
5959

6060
[[nodiscard]] Value get(Operand) const;
@@ -75,8 +75,8 @@ class JS_API Interpreter {
7575

7676
void enter_object_environment(Object&);
7777

78-
Executable& current_executable() { return *m_current_executable; }
79-
Executable const& current_executable() const { return *m_current_executable; }
78+
Executable& current_executable() { return *m_running_execution_context->executable; }
79+
Executable const& current_executable() const { return *m_running_execution_context->executable; }
8080

8181
ExecutionContext& running_execution_context() { return *m_running_execution_context; }
8282

@@ -98,14 +98,7 @@ class JS_API Interpreter {
9898
[[nodiscard]] HandleExceptionResponse handle_exception(u32& program_counter, Value exception);
9999

100100
VM& m_vm;
101-
Optional<size_t> m_scheduled_jump;
102-
GC::Ptr<Executable> m_current_executable { nullptr };
103-
GC::Ptr<Realm> m_realm { nullptr };
104-
GC::Ptr<Object> m_global_object { nullptr };
105-
GC::Ptr<DeclarativeEnvironment> m_global_declarative_environment { nullptr };
106-
Span<Value> m_registers_and_constants_and_locals_arguments;
107101
ExecutionContext* m_running_execution_context { nullptr };
108-
ReadonlySpan<Utf16FlyString> m_identifier_table;
109102
};
110103

111104
JS_API extern bool g_dump_bytecode;

Libraries/LibJS/Runtime/ExecutionContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ struct JS_API ExecutionContext {
5555
GC::Ptr<Environment> variable_environment; // [[VariableEnvironment]]
5656
GC::Ptr<PrivateEnvironment> private_environment; // [[PrivateEnvironment]]
5757

58+
Optional<size_t> scheduled_jump;
59+
GC::Ptr<Object> global_object;
60+
GC::Ptr<DeclarativeEnvironment> global_declarative_environment;
61+
Span<Value> registers_and_constants_and_locals_arguments;
62+
ReadonlySpan<Utf16FlyString> identifier_table;
63+
5864
// Non-standard: This points at something that owns this ExecutionContext, in case it needs to be protected from GC.
5965
GC::Ptr<Cell> context_owner;
6066

0 commit comments

Comments
 (0)