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