1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 03:18:11 +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; 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); 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(); auto block = entry_point ?: &executable.basic_blocks.first();
if (!m_manually_entered_frames.is_empty() && m_manually_entered_frames.last()) { if (in_frame)
m_register_windows.append(make<RegisterWindow>(m_register_windows.last())); m_register_windows.append(in_frame);
} else { else
m_register_windows.append(make<RegisterWindow>(MarkedVector<Value>(vm().heap()), MarkedVector<Environment*>(vm().heap()), MarkedVector<Environment*>(vm().heap()))); 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().resize(executable.number_of_registers);
registers()[Register::global_object_index] = Value(&global_object()); registers()[Register::global_object_index] = Value(&global_object());
m_manually_entered_frames.append(false);
for (;;) { for (;;) {
Bytecode::InstructionStreamIterator pc(block->instruction_stream()); Bytecode::InstructionStreamIterator pc(block->instruction_stream());
@ -147,18 +145,14 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
} }
} }
OwnPtr<RegisterWindow> frame; auto frame = m_register_windows.take_last();
if (!m_manually_entered_frames.last()) {
frame = m_register_windows.take_last();
m_manually_entered_frames.take_last();
}
auto return_value = m_return_value.value_or(js_undefined()); auto return_value = m_return_value.value_or(js_undefined());
m_return_value = {}; m_return_value = {};
// NOTE: The return value from a called function is put into $0 in the caller context. // NOTE: The return value from a called function is put into $0 in the caller context.
if (!m_register_windows.is_empty()) 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, // 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. // 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()) { if (!m_saved_exception.is_null()) {
Value thrown_value = m_saved_exception.value(); Value thrown_value = m_saved_exception.value();
m_saved_exception = {}; 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) void Interpreter::enter_unwind_context(Optional<Label> handler_target, Optional<Label> finalizer_target)

View file

@ -46,27 +46,13 @@ public:
ThrowCompletionOr<Value> value; ThrowCompletionOr<Value> value;
OwnPtr<RegisterWindow> frame; 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()); } ALWAYS_INLINE Value& accumulator() { return reg(Register::accumulator()); }
Value& reg(Register const& r) { return registers()[r.index()]; } 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_lexical_environment_stack() { return window().saved_lexical_environments; }
auto& saved_variable_environment_stack() { return m_register_windows.last().saved_variable_environments; } auto& saved_variable_environment_stack() { return window().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();
}
void jump(Label const& label) void jump(Label const& label)
{ {
@ -89,15 +75,24 @@ public:
VM::InterpreterExecutionScope ast_interpreter_scope(); VM::InterpreterExecutionScope ast_interpreter_scope();
private: 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; static AK::Array<OwnPtr<PassManager>, static_cast<UnderlyingType<Interpreter::OptimizationLevel>>(Interpreter::OptimizationLevel::__Count)> s_optimization_pipelines;
VM& m_vm; VM& m_vm;
GlobalObject& m_global_object; GlobalObject& m_global_object;
Realm& m_realm; Realm& m_realm;
NonnullOwnPtrVector<RegisterWindow> m_register_windows; Vector<Variant<NonnullOwnPtr<RegisterWindow>, RegisterWindow*>> m_register_windows;
Vector<bool> m_manually_entered_frames;
Optional<BasicBlock const*> m_pending_jump; Optional<BasicBlock const*> m_pending_jump;
Value m_return_value; Value m_return_value;
Executable const* m_current_executable { nullptr }; Executable const* m_current_executable { nullptr };

View file

@ -92,9 +92,6 @@ ThrowCompletionOr<Value> GeneratorObject::next_impl(VM& vm, GlobalObject& global
// Make sure it's an actual block // Make sure it's an actual block
VERIFY(!m_generating_function->bytecode_executable()->basic_blocks.find_if([next_block](auto& block) { return block == next_block; }).is_end()); VERIFY(!m_generating_function->bytecode_executable()->basic_blocks.find_if([next_block](auto& block) { return block == next_block; }).is_end());
// Restore the snapshot registers
bytecode_interpreter->enter_frame(*m_frame);
// Temporarily switch to the captured execution context // Temporarily switch to the captured execution context
TRY(vm.push_execution_context(m_execution_context, global_object)); TRY(vm.push_execution_context(m_execution_context, global_object));
@ -102,19 +99,22 @@ ThrowCompletionOr<Value> GeneratorObject::next_impl(VM& vm, GlobalObject& global
if (value_to_throw.has_value()) { if (value_to_throw.has_value()) {
bytecode_interpreter->accumulator() = js_undefined(); bytecode_interpreter->accumulator() = js_undefined();
return throw_completion(value_to_throw.release_value()); return throw_completion(value_to_throw.release_value());
} else {
bytecode_interpreter->accumulator() = next_argument.value_or(js_undefined());
} }
bytecode_interpreter->accumulator() = next_argument.value_or(js_undefined());
auto next_result = bytecode_interpreter->run(*m_generating_function->bytecode_executable(), next_block); Bytecode::RegisterWindow* frame = nullptr;
if (m_frame.has_value())
frame = &m_frame.value();
m_frame = move(*bytecode_interpreter->pop_frame()); auto next_result = bytecode_interpreter->run_and_return_frame(*m_generating_function->bytecode_executable(), next_block, frame);
vm.pop_execution_context(); vm.pop_execution_context();
m_done = TRY(generated_continuation(m_previous_value)) == nullptr; if (!m_frame.has_value())
m_frame = move(*next_result.frame);
m_previous_value = TRY(next_result); m_previous_value = TRY(move(next_result.value));
m_done = TRY(generated_continuation(m_previous_value)) == nullptr;
result->define_direct_property("value", TRY(generated_value(m_previous_value)), default_attributes); result->define_direct_property("value", TRY(generated_value(m_previous_value)), default_attributes);
result->define_direct_property("done", Value(m_done), default_attributes); result->define_direct_property("done", Value(m_done), default_attributes);