1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 14:47:44 +00:00

LibJS: Avoid copying the frame into the interpreter in BC generators

This commit is contained in:
Ali Mohammad Pur 2022-04-15 20:20:51 +04:30 committed by Ali Mohammad Pur
parent 063ea0088e
commit d5791c85b4
3 changed files with 36 additions and 43 deletions

View file

@ -40,7 +40,7 @@ Interpreter::~Interpreter()
s_current = nullptr;
}
Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& executable, BasicBlock const* entry_point)
Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& executable, BasicBlock const* entry_point, RegisterWindow* in_frame)
{
dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter will run unit {:p}", &executable);
@ -64,15 +64,13 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
}
auto block = entry_point ?: &executable.basic_blocks.first();
if (!m_manually_entered_frames.is_empty() && m_manually_entered_frames.last()) {
m_register_windows.append(make<RegisterWindow>(m_register_windows.last()));
} else {
if (in_frame)
m_register_windows.append(in_frame);
else
m_register_windows.append(make<RegisterWindow>(MarkedVector<Value>(vm().heap()), MarkedVector<Environment*>(vm().heap()), MarkedVector<Environment*>(vm().heap())));
}
registers().resize(executable.number_of_registers);
registers()[Register::global_object_index] = Value(&global_object());
m_manually_entered_frames.append(false);
for (;;) {
Bytecode::InstructionStreamIterator pc(block->instruction_stream());
@ -147,18 +145,14 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
}
}
OwnPtr<RegisterWindow> frame;
if (!m_manually_entered_frames.last()) {
frame = m_register_windows.take_last();
m_manually_entered_frames.take_last();
}
auto frame = m_register_windows.take_last();
auto return_value = m_return_value.value_or(js_undefined());
m_return_value = {};
// NOTE: The return value from a called function is put into $0 in the caller context.
if (!m_register_windows.is_empty())
m_register_windows.last().registers[0] = return_value;
window().registers[0] = return_value;
// At this point we may have already run any queued promise jobs via on_call_stack_emptied,
// in which case this is a no-op.
@ -174,10 +168,14 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
if (!m_saved_exception.is_null()) {
Value thrown_value = m_saved_exception.value();
m_saved_exception = {};
return { throw_completion(thrown_value), move(frame) };
if (auto* register_window = frame.get_pointer<NonnullOwnPtr<RegisterWindow>>())
return { throw_completion(thrown_value), move(*register_window) };
return { throw_completion(thrown_value), nullptr };
}
return { return_value, move(frame) };
if (auto register_window = frame.get_pointer<NonnullOwnPtr<RegisterWindow>>())
return { return_value, move(*register_window) };
return { return_value, nullptr };
}
void Interpreter::enter_unwind_context(Optional<Label> handler_target, Optional<Label> finalizer_target)

View file

@ -46,27 +46,13 @@ public:
ThrowCompletionOr<Value> value;
OwnPtr<RegisterWindow> frame;
};
ValueAndFrame run_and_return_frame(Bytecode::Executable const&, Bytecode::BasicBlock const* entry_point);
ValueAndFrame run_and_return_frame(Bytecode::Executable const&, Bytecode::BasicBlock const* entry_point, RegisterWindow* = nullptr);
ALWAYS_INLINE Value& accumulator() { return reg(Register::accumulator()); }
Value& reg(Register const& r) { return registers()[r.index()]; }
[[nodiscard]] RegisterWindow snapshot_frame() const { return m_register_windows.last(); }
auto& saved_lexical_environment_stack() { return m_register_windows.last().saved_lexical_environments; }
auto& saved_variable_environment_stack() { return m_register_windows.last().saved_variable_environments; }
void enter_frame(RegisterWindow const& frame)
{
m_manually_entered_frames.append(true);
m_register_windows.append(make<RegisterWindow>(frame));
}
NonnullOwnPtr<RegisterWindow> pop_frame()
{
VERIFY(!m_manually_entered_frames.is_empty());
VERIFY(m_manually_entered_frames.last());
m_manually_entered_frames.take_last();
return m_register_windows.take_last();
}
auto& saved_lexical_environment_stack() { return window().saved_lexical_environments; }
auto& saved_variable_environment_stack() { return window().saved_variable_environments; }
void jump(Label const& label)
{
@ -89,15 +75,24 @@ public:
VM::InterpreterExecutionScope ast_interpreter_scope();
private:
MarkedVector<Value>& registers() { return m_register_windows.last().registers; }
RegisterWindow& window()
{
return m_register_windows.last().visit([](auto& x) -> RegisterWindow& { return *x; });
}
RegisterWindow const& window() const
{
return const_cast<Interpreter*>(this)->window();
}
MarkedVector<Value>& registers() { return window().registers; }
static AK::Array<OwnPtr<PassManager>, static_cast<UnderlyingType<Interpreter::OptimizationLevel>>(Interpreter::OptimizationLevel::__Count)> s_optimization_pipelines;
VM& m_vm;
GlobalObject& m_global_object;
Realm& m_realm;
NonnullOwnPtrVector<RegisterWindow> m_register_windows;
Vector<bool> m_manually_entered_frames;
Vector<Variant<NonnullOwnPtr<RegisterWindow>, RegisterWindow*>> m_register_windows;
Optional<BasicBlock const*> m_pending_jump;
Value m_return_value;
Executable const* m_current_executable { nullptr };