diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h index c847713e996..432e2372113 100644 --- a/Userland/Libraries/LibJS/Forward.h +++ b/Userland/Libraries/LibJS/Forward.h @@ -156,6 +156,7 @@ class Accessor; struct AsyncGeneratorRequest; class BigInt; class BoundFunction; +struct CachedSourceRange; class Cell; class CellAllocator; class ClassExpression; diff --git a/Userland/Libraries/LibJS/Runtime/Error.cpp b/Userland/Libraries/LibJS/Runtime/Error.cpp index 33d7aff7dfb..eee4d9c55d5 100644 --- a/Userland/Libraries/LibJS/Runtime/Error.cpp +++ b/Userland/Libraries/LibJS/Runtime/Error.cpp @@ -17,19 +17,21 @@ namespace JS { JS_DEFINE_ALLOCATOR(Error); +static SourceRange dummy_source_range { SourceCode::create(String {}, String {}), {}, {} }; + SourceRange const& TracebackFrame::source_range() const { - if (auto* unrealized = source_range_storage.get_pointer()) { + if (!cached_source_range) + return dummy_source_range; + if (auto* unrealized = cached_source_range->source_range.get_pointer()) { auto source_range = [&] { - if (!unrealized->source_code) { - static auto dummy_source_code = SourceCode::create(String {}, String {}); - return SourceRange { dummy_source_code, {}, {} }; - } + if (!unrealized->source_code) + return dummy_source_range; return unrealized->realize(); }(); - source_range_storage = move(source_range); + cached_source_range->source_range = move(source_range); } - return source_range_storage.get(); + return cached_source_range->source_range.get(); } NonnullGCPtr Error::create(Realm& realm) @@ -81,12 +83,9 @@ void Error::populate_stack() m_traceback.ensure_capacity(stack_trace.size()); for (auto& element : stack_trace) { auto* context = element.execution_context; - UnrealizedSourceRange range = {}; - if (element.source_range.has_value()) - range = element.source_range.value(); TracebackFrame frame { .function_name = context->function_name ? context->function_name->byte_string() : "", - .source_range_storage = range, + .cached_source_range = element.source_range, }; m_traceback.append(move(frame)); diff --git a/Userland/Libraries/LibJS/Runtime/Error.h b/Userland/Libraries/LibJS/Runtime/Error.h index 01bc5d8fbad..df847706a49 100644 --- a/Userland/Libraries/LibJS/Runtime/Error.h +++ b/Userland/Libraries/LibJS/Runtime/Error.h @@ -19,7 +19,7 @@ struct TracebackFrame { DeprecatedFlyString function_name; [[nodiscard]] SourceRange const& source_range() const; - mutable Variant source_range_storage; + RefPtr cached_source_range; }; enum CompactTraceback { diff --git a/Userland/Libraries/LibJS/Runtime/ExecutionContext.h b/Userland/Libraries/LibJS/Runtime/ExecutionContext.h index d2d884d391d..83dc66e03fa 100644 --- a/Userland/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Userland/Libraries/LibJS/Runtime/ExecutionContext.h @@ -21,6 +21,16 @@ namespace JS { using ScriptOrModule = Variant, NonnullGCPtr>; +struct CachedSourceRange : public RefCounted { + CachedSourceRange(size_t program_counter, Variant source_range) + : program_counter(program_counter) + , source_range(move(source_range)) + { + } + size_t program_counter { 0 }; + Variant source_range; +}; + // 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts struct ExecutionContext { static NonnullOwnPtr create(); @@ -49,6 +59,9 @@ public: GCPtr context_owner; Optional program_counter; + + mutable RefPtr cached_source_range; + GCPtr function_name; Value this_value; @@ -82,7 +95,7 @@ public: struct StackTraceElement { ExecutionContext* execution_context; - Optional source_range; + RefPtr source_range; }; } diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index 524d30afbc1..d32a197ac79 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -731,7 +731,7 @@ struct [[gnu::packed]] NativeStackFrame { }; #endif -static Optional get_source_range(ExecutionContext const* context) +static RefPtr get_source_range(ExecutionContext const* context) { // native function if (!context->executable) @@ -740,7 +740,14 @@ static Optional get_source_range(ExecutionContext const* if (!context->program_counter.has_value()) return {}; - return context->executable->source_range_at(context->program_counter.value()); + if (!context->cached_source_range + || context->cached_source_range->program_counter != context->program_counter.value()) { + auto unrealized_source_range = context->executable->source_range_at(context->program_counter.value()); + context->cached_source_range = adopt_ref(*new CachedSourceRange( + context->program_counter.value(), + move(unrealized_source_range))); + } + return context->cached_source_range; } Vector VM::stack_trace() const @@ -750,7 +757,7 @@ Vector VM::stack_trace() const auto* context = m_execution_context_stack[i]; stack_trace.append({ .execution_context = context, - .source_range = get_source_range(context).value_or({}), + .source_range = get_source_range(context), }); }