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