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
24namespace clang {
25namespace interp {
26class Block;
27class DeadBlock;
28class InterpState;
29class Pointer;
30enum PrimType : unsigned;
31
32/// A memory block, either on the stack or in the heap.
33///
34/// The storage described by the block is immediately followed by
35/// optional metadata, which is followed by the actual data.
36///
37/// Block* rawData() data()
38/// │ │ │
39/// │ │ │
40/// ▼ ▼ ▼
41/// ┌───────────────┬─────────────────────────┬─────────────────┐
42/// │ Block │ Metadata │ Data │
43/// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │
44/// └───────────────┴─────────────────────────┴─────────────────┘
45///
46/// Desc->getAllocSize() describes the size after the Block, i.e.
47/// the data size and the metadata size.
48///
49class Block final {
50public:
51 /// Creates a new block.
52 Block(const std::optional<unsigned> &DeclID, const Descriptor *Desc,
53 bool IsStatic = false, bool IsExtern = false)
54 : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
55
56 Block(const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
57 : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern),
58 Desc(Desc) {}
59
60 /// Returns the block's descriptor.
61 const Descriptor *getDescriptor() const { return Desc; }
62 /// Checks if the block has any live pointers.
63 bool hasPointers() const { return Pointers; }
64 /// Checks if the block is extern.
65 bool isExtern() const { return IsExtern; }
66 /// Checks if the block has static storage duration.
67 bool isStatic() const { return IsStatic; }
68 /// Checks if the block is temporary.
69 bool isTemporary() const { return Desc->IsTemporary; }
70 /// Returns the size of the block.
71 unsigned getSize() const { return Desc->getAllocSize(); }
72 /// Returns the declaration ID.
73 std::optional<unsigned> getDeclID() const { return DeclID; }
74 bool isInitialized() const { return IsInitialized; }
75
76 /// Returns a pointer to the stored data.
77 /// You are allowed to read Desc->getSize() bytes from this address.
78 std::byte *data() {
79 // rawData might contain metadata as well.
80 size_t DataOffset = Desc->getMetadataSize();
81 return rawData() + DataOffset;
82 }
83 const std::byte *data() const {
84 // rawData might contain metadata as well.
85 size_t DataOffset = Desc->getMetadataSize();
86 return rawData() + DataOffset;
87 }
88
89 /// Returns a pointer to the raw data, including metadata.
90 /// You are allowed to read Desc->getAllocSize() bytes from this address.
91 std::byte *rawData() {
92 return reinterpret_cast<std::byte *>(this) + sizeof(Block);
93 }
94 const std::byte *rawData() const {
95 return reinterpret_cast<const std::byte *>(this) + sizeof(Block);
96 }
97
98 /// Returns a view over the data.
99 template <typename T>
100 T &deref() { return *reinterpret_cast<T *>(data()); }
101 template <typename T> const T &deref() const {
102 return *reinterpret_cast<const T *>(data());
103 }
104
105 /// Invokes the constructor.
106 void invokeCtor() {
107 std::memset(s: rawData(), c: 0, n: Desc->getAllocSize());
108 if (Desc->CtorFn)
109 Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
110 /*isActive=*/true, Desc);
111 IsInitialized = true;
112 }
113
114 /// Invokes the Destructor.
115 void invokeDtor() {
116 if (Desc->DtorFn)
117 Desc->DtorFn(this, data(), Desc);
118 IsInitialized = false;
119 }
120
121 void dump() const { dump(OS&: llvm::errs()); }
122 void dump(llvm::raw_ostream &OS) const;
123
124protected:
125 friend class Pointer;
126 friend class DeadBlock;
127 friend class InterpState;
128
129 Block(const Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead)
130 : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {}
131
132 /// Deletes a dead block at the end of its lifetime.
133 void cleanup();
134
135 /// Pointer chain management.
136 void addPointer(Pointer *P);
137 void removePointer(Pointer *P);
138 void replacePointer(Pointer *Old, Pointer *New);
139#ifndef NDEBUG
140 bool hasPointer(const Pointer *P) const;
141#endif
142
143 /// Start of the chain of pointers.
144 Pointer *Pointers = nullptr;
145 /// Unique identifier of the declaration.
146 std::optional<unsigned> DeclID;
147 /// Flag indicating if the block has static storage duration.
148 bool IsStatic = false;
149 /// Flag indicating if the block is an extern.
150 bool IsExtern = false;
151 /// Flag indicating if the pointer is dead. This is only ever
152 /// set once, when converting the Block to a DeadBlock.
153 bool IsDead = false;
154 /// Flag indicating if the block contents have been initialized
155 /// via invokeCtor.
156 bool IsInitialized = false;
157 /// Pointer to the stack slot descriptor.
158 const Descriptor *Desc;
159};
160
161/// Descriptor for a dead block.
162///
163/// Dead blocks are chained in a double-linked list to deallocate them
164/// whenever pointers become dead.
165class DeadBlock final {
166public:
167 /// Copies the block.
168 DeadBlock(DeadBlock *&Root, Block *Blk);
169
170 /// Returns a pointer to the stored data.
171 std::byte *data() { return B.data(); }
172 std::byte *rawData() { return B.rawData(); }
173
174private:
175 friend class Block;
176 friend class InterpState;
177
178 void free();
179
180 /// Root pointer of the list.
181 DeadBlock *&Root;
182 /// Previous block in the list.
183 DeadBlock *Prev;
184 /// Next block in the list.
185 DeadBlock *Next;
186
187 /// Actual block storing data and tracking pointers.
188 Block B;
189};
190
191} // namespace interp
192} // namespace clang
193
194#endif
195

source code of clang/lib/AST/Interp/InterpBlock.h