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