Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Program.h
35291 views
1
//===--- Program.h - Bytecode for the constexpr VM --------------*- 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 a program which organises and links multiple bytecode functions.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H
14
#define LLVM_CLANG_AST_INTERP_PROGRAM_H
15
16
#include <map>
17
#include <vector>
18
#include "Function.h"
19
#include "Pointer.h"
20
#include "PrimType.h"
21
#include "Record.h"
22
#include "Source.h"
23
#include "llvm/ADT/DenseMap.h"
24
#include "llvm/ADT/PointerUnion.h"
25
#include "llvm/ADT/StringRef.h"
26
#include "llvm/Support/Allocator.h"
27
28
namespace clang {
29
class RecordDecl;
30
class Expr;
31
class FunctionDecl;
32
class StringLiteral;
33
class VarDecl;
34
35
namespace interp {
36
class Context;
37
38
/// The program contains and links the bytecode for all functions.
39
class Program final {
40
public:
41
Program(Context &Ctx) : Ctx(Ctx) {}
42
43
~Program() {
44
// Manually destroy all the blocks. They are almost all harmless,
45
// but primitive arrays might have an InitMap* heap allocated and
46
// that needs to be freed.
47
for (Global *G : Globals)
48
if (Block *B = G->block(); B->isInitialized())
49
B->invokeDtor();
50
51
// Records might actually allocate memory themselves, but they
52
// are allocated using a BumpPtrAllocator. Call their desctructors
53
// here manually so they are properly freeing their resources.
54
for (auto RecordPair : Records) {
55
if (Record *R = RecordPair.second)
56
R->~Record();
57
}
58
}
59
60
/// Marshals a native pointer to an ID for embedding in bytecode.
61
unsigned getOrCreateNativePointer(const void *Ptr);
62
63
/// Returns the value of a marshalled native pointer.
64
const void *getNativePointer(unsigned Idx);
65
66
/// Emits a string literal among global data.
67
unsigned createGlobalString(const StringLiteral *S);
68
69
/// Returns a pointer to a global.
70
Pointer getPtrGlobal(unsigned Idx) const;
71
72
/// Returns the value of a global.
73
Block *getGlobal(unsigned Idx) {
74
assert(Idx < Globals.size());
75
return Globals[Idx]->block();
76
}
77
78
/// Finds a global's index.
79
std::optional<unsigned> getGlobal(const ValueDecl *VD);
80
std::optional<unsigned> getGlobal(const Expr *E);
81
82
/// Returns or creates a global an creates an index to it.
83
std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
84
const Expr *Init = nullptr);
85
86
/// Returns or creates a dummy value for unknown declarations.
87
std::optional<unsigned> getOrCreateDummy(const ValueDecl *VD);
88
89
/// Creates a global and returns its index.
90
std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init);
91
92
/// Creates a global from a lifetime-extended temporary.
93
std::optional<unsigned> createGlobal(const Expr *E);
94
95
/// Creates a new function from a code range.
96
template <typename... Ts>
97
Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
98
Def = Def->getCanonicalDecl();
99
auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
100
Funcs.insert({Def, std::unique_ptr<Function>(Func)});
101
return Func;
102
}
103
/// Creates an anonymous function.
104
template <typename... Ts>
105
Function *createFunction(Ts &&... Args) {
106
auto *Func = new Function(*this, std::forward<Ts>(Args)...);
107
AnonFuncs.emplace_back(Func);
108
return Func;
109
}
110
111
/// Returns a function.
112
Function *getFunction(const FunctionDecl *F);
113
114
/// Returns a record or creates one if it does not exist.
115
Record *getOrCreateRecord(const RecordDecl *RD);
116
117
/// Creates a descriptor for a primitive type.
118
Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
119
Descriptor::MetadataSize MDSize = std::nullopt,
120
bool IsConst = false, bool IsTemporary = false,
121
bool IsMutable = false) {
122
return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
123
}
124
125
/// Creates a descriptor for a composite type.
126
Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
127
Descriptor::MetadataSize MDSize = std::nullopt,
128
bool IsConst = false, bool IsTemporary = false,
129
bool IsMutable = false,
130
const Expr *Init = nullptr);
131
132
/// Context to manage declaration lifetimes.
133
class DeclScope {
134
public:
135
DeclScope(Program &P, const ValueDecl *VD) : P(P) {
136
P.startDeclaration(VD);
137
}
138
~DeclScope() { P.endDeclaration(); }
139
140
private:
141
Program &P;
142
};
143
144
/// Returns the current declaration ID.
145
std::optional<unsigned> getCurrentDecl() const {
146
if (CurrentDeclaration == NoDeclaration)
147
return std::optional<unsigned>{};
148
return LastDeclaration;
149
}
150
151
private:
152
friend class DeclScope;
153
154
std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
155
bool IsStatic, bool IsExtern,
156
const Expr *Init = nullptr);
157
158
/// Reference to the VM context.
159
Context &Ctx;
160
/// Mapping from decls to cached bytecode functions.
161
llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
162
/// List of anonymous functions.
163
std::vector<std::unique_ptr<Function>> AnonFuncs;
164
165
/// Function relocation locations.
166
llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
167
168
/// Native pointers referenced by bytecode.
169
std::vector<const void *> NativePointers;
170
/// Cached native pointer indices.
171
llvm::DenseMap<const void *, unsigned> NativePointerIndices;
172
173
/// Custom allocator for global storage.
174
using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
175
176
/// Descriptor + storage for a global object.
177
///
178
/// Global objects never go out of scope, thus they do not track pointers.
179
class Global {
180
public:
181
/// Create a global descriptor for string literals.
182
template <typename... Tys>
183
Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
184
185
/// Allocates the global in the pool, reserving storate for data.
186
void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
187
return Alloc.Allocate(Meta + Data, alignof(void *));
188
}
189
190
/// Return a pointer to the data.
191
std::byte *data() { return B.data(); }
192
/// Return a pointer to the block.
193
Block *block() { return &B; }
194
const Block *block() const { return &B; }
195
196
private:
197
/// Required metadata - does not actually track pointers.
198
Block B;
199
};
200
201
/// Allocator for globals.
202
PoolAllocTy Allocator;
203
204
/// Global objects.
205
std::vector<Global *> Globals;
206
/// Cached global indices.
207
llvm::DenseMap<const void *, unsigned> GlobalIndices;
208
209
/// Mapping from decls to record metadata.
210
llvm::DenseMap<const RecordDecl *, Record *> Records;
211
212
/// Dummy parameter to generate pointers from.
213
llvm::DenseMap<const ValueDecl *, unsigned> DummyVariables;
214
215
/// Creates a new descriptor.
216
template <typename... Ts>
217
Descriptor *allocateDescriptor(Ts &&... Args) {
218
return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
219
}
220
221
/// No declaration ID.
222
static constexpr unsigned NoDeclaration = (unsigned)-1;
223
/// Last declaration ID.
224
unsigned LastDeclaration = 0;
225
/// Current declaration ID.
226
unsigned CurrentDeclaration = NoDeclaration;
227
228
/// Starts evaluating a declaration.
229
void startDeclaration(const ValueDecl *Decl) {
230
LastDeclaration += 1;
231
CurrentDeclaration = LastDeclaration;
232
}
233
234
/// Ends a global declaration.
235
void endDeclaration() {
236
CurrentDeclaration = NoDeclaration;
237
}
238
239
public:
240
/// Dumps the disassembled bytecode to \c llvm::errs().
241
void dump() const;
242
void dump(llvm::raw_ostream &OS) const;
243
};
244
245
} // namespace interp
246
} // namespace clang
247
248
#endif
249
250