UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
VVMWriteBarrier.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#if WITH_VERSE_VM || defined(__INTELLISENSE__)
6
7#include "UObject/Object.h"
9#include "VVMAux.h"
10#include "VVMContext.h"
11#include "VVMContextImpl.h"
12#include "VVMValue.h"
13
14namespace Verse
15{
16
17// This class is a smart pointer that runs a GC write barrier whenever the stored pointer is changed
18// Fundamental law of concurrent GC: when thoust mutated the heap thou shalt run the barrier template
19// When a VValue of heap pointer type (VCell*) is written, a barrier is run (int32s and floats don't run a barrier)
20// The barrier will inform the GC about a new edge in the heap, and GC will immediately mark the cell if a collection is ongoing
21// This is necessary because GC might have already visited the previous content of Value, and might miss the updated value in that case
22// No barrier is needed when _deleting_ heap references, therefore we don't care about the previous Value during mutation
23// It does not matter if the barrier is run before or after mutation since we unconditionally mark only the new value
24// We also run the barrier during TWriteBarrier construction since a white (= otherwise unreachable) cell might have been assigned
25// New cells are allocated black (marked, reachable) so we are not worried about those here
26template <typename T>
27struct TWriteBarrier
28{
29 static constexpr bool bIsVValue = std::is_same_v<T, VValue> || std::is_same_v<T, VInt>;
30 static constexpr bool bIsAux = IsTAux<T>;
31 using TValue = typename std::conditional_t<bIsVValue || bIsAux, T, T*>;
32 using TConstValue = typename std::conditional_t<bIsVValue || bIsAux, T, const T*>;
33 using TEncodedValue = typename std::conditional<bIsVValue, uint64, T*>::type;
34
35 TWriteBarrier() = default;
36
39 {
41 Value = Other.Value;
42 }
43
44 TWriteBarrier& operator=(const TWriteBarrier& Other)
45 {
47 Value = Other.Value;
48 return *this;
49 }
50
53 {
55 Move(Value, Other.Value);
56 }
57
59 {
61 Move(Value, Other.Value);
62 return *this;
63 }
64
65 bool Equals(const TWriteBarrier& Other) const
66 {
67 return Value == Other.Value;
68 }
69
70 // Needed to allow for `TWriteBarrier` to be usable with `TMap`.
71 bool operator==(const TWriteBarrier& Other) const
72 {
73 return Equals(Other);
74 }
75
76 // Allows `TMap::RemoveByHash` to match a `VCell*` with a `TWriteBarrier<VCell>`, or a
77 // `VValue` with a `TWriteBarrier<VValue>`, which lets us remove elements from a container
78 // without constructing an extraneous write barrier.
79 bool operator==(TConstValue Other) const
80 {
81 return Value == Other;
82 }
83
85 {
87 }
88
89 template <
90 typename U = T,
91 std::enable_if_t<!bIsVValue && std::is_convertible_v<U*, T*>>* = nullptr>
92 TWriteBarrier(FAccessContext Context, std::enable_if_t<!bIsVValue, U>& Value)
93 {
94 Set(Context, &Value);
95 }
96
97 void Reset()
98 {
99 if constexpr (bIsVValue || bIsAux)
100 {
101 Value = {};
102 }
103 else
104 {
105 Value = nullptr;
106 }
107 }
108
109 void ResetTransactionally(FAllocationContext);
110
111 template <bool bTransactional, typename TContext>
112 void Reset(TContext&& Context)
113 {
114 if constexpr (bTransactional)
115 {
117 }
118 else
119 {
120 Reset();
121 }
122 }
123
124 void Set(FAccessContext Context, TValue NewValue)
125 {
126 RunBarrier(Context, NewValue);
127 Value = NewValue;
128 }
129
130 template <typename TResult = void>
131 std::enable_if_t<!bIsVValue, TResult> Set(FAccessContext Context, T& NewValue)
132 {
133 Set(Context, &NewValue);
134 }
135
136 void SetTransactionally(FAllocationContext, TValue);
137
138 template <typename TResult = void>
139 std::enable_if_t<!bIsVValue, TResult> SetTransactionally(FAllocationContext, T&);
140
141 template <bool bTransactional, typename TContext, typename TArg>
142 void Set(TContext&& Context, TArg&& Arg)
143 {
144 if constexpr (bTransactional)
145 {
147 }
148 else
149 {
151 }
152 }
153
154 void SetTrailed(FAllocationContext, TValue);
155
156 template <typename TResult = void>
157 constexpr std::enable_if_t<bIsVValue, TResult> SetNonCellNorPlaceholder(VValue NewValue)
158 {
159 checkSlow(!NewValue.IsCell());
160 checkSlow(!NewValue.IsPlaceholder());
161 Value = NewValue;
162 }
163
164 template <typename TResult = void>
165 std::enable_if_t<bIsVValue, TResult> SetNonCellNorPlaceholderTransactionally(FAllocationContext, VValue);
166
167 template <typename TResult = void>
168 std::enable_if_t<bIsVValue, TResult> SetNonCellNorPlaceholderTrailed(FAllocationContext, VValue);
169
170 TValue Get() const { return Value; }
171 template <typename TResult = TValue>
172 std::enable_if_t<bIsVValue, TResult> Follow() const { return Get().Follow(); }
173
174 // nb: operators "*" and "->" disabled for TWriteBarrier<VValue>;
175 // use Get() + VValue member functions to check/access boxed values
176
177 template <typename TResult = TValue>
178 std::enable_if_t<!bIsVValue && !bIsAux, TResult> operator->() const { return Value; }
179
180 template <typename TResult = T>
181 std::enable_if_t<!bIsVValue && !bIsAux, TResult&> operator*() const { return *Value; }
182
183 explicit operator bool() const { return !!Value; }
184
186 {
187 using ::GetTypeHash;
188 if constexpr (bIsVValue)
189 {
190 return GetTypeHash(WriteBarrier.Get());
191 }
192 else if (WriteBarrier)
193 {
194 return GetTypeHash(*WriteBarrier.Get());
195 }
196 else
197 {
198 return 0;
199 }
200 }
201
202private:
203 TValue Value{};
204
205 template <typename ContextType>
206 static void RunBarrier(ContextType Context, TValue Value)
207 {
208 if (!FHeap::IsMarking())
209 {
210 return;
211 }
213 {
214 if constexpr (bIsAux)
215 {
216 if (!FHeap::IsMarked(Value.GetPtr()))
217 {
218 FAccessContext(Context).RunAuxWriteBarrierNonNullDuringMarking(Value.GetPtr());
219 }
220 }
221 else if constexpr (bIsVValue)
222 {
223 if (VCell* Cell = Value.ExtractCell())
224 {
225 if (!FHeap::IsMarked(Cell))
226 {
227 // Delay construction of the context (which does the expensive TLS lookup), until we actually need the mark stack to do marking.
228 FAccessContext(Context).RunWriteBarrierNonNullDuringMarking(Cell);
229 }
230 }
231 else if (UObject* Object = Value.ExtractUObject())
232 {
234 {
235 Object->VerseMarkAsReachable();
236 }
237 }
238 }
239 else
240 {
241 VCell* Cell = reinterpret_cast<VCell*>(Value);
242 if (Cell && !FHeap::IsMarked(Cell))
243 {
244 FAccessContext(Context).RunWriteBarrierNonNullDuringMarking(Cell);
245 }
246 }
247 };
248 }
249};
250
251template <typename TArg>
253} // namespace Verse
254
255template <class VCellType>
256inline void FReferenceCollector::AddReferencedVerseValue(Verse::TWriteBarrier<VCellType>& InValue, const UObject* ReferencingObject, const FProperty* ReferencingProperty)
257{
258 if constexpr (Verse::TWriteBarrier<VCellType>::bIsAux)
259 {
260 static_assert(!Verse::TWriteBarrier<VCellType>::bIsAux, "AddReferencedVerseValue: Element must be a VValue or a type derived from VCell");
261 }
262 else if constexpr (Verse::TWriteBarrier<VCellType>::bIsVValue)
263 {
264 Verse::VValue Value = InValue.Get();
265 if (Verse::VCell* Cell = Value.ExtractCell())
266 {
267 HandleVCellReference(Cell, ReferencingObject, ReferencingProperty);
268 }
269 else if (UObject* Object = Value.ExtractUObject())
270 {
272 }
273 }
274 else
275 {
276 Verse::VCell* Cell = InValue.Get();
277 HandleVCellReference(Cell, ReferencingObject, ReferencingProperty);
278 }
279}
280#endif // WITH_VERSE_VM
#define checkSlow(expr)
Definition AssertionMacros.h:332
UE_FORCEINLINE_HINT FLinearColor operator*(float Scalar, const FLinearColor &Color)
Definition Color.h:473
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
const bool
Definition NetworkReplayStreaming.h:178
void Move(T &A, typename TMoveSupportTraits< T >::Copy B)
Definition UnrealTemplate.h:24
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition UnrealType.h:174
virtual void HandleObjectReference(UObject *&InObject, const UObject *InReferencingObject, const FProperty *InReferencingProperty)=0
Definition Object.h:95
uint32 GetTypeHash(const FKey &Key)
Definition BlackboardKey.h:35
FORCEINLINE T * Get(const FObjectPtr &ObjectPtr)
Definition ObjectPtr.h:426
bool operator==(const FCachedAssetKey &A, const FCachedAssetKey &B)
Definition AssetDataMap.h:501
bool GIsIncrementalReachabilityPending
Definition GarbageCollection.cpp:620
Definition Archive.h:36