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: 41 Program(Context &Ctx) : Ctx(Ctx) {} 42 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. 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> 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. 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 } 141 void Deallocate(void *Ptr) const {} 142 143 /// Context to manage declaration lifetimes. 144 class DeclScope { 145 public: 146 DeclScope(Program &P) : P(P), PrevDecl(P.CurrentDeclaration) { 147 ++P.LastDeclaration; 148 P.CurrentDeclaration = P.LastDeclaration; 149 } 150 ~DeclScope() { P.CurrentDeclaration = PrevDecl; } 151 152 private: 153 Program &P; 154 unsigned PrevDecl; 155 }; 156 157 /// Returns the current declaration ID. 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> 196 Global(Tys... Args) : B(std::forward<Tys>(Args)...) {} 197 198 /// Allocates the global in the pool, reserving storate for 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. 204 std::byte *data() { return B.data(); } 205 /// Return a pointer to the block. 206 Block *block() { return &B; } 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. 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 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