mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-04 09:22:53 +00:00
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.
90 lines
2.8 KiB
C++
90 lines
2.8 KiB
C++
/*
|
|
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
|
|
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
|
|
* Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/DeprecatedFlyString.h>
|
|
#include <AK/WeakPtr.h>
|
|
#include <LibJS/Bytecode/BasicBlock.h>
|
|
#include <LibJS/Bytecode/Instruction.h>
|
|
#include <LibJS/Forward.h>
|
|
#include <LibJS/Module.h>
|
|
#include <LibJS/Runtime/PrivateEnvironment.h>
|
|
#include <LibJS/Runtime/Value.h>
|
|
#include <LibJS/SourceRange.h>
|
|
|
|
namespace JS {
|
|
|
|
using ScriptOrModule = Variant<Empty, NonnullGCPtr<Script>, NonnullGCPtr<Module>>;
|
|
|
|
// 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts
|
|
struct ExecutionContext {
|
|
static NonnullOwnPtr<ExecutionContext> create(Heap&);
|
|
[[nodiscard]] NonnullOwnPtr<ExecutionContext> copy() const;
|
|
|
|
~ExecutionContext();
|
|
|
|
void visit_edges(Cell::Visitor&);
|
|
|
|
private:
|
|
ExecutionContext(Heap&);
|
|
|
|
IntrusiveListNode<ExecutionContext> m_list_node;
|
|
|
|
public:
|
|
Heap& m_heap;
|
|
|
|
using List = IntrusiveList<&ExecutionContext::m_list_node>;
|
|
|
|
GCPtr<FunctionObject> function; // [[Function]]
|
|
GCPtr<Realm> realm; // [[Realm]]
|
|
ScriptOrModule script_or_module; // [[ScriptOrModule]]
|
|
GCPtr<Environment> lexical_environment; // [[LexicalEnvironment]]
|
|
GCPtr<Environment> variable_environment; // [[VariableEnvironment]]
|
|
GCPtr<PrivateEnvironment> private_environment; // [[PrivateEnvironment]]
|
|
|
|
// Non-standard: This points at something that owns this ExecutionContext, in case it needs to be protected from GC.
|
|
GCPtr<Cell> context_owner;
|
|
|
|
Optional<Bytecode::InstructionStreamIterator> instruction_stream_iterator;
|
|
GCPtr<PrimitiveString> function_name;
|
|
Value this_value;
|
|
bool is_strict_mode { false };
|
|
|
|
GCPtr<Bytecode::Executable> executable;
|
|
|
|
// https://html.spec.whatwg.org/multipage/webappapis.html#skip-when-determining-incumbent-counter
|
|
// FIXME: Move this out of LibJS (e.g. by using the CustomData concept), as it's used exclusively by LibWeb.
|
|
size_t skip_when_determining_incumbent_counter { 0 };
|
|
|
|
Value argument(size_t index) const
|
|
{
|
|
if (index >= arguments.size()) [[unlikely]]
|
|
return js_undefined();
|
|
return arguments[index];
|
|
}
|
|
|
|
Value& local(size_t index)
|
|
{
|
|
return locals[index];
|
|
}
|
|
|
|
Vector<Value> arguments;
|
|
Vector<Value> locals;
|
|
Vector<Value> registers;
|
|
Vector<Bytecode::UnwindInfo> unwind_contexts;
|
|
Vector<Bytecode::BasicBlock const*> previously_scheduled_jumps;
|
|
Vector<GCPtr<Environment>> saved_lexical_environments;
|
|
};
|
|
|
|
struct StackTraceElement {
|
|
ExecutionContext* execution_context;
|
|
Optional<UnrealizedSourceRange> source_range;
|
|
};
|
|
|
|
}
|