brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.4 KiB · c879550 Raw
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