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:
Aliaksandr Kalenik 2024-05-01 19:33:49 +02:00 committed by Andreas Kling
commit 865e651a7d
Notes: sideshowbarker 2024-07-17 10:39:39 +09:00
15 changed files with 121 additions and 187 deletions

View file

@ -16,7 +16,7 @@ namespace JS {
JS_DEFINE_ALLOCATOR(GeneratorObject);
ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, NonnullOwnPtr<ExecutionContext> execution_context, NonnullOwnPtr<Bytecode::CallFrame> frame)
ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, NonnullOwnPtr<ExecutionContext> execution_context)
{
auto& vm = realm.vm();
// This is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
@ -32,7 +32,6 @@ ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm&
auto generating_function_prototype_object = TRY(generating_function_prototype.to_object(vm));
auto object = realm.heap().allocate<GeneratorObject>(realm, realm, generating_function_prototype_object, move(execution_context));
object->m_generating_function = generating_function;
object->m_frame = move(frame);
object->m_previous_value = initial_value;
return object;
}
@ -49,8 +48,6 @@ void GeneratorObject::visit_edges(Cell::Visitor& visitor)
Base::visit_edges(visitor);
visitor.visit(m_generating_function);
visitor.visit(m_previous_value);
if (m_frame)
m_frame->visit_edges(visitor);
m_execution_context->visit_edges(visitor);
}
@ -113,22 +110,12 @@ ThrowCompletionOr<Value> GeneratorObject::execute(VM& vm, Completion const& comp
VERIFY(!m_generating_function->bytecode_executable()->basic_blocks.find_if([next_block](auto& block) { return block == next_block; }).is_end());
Bytecode::CallFrame* frame = nullptr;
if (m_frame)
frame = m_frame;
bytecode_interpreter.registers()[0] = completion_object;
if (frame)
frame->registers()[0] = completion_object;
else
bytecode_interpreter.accumulator() = completion_object;
auto next_result = bytecode_interpreter.run_and_return_frame(*m_generating_function->bytecode_executable(), next_block, frame);
auto next_result = bytecode_interpreter.run_executable(*m_generating_function->bytecode_executable(), next_block);
vm.pop_execution_context();
if (!m_frame)
m_frame = move(next_result.frame);
auto result_value = move(next_result.value);
if (result_value.is_throw_completion()) {
// Uncaught exceptions disable the generator.