Skip to content

Commit

Permalink
LibJS: Ref-counted execution context
Browse files Browse the repository at this point in the history
  • Loading branch information
kalenikaliaksandr committed May 16, 2024
1 parent ed50eb0 commit e398220
Show file tree
Hide file tree
Showing 17 changed files with 46 additions and 37 deletions.
1 change: 1 addition & 0 deletions Userland/Libraries/LibJS/Bytecode/Executable.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <AK/DeprecatedFlyString.h>
#include <AK/HashMap.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/NonnullRefPtr.h>
#include <AK/OwnPtr.h>
#include <AK/WeakPtr.h>
#include <LibJS/Bytecode/IdentifierTable.h>
Expand Down
5 changes: 5 additions & 0 deletions Userland/Libraries/LibJS/Forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ class Interpreter;
class Operand;
class RegexTable;
class Register;

namespace Op {
class Call;
};

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class AsyncFunctionDriverWrapper final : public Promise {
NonnullGCPtr<Promise> m_top_level_promise;
GCPtr<Promise> m_current_promise { nullptr };
Handle<AsyncFunctionDriverWrapper> m_self_handle;
OwnPtr<ExecutionContext> m_suspended_execution_context;
RefPtr<ExecutionContext> m_suspended_execution_context;
};

}
4 changes: 2 additions & 2 deletions Userland/Libraries/LibJS/Runtime/AsyncGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace JS {

JS_DEFINE_ALLOCATOR(AsyncGenerator);

ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> AsyncGenerator::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, NonnullOwnPtr<ExecutionContext> execution_context)
ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> AsyncGenerator::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, NonnullRefPtr<ExecutionContext> execution_context)
{
auto& vm = realm.vm();
// This is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
Expand All @@ -28,7 +28,7 @@ ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> AsyncGenerator::create(Realm& re
return object;
}

AsyncGenerator::AsyncGenerator(Realm&, Object& prototype, NonnullOwnPtr<ExecutionContext> context)
AsyncGenerator::AsyncGenerator(Realm&, Object& prototype, NonnullRefPtr<ExecutionContext> context)
: Object(ConstructWithPrototypeTag::Tag, prototype)
, m_async_generator_context(move(context))
{
Expand Down
6 changes: 3 additions & 3 deletions Userland/Libraries/LibJS/Runtime/AsyncGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class AsyncGenerator final : public Object {
Completed,
};

static ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> create(Realm&, Value, ECMAScriptFunctionObject*, NonnullOwnPtr<ExecutionContext>);
static ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> create(Realm&, Value, ECMAScriptFunctionObject*, NonnullRefPtr<ExecutionContext>);

virtual ~AsyncGenerator() override = default;

Expand All @@ -44,7 +44,7 @@ class AsyncGenerator final : public Object {
Optional<String> const& generator_brand() const { return m_generator_brand; }

private:
AsyncGenerator(Realm&, Object& prototype, NonnullOwnPtr<ExecutionContext>);
AsyncGenerator(Realm&, Object& prototype, NonnullRefPtr<ExecutionContext>);

virtual void visit_edges(Cell::Visitor&) override;

Expand All @@ -54,7 +54,7 @@ class AsyncGenerator final : public Object {
// At the time of constructing an AsyncGenerator, we still need to point to an
// execution context on the stack, but later need to 'adopt' it.
State m_async_generator_state { State::SuspendedStart }; // [[AsyncGeneratorState]]
NonnullOwnPtr<ExecutionContext> m_async_generator_context; // [[AsyncGeneratorContext]]
NonnullRefPtr<ExecutionContext> m_async_generator_context; // [[AsyncGeneratorContext]]
Vector<AsyncGeneratorRequest> m_async_generator_queue; // [[AsyncGeneratorQueue]]
Optional<String> m_generator_brand; // [[GeneratorBrand]]

Expand Down
6 changes: 3 additions & 3 deletions Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

namespace JS {

NonnullOwnPtr<ExecutionContext> ExecutionContext::create(Heap& heap)
NonnullRefPtr<ExecutionContext> ExecutionContext::create(Heap& heap)
{
return adopt_own(*new ExecutionContext(heap));
return adopt_ref(*new ExecutionContext(heap));
}

ExecutionContext::ExecutionContext(Heap& heap)
Expand All @@ -27,7 +27,7 @@ ExecutionContext::~ExecutionContext()
{
}

NonnullOwnPtr<ExecutionContext> ExecutionContext::copy() const
NonnullRefPtr<ExecutionContext> ExecutionContext::copy() const
{
auto copy = create(m_heap);
copy->function = function;
Expand Down
9 changes: 6 additions & 3 deletions Userland/Libraries/LibJS/Runtime/ExecutionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ 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;
struct ExecutionContext : RefCounted<ExecutionContext> {
static NonnullRefPtr<ExecutionContext> create(Heap&);
[[nodiscard]] NonnullRefPtr<ExecutionContext> copy() const;

~ExecutionContext();

Expand Down Expand Up @@ -80,6 +80,9 @@ struct ExecutionContext {
Vector<Bytecode::UnwindInfo> unwind_contexts;
Vector<Optional<size_t>> previously_scheduled_jumps;
Vector<GCPtr<Environment>> saved_lexical_environments;

Optional<Bytecode::Operand> result_dst;
Function<ThrowCompletionOr<Value>(Value)> return_steps;
};

struct StackTraceElement {
Expand Down
4 changes: 2 additions & 2 deletions Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, NonnullRefPtr<ExecutionContext> execution_context)
{
auto& vm = realm.vm();
// This is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
Expand All @@ -36,7 +36,7 @@ ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm&
return object;
}

GeneratorObject::GeneratorObject(Realm&, Object& prototype, NonnullOwnPtr<ExecutionContext> context, Optional<StringView> generator_brand)
GeneratorObject::GeneratorObject(Realm&, Object& prototype, NonnullRefPtr<ExecutionContext> context, Optional<StringView> generator_brand)
: Object(ConstructWithPrototypeTag::Tag, prototype)
, m_execution_context(move(context))
, m_generator_brand(move(generator_brand))
Expand Down
6 changes: 3 additions & 3 deletions Userland/Libraries/LibJS/Runtime/GeneratorObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class GeneratorObject : public Object {
JS_DECLARE_ALLOCATOR(GeneratorObject);

public:
static ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> create(Realm&, Value, ECMAScriptFunctionObject*, NonnullOwnPtr<ExecutionContext>);
static ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> create(Realm&, Value, ECMAScriptFunctionObject*, NonnullRefPtr<ExecutionContext>);
virtual ~GeneratorObject() override = default;
void visit_edges(Cell::Visitor&) override;

Expand All @@ -34,13 +34,13 @@ class GeneratorObject : public Object {
void set_generator_state(GeneratorState generator_state) { m_generator_state = generator_state; }

protected:
GeneratorObject(Realm&, Object& prototype, NonnullOwnPtr<ExecutionContext>, Optional<StringView> generator_brand = {});
GeneratorObject(Realm&, Object& prototype, NonnullRefPtr<ExecutionContext>, Optional<StringView> generator_brand = {});

ThrowCompletionOr<GeneratorState> validate(VM&, Optional<StringView> const& generator_brand);
virtual ThrowCompletionOr<Value> execute(VM&, JS::Completion const& completion);

private:
NonnullOwnPtr<ExecutionContext> m_execution_context;
NonnullRefPtr<ExecutionContext> m_execution_context;
GCPtr<ECMAScriptFunctionObject> m_generating_function;
Value m_previous_value;
GeneratorState m_generator_state { GeneratorState::SuspendedStart };
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibJS/Runtime/Realm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ ThrowCompletionOr<NonnullGCPtr<Realm>> Realm::create(VM& vm)
}

// 9.6 InitializeHostDefinedRealm ( ), https://tc39.es/ecma262/#sec-initializehostdefinedrealm
ThrowCompletionOr<NonnullOwnPtr<ExecutionContext>> Realm::initialize_host_defined_realm(VM& vm, Function<Object*(Realm&)> create_global_object, Function<Object*(Realm&)> create_global_this_value)
ThrowCompletionOr<NonnullRefPtr<ExecutionContext>> Realm::initialize_host_defined_realm(VM& vm, Function<Object*(Realm&)> create_global_object, Function<Object*(Realm&)> create_global_this_value)
{
DeferGC defer_gc(vm.heap());

Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibJS/Runtime/Realm.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Realm final : public Cell {
};

static ThrowCompletionOr<NonnullGCPtr<Realm>> create(VM&);
static ThrowCompletionOr<NonnullOwnPtr<ExecutionContext>> initialize_host_defined_realm(VM&, NOESCAPE Function<Object*(Realm&)> create_global_object, NOESCAPE Function<Object*(Realm&)> create_global_this_value);
static ThrowCompletionOr<NonnullRefPtr<ExecutionContext>> initialize_host_defined_realm(VM&, NOESCAPE Function<Object*(Realm&)> create_global_object, NOESCAPE Function<Object*(Realm&)> create_global_this_value);

void set_global_object(Object* global_object, Object* this_value);

Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace JS {

JS_DEFINE_ALLOCATOR(ShadowRealm);

ShadowRealm::ShadowRealm(Realm& shadow_realm, NonnullOwnPtr<ExecutionContext> execution_context, Object& prototype)
ShadowRealm::ShadowRealm(Realm& shadow_realm, NonnullRefPtr<ExecutionContext> execution_context, Object& prototype)
: Object(ConstructWithPrototypeTag::Tag, prototype)
, m_shadow_realm(shadow_realm)
, m_execution_context(move(execution_context))
Expand Down
4 changes: 2 additions & 2 deletions Userland/Libraries/LibJS/Runtime/ShadowRealm.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ class ShadowRealm final : public Object {
[[nodiscard]] ExecutionContext& execution_context() { return *m_execution_context; }

private:
ShadowRealm(Realm&, NonnullOwnPtr<ExecutionContext>, Object& prototype);
ShadowRealm(Realm&, NonnullRefPtr<ExecutionContext>, Object& prototype);

virtual void visit_edges(Visitor&) override;

// 3.5 Properties of ShadowRealm Instances, https://tc39.es/proposal-shadowrealm/#sec-properties-of-shadowrealm-instances
NonnullGCPtr<Realm> m_shadow_realm; // [[ShadowRealm]]
NonnullOwnPtr<ExecutionContext> m_execution_context; // [[ExecutionContext]]
NonnullRefPtr<ExecutionContext> m_execution_context; // [[ExecutionContext]]
};

ThrowCompletionOr<void> copy_name_and_length(VM&, FunctionObject& function, FunctionObject& target, Optional<StringView> prefix = {}, Optional<unsigned> arg_count = {});
Expand Down
10 changes: 5 additions & 5 deletions Userland/Libraries/LibJS/Runtime/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ void VM::gather_roots(HashMap<Cell*, HeapRoot>& roots)
for (auto finalization_registry : m_finalization_registry_cleanup_jobs)
roots.set(finalization_registry, HeapRoot { .type = HeapRoot::Type::VM });

auto gather_roots_from_execution_context_stack = [&roots](Vector<ExecutionContext*> const& stack) {
auto gather_roots_from_execution_context_stack = [&roots](Vector<NonnullRefPtr<ExecutionContext>> const& stack) {
for (auto const& execution_context : stack) {
ExecutionContextRootsCollector visitor;
execution_context->visit_edges(visitor);
Expand Down Expand Up @@ -686,16 +686,16 @@ void VM::load_imported_module(ImportedModuleReferrer referrer, ModuleRequest con
finish_loading_imported_module(referrer, module_request, payload, module);
}

void VM::push_execution_context(ExecutionContext& context)
void VM::push_execution_context(NonnullRefPtr<ExecutionContext> context)
{
if (!m_execution_context_stack.is_empty())
m_execution_context_stack.last()->program_counter = bytecode_interpreter().program_counter();
m_execution_context_stack.append(&context);
m_execution_context_stack.append(move(context));
}

void VM::pop_execution_context()
{
m_execution_context_stack.take_last();
(void)m_execution_context_stack.take_last();
if (m_execution_context_stack.is_empty() && on_call_stack_emptied)
on_call_stack_emptied();
}
Expand Down Expand Up @@ -723,7 +723,7 @@ Vector<StackTraceElement> VM::stack_trace() const
{
Vector<StackTraceElement> stack_trace;
for (ssize_t i = m_execution_context_stack.size() - 1; i >= 0; i--) {
auto* context = m_execution_context_stack[i];
auto context = m_execution_context_stack[i];
stack_trace.append({
.execution_context = context,
.source_range = get_source_range(context).value_or({}),
Expand Down
16 changes: 8 additions & 8 deletions Userland/Libraries/LibJS/Runtime/VM.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,16 @@ class VM : public RefCounted<VM> {
// TODO: Rename this function instead of providing a second argument, now that the global object is no longer passed in.
struct CheckStackSpaceLimitTag { };

ThrowCompletionOr<void> push_execution_context(ExecutionContext& context, CheckStackSpaceLimitTag)
ThrowCompletionOr<void> push_execution_context(NonnullRefPtr<ExecutionContext> context, CheckStackSpaceLimitTag)
{
// Ensure we got some stack space left, so the next function call doesn't kill us.
if (did_reach_stack_space_limit())
return throw_completion<InternalError>(ErrorType::CallStackSizeExceeded);
push_execution_context(context);
push_execution_context(move(context));
return {};
}

void push_execution_context(ExecutionContext&);
void push_execution_context(NonnullRefPtr<ExecutionContext>);
void pop_execution_context();

// https://tc39.es/ecma262/#running-execution-context
Expand All @@ -135,8 +135,8 @@ class VM : public RefCounted<VM> {

// https://tc39.es/ecma262/#execution-context-stack
// The execution context stack is used to track execution contexts.
Vector<ExecutionContext*> const& execution_context_stack() const { return m_execution_context_stack; }
Vector<ExecutionContext*>& execution_context_stack() { return m_execution_context_stack; }
Vector<NonnullRefPtr<ExecutionContext>> const& execution_context_stack() const { return m_execution_context_stack; }
Vector<NonnullRefPtr<ExecutionContext>>& execution_context_stack() { return m_execution_context_stack; }

Environment const* lexical_environment() const { return running_execution_context().lexical_environment; }
Environment* lexical_environment() { return running_execution_context().lexical_environment; }
Expand Down Expand Up @@ -282,9 +282,9 @@ class VM : public RefCounted<VM> {

Heap m_heap;

Vector<ExecutionContext*> m_execution_context_stack;
Vector<NonnullRefPtr<ExecutionContext>> m_execution_context_stack;

Vector<Vector<ExecutionContext*>> m_saved_execution_context_stacks;
Vector<Vector<NonnullRefPtr<ExecutionContext>>> m_saved_execution_context_stacks;

StackInfo m_stack_info;

Expand Down Expand Up @@ -323,7 +323,7 @@ class VM : public RefCounted<VM> {
};

template<typename GlobalObjectType, typename... Args>
[[nodiscard]] static NonnullOwnPtr<ExecutionContext> create_simple_execution_context(VM& vm, Args&&... args)
[[nodiscard]] static NonnullRefPtr<ExecutionContext> create_simple_execution_context(VM& vm, Args&&... args)
{
auto root_execution_context = MUST(Realm::initialize_host_defined_realm(
vm,
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibJS/SourceTextModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class SourceTextModule final : public CyclicModule {
virtual void visit_edges(Cell::Visitor&) override;

NonnullRefPtr<Program> m_ecmascript_code; // [[ECMAScriptCode]]
NonnullOwnPtr<ExecutionContext> m_execution_context; // [[Context]]
NonnullRefPtr<ExecutionContext> m_execution_context; // [[Context]]
GCPtr<Object> m_import_meta; // [[ImportMeta]]
Vector<ImportEntry> m_import_entries; // [[ImportEntries]]
Vector<ExportEntry> m_local_export_entries; // [[LocalExportEntries]]
Expand Down
2 changes: 1 addition & 1 deletion Userland/Utilities/js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
TRY(repl(realm));
s_editor->save_history(s_history_path.to_byte_string());
} else {
OwnPtr<JS::ExecutionContext> root_execution_context;
RefPtr<JS::ExecutionContext> root_execution_context;
if (use_test262_global)
root_execution_context = JS::create_simple_execution_context<JS::Test262::GlobalObject>(*g_vm);
else
Expand Down

0 comments on commit e398220

Please sign in to comment.