diff --git a/Libraries/LibJS/Bytecode/Executable.cpp b/Libraries/LibJS/Bytecode/Executable.cpp index a6eb14ae153..16be8f4dc72 100644 --- a/Libraries/LibJS/Bytecode/Executable.cpp +++ b/Libraries/LibJS/Bytecode/Executable.cpp @@ -246,6 +246,17 @@ UnrealizedSourceRange Executable::source_range_at(size_t offset) const }; } +SourceRange const& Executable::get_source_range(u32 program_counter) +{ + return m_source_range_cache.ensure(program_counter, [&] { + auto unrealized = source_range_at(program_counter); + if (unrealized.source_code) + return unrealized.realize(); + static SourceRange dummy { SourceCode::create({}, {}), {}, {} }; + return dummy; + }); +} + Operand Executable::original_operand_from_raw(u32 raw) const { // NB: Layout is [registers | locals | constants | arguments] diff --git a/Libraries/LibJS/Bytecode/Executable.h b/Libraries/LibJS/Bytecode/Executable.h index 1b3ba68948b..6254016a732 100644 --- a/Libraries/LibJS/Bytecode/Executable.h +++ b/Libraries/LibJS/Bytecode/Executable.h @@ -183,6 +183,8 @@ public: [[nodiscard]] UnrealizedSourceRange source_range_at(size_t offset) const; + [[nodiscard]] SourceRange const& get_source_range(u32 program_counter); + void fixup_cache_pointers(); void dump() const; @@ -194,6 +196,8 @@ public: private: virtual void visit_edges(Visitor&) override; + + HashMap m_source_range_cache; }; } diff --git a/Libraries/LibJS/Console.cpp b/Libraries/LibJS/Console.cpp index f556eec610e..6d33cb29c21 100644 --- a/Libraries/LibJS/Console.cpp +++ b/Libraries/LibJS/Console.cpp @@ -358,8 +358,8 @@ ThrowCompletionOr Console::trace() auto function_name = (context && context->function) ? context->function->name_for_call_stack() : ""_utf16; frame.function_name = function_name.is_empty() ? ""_string : function_name.to_utf8(); - if (element.source_range) { - auto const& source_range = element.source_range->realize_source_range(); + if (element.source_range.has_value()) { + auto const& source_range = *element.source_range; if (!source_range.filename().is_empty()) { frame.source_file = MUST(String::from_byte_string(source_range.filename())); frame.line = source_range.start.line; diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index c84ee67d21b..a8d32b7b567 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -170,7 +170,6 @@ struct AsyncGeneratorRequest; class BigInt; class BoundFunction; class BuiltinIterator; -class CachedSourceRange; class Cell; class ClassExpression; struct ClassFieldDefinition; diff --git a/Libraries/LibJS/Runtime/Error.cpp b/Libraries/LibJS/Runtime/Error.cpp index 459e9faaf2a..31cbd1c527d 100644 --- a/Libraries/LibJS/Runtime/Error.cpp +++ b/Libraries/LibJS/Runtime/Error.cpp @@ -21,9 +21,9 @@ static SourceRange dummy_source_range { SourceCode::create({}, {}), {}, {} }; SourceRange const& TracebackFrame::source_range() const { - if (!cached_source_range) + if (!cached_source_range.has_value()) return dummy_source_range; - return cached_source_range->realize_source_range(); + return *cached_source_range; } GC::Ref Error::create(Realm& realm) @@ -53,8 +53,6 @@ void Error::visit_edges(Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_cached_string); - for (auto& frame : m_traceback) - visitor.visit(frame.cached_source_range); } // 20.5.8.1 InstallErrorCause ( O, options ), https://tc39.es/ecma262/#sec-installerrorcause @@ -89,12 +87,10 @@ void Error::populate_stack() m_traceback.ensure_capacity(stack_trace.size()); for (auto& element : stack_trace) { auto* context = element.execution_context; - TracebackFrame frame { + m_traceback.append({ .function_name = context->function ? context->function->name_for_call_stack() : ""_utf16, - .cached_source_range = element.source_range, - }; - - m_traceback.append(move(frame)); + .cached_source_range = move(element.source_range), + }); } } diff --git a/Libraries/LibJS/Runtime/Error.h b/Libraries/LibJS/Runtime/Error.h index e072e699adb..19f7d5ed797 100644 --- a/Libraries/LibJS/Runtime/Error.h +++ b/Libraries/LibJS/Runtime/Error.h @@ -21,7 +21,7 @@ struct JS_API TracebackFrame { Utf16String function_name; [[nodiscard]] SourceRange const& source_range() const; - GC::Ptr cached_source_range; + Optional cached_source_range; }; enum CompactTraceback { diff --git a/Libraries/LibJS/Runtime/ExecutionContext.cpp b/Libraries/LibJS/Runtime/ExecutionContext.cpp index b7d069236be..099640f656e 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.cpp +++ b/Libraries/LibJS/Runtime/ExecutionContext.cpp @@ -15,8 +15,6 @@ namespace JS { -GC_DEFINE_ALLOCATOR(CachedSourceRange); - class ExecutionContextAllocator { public: NonnullOwnPtr allocate(u32 registers_and_locals_count, u32 constants_count, u32 arguments_count) @@ -131,7 +129,6 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor) visitor.visit(variable_environment); visitor.visit(lexical_environment); visitor.visit(private_environment); - visitor.visit(cached_source_range); visitor.visit(this_value); visitor.visit(executable); visitor.visit(caller_executable); diff --git a/Libraries/LibJS/Runtime/ExecutionContext.h b/Libraries/LibJS/Runtime/ExecutionContext.h index b79a9bb4805..23a87cd45e0 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Libraries/LibJS/Runtime/ExecutionContext.h @@ -22,35 +22,6 @@ namespace JS { using ScriptOrModule = Variant, GC::Ref>; -class CachedSourceRange final : public GC::Cell { - GC_CELL(CachedSourceRange, GC::Cell); - GC_DECLARE_ALLOCATOR(CachedSourceRange); - -public: - CachedSourceRange(size_t program_counter, Variant source_range) - : program_counter(program_counter) - , source_range(move(source_range)) - { - } - - SourceRange const& realize_source_range() - { - static SourceRange dummy_source_range { SourceCode::create({}, {}), {}, {} }; - - if (auto* unrealized = source_range.get_pointer()) { - if (unrealized->source_code) { - source_range = unrealized->realize(); - } else { - source_range = dummy_source_range; - } - } - return source_range.get(); - } - - size_t program_counter { 0 }; - Variant source_range; -}; - // 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts struct JS_API ExecutionContext { static NonnullOwnPtr create(u32 registers_and_locals_count, u32 constants_count, u32 arguments_count); @@ -115,8 +86,6 @@ public: Span arguments; - mutable GC::Ptr cached_source_range; - // Non-standard: Inline frame linkage for the bytecode interpreter. // When a JS-to-JS call is inlined in the dispatch loop, these fields // allow the Return handler to restore the caller's frame. @@ -142,7 +111,7 @@ static_assert(IsTriviallyDestructible); struct StackTraceElement { ExecutionContext* execution_context { nullptr }; - GC::Ptr source_range; + Optional source_range; }; } diff --git a/Libraries/LibJS/Runtime/VM.cpp b/Libraries/LibJS/Runtime/VM.cpp index f72ca5ef5e2..7906f2da2a3 100644 --- a/Libraries/LibJS/Runtime/VM.cpp +++ b/Libraries/LibJS/Runtime/VM.cpp @@ -797,30 +797,17 @@ void VM::load_imported_module(ImportedModuleReferrer referrer, ModuleRequest con finish_loading_imported_module(referrer, module_request, payload, module); } -static GC::Ptr get_source_range(ExecutionContext* context) +Vector VM::stack_trace() const { - // native function - if (!context->executable) - return {}; - - 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->cached_source_range = context->executable->heap().allocate( - context->program_counter, - move(unrealized_source_range)); - } - return context->cached_source_range; -} - -GC::ConservativeVector VM::stack_trace() const -{ - GC::ConservativeVector stack_trace(heap()); + Vector stack_trace; stack_trace.ensure_capacity(m_execution_context_stack.size()); for (auto* context : m_execution_context_stack.in_reverse()) { + Optional source_range; + if (context->executable) + source_range = context->executable->get_source_range(context->program_counter); stack_trace.append({ .execution_context = context, - .source_range = get_source_range(context), + .source_range = move(source_range), }); } diff --git a/Libraries/LibJS/Runtime/VM.h b/Libraries/LibJS/Runtime/VM.h index 01745c07f2a..5182422192d 100644 --- a/Libraries/LibJS/Runtime/VM.h +++ b/Libraries/LibJS/Runtime/VM.h @@ -300,7 +300,7 @@ public: Function(Realm&, NonnullOwnPtr, ShadowRealm&)> host_initialize_shadow_realm; Function host_system_utc_epoch_nanoseconds; - [[nodiscard]] GC::ConservativeVector stack_trace() const; + [[nodiscard]] Vector stack_trace() const; private: using ErrorMessages = AK::Array;