Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/InterpBlock.h
213799 views
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 "clang/AST/ComparisonCategories.h"
18
#include "clang/AST/Decl.h"
19
#include "clang/AST/DeclCXX.h"
20
#include "clang/AST/Expr.h"
21
#include "llvm/ADT/PointerUnion.h"
22
#include "llvm/Support/raw_ostream.h"
23
24
namespace clang {
25
namespace interp {
26
class Block;
27
class DeadBlock;
28
class InterpState;
29
class Pointer;
30
enum PrimType : unsigned;
31
32
/// A memory block, either on the stack or in the heap.
33
///
34
/// The storage described by the block is immediately followed by
35
/// optional metadata, which is followed by the actual data.
36
///
37
/// Block* rawData() data()
38
/// │ │ │
39
/// │ │ │
40
/// ▼ ▼ ▼
41
/// ┌───────────────┬─────────────────────────┬─────────────────┐
42
/// │ Block │ Metadata │ Data │
43
/// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │
44
/// └───────────────┴─────────────────────────┴─────────────────┘
45
///
46
/// Desc->getAllocSize() describes the size after the Block, i.e.
47
/// the data size and the metadata size.
48
///
49
class Block final {
50
public:
51
/// Creates a new block.
52
Block(unsigned EvalID, const std::optional<unsigned> &DeclID,
53
const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false,
54
bool IsWeak = false)
55
: EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern),
56
IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
57
assert(Desc);
58
}
59
60
Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
61
bool IsExtern = false, bool IsWeak = false)
62
: EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic),
63
IsExtern(IsExtern), IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
64
assert(Desc);
65
}
66
67
/// Returns the block's descriptor.
68
const Descriptor *getDescriptor() const { return Desc; }
69
/// Checks if the block has any live pointers.
70
bool hasPointers() const { return Pointers; }
71
/// Checks if the block is extern.
72
bool isExtern() const { return IsExtern; }
73
/// Checks if the block has static storage duration.
74
bool isStatic() const { return IsStatic; }
75
/// Checks if the block is temporary.
76
bool isTemporary() const { return Desc->IsTemporary; }
77
bool isWeak() const { return IsWeak; }
78
bool isDynamic() const { return IsDynamic; }
79
/// Returns the size of the block.
80
unsigned getSize() const { return Desc->getAllocSize(); }
81
/// Returns the declaration ID.
82
std::optional<unsigned> getDeclID() const { return DeclID; }
83
/// Returns whether the data of this block has been initialized via
84
/// invoking the Ctor func.
85
bool isInitialized() const { return IsInitialized; }
86
/// The Evaluation ID this block was created in.
87
unsigned getEvalID() const { return EvalID; }
88
89
/// Returns a pointer to the stored data.
90
/// You are allowed to read Desc->getSize() bytes from this address.
91
std::byte *data() {
92
// rawData might contain metadata as well.
93
size_t DataOffset = Desc->getMetadataSize();
94
return rawData() + DataOffset;
95
}
96
const std::byte *data() const {
97
// rawData might contain metadata as well.
98
size_t DataOffset = Desc->getMetadataSize();
99
return rawData() + DataOffset;
100
}
101
102
/// Returns a pointer to the raw data, including metadata.
103
/// You are allowed to read Desc->getAllocSize() bytes from this address.
104
std::byte *rawData() {
105
return reinterpret_cast<std::byte *>(this) + sizeof(Block);
106
}
107
const std::byte *rawData() const {
108
return reinterpret_cast<const std::byte *>(this) + sizeof(Block);
109
}
110
111
/// Invokes the constructor.
112
void invokeCtor() {
113
assert(!IsInitialized);
114
std::memset(rawData(), 0, Desc->getAllocSize());
115
if (Desc->CtorFn) {
116
Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
117
Desc->IsVolatile,
118
/*isActive=*/true, /*InUnion=*/false, Desc);
119
}
120
IsInitialized = true;
121
}
122
123
/// Invokes the Destructor.
124
void invokeDtor() {
125
assert(IsInitialized);
126
if (Desc->DtorFn)
127
Desc->DtorFn(this, data(), Desc);
128
IsInitialized = false;
129
}
130
131
void dump() const { dump(llvm::errs()); }
132
void dump(llvm::raw_ostream &OS) const;
133
134
private:
135
friend class Pointer;
136
friend class DeadBlock;
137
friend class InterpState;
138
friend class DynamicAllocator;
139
140
Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic,
141
bool IsWeak, bool IsDead)
142
: EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true),
143
IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
144
assert(Desc);
145
}
146
147
/// Deletes a dead block at the end of its lifetime.
148
void cleanup();
149
150
/// Pointer chain management.
151
void addPointer(Pointer *P);
152
void removePointer(Pointer *P);
153
void replacePointer(Pointer *Old, Pointer *New);
154
#ifndef NDEBUG
155
bool hasPointer(const Pointer *P) const;
156
#endif
157
158
const unsigned EvalID = ~0u;
159
/// Start of the chain of pointers.
160
Pointer *Pointers = nullptr;
161
/// Unique identifier of the declaration.
162
std::optional<unsigned> DeclID;
163
/// Flag indicating if the block has static storage duration.
164
bool IsStatic = false;
165
/// Flag indicating if the block is an extern.
166
bool IsExtern = false;
167
/// Flag indicating if the pointer is dead. This is only ever
168
/// set once, when converting the Block to a DeadBlock.
169
bool IsDead = false;
170
/// Flag indicating if the block contents have been initialized
171
/// via invokeCtor.
172
bool IsInitialized = false;
173
/// Flag indicating if this block has been allocated via dynamic
174
/// memory allocation (e.g. malloc).
175
bool IsDynamic = false;
176
bool IsWeak = false;
177
/// Pointer to the stack slot descriptor.
178
const Descriptor *Desc;
179
};
180
181
/// Descriptor for a dead block.
182
///
183
/// Dead blocks are chained in a double-linked list to deallocate them
184
/// whenever pointers become dead.
185
class DeadBlock final {
186
public:
187
/// Copies the block.
188
DeadBlock(DeadBlock *&Root, Block *Blk);
189
190
/// Returns a pointer to the stored data.
191
std::byte *data() { return B.data(); }
192
std::byte *rawData() { return B.rawData(); }
193
194
private:
195
friend class Block;
196
friend class InterpState;
197
198
void free();
199
200
/// Root pointer of the list.
201
DeadBlock *&Root;
202
/// Previous block in the list.
203
DeadBlock *Prev;
204
/// Next block in the list.
205
DeadBlock *Next;
206
207
/// Actual block storing data and tracking pointers.
208
Block B;
209
};
210
211
} // namespace interp
212
} // namespace clang
213
214
#endif
215
216