xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===-- InterpBlock.h - Allocated blocks for the interpreter -*- C++ ----*-===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric //
9*5ffd83dbSDimitry Andric // Defines the classes describing allocated blocks.
10*5ffd83dbSDimitry Andric //
11*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
12*5ffd83dbSDimitry Andric 
13*5ffd83dbSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_BLOCK_H
14*5ffd83dbSDimitry Andric #define LLVM_CLANG_AST_INTERP_BLOCK_H
15*5ffd83dbSDimitry Andric 
16*5ffd83dbSDimitry Andric #include "Descriptor.h"
17*5ffd83dbSDimitry Andric #include "clang/AST/Decl.h"
18*5ffd83dbSDimitry Andric #include "clang/AST/DeclCXX.h"
19*5ffd83dbSDimitry Andric #include "clang/AST/Expr.h"
20*5ffd83dbSDimitry Andric #include "clang/AST/ComparisonCategories.h"
21*5ffd83dbSDimitry Andric #include "llvm/ADT/PointerUnion.h"
22*5ffd83dbSDimitry Andric #include "llvm/Support/raw_ostream.h"
23*5ffd83dbSDimitry Andric 
24*5ffd83dbSDimitry Andric namespace clang {
25*5ffd83dbSDimitry Andric namespace interp {
26*5ffd83dbSDimitry Andric class Block;
27*5ffd83dbSDimitry Andric class DeadBlock;
28*5ffd83dbSDimitry Andric class Context;
29*5ffd83dbSDimitry Andric class InterpState;
30*5ffd83dbSDimitry Andric class Pointer;
31*5ffd83dbSDimitry Andric class Function;
32*5ffd83dbSDimitry Andric enum PrimType : unsigned;
33*5ffd83dbSDimitry Andric 
34*5ffd83dbSDimitry Andric /// A memory block, either on the stack or in the heap.
35*5ffd83dbSDimitry Andric ///
36*5ffd83dbSDimitry Andric /// The storage described by the block immediately follows it in memory.
37*5ffd83dbSDimitry Andric class Block {
38*5ffd83dbSDimitry Andric public:
39*5ffd83dbSDimitry Andric   // Creates a new block.
40*5ffd83dbSDimitry Andric   Block(const llvm::Optional<unsigned> &DeclID, Descriptor *Desc,
41*5ffd83dbSDimitry Andric         bool IsStatic = false, bool IsExtern = false)
42*5ffd83dbSDimitry Andric       : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
43*5ffd83dbSDimitry Andric 
44*5ffd83dbSDimitry Andric   Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
45*5ffd83dbSDimitry Andric       : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern),
46*5ffd83dbSDimitry Andric         Desc(Desc) {}
47*5ffd83dbSDimitry Andric 
48*5ffd83dbSDimitry Andric   /// Returns the block's descriptor.
49*5ffd83dbSDimitry Andric   Descriptor *getDescriptor() const { return Desc; }
50*5ffd83dbSDimitry Andric   /// Checks if the block has any live pointers.
51*5ffd83dbSDimitry Andric   bool hasPointers() const { return Pointers; }
52*5ffd83dbSDimitry Andric   /// Checks if the block is extern.
53*5ffd83dbSDimitry Andric   bool isExtern() const { return IsExtern; }
54*5ffd83dbSDimitry Andric   /// Checks if the block has static storage duration.
55*5ffd83dbSDimitry Andric   bool isStatic() const { return IsStatic; }
56*5ffd83dbSDimitry Andric   /// Checks if the block is temporary.
57*5ffd83dbSDimitry Andric   bool isTemporary() const { return Desc->IsTemporary; }
58*5ffd83dbSDimitry Andric   /// Returns the size of the block.
59*5ffd83dbSDimitry Andric   InterpSize getSize() const { return Desc->getAllocSize(); }
60*5ffd83dbSDimitry Andric   /// Returns the declaration ID.
61*5ffd83dbSDimitry Andric   llvm::Optional<unsigned> getDeclID() const { return DeclID; }
62*5ffd83dbSDimitry Andric 
63*5ffd83dbSDimitry Andric   /// Returns a pointer to the stored data.
64*5ffd83dbSDimitry Andric   char *data() { return reinterpret_cast<char *>(this + 1); }
65*5ffd83dbSDimitry Andric 
66*5ffd83dbSDimitry Andric   /// Returns a view over the data.
67*5ffd83dbSDimitry Andric   template <typename T>
68*5ffd83dbSDimitry Andric   T &deref() { return *reinterpret_cast<T *>(data()); }
69*5ffd83dbSDimitry Andric 
70*5ffd83dbSDimitry Andric   /// Invokes the constructor.
71*5ffd83dbSDimitry Andric   void invokeCtor() {
72*5ffd83dbSDimitry Andric     std::memset(data(), 0, getSize());
73*5ffd83dbSDimitry Andric     if (Desc->CtorFn)
74*5ffd83dbSDimitry Andric       Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
75*5ffd83dbSDimitry Andric                    /*isActive=*/true, Desc);
76*5ffd83dbSDimitry Andric   }
77*5ffd83dbSDimitry Andric 
78*5ffd83dbSDimitry Andric protected:
79*5ffd83dbSDimitry Andric   friend class Pointer;
80*5ffd83dbSDimitry Andric   friend class DeadBlock;
81*5ffd83dbSDimitry Andric   friend class InterpState;
82*5ffd83dbSDimitry Andric 
83*5ffd83dbSDimitry Andric   Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead)
84*5ffd83dbSDimitry Andric     : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {}
85*5ffd83dbSDimitry Andric 
86*5ffd83dbSDimitry Andric   // Deletes a dead block at the end of its lifetime.
87*5ffd83dbSDimitry Andric   void cleanup();
88*5ffd83dbSDimitry Andric 
89*5ffd83dbSDimitry Andric   // Pointer chain management.
90*5ffd83dbSDimitry Andric   void addPointer(Pointer *P);
91*5ffd83dbSDimitry Andric   void removePointer(Pointer *P);
92*5ffd83dbSDimitry Andric   void movePointer(Pointer *From, Pointer *To);
93*5ffd83dbSDimitry Andric 
94*5ffd83dbSDimitry Andric   /// Start of the chain of pointers.
95*5ffd83dbSDimitry Andric   Pointer *Pointers = nullptr;
96*5ffd83dbSDimitry Andric   /// Unique identifier of the declaration.
97*5ffd83dbSDimitry Andric   llvm::Optional<unsigned> DeclID;
98*5ffd83dbSDimitry Andric   /// Flag indicating if the block has static storage duration.
99*5ffd83dbSDimitry Andric   bool IsStatic = false;
100*5ffd83dbSDimitry Andric   /// Flag indicating if the block is an extern.
101*5ffd83dbSDimitry Andric   bool IsExtern = false;
102*5ffd83dbSDimitry Andric   /// Flag indicating if the pointer is dead.
103*5ffd83dbSDimitry Andric   bool IsDead = false;
104*5ffd83dbSDimitry Andric   /// Pointer to the stack slot descriptor.
105*5ffd83dbSDimitry Andric   Descriptor *Desc;
106*5ffd83dbSDimitry Andric };
107*5ffd83dbSDimitry Andric 
108*5ffd83dbSDimitry Andric /// Descriptor for a dead block.
109*5ffd83dbSDimitry Andric ///
110*5ffd83dbSDimitry Andric /// Dead blocks are chained in a double-linked list to deallocate them
111*5ffd83dbSDimitry Andric /// whenever pointers become dead.
112*5ffd83dbSDimitry Andric class DeadBlock {
113*5ffd83dbSDimitry Andric public:
114*5ffd83dbSDimitry Andric   /// Copies the block.
115*5ffd83dbSDimitry Andric   DeadBlock(DeadBlock *&Root, Block *Blk);
116*5ffd83dbSDimitry Andric 
117*5ffd83dbSDimitry Andric   /// Returns a pointer to the stored data.
118*5ffd83dbSDimitry Andric   char *data() { return B.data(); }
119*5ffd83dbSDimitry Andric 
120*5ffd83dbSDimitry Andric private:
121*5ffd83dbSDimitry Andric   friend class Block;
122*5ffd83dbSDimitry Andric   friend class InterpState;
123*5ffd83dbSDimitry Andric 
124*5ffd83dbSDimitry Andric   void free();
125*5ffd83dbSDimitry Andric 
126*5ffd83dbSDimitry Andric   /// Root pointer of the list.
127*5ffd83dbSDimitry Andric   DeadBlock *&Root;
128*5ffd83dbSDimitry Andric   /// Previous block in the list.
129*5ffd83dbSDimitry Andric   DeadBlock *Prev;
130*5ffd83dbSDimitry Andric   /// Next block in the list.
131*5ffd83dbSDimitry Andric   DeadBlock *Next;
132*5ffd83dbSDimitry Andric 
133*5ffd83dbSDimitry Andric   /// Actual block storing data and tracking pointers.
134*5ffd83dbSDimitry Andric   Block B;
135*5ffd83dbSDimitry Andric };
136*5ffd83dbSDimitry Andric 
137*5ffd83dbSDimitry Andric } // namespace interp
138*5ffd83dbSDimitry Andric } // namespace clang
139*5ffd83dbSDimitry Andric 
140*5ffd83dbSDimitry Andric #endif
141