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