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