UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
FastReferenceCollector.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "Stats/Stats.h"
9#include "UObject/Class.h"
10#include "UObject/Package.h"
12#include "UObject/UnrealType.h"
13#include "Misc/ScopeLock.h"
14#include "HAL/PlatformProcess.h"
15#include "UObject/FieldPath.h"
16#include "Async/ParallelFor.h"
19#include "UObject/GCObject.h"
20
21#if WITH_VERSE_VM || defined(__INTELLISENSE__)
24#include "VerseVM/VVMValue.h"
26#endif
27
28#if ENABLE_GC_HISTORY
30#endif
31
32/*=============================================================================
33 FastReferenceCollector.h: Unreal realtime garbage collection helpers
34=============================================================================*/
35
36namespace UE::GC
37{
38class FWorkCoordinator;
39struct FWorkerContext;
40}
41
42enum class EGCOptions : uint32
43{
44 None = 0,
45 Parallel = 1 << 0, // Use all task workers to collect references, must be started on main thread
46 AutogenerateSchemas = 1 << 1, // Assemble schemas for new UClasses
47 WithPendingKill UE_DEPRECATED(5.4, "WithPendingKill should no longer be used. Use EliminateGarbage.") = 1 << 2, // Internal flag used by reachability analysis
48 EliminateGarbage = 1 << 2, // Internal flag used by reachability analysis
49 IncrementalReachability = 1 << 3 // Run Reachability Analysis incrementally
50};
52
53inline constexpr bool IsParallel(EGCOptions Options) { return !!(Options & EGCOptions::Parallel); }
54
55inline constexpr bool IsEliminatingGarbage(EGCOptions Options) { return !!(Options & EGCOptions::EliminateGarbage); }
56UE_DEPRECATED(5.4, "IsPendingKill should no longer be used. Use IsEliminatingGarbage.")
58
61{
62 FORCEINLINE static FUObjectItem* GetResolvedOwner(FFieldPath& Path) { return Path.GetResolvedOwnerItemInternal(); }
63 FORCEINLINE static void ClearCachedField(FFieldPath& Path) { Path.ClearCachedFieldInternal(); }
64};
65
73
75
76namespace UE::GC
77{
78
79#if !WITH_VERSE_BPVM || defined(__INTELLISENSE__)
80// Avoid name lookup into UE::Verse, sometimes pulled into the TU before this header.
81namespace Verse = ::Verse;
82#endif
83
84struct FStructArrayBlock;
85
86static constexpr uint32 ObjectLookahead = 16;
87
88// Prefetches ClassPrivate, OuterPrivate, class schema and schema data while iterating over an object array
89//
90// Tuned on a Gen5 console using an internal game replay and an in-game GC pass
92{
93public:
94 // Objects must be padded with PadObjects
96 : It(Objects.begin())
97 , End(Objects.end())
98 , PrefetchedSchema(Objects.Num() ? &It[1]->GetClass()->ReferenceSchema.Get() : nullptr)
99 {}
100
102 {
103 FPlatformMisc::Prefetch(PrefetchedSchema->GetWords());
104 PrefetchedSchema = &It[2]->GetClass()->ReferenceSchema.Get();
105
107 FPlatformMisc::Prefetch(It[6]->GetClass(), offsetof(UClass, ReferenceSchema));
108 UObjectBase::PrefetchClass(It[ObjectLookahead]);
109
110 ++It;
111 }
112
113 bool HasMore() const { return It != End; }
114 UObject* GetCurrentObject() { return *It; }
115
116private:
117 UObject*const* It;
118 UObject*const* End;
119 const FSchemaView* PrefetchedSchema;
120};
121
122// Pad object array for FPrefetchingObjectIterator use
124
126
129{
130 static constexpr uint32 ObjectCapacity = 512 - /* Previous */ 1 - ObjectLookahead;
131
133 UObject* Objects[ObjectCapacity + ObjectLookahead];
134
137};
138
139class FWorkstealingQueue;
140
143{
144public:
146 FWorkBlockifier() = default;
148
149 void Init() { AllocateWipBlock(); }
150 void SetAsyncQueue(FWorkstealingQueue& Queue) { AsyncQueue = &Queue; }
151 void ResetAsyncQueue();
152
153 template<EGCOptions Options>
155 {
156 *WipIt = Object;
157 if (++WipIt == Wip->GetPadding().GetData())
158 {
159 if constexpr (IsParallel(Options))
160 {
161 PushFullBlockAsync();
162 }
163 else
164 {
165 PushFullBlockSync();
166 }
167 }
168 }
169
171 {
172 if (int32 Num = PartialNum())
173 {
174 OutNum = Num;
175 return PopWipBlock();
176 }
177
178 return nullptr;
179 }
180
181 template<EGCOptions Options>
183 {
184 return IsParallel(Options) ? PopFullBlockAsync() : PopFullBlockSync();
185 }
186
188 {
189 return StealAsyncBlock();
190 }
191
193
195 {
196 return PartialNum() == 0 && SyncQueue == nullptr;
197 }
198
199 void SetWorkerIndex(int32 Idx) { WorkerIndex = Idx; }
200 int32 GetWorkerIndex() const { return WorkerIndex; }
201
202 bool HasWork() const
203 {
204 return PartialNum() != 0;
205 }
206
207private:
208 UObject** WipIt; // Wip->Objects cursor
209 FWorkBlock* Wip;
210 union
211 {
214 };
215 int32 WorkerIndex = INDEX_NONE;
216
217 void AllocateWipBlock();
218 COREUOBJECT_API void PushFullBlockSync();
219 COREUOBJECT_API void PushFullBlockAsync();
220 COREUOBJECT_API FWorkBlock* PopFullBlockSync();
221 COREUOBJECT_API FWorkBlock* PopFullBlockAsync();
222 COREUOBJECT_API FWorkBlock* PopWipBlock();
223 COREUOBJECT_API FWorkBlock* StealAsyncBlock() const;
224
225 FORCEINLINE int32 PartialNum() const
226 {
227 return static_cast<int32>(WipIt - Wip->Objects);
228 }
229};
230
232
241
243
245{
246#if UE_BUILD_SHIPPING
247 static constexpr uint32 NumObjects = 0;
248 static constexpr uint32 NumReferences = 0;
249 static constexpr uint32 NumVerseCells = 0;
250 static constexpr bool bFoundGarbageRef = false;
251 FORCEINLINE constexpr void AddObjects(uint32) {}
252 FORCEINLINE constexpr void AddReferences(uint32) {}
253 FORCEINLINE constexpr void AddVerseCells(uint32) {}
254 FORCEINLINE constexpr void TrackPotentialGarbageReference(bool) {}
255#else
259 bool bFoundGarbageRef = false;
264#endif
265
273};
274
282
284{
286 FStructArray* WipIt = nullptr;
287
289 {
290 return !!Wip;
291 }
292};
293
300
303{
304#if !UE_BUILD_SHIPPING
308
310 : Member(0)
311 , Prev(nullptr)
312 {
313 }
315 : Member(0)
317 , Prev(PrevNode)
318 {
319 }
320#endif // !UE_BUILD_SHIPPING
321
323 {
324#if !UE_BUILD_SHIPPING
325 Member = MemberId;
326#endif
327 }
328
329 COREUOBJECT_API FString ToString() const;
330};
331
334{
335private:
336 template <typename ProcessorType, typename CollectorType>
338 friend class FSlowAROManager;
339
340 // This is set by GC when processing references from the current referencing object
341 UObject* ReferencingObject = nullptr;
342 TConstArrayView<UObject*> InitialObjects;
343#if WITH_VERSE_VM || defined(__INTELLISENSE__)
345#endif
346public:
350
353 FWorkCoordinator* Coordinator = nullptr;
356
357#if !UE_BUILD_SHIPPING
359#endif
360#if ENABLE_GC_HISTORY
362#endif
363
365 bool bIsSuspended = false;
366 bool bDidWork = false;
367
368 FDebugSchemaStackNode* SchemaStack = nullptr;
369
370 FORCEINLINE UObject* GetReferencingObject() { return ReferencingObject; }
371
372 TConstArrayView<UObject*> GetInitialObjects() { return InitialObjects; }
373 void ResetInitialObjects() { InitialObjects = {}; }
374
377 {
378 PadObjectArray(Objects);
379 SetInitialObjectsPrepadded(Objects);
380 }
381
384 {
385 check(PaddedObjects.IsEmpty() || PaddedObjects.GetData()[PaddedObjects.Num() + ObjectLookahead - 1]->IsValidLowLevel() );
386 InitialObjects = PaddedObjects;
387 }
388
389#if WITH_VERSE_VM || defined(__INTELLISENSE__)
391
393
395 {
397 }
398#endif
399
402 {
403 return WeakReferences.GetAllocatedSize() + sizeof(FWorkBlock);
404 }
405
406 FORCEINLINE int32 GetWorkerIndex() const { return ObjectsToSerialize.GetWorkerIndex(); }
407 void AllocateWorkerIndex();
408 void FreeWorkerIndex();
409};
410
412
414{
415#if !UE_BUILD_SHIPPING
418#endif
419
421#if !UE_BUILD_SHIPPING
423 , Node(Schema, InContext.SchemaStack)
424#endif
425 {
426#if !UE_BUILD_SHIPPING
427 InContext.SchemaStack = &Node;
428#endif
429 }
431 {
432#if !UE_BUILD_SHIPPING
433 Context.SchemaStack = Node.Prev;
434#endif
435 }
436};
437
444
446
447namespace Private {
448
450{
452 : Type(static_cast<EMemberType>(In.Type))
453 , WordOffset(In.WordOffset)
454 {
455 check(Type < EMemberType::Count);
456 }
459};
460
462{
463 FMemberWordUnpacked(const FMemberPacked In[4]) : Members{In[0], In[1], In[2], In[3]} {}
464 FMemberUnpacked Members[4];
465};
466
472
479
481{
484
485 UObject*& operator*() { return *It; }
486 FStridedReferenceIterator& operator++() { It += Stride; return *this;}
487 bool operator!=(FStridedReferenceIterator Rhs) const { return It != Rhs.It; }
488};
489
494{
495 return { reinterpret_cast<UObject**>(In.Array->GetData()) + In.Layout.WordOffset, In.Array->Num(), In.Layout.WordStride };
496}
497
499{
500 return reinterpret_cast<uint8*>(Set.GetData(0, FScriptSetLayout{}));
501}
502
504{
505 return reinterpret_cast<const uint8*>(Set.GetData(0, FScriptSetLayout{}));
506}
507
508template<class DispatcherType>
509FORCENOINLINE void VisitNestedStructMembers(DispatcherType& Dispatcher, FSchemaView Schema, uint8* Instance);
510
511template<class DispatcherType>
512FORCEINLINE_DEBUGGABLE void VisitStructs(DispatcherType& Dispatcher, FSchemaView StructSchema, uint8* It, const int32 Num)
513{
514 check(!StructSchema.IsEmpty());
515 if constexpr (DispatcherType::bBatching)
516 {
517 Dispatcher.QueueStructArray(StructSchema, It, Num);
518 }
519 else
520 {
521 uint32 Stride = StructSchema.GetStructStride();
522 for (uint8* End = It + Num*Stride; It != End; It += Stride)
523 {
524 VisitNestedStructMembers(Dispatcher, StructSchema, It);
525 }
526 }
527}
528
529template<class DispatcherType, class ArrayType>
530FORCEINLINE_DEBUGGABLE void VisitStructArray(DispatcherType& Dispatcher, FSchemaView StructSchema, ArrayType& Array)
531{
532 typename DispatcherType::SchemaStackScopeType SchemaStack(Dispatcher.Context, StructSchema);
533 VisitStructs(Dispatcher, StructSchema, (uint8*)Array.GetData(), Array.Num());
534}
535
536template<class DispatcherType>
538{
539 check(!StructSchema.IsEmpty());
540 if constexpr (DispatcherType::bBatching)
541 {
542 Dispatcher.QueueSparseStructArray(StructSchema, Set);
543 }
544 else if (int32 Num = Set.Num())
545 {
546 uint8* It = GetSetData(Set);
547 const uint32 Stride = StructSchema.GetStructStride();
548 for (int32 Idx = 0, MaxIdx = Set.GetMaxIndex(); Idx < MaxIdx; ++Idx, It += Stride)
549 {
550 if (Set.IsValidIndex(Idx))
551 {
552 typename DispatcherType::SchemaStackScopeType SchemaStack(Dispatcher.Context, StructSchema);
553 VisitNestedStructMembers(Dispatcher, StructSchema, It);
554 }
555 }
556 }
557}
558
559template<class DispatcherType>
560FORCEINLINE_DEBUGGABLE void VisitFieldPath(DispatcherType& Dispatcher, FFieldPath& FieldPath, EOrigin Origin, uint32 MemberIdx)
561{
563 {
564 UObject* OwnerObject = static_cast<UObject*>(FieldOwnerItem->GetObject());
565 UObject* PreviousOwner = OwnerObject;
566 Dispatcher.HandleReferenceDirectly(Dispatcher.Context.GetReferencingObject(), OwnerObject, FMemberId(MemberIdx), Origin, true);
567
568 // Handle reference elimination (PendingKill owner)
569 if (PreviousOwner && !OwnerObject)
570 {
572 }
573 }
574}
575template<class DispatcherType>
577{
579 {
580 VisitFieldPath(Dispatcher, FieldPath, Origin, MemberIdx);
581 }
582}
583
584template<class DispatcherType>
586{
587 check(!StructSchema.IsEmpty());
588 uint32 ValueSize = StructSchema.GetStructStride();
589 bool bIsSet = *(bool*)(Instance + ValueSize);
590 typename DispatcherType::SchemaStackScopeType SchemaStack(Dispatcher.Context, StructSchema);
591 VisitStructs(Dispatcher, StructSchema, Instance, bIsSet);
592}
593
594template<class DispatcherType>
596{
597 Value.GetType().MarkReachable(Dispatcher.Collector);
598 if (Value.GetType().GetContainsReferences() != UE::FDynamicallyTypedValueType::EContainsReferences::DoesNot)
599 {
600 Value.GetType().MarkValueReachable(Value.GetDataPointer(), Dispatcher.Collector);
601 }
602}
603
604#if WITH_EDITORONLY_DATA
606#endif
607
608template<class DispatcherType>
610{
612 {
613 // Object was constructed in a transaction that was aborted.
614 // The object is in a pre-construction state and won't have any valid subreferences.
615 return;
616 }
617
618#if WITH_EDITORONLY_DATA
621 Word.ObjectARO(Instance, Dispatcher.Collector);
622 if (!bCalledSuperARO)
623 {
624 UE_LOG(LogGarbage, Warning, TEXT("Class %s or a super class did not call Super::AddReferencedObjects"), *Instance->GetClass()->GetName());
625 }
626#else
627 Word.ObjectARO(Instance, Dispatcher.Collector);
628#endif
629}
630
631template<class DispatcherType>
632FORCEINLINE_DEBUGGABLE void CallARO(DispatcherType& Dispatcher, uint8* Instance, FMemberWord Word)
633{
634 Word.StructARO(Instance, Dispatcher.Collector);
635}
636
637template<class DispatcherType>
639{
640 if constexpr (DispatcherType::bBatching && DispatcherType::bParallel)
641 {
642 if (!FSlowARO::TryQueueCall(SlowAROIdx, Instance, Dispatcher.Context))
643 {
644 FSlowARO::CallSync(SlowAROIdx, Instance, Dispatcher.Collector);
645 }
646 }
647 else
648 {
649 FSlowARO::CallSync(SlowAROIdx, Instance, Dispatcher.Collector);
650 }
651}
652
653FORCENOINLINE static void LogIllegalTypeFatal(EMemberType Type, uint32 Idx, UObject* Instance)
654{
655 UE_LOG(LogGarbage, Fatal, TEXT("Illegal GC object member type %d at %d, class:%s object:%s"), int(Type), Idx, Instance ? *GetNameSafe(Instance->GetClass()) : TEXT("Unknown"), *GetPathNameSafe(Instance));
656}
657
658FORCENOINLINE static void LogIllegalTypeFatal(EMemberType Type, uint32 Idx, uint8*)
659{
660 UE_LOG(LogGarbage, Fatal, TEXT("Illegal GC struct member type %d at %d"), int(Type), Idx);
661}
662
663template<class DispatcherType>
665{
666 LogIllegalTypeFatal(EMemberType::SlowARO, MemberIdx, Instance);
667}
668
669template <typename ObjectType>
671{
672 return Schema.GetOrigin();
673}
674#if UE_WITH_REMOTE_OBJECT_HANDLE
675template <>
676FORCEINLINE EOrigin GetSchemaOrigin(FSchemaView Schema, UObject* Instance)
677{
679 // Consider borrowed objects to always be non-BP to prevent garbage elimination from mutating these objects
680 return !Item->HasAnyFlags(EInternalObjectFlags::Borrowed) ? Schema.GetOrigin() : EOrigin::Other;
681}
682#endif // UE_WITH_REMOTE_OBJECT_HANDLE
683
684template<class DispatcherType, typename ObjectType>
685FORCEINLINE_DEBUGGABLE void VisitMembers(DispatcherType& Dispatcher, FSchemaView Schema, ObjectType* Instance)
686{
687 check(!Schema.IsEmpty());
688
689 const EOrigin Origin = GetSchemaOrigin(Schema, Instance);
690 uint64* InstanceCursor = (uint64*)Instance; // Advanced via Jump to reach far members
691 uint32 DebugIdx = 0;
692 for (const FMemberWord* WordIt = Schema.GetWords(); true; ++WordIt)
693 {
694 const FMemberWordUnpacked Quad(WordIt->Members);
695 for (FMemberUnpacked Member : Quad.Members)
696 {
697 uint8* MemberPtr = (uint8*)(InstanceCursor + Member.WordOffset);
698 Dispatcher.SetDebugSchemaStackMemberId(FMemberId(DebugIdx));
699
700 switch (Member.Type)
701 {
702 case EMemberType::Reference: Dispatcher.HandleKillableReference(*(UObject**)MemberPtr, FMemberId(DebugIdx), Origin);
703 break;
704 case EMemberType::ReferenceArray: Dispatcher.HandleKillableArray(*(TArray<UObject*>*)MemberPtr, FMemberId(DebugIdx), Origin);
705 break;
706 case EMemberType::StridedArray: Dispatcher.HandleKillableArray(FStridedReferenceArray{(FScriptArray*)MemberPtr, (++WordIt)->StridedLayout}, FMemberId(DebugIdx), Origin);
707 break;
708 case EMemberType::FreezableReferenceArray: Dispatcher.HandleKillableReferences(*(TArray<UObject*, FMemoryImageAllocator>*)MemberPtr, FMemberId(DebugIdx), Origin);
709 break;
710 case EMemberType::StructArray: VisitStructArray( Dispatcher, FSchemaView((++WordIt)->InnerSchema, Origin), *(FScriptArray*)MemberPtr);
711 break;
712 case EMemberType::StructSet: VisitStructSet( Dispatcher, FSchemaView((++WordIt)->InnerSchema, Origin), *(FScriptSet*)MemberPtr);
713 break;
714 case EMemberType::FreezableStructArray: VisitStructArray( Dispatcher, FSchemaView((++WordIt)->InnerSchema, Origin), *(FFreezableScriptArray*)MemberPtr);
715 break;
716 case EMemberType::Optional: VisitOptional( Dispatcher, FSchemaView((++WordIt)->InnerSchema, Origin), MemberPtr);
717 break;
718 case EMemberType::FieldPath: VisitFieldPath( Dispatcher, *(FFieldPath*)MemberPtr, Origin, DebugIdx);
719 break;
720 case EMemberType::FieldPathArray: VisitFieldPathArray( Dispatcher, *(TArray<FFieldPath>*)MemberPtr, Origin, DebugIdx);
721 break;
722 case EMemberType::DynamicallyTypedValue: VisitDynamicallyTypedValue( Dispatcher, *(UE::FDynamicallyTypedValue*)MemberPtr);
723 break;
724 case EMemberType::Jump: InstanceCursor += (Member.WordOffset + 1) * FMemberPacked::OffsetRange;
725 break;
726 case EMemberType::MemberARO: CallARO(Dispatcher, MemberPtr, *++WordIt);
727 break; // Struct member ARO isn't an implicit stop
728 case EMemberType::ARO: CallARO(Dispatcher, Instance, *++WordIt);
729 return; // Instance ARO is an implicit stop
730 case EMemberType::SlowARO: CallSlowARO(Dispatcher, /* slow ARO index */ Member.WordOffset, Instance, DebugIdx);
731 return; // ARO is an implicit stop
732 case EMemberType::Stop:
733 return; // Stop schema without ARO call
734#if WITH_VERSE_VM || defined(__INTELLISENSE__)
735 case EMemberType::VerseValue: Dispatcher.HandleVerseValue(*(Verse::VValue*)MemberPtr, FMemberId(DebugIdx), Origin);
736 break;
737 case EMemberType::VerseValueArray: Dispatcher.HandleVerseValueArray(*(TArray<Verse::VValue>*)MemberPtr, FMemberId(DebugIdx), Origin);
738 break;
739#endif
740 case EMemberType::Count:
741 default: LogIllegalTypeFatal(Member.Type, DebugIdx, Instance);
742 return;
743 }
744
746 } // for quad members
747 } // for schema member words
748}
749
750template<class DispatcherType>
751void VisitNestedStructMembers(DispatcherType& Dispatcher, FSchemaView Schema, uint8* Instance)
752{
753 static_assert(!DispatcherType::bBatching);
754 VisitMembers(Dispatcher, Schema, Instance);
755}
756
757} // namespace Private
758
760
761#if WITH_VERSE_VM || defined(__INTELLISENSE__)
762// Some helper templates to detect if the ProcessorType supports HasHandleTokenStreamVerseCellReference
763template <typename T, typename = void>
764struct HasHandleTokenStreamVerseCellReference : std::false_type {};
765
766template <typename T>
767using HandleTokenStreamVerseCellReference_t = decltype(std::declval<T>().HandleTokenStreamVerseCellReference(std::declval<FWorkerContext&>(), std::declval<UObject*>(), std::declval<Verse::VCell*>(), std::declval<FMemberId>(), std::declval<EOrigin>()));
768
769template <typename T>
770struct HasHandleTokenStreamVerseCellReference <T, std::void_t<HandleTokenStreamVerseCellReference_t<T>>> : std::true_type {};
771#endif
772
774template<class ProcessorType>
776{
777 static constexpr bool bBatching = false;
778 static constexpr bool bParallel = IsParallel(ProcessorType::Options);
779
781 ProcessorType& Processor;
784
786 {
787 if (IsObjectHandleResolved_ForGC(*reinterpret_cast<FObjectHandle*>(&Object)))
788 {
789 Processor.HandleTokenStreamObjectReference(Context, ReferencingObject, Object, MemberId, Origin, bAllowReferenceElimination);
790 }
791 Context.Stats.AddReferences(1);
792 }
793
795 {
796 HandleReferenceDirectly(Context.GetReferencingObject(), Object, MemberId, Origin, true);
797 }
798
800 {
801 HandleReferenceDirectly(Context.GetReferencingObject(), Object, MemberId, Origin, false);
802 }
803
804 template<class ArrayType>
805 FORCEINLINE void HandleKillableReferences(ArrayType&& Objects , FMemberId MemberId, EOrigin Origin) const
806 {
807 for (UObject*& Object : Objects)
808 {
809 HandleReferenceDirectly(Context.GetReferencingObject(), Object, MemberId, Origin, true);
810 }
811 }
812
814 {
815 HandleKillableReferences(Array, MemberId, Origin);
816 }
817
819 {
820 HandleKillableReferences(ToView(Array), MemberId, Origin);
821 }
822
823#if WITH_VERSE_VM || defined(__INTELLISENSE__)
824 FORCEINLINE_DEBUGGABLE void HandleVerseCellDirectly(UObject* ReferencingObject, Verse::VCell* Cell, FMemberId MemberId, EOrigin Origin) const
825 {
826 if constexpr (HasHandleTokenStreamVerseCellReference<ProcessorType>::value)
827 {
828 Processor.HandleTokenStreamVerseCellReference(Context, ReferencingObject, Cell, MemberId, Origin);
829 }
830 Context.Stats.AddVerseCells(1);
831 }
832
833 FORCEINLINE_DEBUGGABLE void HandleVerseValueDirectly(UObject* ReferencingObject, Verse::VValue Value, FMemberId MemberId, EOrigin Origin) const
834 {
835 if (Verse::VCell* Cell = Value.ExtractCell())
836 {
837 HandleVerseCellDirectly(ReferencingObject, Cell, MemberId, Origin);
838 }
839 else if (UObject* Object = Value.ExtractUObject())
840 {
841 HandleImmutableReference(Object, MemberId, Origin);
842 }
843 }
844
845 FORCEINLINE_DEBUGGABLE void HandleVerseValue(Verse::VValue Value, FMemberId MemberId, EOrigin Origin)
846 {
847 HandleVerseValueDirectly(Context.GetReferencingObject(), Value, MemberId, Origin);
848 }
849
850 FORCEINLINE void HandleVerseValueArray(TArrayView<Verse::VValue> Values, FMemberId MemberId, EOrigin Origin)
851 {
852 for (Verse::VValue Value : Values)
853 {
854 HandleVerseValueDirectly(Context.GetReferencingObject(), Value, MemberId, Origin);
855 }
856 }
857#endif
858
859 void Suspend()
860 {
861 }
862
864 {
865 Context.SchemaStack->SetMemberId(Member);
866 }
867};
868
869// Default implementation is to create new direct dispatcher
870template<class CollectorType, class ProcessorType>
875
876template<class CollectorType, class ProcessorType, class = void >
878{
879 using RetType = decltype(GetDispatcher(*(CollectorType*)nullptr, *(ProcessorType*)nullptr, *(FWorkerContext*)nullptr));
880 using Type = typename std::remove_reference_t<RetType>;
881};
882
884
885enum class ELoot { Nothing, Block, ARO, Context };
886COREUOBJECT_API ELoot StealWork(FWorkerContext& Context, FReferenceCollector& Collector, FWorkBlock*& OutBlock, EGCOptions Options);
887
888COREUOBJECT_API void SuspendWork(FWorkerContext& Context);
889
891COREUOBJECT_API void ProcessAsync(void (*ProcessSync)(void*, FWorkerContext&), void* Processor, FWorkerContext& InitialContext);
892
894
904template <typename ProcessorType, typename CollectorType>
906{
907public:
909
911 {
912 Context.bDidWork = true;
913 Context.bIsSuspended = false;
914 static_assert(!EnumHasAllFlags(Options, EGCOptions::Parallel | EGCOptions::AutogenerateSchemas), "Can't assemble token streams in parallel");
915
917
918 // Either TDirectDispatcher living on the stack or TBatchDispatcher reference owned by Collector
920
922 // Process initial references first
923 Context.ReferencingObject = FGCObject::GGCObjectReferencer;
924 for (UObject** InitialReference : Context.InitialNativeReferences)
925 {
926 Dispatcher.HandleKillableReference(*InitialReference, EMemberlessId::InitialReference, EOrigin::Other);
927 }
928
929#if WITH_VERSE_VM || defined(__INTELLISENSE__)
930 // Just process native structs once
931 ProcessNativeStructs(Dispatcher, Context.InitialNativeStructs);
932#endif
933
935 while (true)
936 {
937 Context.Stats.AddObjects(CurrentObjects.Num());
938 ProcessObjects(Dispatcher, CurrentObjects);
939
940 // Free finished work block
941 if (CurrentObjects.GetData() != Context.InitialObjects.GetData())
942 {
943 Context.ObjectsToSerialize.FreeOwningBlock(CurrentObjects.GetData());
944 }
945
946 if (Processor.IsTimeLimitExceeded())
947 {
948 FlushWork(Dispatcher);
949 Dispatcher.Suspend();
951 return;
952 }
953
954 int32 BlockSize = FWorkBlock::ObjectCapacity;
955 FWorkBlockifier& RemainingObjects = Context.ObjectsToSerialize;
956 FWorkBlock* Block = RemainingObjects.PopFullBlock<Options>();
957 if (!Block)
958 {
959 if constexpr (bIsParallel)
960 {
961 FSlowARO::ProcessUnbalancedCalls(Context, Collector);
962 }
963
965 FlushWork(Dispatcher);
966
967 if ( Block = RemainingObjects.PopFullBlock<Options>(); Block);
968 else if (Block = RemainingObjects.PopPartialBlock(/* out if successful */ BlockSize); Block);
969 else if (bIsParallel) // if constexpr yields MSVC unreferenced label warning
970 {
971 switch (StealWork(/* in-out */ Context, Collector, /* out */ Block, Options))
972 {
973 case ELoot::Nothing: break; // Done, stop working
974 case ELoot::Block: break; // Stole full block, process it
975 case ELoot::ARO: goto StoleARO; // Stole and made ARO calls that feed into Dispatcher queues and RemainingObjects
976 case ELoot::Context: goto StoleContext; // Stole initial references and initial objects worker that hasn't started working
977 }
978 }
979
980 if (!Block)
981 {
982 break;
983 }
984 }
985
986 CurrentObjects = MakeArrayView(Block->Objects, BlockSize);
987 } // while (true)
988
989 Processor.LogDetailedStatsSummary();
990 }
991
992private:
993 using DispatcherType = typename TGetDispatcherType<CollectorType, ProcessorType>::Type;
994 static constexpr EGCOptions Options = ProcessorType::Options;
995 static constexpr bool bIsParallel = IsParallel(Options);
996
997 ProcessorType& Processor;
998
999 FORCEINLINE_DEBUGGABLE void ProcessObjects(DispatcherType& Dispatcher, TConstArrayView<UObject*> CurrentObjects)
1000 {
1001 for (FPrefetchingObjectIterator It(CurrentObjects); It.HasMore(); It.Advance())
1002 {
1003 UObject* CurrentObject = It.GetCurrentObject();
1004 UClass* Class = CurrentObject->GetClass();
1005 UObject* Outer = CurrentObject->GetOuter();
1006
1007 if (!!(Options & EGCOptions::AutogenerateSchemas) && !Class->HasAnyClassFlags(CLASS_TokenStreamAssembled))
1008 {
1009 Class->AssembleReferenceTokenStream();
1010 }
1011
1012 FSchemaView Schema = Class->ReferenceSchema.Get();
1013 Dispatcher.Context.ReferencingObject = CurrentObject;
1014
1015 // Emit base references
1016 Dispatcher.HandleImmutableReference(Class, EMemberlessId::Class, EOrigin::Other);
1017 Dispatcher.HandleImmutableReference(Outer, EMemberlessId::Outer, EOrigin::Other);
1018#if WITH_EDITOR
1019 UObject* Package = CurrentObject->GetExternalPackageInternal();
1020 Package = Package != CurrentObject ? Package : nullptr;
1021 Dispatcher.HandleImmutableReference(Package, EMemberlessId::ExternalPackage, EOrigin::Other);
1022#endif
1023 if (!Schema.IsEmpty())
1024 {
1025 typename DispatcherType::SchemaStackScopeType SchemaStack(Dispatcher.Context, Schema);
1026 Processor.BeginTimingObject(CurrentObject);
1027 Private::VisitMembers(Dispatcher, Schema, CurrentObject);
1028 Processor.UpdateDetailedStats(CurrentObject);
1029 }
1030 }
1031 }
1032
1033#if WITH_VERSE_VM || defined(__INTELLISENSE__)
1035 {
1036 // Not doing any prefetching here, as expected number of native structs is currently small
1037 for (Verse::VNativeStruct* NativeStruct : CurrentNativeStructs)
1038 {
1039 Verse::VEmergentType* EmergentType = NativeStruct->GetEmergentType();
1040 UVerseStruct* VerseStruct = CastChecked<UVerseStruct>(Verse::VNativeStruct::GetUScriptStruct(*EmergentType));
1041 FSchemaView Schema = VerseStruct->ReferenceSchema.Get();
1042 check(!Schema.IsEmpty()); // Native structs with empty schemas should not be in the list to begin with
1043 typename DispatcherType::SchemaStackScopeType SchemaStack(Dispatcher.Context, Schema);
1044 Private::VisitMembers(Dispatcher, Schema, (uint8*)NativeStruct->GetStruct());
1045 }
1046 }
1047#endif
1048
1049 // Some helper templates to detect if the DispatcherType supports FlushWork
1050 template <typename T, typename = void>
1051 struct HasFlushWork : std::false_type {};
1052
1053 template <typename T>
1054 struct HasFlushWork <T, std::void_t<decltype(std::declval<T>().FlushWork())>> : std::true_type {};
1055
1056 FORCEINLINE_DEBUGGABLE void FlushWork(DispatcherType& Dispatcher)
1057 {
1058 if constexpr (DispatcherType::bBatching)
1059 {
1060 if (Dispatcher.FlushToStructBlocks())
1061 {
1062 ProcessStructs(Dispatcher);
1063 }
1064
1065 Dispatcher.FlushQueuedReferences();
1066 }
1067
1068 if constexpr (HasFlushWork<DispatcherType>::value)
1069 {
1070 Dispatcher.FlushWork();
1071 }
1072 }
1073
1074 FORCENOINLINE void ProcessStructs(DispatcherType& Dispatcher);
1075};
1076
1078
1080template <typename ProcessorType>
1082{
1083protected:
1084 ProcessorType& Processor;
1086
1087public:
1092
1093 virtual void HandleObjectReference(UObject*& Object, const UObject* ReferencingObject, const FProperty* ReferencingProperty) override
1094 {
1095 if (!ReferencingObject)
1096 {
1097 ReferencingObject = Context.GetReferencingObject();
1098 }
1099 Processor.HandleTokenStreamObjectReference(Context, const_cast<UObject*>(ReferencingObject), Object, EMemberlessId::Collector, EOrigin::Other, false);
1100 }
1101 virtual void HandleObjectReferences(UObject** InObjects, const int32 ObjectNum, const UObject* ReferencingObject, const FProperty* InReferencingProperty) override
1102 {
1103 if (!ReferencingObject)
1104 {
1105 ReferencingObject = Context.GetReferencingObject();
1106 }
1107 for (int32 ObjectIndex = 0; ObjectIndex < ObjectNum; ++ObjectIndex)
1108 {
1109 UObject*& Object = InObjects[ObjectIndex];
1110 Processor.HandleTokenStreamObjectReference(Context, const_cast<UObject*>(ReferencingObject), Object, EMemberlessId::Collector, EOrigin::Other, false);
1111 }
1112 }
1113
1114#if WITH_VERSE_VM || defined(__INTELLISENSE__)
1115 virtual void HandleVCellReference(Verse::VCell* Cell, const UObject* ReferencingObject, const FProperty* ReferencingProperty) override
1116 {
1117 if (!ReferencingObject)
1118 {
1119 ReferencingObject = Context.GetReferencingObject();
1120 }
1121 if constexpr (HasHandleTokenStreamVerseCellReference<ProcessorType>::value)
1122 {
1123 Processor.HandleTokenStreamVerseCellReference(Context, const_cast<UObject*>(ReferencingObject), Cell, EMemberlessId::Collector, EOrigin::Other);
1124 }
1125 }
1126#endif
1127
1128 virtual bool IsIgnoringArchetypeRef() const override { return false;}
1129 virtual bool IsIgnoringTransient() const override { return false; }
1130};
1131
1133
1134} // namespace UE::GC
1135
1138{
1139public:
1144
1145 static constexpr EGCOptions Options = UE::GC::DefaultOptions;
1146
1147 // These functions are implemented in the GC collectors to generate detail stats on objects considered by GC.
1148 // They are generally not needed for other reference collection tasks.
1149 void BeginTimingObject(UObject* CurrentObject) {}
1150 void UpdateDetailedStats(UObject* CurrentObject) {}
1152
1154 {
1155 return false;
1156 }
1157
1158 // Implement this in your derived class, don't make this virtual as it will affect performance!
1159 //FORCEINLINE void HandleTokenStreamObjectReference(FWorkerContext& Context, UObject* ReferencingObject, UObject*& Object, FMemberId MemberId, EOrigin Origin, bool bAllowReferenceElimination)
1160
1161 // Implement this in your derived class to add VCell support, don't make this virtual as it will affect performance!
1162 //FORCEINLINE void HandleTokenStreamVerseCellReference(FWorkerContext& Context, UObject* ReferencingObject, Verse::VCell* Cell, FMemberId MemberId, EOrigin Origin)
1163};
1164
1165
1166template<class CollectorType, class ProcessorType>
1167FORCEINLINE static void CollectReferences(ProcessorType& Processor, UE::GC::FWorkerContext& Context)
1168{
1169 using namespace UE::GC;
1171
1172 if (IsParallel(ProcessorType::Options) && !UE::GC::GIsIncrementalReachabilityPending)
1173 {
1174 ProcessAsync([](void* P, FWorkerContext& C) { FastReferenceCollector(*reinterpret_cast<ProcessorType*>(P)).ProcessObjectArray(C); }, &Processor, Context);
1175 }
1176 else
1177 {
1179 }
1180}
1181
1182template<class ProcessorType>
1183FORCEINLINE static void CollectReferences(ProcessorType& Processor, UE::GC::FWorkerContext& Context)
1184{
1186}
1187
1188// Get number of workers to use when calling CollectReferences in parallel
1190
1191// Temporary aliases to old types
1192
1196namespace UE::GC { using FTokenId = FMemberId; }
1197namespace UE::GC { using ETokenlessId = EMemberlessId; }
#define FORCENOINLINE
Definition AndroidPlatform.h:142
#define FORCEINLINE
Definition AndroidPlatform.h:140
constexpr auto MakeArrayView(OtherRangeType &&Other)
Definition ArrayView.h:873
#define check(expr)
Definition AssertionMacros.h:314
@ NoInit
Definition CoreMiscDefines.h:158
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define FORCEINLINE_DEBUGGABLE
Definition CoreMiscDefines.h:74
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
FString GetPathNameSafe(const FField *InField, const UObject *StopOuter)
Definition Field.cpp:1150
FString GetNameSafe(const FField *InField)
Definition Field.h:1230
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
constexpr bool EnumHasAllFlags(Enum Flags, Enum Contains)
Definition EnumClassFlags.h:28
#define ENUM_CLASS_FLAGS(Enum)
Definition EnumClassFlags.h:6
constexpr bool IsParallel(EGCOptions Options)
Definition FastReferenceCollector.h:53
constexpr bool IsEliminatingGarbage(EGCOptions Options)
Definition FastReferenceCollector.h:55
constexpr bool IsPendingKill(EGCOptions Options)
Definition FastReferenceCollector.h:57
EGCOptions
Definition FastReferenceCollector.h:43
@ AutogenerateSchemas
@ IncrementalReachability
#define UE_GC_DEBUGNAMES
Definition GarbageCollectionSchema.h:18
int32 GetNumCollectReferenceWorkers()
Definition GarbageCollection.cpp:7324
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
@ Num
Definition MetalRHIPrivate.h:234
bool IsObjectHandleResolved_ForGC(FObjectHandle Handle)
Definition ObjectHandle.h:232
@ CLASS_TokenStreamAssembled
Definition ObjectMacros.h:256
auto GetNum(const TStringConversion< Converter, DefaultConversionSize > &Conversion) -> decltype(Conversion.Length())
Definition StringConv.h:808
FUObjectArray GUObjectArray
Definition UObjectHash.cpp:55
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
static COREUOBJECT_API UGCObjectReferencer * GGCObjectReferencer
Definition GCObject.h:134
Definition FastReferenceCollector.h:68
virtual ~FGarbageCollectionTracer()
Definition FastReferenceCollector.h:70
virtual void PerformReachabilityAnalysisOnObjects(UE::GC::FWorkerContext *Context, EGCOptions Options)=0
Definition UnrealType.h:174
Definition UObjectGlobals.h:2492
Definition ScriptArray.h:328
Definition FastReferenceCollector.h:1138
void UpdateDetailedStats(UObject *CurrentObject)
Definition FastReferenceCollector.h:1150
void LogDetailedStatsSummary()
Definition FastReferenceCollector.h:1151
FORCEINLINE bool IsTimeLimitExceeded() const
Definition FastReferenceCollector.h:1153
void BeginTimingObject(UObject *CurrentObject)
Definition FastReferenceCollector.h:1149
FUObjectItem * ObjectToObjectItem(const UObjectBase *Object)
Definition UObjectArray.h:1117
Definition ArrayView.h:139
Definition Array.h:670
UE_NODEBUG UE_FORCEINLINE_HINT SIZE_T GetAllocatedSize(void) const
Definition Array.h:1059
Definition UnrealString.h.inl:34
Definition ScriptArray.h:21
FORCEINLINE int32 Num() const
Definition ScriptArray.h:40
FORCEINLINE void * GetData()
Definition ScriptArray.h:24
Definition ScriptSparseSet.h:26
Definition Class.h:3793
UE::GC::FSchemaOwner ReferenceSchema
Definition Class.h:4022
Definition GarbageCollectionSchema.h:157
Definition FastReferenceCollector.h:92
FPrefetchingObjectIterator(TConstArrayView< UObject * > Objects)
Definition FastReferenceCollector.h:95
UObject * GetCurrentObject()
Definition FastReferenceCollector.h:114
bool HasMore() const
Definition FastReferenceCollector.h:113
FORCEINLINE_DEBUGGABLE void Advance()
Definition FastReferenceCollector.h:101
Definition GarbageCollectionSchema.h:62
const FSchemaView & Get() const
Definition GarbageCollection.h:81
Definition GarbageCollectionSchema.h:115
const FMemberWord * GetWords() const
Definition GarbageCollectionSchema.h:130
bool IsEmpty() const
Definition GarbageCollectionSchema.h:132
EOrigin GetOrigin() const
Definition GarbageCollectionSchema.h:131
Definition GarbageCollection.cpp:2653
Definition FastReferenceCollector.h:143
FORCEINLINE_DEBUGGABLE void Add(UObject *Object)
Definition FastReferenceCollector.h:154
FWorkstealingQueue * AsyncQueue
Definition FastReferenceCollector.h:213
void SetWorkerIndex(int32 Idx)
Definition FastReferenceCollector.h:199
COREUOBJECT_API void FreeOwningBlock(UObject *const *BlockObjects)
Definition GarbageCollection.cpp:2367
void ResetAsyncQueue()
Definition GarbageCollection.cpp:2386
UE_NONCOPYABLE(FWorkBlockifier)
void Init()
Definition FastReferenceCollector.h:149
FORCEINLINE_DEBUGGABLE FWorkBlock * PopPartialBlock(int32 &OutNum)
Definition FastReferenceCollector.h:170
COREUOBJECT_API ~FWorkBlockifier()
Definition GarbageCollection.cpp:2379
FORCEINLINE FWorkBlock * StealFullBlock() const
Definition FastReferenceCollector.h:187
FORCEINLINE bool IsUnused() const
Definition FastReferenceCollector.h:194
bool HasWork() const
Definition FastReferenceCollector.h:202
int32 GetWorkerIndex() const
Definition FastReferenceCollector.h:200
FORCEINLINE FWorkBlock * PopFullBlock()
Definition FastReferenceCollector.h:182
void SetAsyncQueue(FWorkstealingQueue &Queue)
Definition FastReferenceCollector.h:150
FWorkBlock * SyncQueue
Definition FastReferenceCollector.h:212
UE_BUILD_SHIPPING.
Definition GarbageCollection.cpp:6964
Definition GarbageCollection.cpp:2273
Definition FastReferenceCollector.h:1082
virtual bool IsIgnoringArchetypeRef() const override
Definition FastReferenceCollector.h:1128
virtual bool IsIgnoringTransient() const override
Definition FastReferenceCollector.h:1129
ProcessorType & Processor
Definition FastReferenceCollector.h:1084
TDefaultCollector(ProcessorType &InProcessor, UE::GC::FWorkerContext &InContext)
Definition FastReferenceCollector.h:1088
UE::GC::FWorkerContext & Context
Definition FastReferenceCollector.h:1085
virtual void HandleObjectReference(UObject *&Object, const UObject *ReferencingObject, const FProperty *ReferencingProperty) override
Definition FastReferenceCollector.h:1093
virtual void HandleObjectReferences(UObject **InObjects, const int32 ObjectNum, const UObject *ReferencingObject, const FProperty *InReferencingProperty) override
Definition FastReferenceCollector.h:1101
Definition FastReferenceCollector.h:906
void ProcessObjectArray(FWorkerContext &Context)
Definition FastReferenceCollector.h:910
TFastReferenceCollector(ProcessorType &InProcessor)
Definition FastReferenceCollector.h:908
FORCEINLINE UObject * GetOuter() const
Definition UObjectBase.h:223
static void PrefetchOuter(UObject *Object)
Definition UObjectBase.h:357
static void PrefetchClass(UObject *Object)
Definition UObjectBase.h:356
COREUOBJECT_API UPackage * GetExternalPackageInternal() const
Definition UObjectBase.cpp:327
FORCEINLINE UClass * GetClass() const
Definition UObjectBase.h:217
Definition Object.h:95
Definition VVMVerseStruct.h:33
Definition OverriddenPropertySet.cpp:45
FORCEINLINE_DEBUGGABLE void VisitMembers(DispatcherType &Dispatcher, FSchemaView Schema, ObjectType *Instance)
Definition FastReferenceCollector.h:685
FORCEINLINE FStridedReferenceIterator begin(FStridedReferenceView View)
Definition FastReferenceCollector.h:490
FORCEINLINE_DEBUGGABLE void VisitOptional(DispatcherType &Dispatcher, FSchemaView StructSchema, uint8 *Instance)
Definition FastReferenceCollector.h:585
FORCEINLINE FStridedReferenceIterator end(FStridedReferenceView View)
Definition FastReferenceCollector.h:491
FORCENOINLINE void VisitNestedStructMembers(DispatcherType &Dispatcher, FSchemaView Schema, uint8 *Instance)
Definition FastReferenceCollector.h:751
FORCEINLINE_DEBUGGABLE void VisitStructSet(DispatcherType &Dispatcher, FSchemaView StructSchema, FScriptSet &Set)
Definition FastReferenceCollector.h:537
FORCEINLINE_DEBUGGABLE void CallSlowARO(DispatcherType &Dispatcher, uint32 SlowAROIdx, UObject *Instance, uint32 MemberIdx)
Definition FastReferenceCollector.h:638
FORCEINLINE_DEBUGGABLE void VisitFieldPath(DispatcherType &Dispatcher, FFieldPath &FieldPath, EOrigin Origin, uint32 MemberIdx)
Definition FastReferenceCollector.h:560
FORCEINLINE_DEBUGGABLE void VisitDynamicallyTypedValue(DispatcherType &Dispatcher, UE::FDynamicallyTypedValue &Value)
Definition FastReferenceCollector.h:595
FORCEINLINE_DEBUGGABLE void VisitFieldPathArray(DispatcherType &Dispatcher, TArray< FFieldPath > &FieldPaths, EOrigin Origin, uint32 MemberIdx)
Definition FastReferenceCollector.h:576
FORCEINLINE FStridedReferenceView ToView(FStridedReferenceArray In)
Definition FastReferenceCollector.h:493
FORCEINLINE EOrigin GetSchemaOrigin(FSchemaView Schema, ObjectType *Instance)
Definition FastReferenceCollector.h:670
FORCEINLINE_DEBUGGABLE void VisitStructs(DispatcherType &Dispatcher, FSchemaView StructSchema, uint8 *It, const int32 Num)
Definition FastReferenceCollector.h:512
FORCEINLINE_DEBUGGABLE void VisitStructArray(DispatcherType &Dispatcher, FSchemaView StructSchema, ArrayType &Array)
Definition FastReferenceCollector.h:530
FORCEINLINE uint8 * GetSetData(FScriptSet &Set)
Definition FastReferenceCollector.h:498
FORCEINLINE_DEBUGGABLE void CallARO(DispatcherType &Dispatcher, UObject *Instance, FMemberWord Word)
Definition FastReferenceCollector.h:609
Definition GCObjectReferencer.cpp:27
bool GIsIncrementalReachabilityPending
Definition GarbageCollection.cpp:620
ELoot
Definition FastReferenceCollector.h:885
ELoot StealWork(FWorkerContext &Context, FReferenceCollector &Collector, FWorkBlock *&OutBlock, EGCOptions Options)
Definition GarbageCollection.cpp:7100
EMemberlessId
Definition GarbageCollectionSchema.h:145
EOrigin
Definition GarbageCollectionSchema.h:53
void SuspendWork(FWorkerContext &Context)
Definition GarbageCollection.cpp:7091
void PadObjectArray(TArray< UObject * > &Objects)
Definition GarbageCollection.cpp:2106
constexpr EGCOptions DefaultOptions
Definition FastReferenceCollector.h:1132
EMemberType
Definition GarbageCollectionSchema.h:25
void ProcessAsync(void(*ProcessSync)(void *, FWorkerContext &), void *Processor, FWorkerContext &InContext)
Definition GarbageCollection.cpp:7238
TDirectDispatcher< ProcessorType > GetDispatcher(CollectorType &Collector, ProcessorType &Processor, FWorkerContext &Context)
Definition FastReferenceCollector.h:871
Definition Archive.h:36
Definition FieldPath.h:36
Definition FastReferenceCollector.h:61
static FORCEINLINE void ClearCachedField(FFieldPath &Path)
Definition FastReferenceCollector.h:63
static FORCEINLINE FUObjectItem * GetResolvedOwner(FFieldPath &Path)
Definition FastReferenceCollector.h:62
static FORCEINLINE void Prefetch(const void *Ptr)
Definition GenericPlatformMisc.h:1443
Definition ScriptSparseSet.h:13
Definition UObjectArray.h:50
UE_FORCEINLINE_HINT bool HasAnyFlags(EInternalObjectFlags InFlags) const
Definition UObjectArray.h:309
Definition UnrealTemplate.h:341
Definition DynamicallyTypedValue.h:72
Definition FastReferenceCollector.h:439
FDebugSchemaStackNoOpScope(FWorkerContext &InContext, FSchemaView Schema)
Definition FastReferenceCollector.h:440
Definition FastReferenceCollector.h:303
FSchemaView Schema
Definition FastReferenceCollector.h:306
FORCEINLINE void SetMemberId(FMemberId MemberId)
Definition FastReferenceCollector.h:322
FDebugSchemaStackNode * Prev
Definition FastReferenceCollector.h:307
COREUOBJECT_API FString ToString() const
Definition GarbageCollection.cpp:3732
FMemberId Member
Definition FastReferenceCollector.h:305
FDebugSchemaStackNode()
Definition FastReferenceCollector.h:309
FDebugSchemaStackNode(FSchemaView InSchema, FDebugSchemaStackNode *PrevNode)
Definition FastReferenceCollector.h:314
Definition FastReferenceCollector.h:414
~FDebugSchemaStackScope()
Definition FastReferenceCollector.h:430
FDebugSchemaStackScope(FWorkerContext &InContext, FSchemaView Schema)
Definition FastReferenceCollector.h:420
FDebugSchemaStackNode Node
Definition FastReferenceCollector.h:417
FWorkerContext & Context
Definition FastReferenceCollector.h:416
Definition GarbageCollectionSchema.h:181
Definition GarbageCollectionSchema.h:195
Definition FastReferenceCollector.h:245
FORCEINLINE void AddReferences(uint32 Num)
Definition FastReferenceCollector.h:261
bool bFoundGarbageRef
Definition FastReferenceCollector.h:259
uint32 NumVerseCells
Definition FastReferenceCollector.h:258
uint32 NumObjects
Definition FastReferenceCollector.h:256
FORCEINLINE void AddVerseCells(uint32 Num)
Definition FastReferenceCollector.h:262
uint32 NumReferences
Definition FastReferenceCollector.h:257
FORCEINLINE void AddObjects(uint32 Num)
Definition FastReferenceCollector.h:260
FORCEINLINE void TrackPotentialGarbageReference(bool bDetectedGarbage)
Definition FastReferenceCollector.h:263
void AddStats(FProcessorStats Stats)
Definition FastReferenceCollector.h:266
Definition FastReferenceCollector.h:234
static COREUOBJECT_API void CallSync(uint32 SlowAROIndex, UObject *Object, FReferenceCollector &Collector)
Definition GarbageCollection.cpp:2853
static COREUOBJECT_API bool ProcessAllCalls(FWorkerContext &Context, FReferenceCollector &Collector)
Definition GarbageCollection.cpp:2876
static COREUOBJECT_API bool TryQueueCall(uint32 SlowAROIndex, UObject *Object, FWorkerContext &Context)
Definition GarbageCollection.cpp:2858
static COREUOBJECT_API void ProcessUnbalancedCalls(FWorkerContext &Context, FReferenceCollector &Collector)
Definition GarbageCollection.cpp:2872
Definition GarbageCollectionSchema.h:208
uint16 WordOffset
Definition GarbageCollectionSchema.h:209
uint16 WordStride
Definition GarbageCollectionSchema.h:210
Definition GarbageCollection.cpp:1790
Definition FastReferenceCollector.h:276
uint32 Stride
Definition FastReferenceCollector.h:280
int32 Num
Definition FastReferenceCollector.h:279
FSchemaView Schema
Definition FastReferenceCollector.h:277
uint8 * Data
Definition FastReferenceCollector.h:278
Definition FastReferenceCollector.h:284
FStructArrayBlock * Wip
Definition FastReferenceCollector.h:285
FORCEINLINE bool ContainsBatchData() const
Definition FastReferenceCollector.h:288
FStructArray * WipIt
Definition FastReferenceCollector.h:286
Definition FastReferenceCollector.h:295
UObject ** Reference
Definition FastReferenceCollector.h:297
UObject * ReferencedObject
Definition FastReferenceCollector.h:296
UObject * ReferenceOwner
Definition FastReferenceCollector.h:298
Definition FastReferenceCollector.h:129
UObject * Objects[ObjectCapacity+ObjectLookahead]
Definition FastReferenceCollector.h:133
TArrayView< UObject * > GetPadding()
Definition FastReferenceCollector.h:136
TArrayView< UObject * > GetObjects()
Definition FastReferenceCollector.h:135
FWorkBlock * Previous
Definition FastReferenceCollector.h:132
static constexpr uint32 ObjectCapacity
Definition FastReferenceCollector.h:130
Definition FastReferenceCollector.h:334
TArray< FWeakReferenceInfo > WeakReferences
Definition FastReferenceCollector.h:354
void SetInitialObjectsUnpadded(TArray< UObject * > &Objects)
Definition FastReferenceCollector.h:376
TArray< FGarbageReferenceInfo > GarbageReferences
Definition FastReferenceCollector.h:358
UE_NONCOPYABLE(FWorkerContext)
int64 GetAllocatedSize() const
Definition FastReferenceCollector.h:401
FWorkBlockifier ObjectsToSerialize
Definition FastReferenceCollector.h:351
FSuspendedStructBatch IncrementalStructs
Definition FastReferenceCollector.h:364
TConstArrayView< UObject * > GetInitialObjects()
Definition FastReferenceCollector.h:372
FORCEINLINE int32 GetWorkerIndex() const
Definition FastReferenceCollector.h:406
FProcessorStats Stats
Definition FastReferenceCollector.h:355
void SetInitialObjectsPrepadded(TConstArrayView< UObject * > PaddedObjects)
Definition FastReferenceCollector.h:383
FORCEINLINE UObject * GetReferencingObject()
Definition FastReferenceCollector.h:370
TConstArrayView< UObject ** > InitialNativeReferences
Definition FastReferenceCollector.h:352
void ResetInitialObjects()
Definition FastReferenceCollector.h:373
Definition FastReferenceCollector.h:450
uint32 WordOffset
Definition FastReferenceCollector.h:458
FMemberUnpacked(FMemberPacked In)
Definition FastReferenceCollector.h:451
EMemberType Type
Definition FastReferenceCollector.h:457
Definition FastReferenceCollector.h:462
FMemberWordUnpacked(const FMemberPacked In[4])
Definition FastReferenceCollector.h:463
Definition FastReferenceCollector.h:468
FStridedLayout Layout
Definition FastReferenceCollector.h:470
FScriptArray * Array
Definition FastReferenceCollector.h:469
Definition FastReferenceCollector.h:481
UObject ** It
Definition FastReferenceCollector.h:482
FStridedReferenceIterator & operator++()
Definition FastReferenceCollector.h:486
UObject *& operator*()
Definition FastReferenceCollector.h:485
uint32 Stride
Definition FastReferenceCollector.h:483
bool operator!=(FStridedReferenceIterator Rhs) const
Definition FastReferenceCollector.h:487
Definition FastReferenceCollector.h:474
uint32 Stride
Definition FastReferenceCollector.h:477
int32 Num
Definition FastReferenceCollector.h:476
UObject ** Data
Definition FastReferenceCollector.h:475
Definition FastReferenceCollector.h:776
FORCEINLINE void HandleKillableArray(Private::FStridedReferenceArray Array, FMemberId MemberId, EOrigin Origin) const
Definition FastReferenceCollector.h:818
FWorkerContext & Context
Definition FastReferenceCollector.h:782
void SetDebugSchemaStackMemberId(FMemberId Member)
Definition FastReferenceCollector.h:863
void Suspend()
Definition FastReferenceCollector.h:859
FORCEINLINE void HandleImmutableReference(UObject *Object, FMemberId MemberId, EOrigin Origin) const
Definition FastReferenceCollector.h:799
FReferenceCollector & Collector
Definition FastReferenceCollector.h:783
FORCEINLINE void HandleKillableArray(TArray< UObject * > &Array, FMemberId MemberId, EOrigin Origin) const
Definition FastReferenceCollector.h:813
FORCEINLINE void HandleReferenceDirectly(UObject *ReferencingObject, UObject *&Object, FMemberId MemberId, EOrigin Origin, bool bAllowReferenceElimination) const
Definition FastReferenceCollector.h:785
ProcessorType & Processor
Definition FastReferenceCollector.h:781
FORCEINLINE void HandleKillableReference(UObject *&Object, FMemberId MemberId, EOrigin Origin) const
Definition FastReferenceCollector.h:794
FORCEINLINE void HandleKillableReferences(ArrayType &&Objects, FMemberId MemberId, EOrigin Origin) const
Definition FastReferenceCollector.h:805
FDebugSchemaStackScope SchemaStackScopeType
Definition FastReferenceCollector.h:780
Definition FastReferenceCollector.h:878
typename std::remove_reference_t< RetType > Type
Definition FastReferenceCollector.h:880
decltype(GetDispatcher(*(CollectorType *) nullptr, *(ProcessorType *) nullptr, *(FWorkerContext *) nullptr)) RetType
Definition FastReferenceCollector.h:879
Definition GarbageCollectionSchema.h:214