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