diff --git a/Libraries/LibJS/Console.cpp b/Libraries/LibJS/Console.cpp index a7672e1d1b..9edc3b3eb0 100644 --- a/Libraries/LibJS/Console.cpp +++ b/Libraries/LibJS/Console.cpp @@ -350,10 +350,10 @@ ThrowCompletionOr Console::trace() auto& execution_context_stack = vm.execution_context_stack(); // NOTE: -2 to skip the console.trace() execution context for (ssize_t i = execution_context_stack.size() - 2; i >= 0; --i) { - auto const& function_name = execution_context_stack[i]->function_name; - trace.stack.append((!function_name || function_name->is_empty()) + auto function_name = execution_context_stack[i]->function ? execution_context_stack[i]->function->name_for_call_stack() : ""_utf16; + trace.stack.append(function_name.is_empty() ? ""_string - : function_name->utf8_string()); + : function_name.to_utf8()); } // 2. Optionally, let formattedData be the result of Formatter(data), and incorporate formattedData as a label for trace. diff --git a/Libraries/LibJS/Runtime/BoundFunction.cpp b/Libraries/LibJS/Runtime/BoundFunction.cpp index 6bc28bf348..b040221f9c 100644 --- a/Libraries/LibJS/Runtime/BoundFunction.cpp +++ b/Libraries/LibJS/Runtime/BoundFunction.cpp @@ -115,4 +115,9 @@ ThrowCompletionOr BoundFunction::get_stack_frame_size(size_t& registers_an return {}; } +Utf16String BoundFunction::name_for_call_stack() const +{ + return m_bound_target_function->name_for_call_stack(); +} + } diff --git a/Libraries/LibJS/Runtime/BoundFunction.h b/Libraries/LibJS/Runtime/BoundFunction.h index 1e8b3e46b3..c49c415701 100644 --- a/Libraries/LibJS/Runtime/BoundFunction.h +++ b/Libraries/LibJS/Runtime/BoundFunction.h @@ -30,6 +30,8 @@ public: Value bound_this() const { return m_bound_this; } Vector const& bound_arguments() const { return m_bound_arguments; } + virtual Utf16String name_for_call_stack() const override; + private: BoundFunction(Realm&, FunctionObject& target_function, Value bound_this, Vector bound_arguments, Object* prototype); diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index b8544c8f40..7d171cec89 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -694,7 +694,6 @@ void ECMAScriptFunctionObject::prepare_for_ordinary_call(VM& vm, ExecutionContex // 3. Set the Function of calleeContext to F. callee_context.function = this; - callee_context.function_name = m_name_string; // 4. Let calleeRealm be F.[[Realm]]. // 5. Set the Realm of calleeContext to calleeRealm. @@ -933,4 +932,9 @@ ECMAScriptFunctionObject::ClassData& ECMAScriptFunctionObject::ensure_class_data return *m_class_data; } +Utf16String ECMAScriptFunctionObject::name_for_call_stack() const +{ + return m_name_string->utf16_string(); +} + } diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index 719ceee96d..8f26f226b9 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -139,6 +139,8 @@ public: Statement const& ecmascript_code() const { return *shared_data().m_ecmascript_code; } [[nodiscard]] virtual FunctionParameters const& formal_parameters() const override { return *shared_data().m_formal_parameters; } + virtual Utf16String name_for_call_stack() const override; + Utf16FlyString const& name() const { return shared_data().m_name; } void set_name(Utf16FlyString const& name); diff --git a/Libraries/LibJS/Runtime/Error.cpp b/Libraries/LibJS/Runtime/Error.cpp index 0f541daaf7..1e6ff41ddd 100644 --- a/Libraries/LibJS/Runtime/Error.cpp +++ b/Libraries/LibJS/Runtime/Error.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Andreas Kling + * Copyright (c) 2020-2025, Andreas Kling * Copyright (c) 2021-2023, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -90,7 +91,7 @@ void Error::populate_stack() for (auto& element : stack_trace) { auto* context = element.execution_context; TracebackFrame frame { - .function_name = context->function_name ? context->function_name->utf8_string() : ""_string, + .function_name = context->function ? context->function->name_for_call_stack() : ""_utf16, .cached_source_range = element.source_range, }; @@ -117,7 +118,7 @@ String Error::stack_string(CompactTraceback compact) const else stack_string_builder.appendff(" at {} ({}:{}:{})\n", function_name, source_range.filename(), source_range.start.line, source_range.start.column); } else { - stack_string_builder.appendff(" at {}\n", function_name.is_empty() ? ""sv : function_name); + stack_string_builder.appendff(" at {}\n", function_name.is_empty() ? ""_utf16 : function_name); } }; diff --git a/Libraries/LibJS/Runtime/Error.h b/Libraries/LibJS/Runtime/Error.h index 1e1dc47bdd..46b5d31787 100644 --- a/Libraries/LibJS/Runtime/Error.h +++ b/Libraries/LibJS/Runtime/Error.h @@ -18,7 +18,7 @@ namespace JS { struct JS_API TracebackFrame { - FlyString function_name; + Utf16String function_name; [[nodiscard]] SourceRange const& source_range() const; RefPtr cached_source_range; diff --git a/Libraries/LibJS/Runtime/ExecutionContext.cpp b/Libraries/LibJS/Runtime/ExecutionContext.cpp index 3e42f2b384..4f3e8e6b99 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.cpp +++ b/Libraries/LibJS/Runtime/ExecutionContext.cpp @@ -122,7 +122,6 @@ NonnullOwnPtr ExecutionContext::copy() const copy->variable_environment = variable_environment; copy->private_environment = private_environment; copy->program_counter = program_counter; - copy->function_name = function_name; copy->this_value = this_value; copy->executable = executable; copy->passed_argument_count = passed_argument_count; @@ -147,7 +146,6 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor) if (this_value.has_value()) visitor.visit(*this_value); visitor.visit(executable); - visitor.visit(function_name); visitor.visit(registers_and_constants_and_locals_and_arguments_span()); for (auto& context : unwind_contexts) { visitor.visit(context.lexical_environment); diff --git a/Libraries/LibJS/Runtime/ExecutionContext.h b/Libraries/LibJS/Runtime/ExecutionContext.h index 841e856164..6b6c791aeb 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Libraries/LibJS/Runtime/ExecutionContext.h @@ -62,7 +62,6 @@ public: mutable RefPtr cached_source_range; - GC::Ptr function_name; Optional this_value; GC::Ptr executable; diff --git a/Libraries/LibJS/Runtime/FunctionObject.h b/Libraries/LibJS/Runtime/FunctionObject.h index 5506b6ec28..4a020777c2 100644 --- a/Libraries/LibJS/Runtime/FunctionObject.h +++ b/Libraries/LibJS/Runtime/FunctionObject.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021, Andreas Kling + * Copyright (c) 2020-2025, Andreas Kling * Copyright (c) 2021-2022, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause @@ -42,6 +42,8 @@ public: virtual FunctionParameters const& formal_parameters() const { VERIFY_NOT_REACHED(); } + virtual Utf16String name_for_call_stack() const = 0; + template bool fast_is() const = delete; diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Libraries/LibJS/Runtime/FunctionPrototype.cpp index 80b1bd114d..5b60f330b8 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -192,4 +192,9 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::symbol_has_instance) return TRY(ordinary_has_instance(vm, vm.argument(0), vm.this_value())); } +Utf16String FunctionPrototype::name_for_call_stack() const +{ + return "(Function.prototype)"_utf16; +} + } diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.h b/Libraries/LibJS/Runtime/FunctionPrototype.h index d56b755dc5..73be62f87e 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.h +++ b/Libraries/LibJS/Runtime/FunctionPrototype.h @@ -20,6 +20,8 @@ public: virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) override; + virtual Utf16String name_for_call_stack() const override; + private: explicit FunctionPrototype(Realm&); diff --git a/Libraries/LibJS/Runtime/NativeFunction.cpp b/Libraries/LibJS/Runtime/NativeFunction.cpp index 7c304d9fe0..a0e3b75606 100644 --- a/Libraries/LibJS/Runtime/NativeFunction.cpp +++ b/Libraries/LibJS/Runtime/NativeFunction.cpp @@ -123,7 +123,6 @@ ThrowCompletionOr NativeFunction::internal_call(ExecutionContext& callee_ // 4. Set the Function of calleeContext to F. callee_context.function = this; - callee_context.function_name = m_name_string; // 5. Let calleeRealm be F.[[Realm]]. auto callee_realm = m_realm; @@ -179,7 +178,6 @@ ThrowCompletionOr> NativeFunction::internal_construct(ExecutionC // 4. Set the Function of calleeContext to F. callee_context.function = this; - callee_context.function_name = m_name_string; // 5. Let calleeRealm be F.[[Realm]]. auto callee_realm = m_realm; @@ -233,4 +231,9 @@ bool NativeFunction::is_strict_mode() const return true; } +Utf16String NativeFunction::name_for_call_stack() const +{ + return m_name.to_utf16_string(); +} + } diff --git a/Libraries/LibJS/Runtime/NativeFunction.h b/Libraries/LibJS/Runtime/NativeFunction.h index 098cf7512c..8ad498b169 100644 --- a/Libraries/LibJS/Runtime/NativeFunction.h +++ b/Libraries/LibJS/Runtime/NativeFunction.h @@ -36,6 +36,8 @@ public: virtual ThrowCompletionOr call(); virtual ThrowCompletionOr> construct(FunctionObject& new_target); + virtual Utf16String name_for_call_stack() const override; + Utf16FlyString const& name() const { return m_name; } virtual bool is_strict_mode() const override; virtual bool has_constructor() const override { return false; } diff --git a/Libraries/LibJS/Runtime/ProxyObject.cpp b/Libraries/LibJS/Runtime/ProxyObject.cpp index 1431f89070..015db4f20f 100644 --- a/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -895,4 +895,9 @@ ThrowCompletionOr ProxyObject::get_stack_frame_size(size_t& registers_and_ return as(*m_target).get_stack_frame_size(registers_and_constants_and_locals_count, argument_count); } +Utf16String ProxyObject::name_for_call_stack() const +{ + return "(Proxy)"_utf16; +} + } diff --git a/Libraries/LibJS/Runtime/ProxyObject.h b/Libraries/LibJS/Runtime/ProxyObject.h index 78c47926b2..53d4728b24 100644 --- a/Libraries/LibJS/Runtime/ProxyObject.h +++ b/Libraries/LibJS/Runtime/ProxyObject.h @@ -46,6 +46,8 @@ public: virtual ThrowCompletionOr> internal_construct(ExecutionContext&, FunctionObject& new_target) override; ThrowCompletionOr validate_non_revoked_proxy() const; + virtual Utf16String name_for_call_stack() const override; + private: ProxyObject(Object& target, Object& handler, Object& prototype); diff --git a/Libraries/LibJS/Runtime/VM.cpp b/Libraries/LibJS/Runtime/VM.cpp index 2498f1bb37..152abde4e8 100644 --- a/Libraries/LibJS/Runtime/VM.cpp +++ b/Libraries/LibJS/Runtime/VM.cpp @@ -483,11 +483,12 @@ void VM::dump_backtrace() const { for (ssize_t i = m_execution_context_stack.size() - 1; i >= 0; --i) { auto& frame = m_execution_context_stack[i]; + if (frame->executable) { auto source_range = frame->executable->source_range_at(frame->program_counter).realize(); - dbgln("-> {} @ {}:{},{}", frame->function_name ? frame->function_name->utf8_string() : ""_string, source_range.filename(), source_range.start.line, source_range.start.column); + dbgln("-> {} @ {}:{},{}", frame->function ? frame->function->name_for_call_stack() : ""_utf16, source_range.filename(), source_range.start.line, source_range.start.column); } else { - dbgln("-> {}", frame->function_name ? frame->function_name->utf8_string() : ""_string); + dbgln("-> {}", frame->function ? frame->function->name_for_call_stack() : ""_utf16); } } } diff --git a/Libraries/LibJS/Runtime/WrappedFunction.cpp b/Libraries/LibJS/Runtime/WrappedFunction.cpp index 2be73e70eb..7d82b37f9a 100644 --- a/Libraries/LibJS/Runtime/WrappedFunction.cpp +++ b/Libraries/LibJS/Runtime/WrappedFunction.cpp @@ -174,4 +174,9 @@ void prepare_for_wrapped_function_call(WrappedFunction& function, ExecutionConte // NOTE: No-op, see NOTE after step 2. } +Utf16String WrappedFunction::name_for_call_stack() const +{ + return "(Wrapped)"_utf16; +} + } diff --git a/Libraries/LibJS/Runtime/WrappedFunction.h b/Libraries/LibJS/Runtime/WrappedFunction.h index 86bc0a7c95..d46294166d 100644 --- a/Libraries/LibJS/Runtime/WrappedFunction.h +++ b/Libraries/LibJS/Runtime/WrappedFunction.h @@ -29,6 +29,8 @@ public: virtual ThrowCompletionOr get_stack_frame_size(size_t& registers_and_constants_and_locals_count, size_t& argument_count) override; + virtual Utf16String name_for_call_stack() const override; + private: WrappedFunction(Realm&, FunctionObject&, Object& prototype); diff --git a/Services/WebContent/DevToolsConsoleClient.cpp b/Services/WebContent/DevToolsConsoleClient.cpp index e9c4fa6011..a65bccada5 100644 --- a/Services/WebContent/DevToolsConsoleClient.cpp +++ b/Services/WebContent/DevToolsConsoleClient.cpp @@ -114,7 +114,7 @@ void DevToolsConsoleClient::report_exception(JS::Error const& exception, bool in WebView::StackFrame stack_frame; if (!frame.function_name.is_empty()) - stack_frame.function = frame.function_name.to_string(); + stack_frame.function = frame.function_name.to_utf8(); if (!source_range.filename().is_empty() || source_range.start.offset != 0 || source_range.end.offset != 0) { stack_frame.file = String::from_utf8_with_replacement_character(source_range.filename());