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