1e5dd7070Spatrick //===--- Program.h - Bytecode for the constexpr VM --------------*- C++ -*-===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick // 9e5dd7070Spatrick // Defines a program which organises and links multiple bytecode functions. 10e5dd7070Spatrick // 11e5dd7070Spatrick //===----------------------------------------------------------------------===// 12e5dd7070Spatrick 13e5dd7070Spatrick #ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H 14e5dd7070Spatrick #define LLVM_CLANG_AST_INTERP_PROGRAM_H 15e5dd7070Spatrick 16e5dd7070Spatrick #include <map> 17e5dd7070Spatrick #include <vector> 18e5dd7070Spatrick #include "Function.h" 19e5dd7070Spatrick #include "Pointer.h" 20e5dd7070Spatrick #include "PrimType.h" 21e5dd7070Spatrick #include "Record.h" 22e5dd7070Spatrick #include "Source.h" 23e5dd7070Spatrick #include "llvm/ADT/DenseMap.h" 24e5dd7070Spatrick #include "llvm/ADT/PointerUnion.h" 25e5dd7070Spatrick #include "llvm/ADT/StringRef.h" 26e5dd7070Spatrick #include "llvm/Support/Allocator.h" 27e5dd7070Spatrick 28e5dd7070Spatrick namespace clang { 29e5dd7070Spatrick class RecordDecl; 30e5dd7070Spatrick class Expr; 31e5dd7070Spatrick class FunctionDecl; 32e5dd7070Spatrick class StringLiteral; 33e5dd7070Spatrick class VarDecl; 34e5dd7070Spatrick 35e5dd7070Spatrick namespace interp { 36e5dd7070Spatrick class Context; 37e5dd7070Spatrick class Record; 38e5dd7070Spatrick 39e5dd7070Spatrick /// The program contains and links the bytecode for all functions. 40*12c85518Srobert class Program final { 41e5dd7070Spatrick public: Program(Context & Ctx)42e5dd7070Spatrick Program(Context &Ctx) : Ctx(Ctx) {} 43e5dd7070Spatrick ~Program()44*12c85518Srobert ~Program() { 45*12c85518Srobert // Manually destroy all the blocks. They are almost all harmless, 46*12c85518Srobert // but primitive arrays might have an InitMap* heap allocated and 47*12c85518Srobert // that needs to be freed. 48*12c85518Srobert for (Global *G : Globals) 49*12c85518Srobert G->block()->invokeDtor(); 50*12c85518Srobert 51*12c85518Srobert // Records might actually allocate memory themselves, but they 52*12c85518Srobert // are allocated using a BumpPtrAllocator. Call their desctructors 53*12c85518Srobert // here manually so they are properly freeing their resources. 54*12c85518Srobert for (auto RecordPair : Records) { 55*12c85518Srobert if (Record *R = RecordPair.second) 56*12c85518Srobert R->~Record(); 57*12c85518Srobert } 58*12c85518Srobert } 59*12c85518Srobert 60*12c85518Srobert /// Marshals a native pointer to an ID for embedding in bytecode. 61*12c85518Srobert unsigned getOrCreateNativePointer(const void *Ptr); 62*12c85518Srobert 63*12c85518Srobert /// Returns the value of a marshalled native pointer. 64*12c85518Srobert const void *getNativePointer(unsigned Idx); 65*12c85518Srobert 66e5dd7070Spatrick /// Emits a string literal among global data. 67e5dd7070Spatrick unsigned createGlobalString(const StringLiteral *S); 68e5dd7070Spatrick 69e5dd7070Spatrick /// Returns a pointer to a global. 70e5dd7070Spatrick Pointer getPtrGlobal(unsigned Idx); 71e5dd7070Spatrick 72e5dd7070Spatrick /// Returns the value of a global. getGlobal(unsigned Idx)73e5dd7070Spatrick Block *getGlobal(unsigned Idx) { 74e5dd7070Spatrick assert(Idx < Globals.size()); 75e5dd7070Spatrick return Globals[Idx]->block(); 76e5dd7070Spatrick } 77e5dd7070Spatrick 78e5dd7070Spatrick /// Finds a global's index. 79*12c85518Srobert std::optional<unsigned> getGlobal(const ValueDecl *VD); 80e5dd7070Spatrick 81e5dd7070Spatrick /// Returns or creates a global an creates an index to it. 82*12c85518Srobert std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD, 83*12c85518Srobert const Expr *Init = nullptr); 84e5dd7070Spatrick 85e5dd7070Spatrick /// Returns or creates a dummy value for parameters. 86*12c85518Srobert std::optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD); 87e5dd7070Spatrick 88e5dd7070Spatrick /// Creates a global and returns its index. 89*12c85518Srobert std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *E); 90e5dd7070Spatrick 91e5dd7070Spatrick /// Creates a global from a lifetime-extended temporary. 92*12c85518Srobert std::optional<unsigned> createGlobal(const Expr *E); 93e5dd7070Spatrick 94e5dd7070Spatrick /// Creates a new function from a code range. 95e5dd7070Spatrick template <typename... Ts> createFunction(const FunctionDecl * Def,Ts &&...Args)96e5dd7070Spatrick Function *createFunction(const FunctionDecl *Def, Ts &&... Args) { 97*12c85518Srobert Def = Def->getCanonicalDecl(); 98e5dd7070Spatrick auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...); 99e5dd7070Spatrick Funcs.insert({Def, std::unique_ptr<Function>(Func)}); 100e5dd7070Spatrick return Func; 101e5dd7070Spatrick } 102e5dd7070Spatrick /// Creates an anonymous function. 103e5dd7070Spatrick template <typename... Ts> createFunction(Ts &&...Args)104e5dd7070Spatrick Function *createFunction(Ts &&... Args) { 105e5dd7070Spatrick auto *Func = new Function(*this, std::forward<Ts>(Args)...); 106e5dd7070Spatrick AnonFuncs.emplace_back(Func); 107e5dd7070Spatrick return Func; 108e5dd7070Spatrick } 109e5dd7070Spatrick 110e5dd7070Spatrick /// Returns a function. 111e5dd7070Spatrick Function *getFunction(const FunctionDecl *F); 112e5dd7070Spatrick 113e5dd7070Spatrick /// Returns a record or creates one if it does not exist. 114e5dd7070Spatrick Record *getOrCreateRecord(const RecordDecl *RD); 115e5dd7070Spatrick 116e5dd7070Spatrick /// Creates a descriptor for a primitive type. 117e5dd7070Spatrick Descriptor *createDescriptor(const DeclTy &D, PrimType Type, 118*12c85518Srobert Descriptor::MetadataSize MDSize = std::nullopt, 119*12c85518Srobert bool IsConst = false, bool IsTemporary = false, 120e5dd7070Spatrick bool IsMutable = false) { 121*12c85518Srobert return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable); 122e5dd7070Spatrick } 123e5dd7070Spatrick 124e5dd7070Spatrick /// Creates a descriptor for a composite type. 125e5dd7070Spatrick Descriptor *createDescriptor(const DeclTy &D, const Type *Ty, 126*12c85518Srobert Descriptor::MetadataSize MDSize = std::nullopt, 127e5dd7070Spatrick bool IsConst = false, bool IsTemporary = false, 128*12c85518Srobert bool IsMutable = false, 129*12c85518Srobert const Expr *Init = nullptr); 130e5dd7070Spatrick 131e5dd7070Spatrick /// Context to manage declaration lifetimes. 132e5dd7070Spatrick class DeclScope { 133e5dd7070Spatrick public: DeclScope(Program & P,const VarDecl * VD)134e5dd7070Spatrick DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); } ~DeclScope()135e5dd7070Spatrick ~DeclScope() { P.endDeclaration(); } 136e5dd7070Spatrick 137e5dd7070Spatrick private: 138e5dd7070Spatrick Program &P; 139e5dd7070Spatrick }; 140e5dd7070Spatrick 141e5dd7070Spatrick /// Returns the current declaration ID. getCurrentDecl()142*12c85518Srobert std::optional<unsigned> getCurrentDecl() const { 143e5dd7070Spatrick if (CurrentDeclaration == NoDeclaration) 144*12c85518Srobert return std::optional<unsigned>{}; 145e5dd7070Spatrick return LastDeclaration; 146e5dd7070Spatrick } 147e5dd7070Spatrick 148e5dd7070Spatrick private: 149e5dd7070Spatrick friend class DeclScope; 150e5dd7070Spatrick 151*12c85518Srobert std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty, 152*12c85518Srobert bool IsStatic, bool IsExtern, 153*12c85518Srobert const Expr *Init = nullptr); 154e5dd7070Spatrick 155e5dd7070Spatrick /// Reference to the VM context. 156e5dd7070Spatrick Context &Ctx; 157e5dd7070Spatrick /// Mapping from decls to cached bytecode functions. 158e5dd7070Spatrick llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs; 159e5dd7070Spatrick /// List of anonymous functions. 160e5dd7070Spatrick std::vector<std::unique_ptr<Function>> AnonFuncs; 161e5dd7070Spatrick 162e5dd7070Spatrick /// Function relocation locations. 163e5dd7070Spatrick llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs; 164e5dd7070Spatrick 165*12c85518Srobert /// Native pointers referenced by bytecode. 166*12c85518Srobert std::vector<const void *> NativePointers; 167*12c85518Srobert /// Cached native pointer indices. 168*12c85518Srobert llvm::DenseMap<const void *, unsigned> NativePointerIndices; 169*12c85518Srobert 170e5dd7070Spatrick /// Custom allocator for global storage. 171e5dd7070Spatrick using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>; 172e5dd7070Spatrick 173e5dd7070Spatrick /// Descriptor + storage for a global object. 174e5dd7070Spatrick /// 175e5dd7070Spatrick /// Global objects never go out of scope, thus they do not track pointers. 176e5dd7070Spatrick class Global { 177e5dd7070Spatrick public: 178e5dd7070Spatrick /// Create a global descriptor for string literals. 179e5dd7070Spatrick template <typename... Tys> Global(Tys...Args)180e5dd7070Spatrick Global(Tys... Args) : B(std::forward<Tys>(Args)...) {} 181e5dd7070Spatrick 182e5dd7070Spatrick /// Allocates the global in the pool, reserving storate for data. new(size_t Meta,PoolAllocTy & Alloc,size_t Data)183e5dd7070Spatrick void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) { 184e5dd7070Spatrick return Alloc.Allocate(Meta + Data, alignof(void *)); 185e5dd7070Spatrick } 186e5dd7070Spatrick 187e5dd7070Spatrick /// Return a pointer to the data. data()188e5dd7070Spatrick char *data() { return B.data(); } 189e5dd7070Spatrick /// Return a pointer to the block. block()190e5dd7070Spatrick Block *block() { return &B; } 191e5dd7070Spatrick 192e5dd7070Spatrick private: 193e5dd7070Spatrick /// Required metadata - does not actually track pointers. 194e5dd7070Spatrick Block B; 195e5dd7070Spatrick }; 196e5dd7070Spatrick 197e5dd7070Spatrick /// Allocator for globals. 198e5dd7070Spatrick PoolAllocTy Allocator; 199e5dd7070Spatrick 200e5dd7070Spatrick /// Global objects. 201e5dd7070Spatrick std::vector<Global *> Globals; 202e5dd7070Spatrick /// Cached global indices. 203e5dd7070Spatrick llvm::DenseMap<const void *, unsigned> GlobalIndices; 204e5dd7070Spatrick 205e5dd7070Spatrick /// Mapping from decls to record metadata. 206e5dd7070Spatrick llvm::DenseMap<const RecordDecl *, Record *> Records; 207e5dd7070Spatrick 208e5dd7070Spatrick /// Dummy parameter to generate pointers from. 209e5dd7070Spatrick llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams; 210e5dd7070Spatrick 211e5dd7070Spatrick /// Creates a new descriptor. 212e5dd7070Spatrick template <typename... Ts> allocateDescriptor(Ts &&...Args)213e5dd7070Spatrick Descriptor *allocateDescriptor(Ts &&... Args) { 214e5dd7070Spatrick return new (Allocator) Descriptor(std::forward<Ts>(Args)...); 215e5dd7070Spatrick } 216e5dd7070Spatrick 217e5dd7070Spatrick /// No declaration ID. 218e5dd7070Spatrick static constexpr unsigned NoDeclaration = (unsigned)-1; 219e5dd7070Spatrick /// Last declaration ID. 220e5dd7070Spatrick unsigned LastDeclaration = 0; 221e5dd7070Spatrick /// Current declaration ID. 222e5dd7070Spatrick unsigned CurrentDeclaration = NoDeclaration; 223e5dd7070Spatrick 224e5dd7070Spatrick /// Starts evaluating a declaration. startDeclaration(const VarDecl * Decl)225e5dd7070Spatrick void startDeclaration(const VarDecl *Decl) { 226e5dd7070Spatrick LastDeclaration += 1; 227e5dd7070Spatrick CurrentDeclaration = LastDeclaration; 228e5dd7070Spatrick } 229e5dd7070Spatrick 230e5dd7070Spatrick /// Ends a global declaration. endDeclaration()231e5dd7070Spatrick void endDeclaration() { 232e5dd7070Spatrick CurrentDeclaration = NoDeclaration; 233e5dd7070Spatrick } 234e5dd7070Spatrick 235e5dd7070Spatrick public: 236e5dd7070Spatrick /// Dumps the disassembled bytecode to \c llvm::errs(). 237e5dd7070Spatrick void dump() const; 238e5dd7070Spatrick void dump(llvm::raw_ostream &OS) const; 239e5dd7070Spatrick }; 240e5dd7070Spatrick 241e5dd7070Spatrick } // namespace interp 242e5dd7070Spatrick } // namespace clang 243e5dd7070Spatrick 244e5dd7070Spatrick #endif 245