xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Program.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 "Function.h"
17 #include "Pointer.h"
18 #include "PrimType.h"
19 #include "Record.h"
20 #include "Source.h"
21 #include "llvm/ADT/DenseMap.h"
22 #include "llvm/ADT/PointerUnion.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/Support/Allocator.h"
25 #include <map>
26 #include <vector>
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:
Program(Context & Ctx)41   Program(Context &Ctx) : Ctx(Ctx) {}
42 
~Program()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                               const Expr *Base = nullptr);
69 
70   /// Returns a pointer to a global.
71   Pointer getPtrGlobal(unsigned Idx) const;
72 
73   /// Returns the value of a global.
getGlobal(unsigned Idx)74   Block *getGlobal(unsigned Idx) {
75     assert(Idx < Globals.size());
76     return Globals[Idx]->block();
77   }
78 
79   /// Finds a global's index.
80   std::optional<unsigned> getGlobal(const ValueDecl *VD);
81   std::optional<unsigned> getGlobal(const Expr *E);
82 
83   /// Returns or creates a global an creates an index to it.
84   std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
85                                             const Expr *Init = nullptr);
86 
87   /// Returns or creates a dummy value for unknown declarations.
88   unsigned getOrCreateDummy(const DeclTy &D);
89 
90   /// Creates a global and returns its index.
91   std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init);
92 
93   /// Creates a global from a lifetime-extended temporary.
94   std::optional<unsigned> createGlobal(const Expr *E);
95 
96   /// Creates a new function from a code range.
97   template <typename... Ts>
createFunction(const FunctionDecl * Def,Ts &&...Args)98   Function *createFunction(const FunctionDecl *Def, Ts &&...Args) {
99     Def = Def->getCanonicalDecl();
100     auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
101     Funcs.insert({Def, std::unique_ptr<Function>(Func)});
102     return Func;
103   }
104   /// Creates an anonymous function.
createFunction(Ts &&...Args)105   template <typename... Ts> 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 T,
119                                const Type *SourceTy = nullptr,
120                                Descriptor::MetadataSize MDSize = std::nullopt,
121                                bool IsConst = false, bool IsTemporary = false,
122                                bool IsMutable = false,
123                                bool IsVolatile = false) {
124     return allocateDescriptor(D, SourceTy, T, MDSize, IsConst, IsTemporary,
125                               IsMutable, IsVolatile);
126   }
127 
128   /// Creates a descriptor for a composite type.
129   Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
130                                Descriptor::MetadataSize MDSize = std::nullopt,
131                                bool IsConst = false, bool IsTemporary = false,
132                                bool IsMutable = false, bool IsVolatile = false,
133                                const Expr *Init = nullptr);
134 
135   void *Allocate(size_t Size, unsigned Align = 8) const {
136     return Allocator.Allocate(Size, Align);
137   }
138   template <typename T> T *Allocate(size_t Num = 1) const {
139     return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
140   }
Deallocate(void * Ptr)141   void Deallocate(void *Ptr) const {}
142 
143   /// Context to manage declaration lifetimes.
144   class DeclScope {
145   public:
DeclScope(Program & P)146     DeclScope(Program &P) : P(P), PrevDecl(P.CurrentDeclaration) {
147       ++P.LastDeclaration;
148       P.CurrentDeclaration = P.LastDeclaration;
149     }
~DeclScope()150     ~DeclScope() { P.CurrentDeclaration = PrevDecl; }
151 
152   private:
153     Program &P;
154     unsigned PrevDecl;
155   };
156 
157   /// Returns the current declaration ID.
getCurrentDecl()158   std::optional<unsigned> getCurrentDecl() const {
159     if (CurrentDeclaration == NoDeclaration)
160       return std::nullopt;
161     return CurrentDeclaration;
162   }
163 
164 private:
165   friend class DeclScope;
166 
167   std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
168                                        bool IsStatic, bool IsExtern,
169                                        bool IsWeak, const Expr *Init = nullptr);
170 
171   /// Reference to the VM context.
172   Context &Ctx;
173   /// Mapping from decls to cached bytecode functions.
174   llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
175   /// List of anonymous functions.
176   std::vector<std::unique_ptr<Function>> AnonFuncs;
177 
178   /// Function relocation locations.
179   llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
180 
181   /// Native pointers referenced by bytecode.
182   std::vector<const void *> NativePointers;
183   /// Cached native pointer indices.
184   llvm::DenseMap<const void *, unsigned> NativePointerIndices;
185 
186   /// Custom allocator for global storage.
187   using PoolAllocTy = llvm::BumpPtrAllocator;
188 
189   /// Descriptor + storage for a global object.
190   ///
191   /// Global objects never go out of scope, thus they do not track pointers.
192   class Global {
193   public:
194     /// Create a global descriptor for string literals.
195     template <typename... Tys>
Global(Tys...Args)196     Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
197 
198     /// Allocates the global in the pool, reserving storate for data.
new(size_t Meta,PoolAllocTy & Alloc,size_t Data)199     void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
200       return Alloc.Allocate(Meta + Data, alignof(void *));
201     }
202 
203     /// Return a pointer to the data.
data()204     std::byte *data() { return B.data(); }
205     /// Return a pointer to the block.
block()206     Block *block() { return &B; }
block()207     const Block *block() const { return &B; }
208 
209   private:
210     /// Required metadata - does not actually track pointers.
211     Block B;
212   };
213 
214   /// Allocator for globals.
215   mutable PoolAllocTy Allocator;
216 
217   /// Global objects.
218   std::vector<Global *> Globals;
219   /// Cached global indices.
220   llvm::DenseMap<const void *, unsigned> GlobalIndices;
221 
222   /// Mapping from decls to record metadata.
223   llvm::DenseMap<const RecordDecl *, Record *> Records;
224 
225   /// Dummy parameter to generate pointers from.
226   llvm::DenseMap<const void *, unsigned> DummyVariables;
227 
228   /// Creates a new descriptor.
allocateDescriptor(Ts &&...Args)229   template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) {
230     return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
231   }
232 
233   /// No declaration ID.
234   static constexpr unsigned NoDeclaration = ~0u;
235   /// Last declaration ID.
236   unsigned LastDeclaration = 0;
237   /// Current declaration ID.
238   unsigned CurrentDeclaration = NoDeclaration;
239 
240 public:
241   /// Dumps the disassembled bytecode to \c llvm::errs().
242   void dump() const;
243   void dump(llvm::raw_ostream &OS) const;
244 };
245 
246 } // namespace interp
247 } // namespace clang
248 
249 inline void *operator new(size_t Bytes, const clang::interp::Program &C,
250                           size_t Alignment = 8) {
251   return C.Allocate(Bytes, Alignment);
252 }
253 
delete(void * Ptr,const clang::interp::Program & C,size_t)254 inline void operator delete(void *Ptr, const clang::interp::Program &C,
255                             size_t) {
256   C.Deallocate(Ptr);
257 }
258 inline void *operator new[](size_t Bytes, const clang::interp::Program &C,
259                             size_t Alignment = 8) {
260   return C.Allocate(Bytes, Alignment);
261 }
262 
263 #endif
264