clang 24.0.0git
InterpBlock.h
Go to the documentation of this file.
1//===-- InterpBlock.h - Allocated blocks for the interpreter -*- C++ ----*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Defines the classes describing allocated blocks.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_BLOCK_H
14#define LLVM_CLANG_AST_INTERP_BLOCK_H
15
16#include "Descriptor.h"
17#include "llvm/Support/raw_ostream.h"
18
19namespace clang {
20namespace interp {
21class Block;
22class DeadBlock;
23class InterpState;
24class Pointer;
25enum PrimType : uint8_t;
26
27/// A memory block, either on the stack or in the heap.
28///
29/// The storage described by the block is immediately followed by
30/// optional metadata, which is followed by the actual data.
31///
32/// Block* rawData() data()
33/// │ │ │
34/// │ │ │
35/// ▼ ▼ ▼
36/// ┌───────────────┬──────────────────┬─────────────────┐
37/// │ Block │ Metadata │ Data │
38/// │ sizeof(Block) │ MDSize │ Desc->getSize() │
39/// └───────────────┴──────────────────┴─────────────────┘
40///
41/// getSize() returns MDSize + Desc->getAllocSize().
42///
43class Block final {
44private:
45 static constexpr uint8_t ExternFlag = 1 << 0;
46 static constexpr uint8_t DeadFlag = 1 << 1;
47 static constexpr uint8_t WeakFlag = 1 << 2;
48 static constexpr uint8_t DummyFlag = 1 << 3;
49
50public:
51 static constexpr uint8_t InlineDescMD = sizeof(InlineDescriptor);
52 static constexpr uint8_t GlobalMD = sizeof(GlobalInlineDescriptor);
53
54 /// Creates a new block.
55 Block(unsigned EvalID, UnsignedOrNone DeclID, const Descriptor *Desc,
56 unsigned MDSize = 0, bool IsStatic = false, bool IsExtern = false,
57 bool IsWeak = false, bool IsDummy = false)
58 : Desc(Desc), DeclID(DeclID), EvalID(EvalID), MDSize(MDSize),
59 IsStatic(IsStatic) {
60 assert(Desc);
61 AccessFlags |= (ExternFlag * IsExtern);
62 AccessFlags |= (WeakFlag * IsWeak);
63 AccessFlags |= (DummyFlag * IsDummy);
64 }
65
66 Block(unsigned EvalID, const Descriptor *Desc, unsigned MDSize = 0,
67 bool IsStatic = false, bool IsExtern = false, bool IsWeak = false,
68 bool IsDummy = false)
69 : Desc(Desc), EvalID(EvalID), MDSize(MDSize), IsStatic(IsStatic) {
70 assert(Desc);
71 AccessFlags |= (ExternFlag * IsExtern);
72 AccessFlags |= (WeakFlag * IsWeak);
73 AccessFlags |= (DummyFlag * IsDummy);
74 }
75
76 /// Returns the block's descriptor.
77 const Descriptor *getDescriptor() const { return Desc; }
78 /// Checks if the block has any live pointers.
79 bool hasPointers() const { return Pointers; }
80 /// Checks if the block is extern.
81 bool isExtern() const { return AccessFlags & ExternFlag; }
82 /// Checks if the block has static storage duration.
83 bool isStatic() const { return IsStatic; }
84 /// Checks if the block is temporary.
85 bool isTemporary() const { return Desc->IsTemporary; }
86 bool isWeak() const { return AccessFlags & WeakFlag; }
87 bool isDynamic() const { return (DynAllocId != std::nullopt); }
88 bool isDummy() const { return AccessFlags & DummyFlag; }
89 bool isDead() const { return AccessFlags & DeadFlag; }
90 /// Returns the size of the block, including metadata.
91 unsigned getSize() const { return Desc->getAllocSize() + MDSize; }
92 /// Returns the size of the metadata.
93 unsigned getMetadataSize() const { return MDSize; }
94 /// Returns the declaration ID.
95 UnsignedOrNone getDeclID() const { return DeclID; }
96 /// Returns whether the data of this block has been initialized via
97 /// invoking the Ctor func.
98 bool isInitialized() const { return IsInitialized; }
99 /// The Evaluation ID this block was created in.
100 unsigned getEvalID() const { return EvalID; }
101 /// Move all pointers from this block to \param B.
102 void movePointersTo(Block *B);
103 /// Make all pointers that currently point to this block point to nullptr.
104 void removePointers();
105
106 /// Returns a pointer to the stored data.
107 /// You are allowed to read Desc->getSize() bytes from this address.
108 std::byte *data() { return rawData() + MDSize; }
109 const std::byte *data() const { return rawData() + MDSize; }
110
111 /// Returns a pointer to the raw data, including metadata.
112 /// You are allowed to read Desc->getAllocSize() bytes from this address.
113 std::byte *rawData() {
114 return reinterpret_cast<std::byte *>(this) + sizeof(Block);
115 }
116 const std::byte *rawData() const {
117 return reinterpret_cast<const std::byte *>(this) + sizeof(Block);
118 }
119
120 template <typename T> const T &deref() const {
121 return *reinterpret_cast<const T *>(data());
122 }
123 template <typename T> T &deref() { return *reinterpret_cast<T *>(data()); }
124
125 template <typename T> T &getBlockDesc() {
126 assert(sizeof(T) == MDSize);
127 return *reinterpret_cast<T *>(rawData());
128 }
129 template <typename T> const T &getBlockDesc() const {
130 return const_cast<Block *>(this)->getBlockDesc<T>();
131 }
132
133 /// Invokes the constructor.
134 void invokeCtor() {
135 assert(!IsInitialized);
136 std::memset(rawData(), 0, getSize());
138 }
139 /// The same, but won't memset() the memory first to zero.
141 assert(!IsInitialized);
142 if (Desc->CtorFn)
143 Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
144 Desc->IsVolatile,
145 /*isActive=*/true, /*InUnion=*/false, Desc);
146
147 IsInitialized = true;
148 }
149
150 /// Invokes the Destructor.
151 void invokeDtor() {
152 assert(IsInitialized);
153 if (Desc->DtorFn)
154 Desc->DtorFn(this, data(), Desc);
155 IsInitialized = false;
156 }
157
158 void dump() const { dump(llvm::errs()); }
159 void dump(llvm::raw_ostream &OS) const;
160
161 bool isAccessible() const { return AccessFlags == 0; }
162
163private:
164 friend class Pointer;
165 friend class DeadBlock;
166 friend class InterpState;
167 friend class DynamicAllocator;
168 friend class Program;
169
170 Block(unsigned EvalID, const Descriptor *Desc, unsigned MDSize, bool IsExtern,
171 bool IsStatic, bool IsWeak, bool IsDummy, bool IsDead)
172 : Desc(Desc), EvalID(EvalID), MDSize(MDSize), IsStatic(IsStatic) {
173 assert(Desc);
174 AccessFlags |= (ExternFlag * IsExtern);
175 AccessFlags |= (DeadFlag * IsDead);
176 AccessFlags |= (WeakFlag * IsWeak);
177 AccessFlags |= (DummyFlag * IsDummy);
178 }
179
180 /// To be called by DynamicAllocator.
181 void setDynAllocId(unsigned ID) { DynAllocId = ID; }
182
183 /// Deletes a dead block at the end of its lifetime.
184 void cleanup();
185
186 /// Pointer chain management.
187 void addPointer(Pointer *P);
188 void removePointer(Pointer *P);
189 void replacePointer(Pointer *Old, Pointer *New);
190#ifndef NDEBUG
191 bool hasPointer(const Pointer *P) const;
192#endif
193
194 /// Pointer to the stack slot descriptor.
195 const Descriptor *Desc;
196 /// Start of the chain of pointers.
197 Pointer *Pointers = nullptr;
198 /// Unique identifier of the declaration.
199 UnsignedOrNone DeclID = std::nullopt;
200 const unsigned EvalID = ~0u;
201 /// Allocation ID for this dynamic allocation, if it is one.
202 UnsignedOrNone DynAllocId = std::nullopt;
203 /// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits.
204 uint8_t AccessFlags = 0;
205 /// Size of the metadata.
206 const uint8_t MDSize = 0;
207 /// Flag indicating if the block has static storage duration.
208 bool IsStatic = false;
209 /// Flag indicating if the block contents have been initialized
210 /// via invokeCtor.
211 bool IsInitialized = false;
212};
213
214/// Descriptor for a dead block.
215///
216/// Dead blocks are chained in a double-linked list to deallocate them
217/// whenever pointers become dead.
218class DeadBlock final {
219public:
220 /// Copies the block.
221 DeadBlock(DeadBlock *&Root, Block *Blk);
222
223 /// Returns a pointer to the stored data.
224 std::byte *data() { return B.data(); }
225 std::byte *rawData() { return B.rawData(); }
226
227private:
228 friend class Block;
229 friend class InterpState;
230
231 void free();
232
233 /// Root pointer of the list.
234 DeadBlock *&Root;
235 /// Previous block in the list.
236 DeadBlock *Prev;
237 /// Next block in the list.
238 DeadBlock *Next;
239
240 /// Actual block storing data and tracking pointers.
241 Block B;
242};
243
244} // namespace interp
245} // namespace clang
246
247#endif
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:43
unsigned getSize() const
Returns the size of the block, including metadata.
Definition InterpBlock.h:91
friend class Program
Block(unsigned EvalID, const Descriptor *Desc, unsigned MDSize=0, bool IsStatic=false, bool IsExtern=false, bool IsWeak=false, bool IsDummy=false)
Definition InterpBlock.h:66
void invokeDtor()
Invokes the Destructor.
const T & deref() const
bool isExtern() const
Checks if the block is extern.
Definition InterpBlock.h:81
void invokeCtorNoMemset()
The same, but won't memset() the memory first to zero.
friend class Pointer
std::byte * data()
Returns a pointer to the stored data.
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition InterpBlock.h:77
static constexpr uint8_t InlineDescMD
Definition InterpBlock.h:51
const std::byte * rawData() const
bool isDead() const
Definition InterpBlock.h:89
static constexpr uint8_t GlobalMD
Definition InterpBlock.h:52
void movePointersTo(Block *B)
Move all pointers from this block to.
void invokeCtor()
Invokes the constructor.
bool isStatic() const
Checks if the block has static storage duration.
Definition InterpBlock.h:83
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition InterpBlock.h:93
const T & getBlockDesc() const
friend class DynamicAllocator
friend class InterpState
Block(unsigned EvalID, UnsignedOrNone DeclID, const Descriptor *Desc, unsigned MDSize=0, bool IsStatic=false, bool IsExtern=false, bool IsWeak=false, bool IsDummy=false)
Creates a new block.
Definition InterpBlock.h:55
bool isTemporary() const
Checks if the block is temporary.
Definition InterpBlock.h:85
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
const std::byte * data() const
bool isInitialized() const
Returns whether the data of this block has been initialized via invoking the Ctor func.
Definition InterpBlock.h:98
bool isDynamic() const
Definition InterpBlock.h:87
UnsignedOrNone getDeclID() const
Returns the declaration ID.
Definition InterpBlock.h:95
friend class DeadBlock
bool isDummy() const
Definition InterpBlock.h:88
unsigned getEvalID() const
The Evaluation ID this block was created in.
bool isWeak() const
Definition InterpBlock.h:86
bool isAccessible() const
bool hasPointers() const
Checks if the block has any live pointers.
Definition InterpBlock.h:79
void removePointers()
Make all pointers that currently point to this block point to nullptr.
Descriptor for a dead block.
std::byte * data()
Returns a pointer to the stored data.
DeadBlock(DeadBlock *&Root, Block *Blk)
Copies the block.
Interpreter context.
Definition InterpState.h:43
A pointer to a memory block, live or dead.
Definition Pointer.h:402
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
Top level wrappers for InstallAPI frontend operations.
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 uint8_t
Describes a memory block created by an allocation site.
Definition Descriptor.h:122
Descriptor used for global variables.
Definition Descriptor.h:49
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:67