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

source code of clang/lib/AST/Interp/Program.h