UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
VVMBytecode.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 "CoreTypes.h"
10#include "VVMBytecodeOps.h"
11#include "VVMLocation.h"
12#include "VVMMarkStackVisitor.h"
13#include "VVMVerse.h"
14
15// NOTE: (yiliang.siew) Silence these warnings for now in the cases below.
16#if defined(__GNUC__) || defined(__clang__)
17#pragma GCC diagnostic push
18#pragma GCC diagnostic ignored "-Wswitch-enum"
19#endif
20
21namespace Verse
22{
23struct VProcedure;
24
25using FOpcodeInt = uint16_t;
26
27enum class EOpcode : FOpcodeInt
28{
29#define VISIT_OP(Name) Name,
31#undef VISIT_OP
32 // Not a real opcode, but one to just check the count.
34};
35
37
38inline bool IsBranch(EOpcode Opcode)
39{
40 switch (Opcode)
41 {
42 case EOpcode::Jump:
43 case EOpcode::JumpIfInitialized:
44 case EOpcode::Switch:
45 case EOpcode::LtFastFail:
46 case EOpcode::LteFastFail:
47 case EOpcode::GtFastFail:
48 case EOpcode::GteFastFail:
49 case EOpcode::EqFastFail:
50 case EOpcode::NeqFastFail:
51 case EOpcode::ArrayIndexFastFail:
52 case EOpcode::TypeCastFastFail:
53 case EOpcode::QueryFastFail:
54 case EOpcode::CreateField:
55 case EOpcode::CreateFieldICValueObjectConstant:
56 case EOpcode::CreateFieldICValueObjectField:
57 case EOpcode::CreateFieldICNativeStruct:
58 case EOpcode::CreateFieldICUObject:
59 case EOpcode::EndTask:
60 case EOpcode::Yield:
61 case EOpcode::BeginDefaultConstructor:
62 return true;
63 default:
64 return false;
65 }
66}
67
68inline bool IsTerminal(EOpcode Opcode)
69{
70 switch (Opcode)
71 {
72 case EOpcode::Err:
73 case EOpcode::ResumeUnwind:
74 case EOpcode::Return:
75 return true;
76 default:
77 return false;
78 }
79}
80
82{
83 if (IsTerminal(Opcode))
84 {
85 return false;
86 }
87
88 if (!IsBranch(Opcode))
89 {
90 return true;
91 }
92
93 switch (Opcode)
94 {
95 case EOpcode::Jump:
96 case EOpcode::Switch:
97 case EOpcode::EndTask:
98 case EOpcode::Yield:
99 return false;
100 case EOpcode::JumpIfInitialized:
101 case EOpcode::LtFastFail:
102 case EOpcode::LteFastFail:
103 case EOpcode::GtFastFail:
104 case EOpcode::GteFastFail:
105 case EOpcode::EqFastFail:
106 case EOpcode::NeqFastFail:
107 case EOpcode::ArrayIndexFastFail:
108 case EOpcode::TypeCastFastFail:
109 case EOpcode::QueryFastFail:
110 case EOpcode::CreateField:
111 case EOpcode::CreateFieldICValueObjectConstant:
112 case EOpcode::CreateFieldICValueObjectField:
113 case EOpcode::CreateFieldICNativeStruct:
114 case EOpcode::CreateFieldICUObject:
115 case EOpcode::BeginDefaultConstructor:
116 return true;
117 default:
118 break;
119 }
120
122 return false;
123}
124
126enum class EOperandRole : uint8
127{
128 Use,
129 Immediate,
131 UnifyDef,
132};
133
134inline bool IsAnyDef(EOperandRole Role)
135{
136 switch (Role)
137 {
138 case EOperandRole::Use:
139 case EOperandRole::Immediate:
140 return false;
141 case EOperandRole::ClobberDef:
142 case EOperandRole::UnifyDef:
143 return true;
144 }
145}
146
147inline bool IsAnyUse(EOperandRole Role)
148{
149 switch (Role)
150 {
151 case EOperandRole::Use:
152 case EOperandRole::UnifyDef:
153 return true;
154 case EOperandRole::Immediate:
155 case EOperandRole::ClobberDef:
156 return false;
157 }
158}
159
160struct FRegisterIndex
161{
162 static constexpr uint32 UNINITIALIZED = INT32_MAX;
163
165 static constexpr uint32 SELF = 0; // for `Self`.
166 static constexpr uint32 SCOPE = 1; // for `(super:)` and other generic captures in the future.
167 static constexpr uint32 PARAMETER_START = 2;
168
169 // Unsigned, but must be less than INT32_MAX
171
172 explicit operator bool() const { return Index < UNINITIALIZED; }
173 friend bool operator==(FRegisterIndex Left, FRegisterIndex Right) { return Left.Index == Right.Index; }
174 friend bool operator!=(FRegisterIndex Left, FRegisterIndex Right) { return Left.Index != Right.Index; }
175 bool operator<(const FRegisterIndex& Other) const { return Index < Other.Index; }
176 bool operator>=(const FRegisterIndex& Other) const { return Index >= Other.Index; }
177 FRegisterIndex& operator++()
178 {
179 ++Index;
180 return *this;
181 }
182
183 template <typename TVisitor>
184 friend void Visit(TVisitor& Visitor, FRegisterIndex& Value)
185 {
186 Visitor.Visit(Value.Index, TEXT("Index"));
187 }
188};
189
191{
192 return ::GetTypeHash(Register.Index);
193}
194
195struct FConstantIndex
196{
197 // Unsigned, but must be less than or equal to INT32_MAX
199};
200
201struct FValueOperand
202{
203 static constexpr uint32 UNINITIALIZED = INT32_MAX;
204
205 union
206 {
210 };
211
212 static_assert(sizeof(Index) == sizeof(Register));
213
216 {
217 }
218
221 {
222 check(Register.Index < UNINITIALIZED);
223 check(IsRegister());
224 }
227 {
228 check(Constant.Index <= UNINITIALIZED);
229 check(IsConstant());
230 }
231
232 V_FORCEINLINE bool IsRegister() const { return Index < UNINITIALIZED; }
233 V_FORCEINLINE bool IsConstant() const { return UNINITIALIZED < Index; }
234
236 {
237 checkSlow(IsRegister());
238 return Register;
239 }
240
242 {
243 checkSlow(IsConstant());
244 return FConstantIndex{~Index};
245 }
246
247 template <typename TVisitor>
248 friend void Visit(TVisitor& Visitor, FValueOperand& Value)
249 {
250 Visitor.Visit(Value.Index, TEXT("Index"));
251 }
252};
253
254template <typename OperandType>
255struct TOperandRange
256{
257 int32 Index;
258 int32 Num;
259
260 template <typename TVisitor>
261 friend void Visit(TVisitor& Visitor, TOperandRange& Value) {}
262};
263
264// We align the bytecode stream to 8 bytes so we don't see tearing from the collector,
265// and in the future other concurrent threads, when writing to a VValue/pointer sized
266// entry.
267constexpr uint8 OpAlignment = alignof(void*);
268
269struct FLabelOffset;
270
271struct alignas(OpAlignment) FOp
272{
274
275 explicit FOp(const EOpcode InOpcode)
276 : Opcode(InOpcode) {}
277
278 // Function should take as parameters (EOperandRole, FRegisterIndex) where FRegisterIndex can be a reference or a value.
279 // This vends the registers used in this FOp.
280 template <typename FunctionType>
281 void ForEachReg(VProcedure& Procedure, FunctionType&& Function);
282
283 // Function should take as parameters (FLabelOffset, const TCHAR*) where FLabelOffset can be a reference or a value.
284 // This vends the jumps used in this FOp.
285 template <typename FunctionType>
286 void ForEachJump(VProcedure&, FunctionType&& Function);
287
288private:
289 template <typename FunctionType>
290 static void ForEachRegImpl(VProcedure&, FRegisterIndex& Register, FunctionType&& Function);
291
292 template <typename FunctionType>
293 static void ForEachRegImpl(VProcedure&, FValueOperand& Operand, FunctionType&& Function);
294
295 template <typename CellType, typename FunctionType>
296 static void ForEachRegImpl(VProcedure&, TWriteBarrier<CellType>&, FunctionType&&);
297
298 template <typename FunctionType>
300
301 template <typename CellType, typename FunctionType>
302 static void ForEachRegImpl(VProcedure&, TOperandRange<TWriteBarrier<CellType>>, FunctionType&&);
303
304 template <typename FunctionType>
305 static void ForEachJumpImpl(VProcedure&, TOperandRange<FLabelOffset> LabelOffsets, const TCHAR* Name, FunctionType&&);
306
307 template <typename FunctionType>
308 static void ForEachJumpImpl(VProcedure&, FLabelOffset&, const TCHAR* Name, FunctionType&&);
309};
310
311struct FLabelOffset
312{
313 int32 Offset; // In bytes, relative to the address of this FLabelOffset
314
315 FOp* GetLabeledPC() const
316 {
317 return const_cast<FOp*>(BitCast<const FOp*>(BitCast<const uint8*>(this) + Offset));
318 }
319
320 template <typename TVisitor>
321 friend void Visit(TVisitor& Visitor, FLabelOffset& Value)
322 {
323 Visitor.Visit(Value.Offset, TEXT("Index"));
324 }
325};
326
327// A range of opcode bytes, with a target label for unwinding from calls within that range.
328// VProcedure holds a sorted array of non-overlapping unwind edges.
329struct FUnwindEdge
330{
331 int32 Begin; // Exclusive
332 int32 End; // Inclusive
334
335 template <typename TVisitor>
336 friend void Visit(TVisitor& Visitor, FUnwindEdge& Value)
337 {
338 Visitor.Visit(Value.Begin, TEXT("Begin"));
339 Visitor.Visit(Value.End, TEXT("End"));
340 Visitor.Visit(Value.OnUnwind, TEXT("OnUnwind"));
341 }
342};
343
344// Mapping of a parameter name to its corresponding register. VProcedures hold an array of such mappings.
345struct FNamedParam
346{
349
350 FNamedParam() = default;
351
353 : Name(Context, InName)
354 , Index(InIndex)
355 {
356 }
357
358 template <typename TVisitor>
359 friend void Visit(TVisitor& Visitor, FNamedParam& Value)
360 {
361 Visitor.Visit(Value.Name, TEXT("Name"));
362 Visitor.Visit(Value.Index, TEXT("Index"));
363 }
364};
365
366// Mapping from an opcode offset to a location. VProcedure holds a sorted array of such
367// mappings where an op's location is the latest entry with an equal or lesser offset.
368struct FOpLocation
369{
370 int32 Begin;
372
373 template <typename TVisitor>
374 friend void Visit(TVisitor& Visitor, FOpLocation& Value)
375 {
376 Visitor.Visit(Value.Begin, TEXT("Begin"));
377 Visitor.Visit(Value.Location, TEXT("Location"));
378 }
379};
380
382
384{
385 uint32 Id;
386
388 {
389 return Left.Id == Right.Id;
390 }
391
393 {
394 using ::GetTypeHash;
395 return GetTypeHash(Arg.Id);
396 }
397};
398} // namespace Verse
399
400#if defined(__GNUC__) || defined(__clang__)
401#pragma GCC diagnostic pop
402#endif
403#endif // WITH_VERSE_VM
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
bool operator<(const FTextFormatString &LHS, const FTextFormatString &RHS)
Definition ITextFormatArgumentModifier.h:147
UE_FORCEINLINE_HINT bool operator!=(const FIndexedPointer &Other) const
Definition LockFreeList.h:76
@ Num
Definition MetalRHIPrivate.h:234
const bool
Definition NetworkReplayStreaming.h:178
decltype(auto) Visit(Func &&Callable, Variants &&... Args)
Definition TVariant.h:271
UE_REWRITE constexpr bool operator>=(const LhsType &Lhs, const RhsType &Rhs)
Definition UEOps.h:104
#define VERSE_UNREACHABLE()
Definition VVMUnreachable.h:8
#define V_FORCEINLINE
Definition VVMVerse.h:30
uint32 Offset
Definition VulkanMemory.cpp:4033
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
@ UNINITIALIZED
Definition SoundFileIOEnums.h:243
@ Visitor
Definition XmppMultiUserChat.h:94
uint32 GetTypeHash(const FKey &Key)
Definition BlackboardKey.h:35
FString ToString(uint16 Value)
Definition PathFollowingComponent.cpp:82
bool operator==(const FCachedAssetKey &A, const FCachedAssetKey &B)
Definition AssetDataMap.h:501
Definition Archive.h:36
uint32 GetTypeHash(TPtrVariant< Ts... > Ptr)
Definition VVMPtrVariant.h:83
U16 Index
Definition radfft.cpp:71