UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
VVMValue.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
8#include "CoreTypes.h"
11#include "VVMMarkStack.h"
12#include "VerseVM/VVMFloat.h"
13
14#include <cinttypes>
15
16class UObject;
17class FJsonObject;
18class FJsonValue;
19
20namespace Verse
21{
22enum class EValueStringFormat;
23enum class EValueJSONFormat;
24enum class EVisitState;
25struct FAccessContext;
26struct FAllocationContext;
27struct FRunningContext;
28struct FOp;
29struct FOpResult;
30struct FPlaceholder;
31struct VCell;
32struct VContext;
33struct VFrame;
34struct VInt;
35struct VPlaceholder;
36struct VSuspension;
37struct VTask;
38struct VRef;
40
41enum class ECompares : uint8
42{
43 Neq,
44 Eq,
46};
47
48struct VValue
49{
50 // Default constructor: initializes to an uninitialized sentry value.
51 constexpr VValue()
52 : EncodedBits(UninitializedValue)
53 {
54 }
55
56 // Untagged value coercion constructors.
57 VValue(VCell& Cell);
58
59 VValue(UObject* Object);
60
62 VValue(std::nullptr_t) = delete;
63
64 static VValue FromInt32(int32 Int32)
65 {
66 VValue Result;
67 Result.EncodedBits = static_cast<uint32>(Int32) | Int32Tag;
68 checkSlow(Result.IsInt32());
69 return Result;
70 }
71
72 VValue(VFloat Float)
73 {
74 uint64 FloatAsU64 = Float.ReinterpretAsUInt64();
75 EncodedBits = FloatAsU64 + FloatOffset;
76 checkfSlow(FloatAsU64 <= MaxPureNaN, TEXT("Casting impure NaN to VValue: 0x%" PRIx64), FloatAsU64);
77 checkSlow(IsFloat());
78 }
79
80 static VValue FromBool(bool Value);
81
82 static VValue EffectDoneMarker()
83 {
84 return FromInt32(static_cast<int32>(0xeffec7));
85 }
86
87 static VValue CreateFieldMarker()
88 {
89 return FromInt32(static_cast<int32>(0xc2ea7e));
90 }
91
92 static VValue ConstructedMarker()
93 {
94 return FromInt32(static_cast<int32>(0x5e7));
95 }
96
97 // Copy constructor/assignment operator
98 constexpr VValue(const VValue& Copyee)
99 : EncodedBits(Copyee.EncodedBits)
100 {
101 }
102 constexpr VValue& operator=(const VValue& Copyee)
103 {
104 EncodedBits = Copyee.EncodedBits;
105 return *this;
106 }
107
108 // Note: This isn't what you want if you want a deep equality check.
109 bool operator==(const VValue& Other) const { return EncodedBits == Other.EncodedBits; }
110 bool operator!=(const VValue& Other) const { return !(*this == Other); }
111 explicit operator bool() const { return EncodedBits != UninitializedValue; }
112
113 // Note: This is what you want if you want a deep equality check.
114 // This will return true if left and/or right are placeholders.
115 template <typename HandlePlaceholderFunction>
117
118 // This may return a placeholder which is suspended upon as a FOpResult::Block result would be.
119 static VValue Melt(FAllocationContext Context, VValue Value);
120 static FOpResult Freeze(FAllocationContext Context, VValue Value, VTask*, FOp* AwaitPC);
121
122 static constexpr VValue Decode(uint64 EncodedBits)
123 {
124 VValue Result;
125 Result.EncodedBits = EncodedBits;
126 return Result;
127 }
128
129 uint64 Encode() const
130 {
131 return EncodedBits;
132 }
133
134 VValue(VPlaceholder&) = delete;
135 bool IsPlaceholder() const { return (EncodedBits & NonCellTagMask) == PlaceholderTag; }
136 static VValue Placeholder(const VPlaceholder& Placeholder)
137 {
138 VValue Result = VValue::Decode(BitCast<uint64>(&Placeholder) | PlaceholderTag);
139 checkSlow(Result.IsPlaceholder());
140 return Result;
141 }
142
143 VValue Follow() const;
144 // This assumes we're a placeholder, does Follow(), and assumes we don't point
145 // (even transitively) to a concrete value. So we must be a placeholder and the
146 // placeholder we point at (transitively) isn't resolved.
147 VPlaceholder& GetRootPlaceholder(); // This does Follow()
149 {
151 return *BitCast<VPlaceholder*>(EncodedBits & ~PlaceholderTag);
152 }
153
155 {
156 if ((EncodedBits & NonCellTagMask) == TransparentRefTag)
157 {
158 return BitCast<VRef*>(EncodedBits & ~TransparentRefTag);
159 }
160 return nullptr;
161 }
162
163 static VValue TransparentRef(VRef& Ref)
164 {
165 return VValue::Decode(BitCast<uint64>(&Ref) | TransparentRefTag);
166 }
167
168 bool IsInt32() const { return (EncodedBits & NumberTagMask) == Int32Tag; }
169 bool IsUint32() const;
170 uint32 AsUint32() const;
171
172 // Returns Value as C++ style int32
173 int32 AsInt32() const
174 {
176 return Bits.Payload;
177 }
178
179 bool IsCell() const { return !(EncodedBits & NonCellTagMask) && EncodedBits != UninitializedValue; }
180 VCell& AsCell() const
181 {
182 checkSlow(IsCell());
183 return *Cell;
184 }
185
187 {
188 if (IsCell())
189 {
190 return Cell;
191 }
192 if (IsPlaceholder())
193 {
194 return reinterpret_cast<VCell*>(&AsPlaceholder());
195 }
196 return nullptr;
197 }
198
199 template <typename ObjectType>
200 bool IsCellOfType() const;
201
202 template <typename ObjectType>
203 ObjectType& StaticCast() const;
204
205 template <typename ObjectType>
206 ObjectType* DynamicCast() const;
207
208 bool IsUObject() const { return (EncodedBits & UObjectTagMask) == UObjectTag; }
209 UObject* AsUObject() const
210 {
211 checkSlow(IsUObject());
212 return BitCast<UObject*>(EncodedBits & ~UObjectTag);
213 }
214
215 UObject* ExtractUObject() const
216 {
217 if (IsUObject())
218 {
219 return AsUObject();
220 }
221 else
222 {
223 return nullptr;
224 }
225 }
226
227 bool IsInt() const;
228 VInt AsInt() const;
229
230 bool IsLogic() const;
231
232 // Returns Value as C++ style bool
233 bool AsBool() const;
234
235 bool IsFloat() const
236 {
237 return (EncodedBits & NumberTagMask) && (EncodedBits & NumberTagMask) != Int32Tag;
238 }
239 VFloat AsFloat() const
240 {
241 checkSlow(IsFloat());
242 return VFloat(BitCast<double>(EncodedBits - FloatOffset));
243 }
244
245 bool IsEnumerator() const;
246
247 bool IsUninitialized() const { return EncodedBits == UninitializedValue; }
248
249 uint64 GetEncodedBits() const { return EncodedBits; }
250
252
253 COREUOBJECT_API void AppendToString(FAllocationContext Context, FUtf8StringBuilderBase& Builder, EValueStringFormat Format, TSet<const void*>& VisitedObjects, uint32 RecursionDepth = 0) const;
254 COREUOBJECT_API FUtf8String ToString(FAllocationContext Context, EValueStringFormat Format, uint32 RecursionDepth = 0) const;
255 COREUOBJECT_API TSharedPtr<FJsonValue> ToJSON(FRunningContext Context, EValueJSONFormat Format, TMap<const void*, EVisitState>& VisitedObjects, const VerseVMToJsonCallback& Callback, uint32 RecursionDepth = 0, FJsonObject* Defs = nullptr);
257
258 static VValue Char(uint8 V)
259 {
260 VValue R;
261 R.EncodedBits = (static_cast<uint64>(V) << NumLowerEncodingBits) | VValue::CharTag;
262 return R;
263 }
264 static VValue Char32(uint32 V)
265 {
266 VValue R;
267 R.EncodedBits = (static_cast<uint64>(V) << NumLowerEncodingBits) | VValue::Char32Tag;
268 return R;
269 }
270
271 bool IsChar() const { return (EncodedBits & VValue::NonCellTagMask) == VValue::CharTag; }
272 bool IsChar32() const { return (EncodedBits & VValue::NonCellTagMask) == VValue::Char32Tag; }
273
274 UTF8CHAR AsChar() const
275 {
276 checkSlow(IsChar());
277 return static_cast<UTF8CHAR>(EncodedBits >> NumLowerEncodingBits);
278 }
279 UTF32CHAR AsChar32() const
280 {
282 return static_cast<UTF32CHAR>(EncodedBits >> NumLowerEncodingBits);
283 }
284
285 static void AutoRTFMAssignFromOpenToClosed(VValue& Closed, const VValue& Open)
286 {
287 Closed = Open;
288 }
289
290private:
291 friend struct VRestValue;
292
293 union
294 {
295 uint64 EncodedBits;
296 VCell* Cell;
297
298 struct
299 {
300 int32 Payload;
301 int32 Tag;
302 } Bits;
303 };
304
305 static constexpr VValue Root(uint16 SplitDepth)
306 {
307 VValue Result = VValue::Decode(RootTag | (static_cast<uint64>(SplitDepth) << 32));
308 return Result;
309 }
310
311 bool IsRoot() const { return (EncodedBits & VValue::NonCellTagMask) == VValue::RootTag; }
312
313 uint16 GetSplitDepth() const
314 {
315 checkSlow(IsRoot());
316 return static_cast<uint16>(EncodedBits >> 32);
317 }
318
319public:
320 // VValue is a NaN-boxed 64-bit payload representing the fundamental value type in the
321 // Verse VM. NaN-boxing allows us to represent immediates like int32s and floats,
322 // and also pointers like VCell, all in a 64-bit payload. We do this by encoding
323 // non-floats in the IEEE754 NaN space. E.g, all non-double VValues will be NaN when
324 // you subtract FloatOffset from them. This means we need to be careful with the
325 // actual set of values we use to store NaN. The NaNs that are safe to be boxed
326 // as a float we call PureNaNs.
327 //
328 // On x86-64 and arm64, doing math on PureNaNs has the following properties:
329 // - When doing binary operations involving one PureNaN, the output is again a PureNaN.
330 // - The exact value you get on newly indefinite results (e.g, Inf - Inf) may vary in the sign, but is a PureNaN.
331 // This means that when doing arithmetic on VFloats, which can't be an impure NaN,
332 // we don't need to purify the result of the arithmetic operation when boxing them
333 // as a VValue. However, when boxing an unknown double value as a VValue, we need to
334 // purify any incoming NaNs.
335
336 // Encoding space by top 16 bits:
337 // 0x0000... Cell/Placeholder/UObject/Root (see below)
338 // 0x0001... \
339 // ... float
340 // 0xfffc... /
341 // 0xfffd... unused
342 // 0xfffe... unused
343 // 0xffff... int32
344
345 // If the top 16 bits are 0000, the lower 4 bits encode as follows:
346 // 0b0000... Cell
347 // 0b0001... Placeholder
348 // 0b0010... Root
349 // 0bX011... UObject
350 // 0b0100... char8
351 // 0b0101... char32
352 // 0b0110... transparent VRef
353 // 0b0111... unused
354 // 0b1XXX... unused (except for 0xb1011)
355
356 // VValue assumes a 48-bit address space for pointers.
357
358 // Special code which means this VValue is uninitialized
359 static constexpr uint64 UninitializedValue = 0;
360
361 // Number-related constants
362 static constexpr uint64 NumberTagMask = 0xffff'0000'0000'0000ull;
363 static constexpr uint64 Int32Tag = 0xffff'0000'0000'0000ull;
364 static constexpr uint64 FloatOffset = 0x0001'0000'0000'0000ull;
365 static constexpr uint64 MaxPureNaN = 0xfffb'ffff'ffff'ffffull;
366 static constexpr uint64 MaxFloatTag = 0xfffc'0000'0000'0000ull;
367
368 // Non-number related constants
369 static constexpr uint64 NumLowerEncodingBits = 4;
370 static constexpr uint64 NonCellTagMask = NumberTagMask | 0xfull; // Used for Placeholder, Root
371 static constexpr uint64 UObjectTagMask = NumberTagMask | 0x7ull; // Used for UObject
372 static constexpr uint64 PlaceholderTag = 0x1ull;
373 static constexpr uint64 RootTag = 0x2ull;
374 static constexpr uint64 UObjectTag = 0x3ull;
375 static constexpr uint64 CharTag = 0x4ull;
376 static constexpr uint64 Char32Tag = 0x5ull;
377 static constexpr uint64 TransparentRefTag = 06ull;
378};
379
380} // namespace Verse
381#endif // WITH_VERSE_VM
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define checkfSlow(expr, format,...)
Definition AssertionMacros.h:333
#define AUTORTFM_INFER
Definition AutoRTFMDefines.h:121
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::UTF32CHAR UTF32CHAR
A 32-bit character containing a UTF32 (Unicode, 32-bit, fixed-width) code unit.
Definition Platform.h:1143
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::UTF8CHAR UTF8CHAR
An 8-bit character containing a UTF8 (Unicode, 8-bit, variable-width) code unit.
Definition Platform.h:1137
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
UE_FORCEINLINE_HINT bool operator!=(const FIndexedPointer &Other) const
Definition LockFreeList.h:76
@ Char
Character type.
const bool
Definition NetworkReplayStreaming.h:178
void AppendToString(const FStringFormatArg &Arg, StringType &StringToAppendTo)
Definition StringFormatter.cpp:64
UE_REWRITE T StaticCast(ArgType &&Arg)
Definition UnrealTemplate.h:638
uint8_t uint8
Definition binka_ue_file_header.h:8
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition JsonObject.h:23
Definition JsonValue.h:22
Definition UnrealString.h.inl:34
Definition SharedPointer.h:692
Definition StringBuilder.h:79
Definition Object.h:95
@ Bits
Definition PacketView.h:34
FString ToString(uint16 Value)
Definition PathFollowingComponent.cpp:82
Definition Array.h:3955
bool operator==(const FCachedAssetKey &A, const FCachedAssetKey &B)
Definition AssetDataMap.h:501
float Encode(EEncoding SourceEncoding, float Value)
Definition TransferFunctions.cpp:51
float Decode(EEncoding SourceEncoding, float Value)
Definition TransferFunctions.cpp:63
To DynamicCast(From *Arg)
Definition Casts.h:541
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
Definition Archive.h:36
EValueJSONFormat
Definition VVMJson.h:47
EValueStringFormat
Definition VVMValuePrinting.h:17
EVisitState
Definition VVMJson.h:54
bool FromJSON(const JSONValue &JSON, bool *Value)
Definition JSON.h:71
bool ToJSON(bool Value, JSONValue *JSON, JSONMemoryPoolAllocator &)
Definition JSON.h:211