xref: /openbsd/gnu/llvm/clang/lib/AST/Interp/Program.h (revision 12c85518)
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 class Record;
38 
39 /// The program contains and links the bytecode for all functions.
40 class Program final {
41 public:
Program(Context & Ctx)42   Program(Context &Ctx) : Ctx(Ctx) {}
43 
~Program()44   ~Program() {
45     // Manually destroy all the blocks. They are almost all harmless,
46     // but primitive arrays might have an InitMap* heap allocated and
47     // that needs to be freed.
48     for (Global *G : Globals)
49       G->block()->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);
71 
72   /// Returns the value of a global.
getGlobal(unsigned Idx)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 
81   /// Returns or creates a global an creates an index to it.
82   std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
83                                             const Expr *Init = nullptr);
84 
85   /// Returns or creates a dummy value for parameters.
86   std::optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
87 
88   /// Creates a global and returns its index.
89   std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *E);
90 
91   /// Creates a global from a lifetime-extended temporary.
92   std::optional<unsigned> createGlobal(const Expr *E);
93 
94   /// Creates a new function from a code range.
95   template <typename... Ts>
createFunction(const FunctionDecl * Def,Ts &&...Args)96   Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
97     Def = Def->getCanonicalDecl();
98     auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
99     Funcs.insert({Def, std::unique_ptr<Function>(Func)});
100     return Func;
101   }
102   /// Creates an anonymous function.
103   template <typename... Ts>
createFunction(Ts &&...Args)104   Function *createFunction(Ts &&... Args) {
105     auto *Func = new Function(*this, std::forward<Ts>(Args)...);
106     AnonFuncs.emplace_back(Func);
107     return Func;
108   }
109 
110   /// Returns a function.
111   Function *getFunction(const FunctionDecl *F);
112 
113   /// Returns a record or creates one if it does not exist.
114   Record *getOrCreateRecord(const RecordDecl *RD);
115 
116   /// Creates a descriptor for a primitive type.
117   Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
118                                Descriptor::MetadataSize MDSize = std::nullopt,
119                                bool IsConst = false, bool IsTemporary = false,
120                                bool IsMutable = false) {
121     return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
122   }
123 
124   /// Creates a descriptor for a composite type.
125   Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
126                                Descriptor::MetadataSize MDSize = std::nullopt,
127                                bool IsConst = false, bool IsTemporary = false,
128                                bool IsMutable = false,
129                                const Expr *Init = nullptr);
130 
131   /// Context to manage declaration lifetimes.
132   class DeclScope {
133   public:
DeclScope(Program & P,const VarDecl * VD)134     DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
~DeclScope()135     ~DeclScope() { P.endDeclaration(); }
136 
137   private:
138     Program &P;
139   };
140 
141   /// Returns the current declaration ID.
getCurrentDecl()142   std::optional<unsigned> getCurrentDecl() const {
143     if (CurrentDeclaration == NoDeclaration)
144       return std::optional<unsigned>{};
145     return LastDeclaration;
146   }
147 
148 private:
149   friend class DeclScope;
150 
151   std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
152                                        bool IsStatic, bool IsExtern,
153                                        const Expr *Init = nullptr);
154 
155   /// Reference to the VM context.
156   Context &Ctx;
157   /// Mapping from decls to cached bytecode functions.
158   llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
159   /// List of anonymous functions.
160   std::vector<std::unique_ptr<Function>> AnonFuncs;
161 
162   /// Function relocation locations.
163   llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
164 
165   /// Native pointers referenced by bytecode.
166   std::vector<const void *> NativePointers;
167   /// Cached native pointer indices.
168   llvm::DenseMap<const void *, unsigned> NativePointerIndices;
169 
170   /// Custom allocator for global storage.
171   using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
172 
173   /// Descriptor + storage for a global object.
174   ///
175   /// Global objects never go out of scope, thus they do not track pointers.
176   class Global {
177   public:
178     /// Create a global descriptor for string literals.
179     template <typename... Tys>
Global(Tys...Args)180     Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
181 
182     /// Allocates the global in the pool, reserving storate for data.
new(size_t Meta,PoolAllocTy & Alloc,size_t Data)183     void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
184       return Alloc.Allocate(Meta + Data, alignof(void *));
185     }
186 
187     /// Return a pointer to the data.
data()188     char *data() { return B.data(); }
189     /// Return a pointer to the block.
block()190     Block *block() { return &B; }
191 
192   private:
193     /// Required metadata - does not actually track pointers.
194     Block B;
195   };
196 
197   /// Allocator for globals.
198   PoolAllocTy Allocator;
199 
200   /// Global objects.
201   std::vector<Global *> Globals;
202   /// Cached global indices.
203   llvm::DenseMap<const void *, unsigned> GlobalIndices;
204 
205   /// Mapping from decls to record metadata.
206   llvm::DenseMap<const RecordDecl *, Record *> Records;
207 
208   /// Dummy parameter to generate pointers from.
209   llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams;
210 
211   /// Creates a new descriptor.
212   template <typename... Ts>
allocateDescriptor(Ts &&...Args)213   Descriptor *allocateDescriptor(Ts &&... Args) {
214     return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
215   }
216 
217   /// No declaration ID.
218   static constexpr unsigned NoDeclaration = (unsigned)-1;
219   /// Last declaration ID.
220   unsigned LastDeclaration = 0;
221   /// Current declaration ID.
222   unsigned CurrentDeclaration = NoDeclaration;
223 
224   /// Starts evaluating a declaration.
startDeclaration(const VarDecl * Decl)225   void startDeclaration(const VarDecl *Decl) {
226     LastDeclaration += 1;
227     CurrentDeclaration = LastDeclaration;
228   }
229 
230   /// Ends a global declaration.
endDeclaration()231   void endDeclaration() {
232     CurrentDeclaration = NoDeclaration;
233   }
234 
235 public:
236   /// Dumps the disassembled bytecode to \c llvm::errs().
237   void dump() const;
238   void dump(llvm::raw_ostream &OS) const;
239 };
240 
241 } // namespace interp
242 } // namespace clang
243 
244 #endif
245