xref: /llvm-project/clang/lib/AST/ByteCode/InterpBlock.h (revision 4e5f8a8f0bf855fdac93fa09b4b82b69339235b9)
1a07aba5dSTimm Baeder //===-- InterpBlock.h - Allocated blocks for the interpreter -*- C++ ----*-===//
2a07aba5dSTimm Baeder //
3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a07aba5dSTimm Baeder //
7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8a07aba5dSTimm Baeder //
9a07aba5dSTimm Baeder // Defines the classes describing allocated blocks.
10a07aba5dSTimm Baeder //
11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
12a07aba5dSTimm Baeder 
13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_BLOCK_H
14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_BLOCK_H
15a07aba5dSTimm Baeder 
16a07aba5dSTimm Baeder #include "Descriptor.h"
17a07aba5dSTimm Baeder #include "clang/AST/ComparisonCategories.h"
18a07aba5dSTimm Baeder #include "clang/AST/Decl.h"
19a07aba5dSTimm Baeder #include "clang/AST/DeclCXX.h"
20a07aba5dSTimm Baeder #include "clang/AST/Expr.h"
21a07aba5dSTimm Baeder #include "llvm/ADT/PointerUnion.h"
22a07aba5dSTimm Baeder #include "llvm/Support/raw_ostream.h"
23a07aba5dSTimm Baeder 
24a07aba5dSTimm Baeder namespace clang {
25a07aba5dSTimm Baeder namespace interp {
26a07aba5dSTimm Baeder class Block;
27a07aba5dSTimm Baeder class DeadBlock;
28a07aba5dSTimm Baeder class InterpState;
29a07aba5dSTimm Baeder class Pointer;
30a07aba5dSTimm Baeder enum PrimType : unsigned;
31a07aba5dSTimm Baeder 
32a07aba5dSTimm Baeder /// A memory block, either on the stack or in the heap.
33a07aba5dSTimm Baeder ///
34a07aba5dSTimm Baeder /// The storage described by the block is immediately followed by
35a07aba5dSTimm Baeder /// optional metadata, which is followed by the actual data.
36a07aba5dSTimm Baeder ///
37a07aba5dSTimm Baeder /// Block*        rawData()                  data()
38a07aba5dSTimm Baeder /// │               │                         │
39a07aba5dSTimm Baeder /// │               │                         │
40a07aba5dSTimm Baeder /// ▼               ▼                         ▼
41a07aba5dSTimm Baeder /// ┌───────────────┬─────────────────────────┬─────────────────┐
42a07aba5dSTimm Baeder /// │ Block         │ Metadata                │ Data            │
43a07aba5dSTimm Baeder /// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │
44a07aba5dSTimm Baeder /// └───────────────┴─────────────────────────┴─────────────────┘
45a07aba5dSTimm Baeder ///
46a07aba5dSTimm Baeder /// Desc->getAllocSize() describes the size after the Block, i.e.
47a07aba5dSTimm Baeder /// the data size and the metadata size.
48a07aba5dSTimm Baeder ///
49a07aba5dSTimm Baeder class Block final {
50a07aba5dSTimm Baeder public:
51a07aba5dSTimm Baeder   /// Creates a new block.
52a07aba5dSTimm Baeder   Block(unsigned EvalID, const std::optional<unsigned> &DeclID,
53*4e5f8a8fSTimm Baeder         const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false,
54*4e5f8a8fSTimm Baeder         bool IsWeak = false)
55a07aba5dSTimm Baeder       : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern),
56*4e5f8a8fSTimm Baeder         IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
57a07aba5dSTimm Baeder     assert(Desc);
58a07aba5dSTimm Baeder   }
59a07aba5dSTimm Baeder 
60a07aba5dSTimm Baeder   Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
61*4e5f8a8fSTimm Baeder         bool IsExtern = false, bool IsWeak = false)
62a07aba5dSTimm Baeder       : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic),
63*4e5f8a8fSTimm Baeder         IsExtern(IsExtern), IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
64a07aba5dSTimm Baeder     assert(Desc);
65a07aba5dSTimm Baeder   }
66a07aba5dSTimm Baeder 
67a07aba5dSTimm Baeder   /// Returns the block's descriptor.
68a07aba5dSTimm Baeder   const Descriptor *getDescriptor() const { return Desc; }
69a07aba5dSTimm Baeder   /// Checks if the block has any live pointers.
70a07aba5dSTimm Baeder   bool hasPointers() const { return Pointers; }
71a07aba5dSTimm Baeder   /// Checks if the block is extern.
72a07aba5dSTimm Baeder   bool isExtern() const { return IsExtern; }
73a07aba5dSTimm Baeder   /// Checks if the block has static storage duration.
74a07aba5dSTimm Baeder   bool isStatic() const { return IsStatic; }
75a07aba5dSTimm Baeder   /// Checks if the block is temporary.
76a07aba5dSTimm Baeder   bool isTemporary() const { return Desc->IsTemporary; }
77*4e5f8a8fSTimm Baeder   bool isWeak() const { return IsWeak; }
78a07aba5dSTimm Baeder   bool isDynamic() const { return IsDynamic; }
79a07aba5dSTimm Baeder   /// Returns the size of the block.
80a07aba5dSTimm Baeder   unsigned getSize() const { return Desc->getAllocSize(); }
81a07aba5dSTimm Baeder   /// Returns the declaration ID.
82a07aba5dSTimm Baeder   std::optional<unsigned> getDeclID() const { return DeclID; }
83a07aba5dSTimm Baeder   /// Returns whether the data of this block has been initialized via
84a07aba5dSTimm Baeder   /// invoking the Ctor func.
85a07aba5dSTimm Baeder   bool isInitialized() const { return IsInitialized; }
86a07aba5dSTimm Baeder   /// The Evaluation ID this block was created in.
87a07aba5dSTimm Baeder   unsigned getEvalID() const { return EvalID; }
88a07aba5dSTimm Baeder 
89a07aba5dSTimm Baeder   /// Returns a pointer to the stored data.
90a07aba5dSTimm Baeder   /// You are allowed to read Desc->getSize() bytes from this address.
91a07aba5dSTimm Baeder   std::byte *data() {
92a07aba5dSTimm Baeder     // rawData might contain metadata as well.
93a07aba5dSTimm Baeder     size_t DataOffset = Desc->getMetadataSize();
94a07aba5dSTimm Baeder     return rawData() + DataOffset;
95a07aba5dSTimm Baeder   }
96a07aba5dSTimm Baeder   const std::byte *data() const {
97a07aba5dSTimm Baeder     // rawData might contain metadata as well.
98a07aba5dSTimm Baeder     size_t DataOffset = Desc->getMetadataSize();
99a07aba5dSTimm Baeder     return rawData() + DataOffset;
100a07aba5dSTimm Baeder   }
101a07aba5dSTimm Baeder 
102a07aba5dSTimm Baeder   /// Returns a pointer to the raw data, including metadata.
103a07aba5dSTimm Baeder   /// You are allowed to read Desc->getAllocSize() bytes from this address.
104a07aba5dSTimm Baeder   std::byte *rawData() {
105a07aba5dSTimm Baeder     return reinterpret_cast<std::byte *>(this) + sizeof(Block);
106a07aba5dSTimm Baeder   }
107a07aba5dSTimm Baeder   const std::byte *rawData() const {
108a07aba5dSTimm Baeder     return reinterpret_cast<const std::byte *>(this) + sizeof(Block);
109a07aba5dSTimm Baeder   }
110a07aba5dSTimm Baeder 
111a07aba5dSTimm Baeder   /// Invokes the constructor.
112a07aba5dSTimm Baeder   void invokeCtor() {
113a07aba5dSTimm Baeder     assert(!IsInitialized);
114a07aba5dSTimm Baeder     std::memset(rawData(), 0, Desc->getAllocSize());
115a07aba5dSTimm Baeder     if (Desc->CtorFn) {
116a07aba5dSTimm Baeder       Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
117a07aba5dSTimm Baeder                    /*isActive=*/true, /*InUnion=*/false, Desc);
118a07aba5dSTimm Baeder     }
119a07aba5dSTimm Baeder     IsInitialized = true;
120a07aba5dSTimm Baeder   }
121a07aba5dSTimm Baeder 
122a07aba5dSTimm Baeder   /// Invokes the Destructor.
123a07aba5dSTimm Baeder   void invokeDtor() {
124a07aba5dSTimm Baeder     assert(IsInitialized);
125a07aba5dSTimm Baeder     if (Desc->DtorFn)
126a07aba5dSTimm Baeder       Desc->DtorFn(this, data(), Desc);
127a07aba5dSTimm Baeder     IsInitialized = false;
128a07aba5dSTimm Baeder   }
129a07aba5dSTimm Baeder 
130a07aba5dSTimm Baeder   void dump() const { dump(llvm::errs()); }
131a07aba5dSTimm Baeder   void dump(llvm::raw_ostream &OS) const;
132a07aba5dSTimm Baeder 
133a07aba5dSTimm Baeder private:
134a07aba5dSTimm Baeder   friend class Pointer;
135a07aba5dSTimm Baeder   friend class DeadBlock;
136a07aba5dSTimm Baeder   friend class InterpState;
137a07aba5dSTimm Baeder   friend class DynamicAllocator;
138a07aba5dSTimm Baeder 
139a07aba5dSTimm Baeder   Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic,
140*4e5f8a8fSTimm Baeder         bool IsWeak, bool IsDead)
141a07aba5dSTimm Baeder       : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true),
142*4e5f8a8fSTimm Baeder         IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
143a07aba5dSTimm Baeder     assert(Desc);
144a07aba5dSTimm Baeder   }
145a07aba5dSTimm Baeder 
146a07aba5dSTimm Baeder   /// Deletes a dead block at the end of its lifetime.
147a07aba5dSTimm Baeder   void cleanup();
148a07aba5dSTimm Baeder 
149a07aba5dSTimm Baeder   /// Pointer chain management.
150a07aba5dSTimm Baeder   void addPointer(Pointer *P);
151a07aba5dSTimm Baeder   void removePointer(Pointer *P);
152a07aba5dSTimm Baeder   void replacePointer(Pointer *Old, Pointer *New);
153a07aba5dSTimm Baeder #ifndef NDEBUG
154a07aba5dSTimm Baeder   bool hasPointer(const Pointer *P) const;
155a07aba5dSTimm Baeder #endif
156a07aba5dSTimm Baeder 
157a07aba5dSTimm Baeder   const unsigned EvalID = ~0u;
158a07aba5dSTimm Baeder   /// Start of the chain of pointers.
159a07aba5dSTimm Baeder   Pointer *Pointers = nullptr;
160a07aba5dSTimm Baeder   /// Unique identifier of the declaration.
161a07aba5dSTimm Baeder   std::optional<unsigned> DeclID;
162a07aba5dSTimm Baeder   /// Flag indicating if the block has static storage duration.
163a07aba5dSTimm Baeder   bool IsStatic = false;
164a07aba5dSTimm Baeder   /// Flag indicating if the block is an extern.
165a07aba5dSTimm Baeder   bool IsExtern = false;
166a07aba5dSTimm Baeder   /// Flag indicating if the pointer is dead. This is only ever
167a07aba5dSTimm Baeder   /// set once, when converting the Block to a DeadBlock.
168a07aba5dSTimm Baeder   bool IsDead = false;
169a07aba5dSTimm Baeder   /// Flag indicating if the block contents have been initialized
170a07aba5dSTimm Baeder   /// via invokeCtor.
171a07aba5dSTimm Baeder   bool IsInitialized = false;
172a07aba5dSTimm Baeder   /// Flag indicating if this block has been allocated via dynamic
173a07aba5dSTimm Baeder   /// memory allocation (e.g. malloc).
174a07aba5dSTimm Baeder   bool IsDynamic = false;
175*4e5f8a8fSTimm Baeder   bool IsWeak = false;
176a07aba5dSTimm Baeder   /// Pointer to the stack slot descriptor.
177a07aba5dSTimm Baeder   const Descriptor *Desc;
178a07aba5dSTimm Baeder };
179a07aba5dSTimm Baeder 
180a07aba5dSTimm Baeder /// Descriptor for a dead block.
181a07aba5dSTimm Baeder ///
182a07aba5dSTimm Baeder /// Dead blocks are chained in a double-linked list to deallocate them
183a07aba5dSTimm Baeder /// whenever pointers become dead.
184a07aba5dSTimm Baeder class DeadBlock final {
185a07aba5dSTimm Baeder public:
186a07aba5dSTimm Baeder   /// Copies the block.
187a07aba5dSTimm Baeder   DeadBlock(DeadBlock *&Root, Block *Blk);
188a07aba5dSTimm Baeder 
189a07aba5dSTimm Baeder   /// Returns a pointer to the stored data.
190a07aba5dSTimm Baeder   std::byte *data() { return B.data(); }
191a07aba5dSTimm Baeder   std::byte *rawData() { return B.rawData(); }
192a07aba5dSTimm Baeder 
193a07aba5dSTimm Baeder private:
194a07aba5dSTimm Baeder   friend class Block;
195a07aba5dSTimm Baeder   friend class InterpState;
196a07aba5dSTimm Baeder 
197a07aba5dSTimm Baeder   void free();
198a07aba5dSTimm Baeder 
199a07aba5dSTimm Baeder   /// Root pointer of the list.
200a07aba5dSTimm Baeder   DeadBlock *&Root;
201a07aba5dSTimm Baeder   /// Previous block in the list.
202a07aba5dSTimm Baeder   DeadBlock *Prev;
203a07aba5dSTimm Baeder   /// Next block in the list.
204a07aba5dSTimm Baeder   DeadBlock *Next;
205a07aba5dSTimm Baeder 
206a07aba5dSTimm Baeder   /// Actual block storing data and tracking pointers.
207a07aba5dSTimm Baeder   Block B;
208a07aba5dSTimm Baeder };
209a07aba5dSTimm Baeder 
210a07aba5dSTimm Baeder } // namespace interp
211a07aba5dSTimm Baeder } // namespace clang
212a07aba5dSTimm Baeder 
213a07aba5dSTimm Baeder #endif
214