UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
DynamicallyTypedValue.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 "HAL/UnrealMemory.h"
11#include "UObject/Object.h"
13#include "AutoRTFM.h"
14
15#if WITH_VERSE_VM
16#include "VerseVM/VVMContext.h"
17#include "VerseVM/VVMValue.h"
18#endif
19
21
22namespace UE
23{
24 // Provides methods to interact with values of a specific type.
26 {
27 enum class EContainsReferences : bool
28 {
29 DoesNot,
30 Maybe,
31 };
32
39
40 // Marks the type itself as reachable.
41 virtual void MarkReachable(FReferenceCollector& Collector) = 0;
42
43 // Marks a value of the type as reachable.
44 virtual void MarkValueReachable(void* Data, FReferenceCollector& Collector) const = 0;
45
46 virtual void InitializeValue(void* Data) const = 0;
47 virtual void InitializeValueFromCopy(void* DestData, const void* SourceData) const = 0;
48 virtual void DestroyValue(void* Data) const = 0;
49
50#if WITH_VERSE_VM
51 virtual ::Verse::VValue ToVValue(::Verse::FAllocationContext Context, const void* Data) const = 0;
52#endif
53
54 virtual void SerializeValue(FStructuredArchive::FSlot Slot, void* Data, const void* DefaultData) const = 0;
55
56 virtual uint32 GetValueHash(const void* Data) const = 0;
57 virtual bool AreIdentical(const void* DataA, const void* DataB) const = 0;
58
59 SIZE_T GetNumBytes() const { return NumBytes; }
60 uint8 GetMinAlignmentLogTwo() const { return MinAlignmentLogTwo; }
61 uint32 GetMinAlignment() const { return 1u << MinAlignmentLogTwo; }
62 EContainsReferences GetContainsReferences() const { return ContainsReferences; }
63
64 private:
65 const SIZE_T NumBytes;
66 const uint8 MinAlignmentLogTwo;
67 const EContainsReferences ContainsReferences;
68 };
69
70 // An value stored in some uninterpreted memory and a pointer to a type that contains methods to interpret it.
72 {
74
76 {
77 // We need `this` to be in a special state such that if we've created this within a transaction
78 // the GC will be able to destroy the value. To do that it needs a very specific null state,
79 // which is what `InitializeToNull` gives us. So run this in the open, but disable any memory
80 // validation on the value as its fine if we've written to this in the open, then write to it in
81 // the closed. Those closed writes will be undone, reverting the value back to the specific null
82 // state, which the GC can handle.
83 UE_AUTORTFM_OPEN_NO_VALIDATION { InitializeToNull(); };
84 }
85
86 // Use a delegated constructor so that the value is nulled correctly before initialized from the copy.
88
89 // Use a delegated constructor so that the value is nulled correctly before initialized from the move.
91
93
95 {
96 if (this != &Copyee)
97 {
98 Deinit();
99 InitializeFromCopy(Copyee);
100 }
101 return *this;
102 }
104 {
105 if (this != &Movee)
106 {
107 Deinit();
108 InitializeFromMove(MoveTemp(Movee));
109 }
110 return *this;
111 }
112
113 // Returns a pointer to the value's data.
114 const void* GetDataPointer() const { return IsInline() ? &InlineData : HeapData; }
115 void* GetDataPointer() { return IsInline() ? &InlineData : HeapData; }
116
117 // Returns the value's type.
118 FDynamicallyTypedValueType& GetType() const { return *Type; }
119
120 // Sets the value to the null state.
122 {
123 Deinit();
124 InitializeToNull();
125 }
126
127 // Sets the value to the initial value of a type.
129 {
130 check(&NewType != nullptr);
131 Deinit();
132 Type = &NewType;
133 AllocateData();
135 MarkTypeReachableIfIncrementalReachabilityPending();
136 }
137
138#if WITH_VERSE_VM
139 ::Verse::VValue ToVValue(::Verse::FAllocationContext Context) const
140 {
141 return Type->ToVValue(Context, GetDataPointer());
142 }
143#endif
144
145 // Returns hash of the underlying FDynamicallyTypedValue's value. Added to allow for FDynamicallyTypedValue to be used as TMap keys.
146 [[nodiscard]] friend uint32 GetTypeHash(const FDynamicallyTypedValue& DynamicallyTypedValue)
147 {
148 return DynamicallyTypedValue.GetType().GetValueHash(DynamicallyTypedValue.GetDataPointer());
149 }
150
151 private:
152 void MarkTypeReachableIfIncrementalReachabilityPending()
153 {
154 struct FTypeReferenceCollector final : public FReferenceCollector
155 {
156 bool IsIgnoringArchetypeRef() const override { return false; }
157 bool IsIgnoringTransient() const override { return false; }
158 void HandleObjectReference(UObject*& InObject, const UObject* InReferencingObject, const FProperty* InReferencingProperty) override
159 {
160 if (InObject)
161 {
162 UE::GC::MarkAsReachable(InObject);
163 }
164 }
165 };
166
168 {
169 // nb: this is done to simulate a write barrier for this type, which
170 // enables it to behave properly with incremental gc.
172 Type->MarkReachable(Collector);
173 }
174 }
175
176 FDynamicallyTypedValueType* Type;
177
178 // Store pointer-sized or smaller values inline, heap allocate all others.
179 union
180 {
182 void* HeapData;
183 };
184
185 // Initialize this value from the primordial state to the null state.
186 void InitializeToNull()
187 {
188 Type = &NullType();
189 HeapData = nullptr;
190 MarkTypeReachableIfIncrementalReachabilityPending();
191 }
192 // Deinitializes this value back to the primordial state.
193 void Deinit()
194 {
195 Type->DestroyValue(GetDataPointer());
196 FreeData();
197 Type = nullptr;
198 }
199 // Copies the data from another value to this one, which is assumed to be in the primordial state.
200 void InitializeFromCopy(const FDynamicallyTypedValue& Copyee)
201 {
202 Type = Copyee.Type;
203 AllocateData();
204 Type->InitializeValueFromCopy(GetDataPointer(), Copyee.GetDataPointer());
205 MarkTypeReachableIfIncrementalReachabilityPending();
206 }
207 // Moves the data from another value to this one, which is assumed to be in the primordial state.
208 // The source value is set to the null state.
209 void InitializeFromMove(FDynamicallyTypedValue&& Movee)
210 {
211 // Simply copy the type and data from the source value.
212 // This assumes that the data is trivially relocatable.
213 Type = Movee.Type;
214 InlineData = Movee.InlineData;
215 MarkTypeReachableIfIncrementalReachabilityPending();
216
217 // Reset the source value to null.
218 Movee.InitializeToNull();
219 }
220
221 // Whether the value's data is stored in InlineData or in the memory pointed to by HeapData.
222 bool IsInline() const
223 {
224 return Type->GetNumBytes() <= sizeof(UPTRINT)
225 && Type->GetMinAlignmentLogTwo() <= UE_FORCE_CONSTEVAL(FMath::ConstExprCeilLogTwo(alignof(UPTRINT)));
226 }
227
228 // Allocates heap memory for the value if it uses it.
229 void AllocateData()
230 {
231 if (IsInline())
232 {
233 // Ensure that the data is zeroed in the inline case to avoid spurious static analysis
234 // errors about passing a reference to uninitialized data to InitializeValueFromCopy.
235 InlineData = 0;
236 }
237 else
238 {
239 HeapData = FMemory::Malloc(Type->GetNumBytes(), Type->GetMinAlignment());
240 }
241 }
242
243 // Frees heap memory for the value if it uses it.
244 void FreeData()
245 {
246 if (!IsInline())
247 {
249 HeapData = nullptr;
250 }
251 else if (::AutoRTFM::IsClosed())
252 {
253 // Assign to InlineData if we're in a closed transaction.
254 // This is done to ensure that the value of InlineData is
255 // recorded in the transaction. This is important as some
256 // code paths destruct then re-construct the
257 // FDynamicallyTypedValue, and the constructor calls
258 // InitializeToNull() in the open (without recording the initial
259 // values). This can result in the FDynamicallyTypedValue being
260 // nulled without a write record to restore the original value.
261 InlineData = 0;
262 }
263 }
264 };
265}
266
#define check(expr)
Definition AssertionMacros.h:314
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::UPTRINT UPTRINT
An unsigned integer the same size as a pointer.
Definition Platform.h:1146
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define UE_FORCE_CONSTEVAL(expr)
Definition UnrealTemplate.h:246
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
#define Expose_TNameOf(type)
Definition UnrealTypeTraits.h:199
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition UnrealType.h:174
Definition UObjectGlobals.h:2492
Definition StructuredArchiveSlots.h:52
Definition Object.h:95
Type
Definition PawnAction_Move.h:11
bool GIsIncrementalReachabilityPending
Definition GarbageCollection.cpp:620
void MarkAsReachable(const UObject *Obj)
Definition GarbageCollection.cpp:603
Definition AdvancedWidgetsModule.cpp:13
static FORCENOINLINE CORE_API void Free(void *Original)
Definition UnrealMemory.cpp:685
Definition DynamicallyTypedValue.h:26
EContainsReferences GetContainsReferences() const
Definition DynamicallyTypedValue.h:62
uint8 GetMinAlignmentLogTwo() const
Definition DynamicallyTypedValue.h:60
virtual bool AreIdentical(const void *DataA, const void *DataB) const =0
virtual void DestroyValue(void *Data) const =0
virtual void InitializeValue(void *Data) const =0
uint32 GetMinAlignment() const
Definition DynamicallyTypedValue.h:61
virtual void MarkReachable(FReferenceCollector &Collector)=0
EContainsReferences
Definition DynamicallyTypedValue.h:28
virtual void InitializeValueFromCopy(void *DestData, const void *SourceData) const =0
constexpr FDynamicallyTypedValueType(SIZE_T InNumBytes, uint8 InMinAlignmentLogTwo, EContainsReferences InContainsReferences)
Definition DynamicallyTypedValue.h:33
virtual void MarkValueReachable(void *Data, FReferenceCollector &Collector) const =0
virtual uint32 GetValueHash(const void *Data) const =0
SIZE_T GetNumBytes() const
Definition DynamicallyTypedValue.h:59
virtual void SerializeValue(FStructuredArchive::FSlot Slot, void *Data, const void *DefaultData) const =0
Definition DynamicallyTypedValue.h:72
~FDynamicallyTypedValue()
Definition DynamicallyTypedValue.h:92
FDynamicallyTypedValue & operator=(const FDynamicallyTypedValue &Copyee)
Definition DynamicallyTypedValue.h:94
void SetToNull()
Definition DynamicallyTypedValue.h:121
static COREUOBJECT_API FDynamicallyTypedValueType & NullType()
Definition DynamicallyTypedValue.cpp:5
friend uint32 GetTypeHash(const FDynamicallyTypedValue &DynamicallyTypedValue)
Definition DynamicallyTypedValue.h:146
UPTRINT InlineData
Definition DynamicallyTypedValue.h:181
void * GetDataPointer()
Definition DynamicallyTypedValue.h:115
FDynamicallyTypedValue()
Definition DynamicallyTypedValue.h:75
FDynamicallyTypedValueType & GetType() const
Definition DynamicallyTypedValue.h:118
const void * GetDataPointer() const
Definition DynamicallyTypedValue.h:114
void * HeapData
Definition DynamicallyTypedValue.h:182
FDynamicallyTypedValue(FDynamicallyTypedValue &&Movee)
Definition DynamicallyTypedValue.h:90
void InitializeAsType(FDynamicallyTypedValueType &NewType)
Definition DynamicallyTypedValue.h:128
FDynamicallyTypedValue & operator=(FDynamicallyTypedValue &&Movee)
Definition DynamicallyTypedValue.h:103
FDynamicallyTypedValue(const FDynamicallyTypedValue &Copyee)
Definition DynamicallyTypedValue.h:87