LibJS: Inline ExecutionContextRareData fields into ExecutionContext
After removing the unwind context stack, ExecutionContextRareData only held two GC::Ptr fields — both trivially destructible. The indirection cost more than it saved: a GC cell allocation per EC, an extra pointer chase on every source range lookup, and unnecessary complexity. Replace the rare data cell with two inline fields on ExecutionContext: cached_source_range and context_owner.
This commit is contained in:
parent
4e1d6faf0e
commit
4fa4ecf31b
4 changed files with 13 additions and 45 deletions
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2020-2026, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
|
||||
* Copyright (c) 2024-2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
namespace JS {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(CachedSourceRange);
|
||||
GC_DEFINE_ALLOCATOR(ExecutionContextRareData);
|
||||
|
||||
class ExecutionContextAllocator {
|
||||
public:
|
||||
|
|
@ -132,7 +131,8 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(variable_environment);
|
||||
visitor.visit(lexical_environment);
|
||||
visitor.visit(private_environment);
|
||||
visitor.visit(m_rare_data);
|
||||
visitor.visit(cached_source_range);
|
||||
visitor.visit(context_owner);
|
||||
visitor.visit(this_value);
|
||||
visitor.visit(executable);
|
||||
visitor.visit(registers_and_constants_and_locals_and_arguments_span());
|
||||
|
|
@ -146,19 +146,4 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor)
|
|||
});
|
||||
}
|
||||
|
||||
void ExecutionContextRareData::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(context_owner);
|
||||
visitor.visit(cached_source_range);
|
||||
}
|
||||
|
||||
GC::Ref<ExecutionContextRareData> ExecutionContext::ensure_rare_data()
|
||||
{
|
||||
if (!m_rare_data) {
|
||||
m_rare_data = GC::Heap::the().allocate<ExecutionContextRareData>();
|
||||
}
|
||||
return *m_rare_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2020-2026, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
|
||||
* Copyright (c) 2024-2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
|
|
@ -51,20 +51,6 @@ public:
|
|||
Variant<UnrealizedSourceRange, SourceRange> source_range;
|
||||
};
|
||||
|
||||
class JS_API ExecutionContextRareData final : public GC::Cell {
|
||||
GC_CELL(ExecutionContextRareData, GC::Cell);
|
||||
GC_DECLARE_ALLOCATOR(ExecutionContextRareData);
|
||||
|
||||
public:
|
||||
mutable GC::Ptr<CachedSourceRange> cached_source_range;
|
||||
|
||||
// Non-standard: This points at something that owns this ExecutionContext, in case it needs to be protected from GC.
|
||||
GC::Ptr<Cell> context_owner;
|
||||
|
||||
private:
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
};
|
||||
|
||||
// 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts
|
||||
struct JS_API ExecutionContext {
|
||||
static NonnullOwnPtr<ExecutionContext> create(u32 registers_and_locals_count, u32 constants_count, u32 arguments_count);
|
||||
|
|
@ -91,9 +77,6 @@ public:
|
|||
arguments = { values + registers_and_locals_and_constants_count, arguments_count };
|
||||
}
|
||||
|
||||
GC::Ptr<ExecutionContextRareData> rare_data() const { return m_rare_data; }
|
||||
GC::Ref<ExecutionContextRareData> ensure_rare_data();
|
||||
|
||||
void operator delete(void* ptr);
|
||||
|
||||
GC::Ptr<FunctionObject> function; // [[Function]]
|
||||
|
|
@ -137,9 +120,10 @@ public:
|
|||
|
||||
Span<Value> arguments;
|
||||
|
||||
// NOTE: Rarely used data members go here to keep the size of ExecutionContext down,
|
||||
// and to avoid needing an ExecutionContext destructor in the common case.
|
||||
GC::Ptr<ExecutionContextRareData> m_rare_data;
|
||||
mutable GC::Ptr<CachedSourceRange> cached_source_range;
|
||||
|
||||
// Non-standard: This points at something that owns this ExecutionContext, in case it needs to be protected from GC.
|
||||
GC::Ptr<GC::Cell> context_owner;
|
||||
|
||||
u32 passed_argument_count { 0 };
|
||||
|
||||
|
|
|
|||
|
|
@ -799,15 +799,14 @@ static GC::Ptr<CachedSourceRange> get_source_range(ExecutionContext* context)
|
|||
if (!context->executable)
|
||||
return {};
|
||||
|
||||
if (!context->rare_data()
|
||||
|| !context->rare_data()->cached_source_range
|
||||
|| context->rare_data()->cached_source_range->program_counter != context->program_counter) {
|
||||
if (!context->cached_source_range
|
||||
|| context->cached_source_range->program_counter != context->program_counter) {
|
||||
auto unrealized_source_range = context->executable->source_range_at(context->program_counter);
|
||||
context->ensure_rare_data()->cached_source_range = context->executable->heap().allocate<CachedSourceRange>(
|
||||
context->cached_source_range = context->executable->heap().allocate<CachedSourceRange>(
|
||||
context->program_counter,
|
||||
move(unrealized_source_range));
|
||||
}
|
||||
return context->rare_data()->cached_source_range;
|
||||
return context->cached_source_range;
|
||||
}
|
||||
|
||||
GC::ConservativeVector<StackTraceElement> VM::stack_trace() const
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ void Environment::visit_edges(Cell::Visitor& visitor)
|
|||
EnvironmentSettingsObject::EnvironmentSettingsObject(NonnullOwnPtr<JS::ExecutionContext> realm_execution_context)
|
||||
: m_realm_execution_context(move(realm_execution_context))
|
||||
{
|
||||
m_realm_execution_context->ensure_rare_data()->context_owner = this;
|
||||
m_realm_execution_context->context_owner = this;
|
||||
|
||||
// Register with the responsible event loop so we can perform step 4 of "perform a microtask checkpoint".
|
||||
responsible_event_loop().register_environment_settings_object({}, *this);
|
||||
|
|
|
|||
Loading…
Reference in a new issue