Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Program.h
35291 views
//===--- Program.h - Bytecode for the constexpr VM --------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines a program which organises and links multiple bytecode functions.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H13#define LLVM_CLANG_AST_INTERP_PROGRAM_H1415#include <map>16#include <vector>17#include "Function.h"18#include "Pointer.h"19#include "PrimType.h"20#include "Record.h"21#include "Source.h"22#include "llvm/ADT/DenseMap.h"23#include "llvm/ADT/PointerUnion.h"24#include "llvm/ADT/StringRef.h"25#include "llvm/Support/Allocator.h"2627namespace clang {28class RecordDecl;29class Expr;30class FunctionDecl;31class StringLiteral;32class VarDecl;3334namespace interp {35class Context;3637/// The program contains and links the bytecode for all functions.38class Program final {39public:40Program(Context &Ctx) : Ctx(Ctx) {}4142~Program() {43// Manually destroy all the blocks. They are almost all harmless,44// but primitive arrays might have an InitMap* heap allocated and45// that needs to be freed.46for (Global *G : Globals)47if (Block *B = G->block(); B->isInitialized())48B->invokeDtor();4950// Records might actually allocate memory themselves, but they51// are allocated using a BumpPtrAllocator. Call their desctructors52// here manually so they are properly freeing their resources.53for (auto RecordPair : Records) {54if (Record *R = RecordPair.second)55R->~Record();56}57}5859/// Marshals a native pointer to an ID for embedding in bytecode.60unsigned getOrCreateNativePointer(const void *Ptr);6162/// Returns the value of a marshalled native pointer.63const void *getNativePointer(unsigned Idx);6465/// Emits a string literal among global data.66unsigned createGlobalString(const StringLiteral *S);6768/// Returns a pointer to a global.69Pointer getPtrGlobal(unsigned Idx) const;7071/// Returns the value of a global.72Block *getGlobal(unsigned Idx) {73assert(Idx < Globals.size());74return Globals[Idx]->block();75}7677/// Finds a global's index.78std::optional<unsigned> getGlobal(const ValueDecl *VD);79std::optional<unsigned> getGlobal(const Expr *E);8081/// Returns or creates a global an creates an index to it.82std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,83const Expr *Init = nullptr);8485/// Returns or creates a dummy value for unknown declarations.86std::optional<unsigned> getOrCreateDummy(const ValueDecl *VD);8788/// Creates a global and returns its index.89std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init);9091/// Creates a global from a lifetime-extended temporary.92std::optional<unsigned> createGlobal(const Expr *E);9394/// Creates a new function from a code range.95template <typename... Ts>96Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {97Def = Def->getCanonicalDecl();98auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);99Funcs.insert({Def, std::unique_ptr<Function>(Func)});100return Func;101}102/// Creates an anonymous function.103template <typename... Ts>104Function *createFunction(Ts &&... Args) {105auto *Func = new Function(*this, std::forward<Ts>(Args)...);106AnonFuncs.emplace_back(Func);107return Func;108}109110/// Returns a function.111Function *getFunction(const FunctionDecl *F);112113/// Returns a record or creates one if it does not exist.114Record *getOrCreateRecord(const RecordDecl *RD);115116/// Creates a descriptor for a primitive type.117Descriptor *createDescriptor(const DeclTy &D, PrimType Type,118Descriptor::MetadataSize MDSize = std::nullopt,119bool IsConst = false, bool IsTemporary = false,120bool IsMutable = false) {121return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);122}123124/// Creates a descriptor for a composite type.125Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,126Descriptor::MetadataSize MDSize = std::nullopt,127bool IsConst = false, bool IsTemporary = false,128bool IsMutable = false,129const Expr *Init = nullptr);130131/// Context to manage declaration lifetimes.132class DeclScope {133public:134DeclScope(Program &P, const ValueDecl *VD) : P(P) {135P.startDeclaration(VD);136}137~DeclScope() { P.endDeclaration(); }138139private:140Program &P;141};142143/// Returns the current declaration ID.144std::optional<unsigned> getCurrentDecl() const {145if (CurrentDeclaration == NoDeclaration)146return std::optional<unsigned>{};147return LastDeclaration;148}149150private:151friend class DeclScope;152153std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,154bool IsStatic, bool IsExtern,155const Expr *Init = nullptr);156157/// Reference to the VM context.158Context &Ctx;159/// Mapping from decls to cached bytecode functions.160llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;161/// List of anonymous functions.162std::vector<std::unique_ptr<Function>> AnonFuncs;163164/// Function relocation locations.165llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;166167/// Native pointers referenced by bytecode.168std::vector<const void *> NativePointers;169/// Cached native pointer indices.170llvm::DenseMap<const void *, unsigned> NativePointerIndices;171172/// Custom allocator for global storage.173using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;174175/// Descriptor + storage for a global object.176///177/// Global objects never go out of scope, thus they do not track pointers.178class Global {179public:180/// Create a global descriptor for string literals.181template <typename... Tys>182Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}183184/// Allocates the global in the pool, reserving storate for data.185void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {186return Alloc.Allocate(Meta + Data, alignof(void *));187}188189/// Return a pointer to the data.190std::byte *data() { return B.data(); }191/// Return a pointer to the block.192Block *block() { return &B; }193const Block *block() const { return &B; }194195private:196/// Required metadata - does not actually track pointers.197Block B;198};199200/// Allocator for globals.201PoolAllocTy Allocator;202203/// Global objects.204std::vector<Global *> Globals;205/// Cached global indices.206llvm::DenseMap<const void *, unsigned> GlobalIndices;207208/// Mapping from decls to record metadata.209llvm::DenseMap<const RecordDecl *, Record *> Records;210211/// Dummy parameter to generate pointers from.212llvm::DenseMap<const ValueDecl *, unsigned> DummyVariables;213214/// Creates a new descriptor.215template <typename... Ts>216Descriptor *allocateDescriptor(Ts &&... Args) {217return new (Allocator) Descriptor(std::forward<Ts>(Args)...);218}219220/// No declaration ID.221static constexpr unsigned NoDeclaration = (unsigned)-1;222/// Last declaration ID.223unsigned LastDeclaration = 0;224/// Current declaration ID.225unsigned CurrentDeclaration = NoDeclaration;226227/// Starts evaluating a declaration.228void startDeclaration(const ValueDecl *Decl) {229LastDeclaration += 1;230CurrentDeclaration = LastDeclaration;231}232233/// Ends a global declaration.234void endDeclaration() {235CurrentDeclaration = NoDeclaration;236}237238public:239/// Dumps the disassembled bytecode to \c llvm::errs().240void dump() const;241void dump(llvm::raw_ostream &OS) const;242};243244} // namespace interp245} // namespace clang246247#endif248249250