mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 10:57:35 +00:00
LibJS: Add GC graph dumper
This change introduces a very basic GC graph dumper. The `dump_graph()` function outputs JSON data that contains information about all nodes in the graph, including their class types and edges. Root nodes will have a property indicating their root type or source location if the root is captured by a SafeFunction. It would be useful to add source location for other types of roots in the future. Output JSON dump have following format: ```json "4908721208": { "class_name": "Accessor", "edges": [ "4909298232", "4909297976" ] }, "4907520440": { "root": "SafeFunction Optional Optional.h:137", "class_name": "Realm", "edges": [ "4908269624", "4924821560", "4908409240", "4908483960", "4924527672" ] }, "4908251320": { "class_name": "CSSStyleRule", "edges": [ "4908302648", "4925101656", "4908251192" ] }, ```
This commit is contained in:
parent
ee29a21ae8
commit
0ff29349e6
7 changed files with 200 additions and 54 deletions
|
@ -9,11 +9,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/SourceLocation.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
void register_safe_function_closure(void*, size_t);
|
||||
void unregister_safe_function_closure(void*, size_t);
|
||||
void register_safe_function_closure(void*, size_t, SourceLocation*);
|
||||
void unregister_safe_function_closure(void*, size_t, SourceLocation*);
|
||||
|
||||
template<typename>
|
||||
class SafeFunction;
|
||||
|
@ -38,7 +39,7 @@ public:
|
|||
if (!m_size)
|
||||
return;
|
||||
if (auto* wrapper = callable_wrapper())
|
||||
register_safe_function_closure(wrapper, m_size);
|
||||
register_safe_function_closure(wrapper, m_size, &m_location);
|
||||
}
|
||||
|
||||
void unregister_closure()
|
||||
|
@ -46,24 +47,27 @@ public:
|
|||
if (!m_size)
|
||||
return;
|
||||
if (auto* wrapper = callable_wrapper())
|
||||
unregister_safe_function_closure(wrapper, m_size);
|
||||
unregister_safe_function_closure(wrapper, m_size, &m_location);
|
||||
}
|
||||
|
||||
template<typename CallableType>
|
||||
SafeFunction(CallableType&& callable)
|
||||
SafeFunction(CallableType&& callable, SourceLocation location = SourceLocation::current())
|
||||
requires((AK::IsFunctionObject<CallableType> && IsCallableWithArguments<CallableType, Out, In...> && !IsSame<RemoveCVReference<CallableType>, SafeFunction>))
|
||||
: m_location(location)
|
||||
{
|
||||
init_with_callable(forward<CallableType>(callable), CallableKind::FunctionObject);
|
||||
}
|
||||
|
||||
template<typename FunctionType>
|
||||
SafeFunction(FunctionType f)
|
||||
SafeFunction(FunctionType f, SourceLocation location = SourceLocation::current())
|
||||
requires((AK::IsFunctionPointer<FunctionType> && IsCallableWithArguments<RemovePointer<FunctionType>, Out, In...> && !IsSame<RemoveCVReference<FunctionType>, SafeFunction>))
|
||||
: m_location(location)
|
||||
{
|
||||
init_with_callable(move(f), CallableKind::FunctionPointer);
|
||||
}
|
||||
|
||||
SafeFunction(SafeFunction&& other)
|
||||
: m_location(move(other.m_location))
|
||||
{
|
||||
move_from(move(other));
|
||||
}
|
||||
|
@ -215,6 +219,7 @@ private:
|
|||
VERIFY(m_kind == FunctionKind::NullPointer);
|
||||
auto* other_wrapper = other.callable_wrapper();
|
||||
m_size = other.m_size;
|
||||
AK::TypedTransfer<SourceLocation>::move(&m_location, &other.m_location, 1);
|
||||
switch (other.m_kind) {
|
||||
case FunctionKind::NullPointer:
|
||||
break;
|
||||
|
@ -225,8 +230,10 @@ private:
|
|||
register_closure();
|
||||
break;
|
||||
case FunctionKind::Outline:
|
||||
other.unregister_closure();
|
||||
*bit_cast<CallableWrapperBase**>(&m_storage) = other_wrapper;
|
||||
m_kind = FunctionKind::Outline;
|
||||
register_closure();
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
@ -238,6 +245,7 @@ private:
|
|||
bool m_deferred_clear { false };
|
||||
mutable Atomic<u16> m_call_nesting_level { 0 };
|
||||
size_t m_size { 0 };
|
||||
SourceLocation m_location;
|
||||
|
||||
// Empirically determined to fit most lambdas and functions.
|
||||
static constexpr size_t inline_capacity = 4 * sizeof(void*);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue