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