xref: /openbsd-src/gnu/llvm/clang/lib/AST/Interp/InterpBlock.h (revision 12c855180aad702bbcca06e0398d774beeafb155)
1ec727ea7Spatrick //===-- InterpBlock.h - Allocated blocks for the interpreter -*- C++ ----*-===//
2ec727ea7Spatrick //
3ec727ea7Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ec727ea7Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ec727ea7Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ec727ea7Spatrick //
7ec727ea7Spatrick //===----------------------------------------------------------------------===//
8ec727ea7Spatrick //
9ec727ea7Spatrick // Defines the classes describing allocated blocks.
10ec727ea7Spatrick //
11ec727ea7Spatrick //===----------------------------------------------------------------------===//
12ec727ea7Spatrick 
13ec727ea7Spatrick #ifndef LLVM_CLANG_AST_INTERP_BLOCK_H
14ec727ea7Spatrick #define LLVM_CLANG_AST_INTERP_BLOCK_H
15ec727ea7Spatrick 
16ec727ea7Spatrick #include "Descriptor.h"
17ec727ea7Spatrick #include "clang/AST/Decl.h"
18ec727ea7Spatrick #include "clang/AST/DeclCXX.h"
19ec727ea7Spatrick #include "clang/AST/Expr.h"
20ec727ea7Spatrick #include "clang/AST/ComparisonCategories.h"
21ec727ea7Spatrick #include "llvm/ADT/PointerUnion.h"
22ec727ea7Spatrick #include "llvm/Support/raw_ostream.h"
23ec727ea7Spatrick 
24ec727ea7Spatrick namespace clang {
25ec727ea7Spatrick namespace interp {
26ec727ea7Spatrick class Block;
27ec727ea7Spatrick class DeadBlock;
28ec727ea7Spatrick class InterpState;
29ec727ea7Spatrick class Pointer;
30ec727ea7Spatrick enum PrimType : unsigned;
31ec727ea7Spatrick 
32ec727ea7Spatrick /// A memory block, either on the stack or in the heap.
33ec727ea7Spatrick ///
34*12c85518Srobert /// The storage described by the block is immediately followed by
35*12c85518Srobert /// optional metadata, which is followed by the actual data.
36*12c85518Srobert ///
37*12c85518Srobert /// Block*        rawData()                  data()
38*12c85518Srobert /// │               │                         │
39*12c85518Srobert /// │               │                         │
40*12c85518Srobert /// ▼               ▼                         ▼
41*12c85518Srobert /// ┌───────────────┬─────────────────────────┬─────────────────┐
42*12c85518Srobert /// │ Block         │ Metadata                │ Data            │
43*12c85518Srobert /// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │
44*12c85518Srobert /// └───────────────┴─────────────────────────┴─────────────────┘
45*12c85518Srobert ///
46*12c85518Srobert /// Desc->getAllocSize() describes the size after the Block, i.e.
47*12c85518Srobert /// the data size and the metadata size.
48*12c85518Srobert ///
49*12c85518Srobert class Block final {
50ec727ea7Spatrick public:
51ec727ea7Spatrick   // Creates a new block.
52*12c85518Srobert   Block(const std::optional<unsigned> &DeclID, Descriptor *Desc,
53ec727ea7Spatrick         bool IsStatic = false, bool IsExtern = false)
DeclID(DeclID)54ec727ea7Spatrick       : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
55ec727ea7Spatrick 
56ec727ea7Spatrick   Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
57ec727ea7Spatrick       : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern),
58ec727ea7Spatrick         Desc(Desc) {}
59ec727ea7Spatrick 
60ec727ea7Spatrick   /// Returns the block's descriptor.
getDescriptor()61ec727ea7Spatrick   Descriptor *getDescriptor() const { return Desc; }
62ec727ea7Spatrick   /// Checks if the block has any live pointers.
hasPointers()63ec727ea7Spatrick   bool hasPointers() const { return Pointers; }
64ec727ea7Spatrick   /// Checks if the block is extern.
isExtern()65ec727ea7Spatrick   bool isExtern() const { return IsExtern; }
66ec727ea7Spatrick   /// Checks if the block has static storage duration.
isStatic()67ec727ea7Spatrick   bool isStatic() const { return IsStatic; }
68ec727ea7Spatrick   /// Checks if the block is temporary.
isTemporary()69ec727ea7Spatrick   bool isTemporary() const { return Desc->IsTemporary; }
70ec727ea7Spatrick   /// Returns the size of the block.
getSize()71ec727ea7Spatrick   InterpSize getSize() const { return Desc->getAllocSize(); }
72ec727ea7Spatrick   /// Returns the declaration ID.
getDeclID()73*12c85518Srobert   std::optional<unsigned> getDeclID() const { return DeclID; }
74ec727ea7Spatrick 
75ec727ea7Spatrick   /// Returns a pointer to the stored data.
76*12c85518Srobert   /// You are allowed to read Desc->getSize() bytes from this address.
data()77*12c85518Srobert   char *data() {
78*12c85518Srobert     // rawData might contain metadata as well.
79*12c85518Srobert     size_t DataOffset = Desc->getMetadataSize();
80*12c85518Srobert     return rawData() + DataOffset;
81*12c85518Srobert   }
data()82*12c85518Srobert   const char *data() const {
83*12c85518Srobert     // rawData might contain metadata as well.
84*12c85518Srobert     size_t DataOffset = Desc->getMetadataSize();
85*12c85518Srobert     return rawData() + DataOffset;
86*12c85518Srobert   }
87*12c85518Srobert 
88*12c85518Srobert   /// Returns a pointer to the raw data, including metadata.
89*12c85518Srobert   /// You are allowed to read Desc->getAllocSize() bytes from this address.
rawData()90*12c85518Srobert   char *rawData() { return reinterpret_cast<char *>(this) + sizeof(Block); }
rawData()91*12c85518Srobert   const char *rawData() const {
92*12c85518Srobert     return reinterpret_cast<const char *>(this) + sizeof(Block);
93*12c85518Srobert   }
94ec727ea7Spatrick 
95ec727ea7Spatrick   /// Returns a view over the data.
96ec727ea7Spatrick   template <typename T>
deref()97ec727ea7Spatrick   T &deref() { return *reinterpret_cast<T *>(data()); }
98ec727ea7Spatrick 
99ec727ea7Spatrick   /// Invokes the constructor.
invokeCtor()100ec727ea7Spatrick   void invokeCtor() {
101*12c85518Srobert     std::memset(rawData(), 0, Desc->getAllocSize());
102ec727ea7Spatrick     if (Desc->CtorFn)
103ec727ea7Spatrick       Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
104ec727ea7Spatrick                    /*isActive=*/true, Desc);
105ec727ea7Spatrick   }
106ec727ea7Spatrick 
107*12c85518Srobert   // Invokes the Destructor.
invokeDtor()108*12c85518Srobert   void invokeDtor() {
109*12c85518Srobert     if (Desc->DtorFn)
110*12c85518Srobert       Desc->DtorFn(this, data(), Desc);
111*12c85518Srobert   }
112*12c85518Srobert 
113ec727ea7Spatrick protected:
114ec727ea7Spatrick   friend class Pointer;
115ec727ea7Spatrick   friend class DeadBlock;
116ec727ea7Spatrick   friend class InterpState;
117ec727ea7Spatrick 
Block(Descriptor * Desc,bool IsExtern,bool IsStatic,bool IsDead)118ec727ea7Spatrick   Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead)
119ec727ea7Spatrick     : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {}
120ec727ea7Spatrick 
121ec727ea7Spatrick   // Deletes a dead block at the end of its lifetime.
122ec727ea7Spatrick   void cleanup();
123ec727ea7Spatrick 
124ec727ea7Spatrick   // Pointer chain management.
125ec727ea7Spatrick   void addPointer(Pointer *P);
126ec727ea7Spatrick   void removePointer(Pointer *P);
127ec727ea7Spatrick   void movePointer(Pointer *From, Pointer *To);
128ec727ea7Spatrick 
129ec727ea7Spatrick   /// Start of the chain of pointers.
130ec727ea7Spatrick   Pointer *Pointers = nullptr;
131ec727ea7Spatrick   /// Unique identifier of the declaration.
132*12c85518Srobert   std::optional<unsigned> DeclID;
133ec727ea7Spatrick   /// Flag indicating if the block has static storage duration.
134ec727ea7Spatrick   bool IsStatic = false;
135ec727ea7Spatrick   /// Flag indicating if the block is an extern.
136ec727ea7Spatrick   bool IsExtern = false;
137ec727ea7Spatrick   /// Flag indicating if the pointer is dead.
138ec727ea7Spatrick   bool IsDead = false;
139ec727ea7Spatrick   /// Pointer to the stack slot descriptor.
140ec727ea7Spatrick   Descriptor *Desc;
141ec727ea7Spatrick };
142ec727ea7Spatrick 
143ec727ea7Spatrick /// Descriptor for a dead block.
144ec727ea7Spatrick ///
145ec727ea7Spatrick /// Dead blocks are chained in a double-linked list to deallocate them
146ec727ea7Spatrick /// whenever pointers become dead.
147*12c85518Srobert class DeadBlock final {
148ec727ea7Spatrick public:
149ec727ea7Spatrick   /// Copies the block.
150ec727ea7Spatrick   DeadBlock(DeadBlock *&Root, Block *Blk);
151ec727ea7Spatrick 
152ec727ea7Spatrick   /// Returns a pointer to the stored data.
data()153ec727ea7Spatrick   char *data() { return B.data(); }
154ec727ea7Spatrick 
155ec727ea7Spatrick private:
156ec727ea7Spatrick   friend class Block;
157ec727ea7Spatrick   friend class InterpState;
158ec727ea7Spatrick 
159ec727ea7Spatrick   void free();
160ec727ea7Spatrick 
161ec727ea7Spatrick   /// Root pointer of the list.
162ec727ea7Spatrick   DeadBlock *&Root;
163ec727ea7Spatrick   /// Previous block in the list.
164ec727ea7Spatrick   DeadBlock *Prev;
165ec727ea7Spatrick   /// Next block in the list.
166ec727ea7Spatrick   DeadBlock *Next;
167ec727ea7Spatrick 
168ec727ea7Spatrick   /// Actual block storing data and tracking pointers.
169ec727ea7Spatrick   Block B;
170ec727ea7Spatrick };
171ec727ea7Spatrick 
172ec727ea7Spatrick } // namespace interp
173ec727ea7Spatrick } // namespace clang
174ec727ea7Spatrick 
175ec727ea7Spatrick #endif
176