mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-09 09:39:39 +00:00
LibJS: Merge CallFrame into ExecutionContext
Before this change both ExecutionContext and CallFrame were created before executing function/module/script with a couple exceptions: - executable created for default function argument evaluation has to run in function's execution context. - `execute_ast_node()` where executable compiled for ASTNode has to be executed in running execution context. This change moves all members previously owned by CallFrame into ExecutionContext, and makes two exceptions where an executable that does not have a corresponding execution context saves and restores registers before running. Now, all execution state lives in a single entity, which makes it a bit easier to reason about and opens opportunities for optimizations, such as moving registers and local variables into a single array.
This commit is contained in:
parent
46b8a3afb7
commit
865e651a7d
Notes:
sideshowbarker
2024-07-17 10:39:39 +09:00
Author: https://github.com/kalenikaliaksandr
Commit: 865e651a7d
Pull-request: https://github.com/SerenityOS/serenity/pull/24180
15 changed files with 121 additions and 187 deletions
|
@ -19,31 +19,6 @@ namespace JS::Bytecode {
|
|||
|
||||
class InstructionStreamIterator;
|
||||
|
||||
struct CallFrame {
|
||||
static NonnullOwnPtr<CallFrame> create(size_t register_count);
|
||||
|
||||
void operator delete(void* ptr) { free(ptr); }
|
||||
|
||||
void visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
visitor.visit(registers());
|
||||
visitor.visit(saved_lexical_environments);
|
||||
for (auto& context : unwind_contexts) {
|
||||
visitor.visit(context.lexical_environment);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<GCPtr<Environment>> saved_lexical_environments;
|
||||
Vector<UnwindInfo> unwind_contexts;
|
||||
Vector<BasicBlock const*> previously_scheduled_jumps;
|
||||
|
||||
Span<Value> registers() { return { register_values, register_count }; }
|
||||
ReadonlySpan<Value> registers() const { return { register_values, register_count }; }
|
||||
|
||||
size_t register_count { 0 };
|
||||
Value register_values[];
|
||||
};
|
||||
|
||||
class Interpreter {
|
||||
public:
|
||||
explicit Interpreter(VM&);
|
||||
|
@ -60,27 +35,30 @@ public:
|
|||
|
||||
ThrowCompletionOr<Value> run(Bytecode::Executable& executable, Bytecode::BasicBlock const* entry_point = nullptr)
|
||||
{
|
||||
auto value_and_frame = run_and_return_frame(executable, entry_point);
|
||||
return move(value_and_frame.value);
|
||||
auto result_and_return_register = run_executable(executable, entry_point);
|
||||
return move(result_and_return_register.value);
|
||||
}
|
||||
|
||||
struct ValueAndFrame {
|
||||
struct ResultAndReturnRegister {
|
||||
ThrowCompletionOr<Value> value;
|
||||
OwnPtr<CallFrame> frame;
|
||||
Value return_register_value;
|
||||
};
|
||||
ValueAndFrame run_and_return_frame(Bytecode::Executable&, Bytecode::BasicBlock const* entry_point, CallFrame* = nullptr);
|
||||
ResultAndReturnRegister run_executable(Bytecode::Executable&, Bytecode::BasicBlock const* entry_point);
|
||||
|
||||
ALWAYS_INLINE Value& accumulator() { return reg(Register::accumulator()); }
|
||||
ALWAYS_INLINE Value& saved_return_value() { return reg(Register::saved_return_value()); }
|
||||
Value& reg(Register const& r) { return registers()[r.index()]; }
|
||||
Value reg(Register const& r) const { return registers()[r.index()]; }
|
||||
Value& reg(Register const& r)
|
||||
{
|
||||
return vm().running_execution_context().registers[r.index()];
|
||||
}
|
||||
Value reg(Register const& r) const
|
||||
{
|
||||
return vm().running_execution_context().registers[r.index()];
|
||||
}
|
||||
|
||||
[[nodiscard]] Value get(Operand) const;
|
||||
void set(Operand, Value);
|
||||
|
||||
auto& saved_lexical_environment_stack() { return call_frame().saved_lexical_environments; }
|
||||
auto& unwind_contexts() { return call_frame().unwind_contexts; }
|
||||
|
||||
void do_return(Value value)
|
||||
{
|
||||
reg(Register::return_value()) = value;
|
||||
|
@ -98,30 +76,13 @@ public:
|
|||
BasicBlock const& current_block() const { return *m_current_block; }
|
||||
Optional<InstructionStreamIterator const&> instruction_stream_iterator() const { return m_pc; }
|
||||
|
||||
void visit_edges(Cell::Visitor&);
|
||||
|
||||
Span<Value> registers() { return m_current_call_frame; }
|
||||
ReadonlySpan<Value> registers() const { return m_current_call_frame; }
|
||||
Vector<Value>& registers() { return vm().running_execution_context().registers; }
|
||||
Vector<Value> const& registers() const { return vm().running_execution_context().registers; }
|
||||
|
||||
private:
|
||||
void run_bytecode();
|
||||
|
||||
CallFrame& call_frame()
|
||||
{
|
||||
return m_call_frames.last().visit([](auto& x) -> CallFrame& { return *x; });
|
||||
}
|
||||
|
||||
CallFrame const& call_frame() const
|
||||
{
|
||||
return const_cast<Interpreter*>(this)->call_frame();
|
||||
}
|
||||
|
||||
void push_call_frame(Variant<NonnullOwnPtr<CallFrame>, CallFrame*>);
|
||||
[[nodiscard]] Variant<NonnullOwnPtr<CallFrame>, CallFrame*> pop_call_frame();
|
||||
|
||||
VM& m_vm;
|
||||
Vector<Variant<NonnullOwnPtr<CallFrame>, CallFrame*>> m_call_frames;
|
||||
Span<Value> m_current_call_frame;
|
||||
BasicBlock const* m_scheduled_jump { nullptr };
|
||||
GCPtr<Executable> m_current_executable { nullptr };
|
||||
BasicBlock const* m_current_block { nullptr };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue