123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- //===--- Program.h - Bytecode for the constexpr VM --------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Defines a program which organises and links multiple bytecode functions.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H
- #define LLVM_CLANG_AST_INTERP_PROGRAM_H
- #include <map>
- #include <vector>
- #include "Function.h"
- #include "Pointer.h"
- #include "PrimType.h"
- #include "Record.h"
- #include "Source.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/PointerUnion.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/Support/Allocator.h"
- namespace clang {
- class RecordDecl;
- class Expr;
- class FunctionDecl;
- class StringLiteral;
- class VarDecl;
- namespace interp {
- class Context;
- class Record;
- /// The program contains and links the bytecode for all functions.
- class Program final {
- public:
- Program(Context &Ctx) : Ctx(Ctx) {}
- ~Program() {
- // Manually destroy all the blocks. They are almost all harmless,
- // but primitive arrays might have an InitMap* heap allocated and
- // that needs to be freed.
- for (Global *G : Globals)
- G->block()->invokeDtor();
- // Records might actually allocate memory themselves, but they
- // are allocated using a BumpPtrAllocator. Call their desctructors
- // here manually so they are properly freeing their resources.
- for (auto RecordPair : Records) {
- if (Record *R = RecordPair.second)
- R->~Record();
- }
- }
- /// Marshals a native pointer to an ID for embedding in bytecode.
- unsigned getOrCreateNativePointer(const void *Ptr);
- /// Returns the value of a marshalled native pointer.
- const void *getNativePointer(unsigned Idx);
- /// Emits a string literal among global data.
- unsigned createGlobalString(const StringLiteral *S);
- /// Returns a pointer to a global.
- Pointer getPtrGlobal(unsigned Idx);
- /// Returns the value of a global.
- Block *getGlobal(unsigned Idx) {
- assert(Idx < Globals.size());
- return Globals[Idx]->block();
- }
- /// Finds a global's index.
- std::optional<unsigned> getGlobal(const ValueDecl *VD);
- /// Returns or creates a global an creates an index to it.
- std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
- const Expr *Init = nullptr);
- /// Returns or creates a dummy value for parameters.
- std::optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
- /// Creates a global and returns its index.
- std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *E);
- /// Creates a global from a lifetime-extended temporary.
- std::optional<unsigned> createGlobal(const Expr *E);
- /// Creates a new function from a code range.
- template <typename... Ts>
- Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
- Def = Def->getCanonicalDecl();
- auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
- Funcs.insert({Def, std::unique_ptr<Function>(Func)});
- return Func;
- }
- /// Creates an anonymous function.
- template <typename... Ts>
- Function *createFunction(Ts &&... Args) {
- auto *Func = new Function(*this, std::forward<Ts>(Args)...);
- AnonFuncs.emplace_back(Func);
- return Func;
- }
- /// Returns a function.
- Function *getFunction(const FunctionDecl *F);
- /// Returns a record or creates one if it does not exist.
- Record *getOrCreateRecord(const RecordDecl *RD);
- /// Creates a descriptor for a primitive type.
- Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
- Descriptor::MetadataSize MDSize = std::nullopt,
- bool IsConst = false, bool IsTemporary = false,
- bool IsMutable = false) {
- return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
- }
- /// Creates a descriptor for a composite type.
- Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
- Descriptor::MetadataSize MDSize = std::nullopt,
- bool IsConst = false, bool IsTemporary = false,
- bool IsMutable = false,
- const Expr *Init = nullptr);
- /// Context to manage declaration lifetimes.
- class DeclScope {
- public:
- DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
- ~DeclScope() { P.endDeclaration(); }
- private:
- Program &P;
- };
- /// Returns the current declaration ID.
- std::optional<unsigned> getCurrentDecl() const {
- if (CurrentDeclaration == NoDeclaration)
- return std::optional<unsigned>{};
- return LastDeclaration;
- }
- private:
- friend class DeclScope;
- std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
- bool IsStatic, bool IsExtern,
- const Expr *Init = nullptr);
- /// Reference to the VM context.
- Context &Ctx;
- /// Mapping from decls to cached bytecode functions.
- llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
- /// List of anonymous functions.
- std::vector<std::unique_ptr<Function>> AnonFuncs;
- /// Function relocation locations.
- llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
- /// Native pointers referenced by bytecode.
- std::vector<const void *> NativePointers;
- /// Cached native pointer indices.
- llvm::DenseMap<const void *, unsigned> NativePointerIndices;
- /// Custom allocator for global storage.
- using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
- /// Descriptor + storage for a global object.
- ///
- /// Global objects never go out of scope, thus they do not track pointers.
- class Global {
- public:
- /// Create a global descriptor for string literals.
- template <typename... Tys>
- Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
- /// Allocates the global in the pool, reserving storate for data.
- void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
- return Alloc.Allocate(Meta + Data, alignof(void *));
- }
- /// Return a pointer to the data.
- char *data() { return B.data(); }
- /// Return a pointer to the block.
- Block *block() { return &B; }
- private:
- /// Required metadata - does not actually track pointers.
- Block B;
- };
- /// Allocator for globals.
- PoolAllocTy Allocator;
- /// Global objects.
- std::vector<Global *> Globals;
- /// Cached global indices.
- llvm::DenseMap<const void *, unsigned> GlobalIndices;
- /// Mapping from decls to record metadata.
- llvm::DenseMap<const RecordDecl *, Record *> Records;
- /// Dummy parameter to generate pointers from.
- llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams;
- /// Creates a new descriptor.
- template <typename... Ts>
- Descriptor *allocateDescriptor(Ts &&... Args) {
- return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
- }
- /// No declaration ID.
- static constexpr unsigned NoDeclaration = (unsigned)-1;
- /// Last declaration ID.
- unsigned LastDeclaration = 0;
- /// Current declaration ID.
- unsigned CurrentDeclaration = NoDeclaration;
- /// Starts evaluating a declaration.
- void startDeclaration(const VarDecl *Decl) {
- LastDeclaration += 1;
- CurrentDeclaration = LastDeclaration;
- }
- /// Ends a global declaration.
- void endDeclaration() {
- CurrentDeclaration = NoDeclaration;
- }
- public:
- /// Dumps the disassembled bytecode to \c llvm::errs().
- void dump() const;
- void dump(llvm::raw_ostream &OS) const;
- };
- } // namespace interp
- } // namespace clang
- #endif
|