xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- InterpBlock.h - Allocated blocks for the interpreter -*- C++ ----*-===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // Defines the classes describing allocated blocks.
105ffd83dbSDimitry Andric //
115ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
125ffd83dbSDimitry Andric 
135ffd83dbSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_BLOCK_H
145ffd83dbSDimitry Andric #define LLVM_CLANG_AST_INTERP_BLOCK_H
155ffd83dbSDimitry Andric 
165ffd83dbSDimitry Andric #include "Descriptor.h"
175ffd83dbSDimitry Andric #include "clang/AST/Decl.h"
185ffd83dbSDimitry Andric #include "clang/AST/DeclCXX.h"
195ffd83dbSDimitry Andric #include "clang/AST/Expr.h"
205ffd83dbSDimitry Andric #include "clang/AST/ComparisonCategories.h"
215ffd83dbSDimitry Andric #include "llvm/ADT/PointerUnion.h"
225ffd83dbSDimitry Andric #include "llvm/Support/raw_ostream.h"
235ffd83dbSDimitry Andric 
245ffd83dbSDimitry Andric namespace clang {
255ffd83dbSDimitry Andric namespace interp {
265ffd83dbSDimitry Andric class Block;
275ffd83dbSDimitry Andric class DeadBlock;
285ffd83dbSDimitry Andric class InterpState;
295ffd83dbSDimitry Andric class Pointer;
305ffd83dbSDimitry Andric enum PrimType : unsigned;
315ffd83dbSDimitry Andric 
325ffd83dbSDimitry Andric /// A memory block, either on the stack or in the heap.
335ffd83dbSDimitry Andric ///
34bdd1243dSDimitry Andric /// The storage described by the block is immediately followed by
35bdd1243dSDimitry Andric /// optional metadata, which is followed by the actual data.
36bdd1243dSDimitry Andric ///
37bdd1243dSDimitry Andric /// Block*        rawData()                  data()
38bdd1243dSDimitry Andric /// │               │                         │
39bdd1243dSDimitry Andric /// │               │                         │
40bdd1243dSDimitry Andric /// ▼               ▼                         ▼
41bdd1243dSDimitry Andric /// ┌───────────────┬─────────────────────────┬─────────────────┐
42bdd1243dSDimitry Andric /// │ Block         │ Metadata                │ Data            │
43bdd1243dSDimitry Andric /// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │
44bdd1243dSDimitry Andric /// └───────────────┴─────────────────────────┴─────────────────┘
45bdd1243dSDimitry Andric ///
46bdd1243dSDimitry Andric /// Desc->getAllocSize() describes the size after the Block, i.e.
47bdd1243dSDimitry Andric /// the data size and the metadata size.
48bdd1243dSDimitry Andric ///
49bdd1243dSDimitry Andric class Block final {
505ffd83dbSDimitry Andric public:
5106c3fb27SDimitry Andric   /// Creates a new block.
52*0fca6ea1SDimitry Andric   Block(unsigned EvalID, const std::optional<unsigned> &DeclID,
53*0fca6ea1SDimitry Andric         const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
54*0fca6ea1SDimitry Andric       : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern),
55*0fca6ea1SDimitry Andric         IsDynamic(false), Desc(Desc) {
56*0fca6ea1SDimitry Andric     assert(Desc);
57*0fca6ea1SDimitry Andric   }
585ffd83dbSDimitry Andric 
59*0fca6ea1SDimitry Andric   Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
60*0fca6ea1SDimitry Andric         bool IsExtern = false)
61*0fca6ea1SDimitry Andric       : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic),
62*0fca6ea1SDimitry Andric         IsExtern(IsExtern), IsDynamic(false), Desc(Desc) {
63*0fca6ea1SDimitry Andric     assert(Desc);
64*0fca6ea1SDimitry Andric   }
655ffd83dbSDimitry Andric 
665ffd83dbSDimitry Andric   /// Returns the block's descriptor.
6706c3fb27SDimitry Andric   const Descriptor *getDescriptor() const { return Desc; }
685ffd83dbSDimitry Andric   /// Checks if the block has any live pointers.
695ffd83dbSDimitry Andric   bool hasPointers() const { return Pointers; }
705ffd83dbSDimitry Andric   /// Checks if the block is extern.
715ffd83dbSDimitry Andric   bool isExtern() const { return IsExtern; }
725ffd83dbSDimitry Andric   /// Checks if the block has static storage duration.
735ffd83dbSDimitry Andric   bool isStatic() const { return IsStatic; }
745ffd83dbSDimitry Andric   /// Checks if the block is temporary.
755ffd83dbSDimitry Andric   bool isTemporary() const { return Desc->IsTemporary; }
76*0fca6ea1SDimitry Andric   bool isDynamic() const { return IsDynamic; }
775ffd83dbSDimitry Andric   /// Returns the size of the block.
7806c3fb27SDimitry Andric   unsigned getSize() const { return Desc->getAllocSize(); }
795ffd83dbSDimitry Andric   /// Returns the declaration ID.
80bdd1243dSDimitry Andric   std::optional<unsigned> getDeclID() const { return DeclID; }
81*0fca6ea1SDimitry Andric   /// Returns whether the data of this block has been initialized via
82*0fca6ea1SDimitry Andric   /// invoking the Ctor func.
835f757f3fSDimitry Andric   bool isInitialized() const { return IsInitialized; }
84*0fca6ea1SDimitry Andric   /// The Evaluation ID this block was created in.
85*0fca6ea1SDimitry Andric   unsigned getEvalID() const { return EvalID; }
865ffd83dbSDimitry Andric 
875ffd83dbSDimitry Andric   /// Returns a pointer to the stored data.
88bdd1243dSDimitry Andric   /// You are allowed to read Desc->getSize() bytes from this address.
895f757f3fSDimitry Andric   std::byte *data() {
90bdd1243dSDimitry Andric     // rawData might contain metadata as well.
91bdd1243dSDimitry Andric     size_t DataOffset = Desc->getMetadataSize();
92bdd1243dSDimitry Andric     return rawData() + DataOffset;
93bdd1243dSDimitry Andric   }
945f757f3fSDimitry Andric   const std::byte *data() const {
95bdd1243dSDimitry Andric     // rawData might contain metadata as well.
96bdd1243dSDimitry Andric     size_t DataOffset = Desc->getMetadataSize();
97bdd1243dSDimitry Andric     return rawData() + DataOffset;
98bdd1243dSDimitry Andric   }
99bdd1243dSDimitry Andric 
100bdd1243dSDimitry Andric   /// Returns a pointer to the raw data, including metadata.
101bdd1243dSDimitry Andric   /// You are allowed to read Desc->getAllocSize() bytes from this address.
1025f757f3fSDimitry Andric   std::byte *rawData() {
1035f757f3fSDimitry Andric     return reinterpret_cast<std::byte *>(this) + sizeof(Block);
1045f757f3fSDimitry Andric   }
1055f757f3fSDimitry Andric   const std::byte *rawData() const {
1065f757f3fSDimitry Andric     return reinterpret_cast<const std::byte *>(this) + sizeof(Block);
107bdd1243dSDimitry Andric   }
1085ffd83dbSDimitry Andric 
1095ffd83dbSDimitry Andric   /// Invokes the constructor.
1105ffd83dbSDimitry Andric   void invokeCtor() {
111*0fca6ea1SDimitry Andric     assert(!IsInitialized);
112bdd1243dSDimitry Andric     std::memset(rawData(), 0, Desc->getAllocSize());
1135ffd83dbSDimitry Andric     if (Desc->CtorFn)
1145ffd83dbSDimitry Andric       Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
1155ffd83dbSDimitry Andric                    /*isActive=*/true, Desc);
1165f757f3fSDimitry Andric     IsInitialized = true;
1175ffd83dbSDimitry Andric   }
1185ffd83dbSDimitry Andric 
11906c3fb27SDimitry Andric   /// Invokes the Destructor.
120bdd1243dSDimitry Andric   void invokeDtor() {
121*0fca6ea1SDimitry Andric     assert(IsInitialized);
122bdd1243dSDimitry Andric     if (Desc->DtorFn)
123bdd1243dSDimitry Andric       Desc->DtorFn(this, data(), Desc);
1245f757f3fSDimitry Andric     IsInitialized = false;
125bdd1243dSDimitry Andric   }
126bdd1243dSDimitry Andric 
127*0fca6ea1SDimitry Andric   void dump() const { dump(llvm::errs()); }
128*0fca6ea1SDimitry Andric   void dump(llvm::raw_ostream &OS) const;
129*0fca6ea1SDimitry Andric 
130*0fca6ea1SDimitry Andric private:
1315ffd83dbSDimitry Andric   friend class Pointer;
1325ffd83dbSDimitry Andric   friend class DeadBlock;
1335ffd83dbSDimitry Andric   friend class InterpState;
134*0fca6ea1SDimitry Andric   friend class DynamicAllocator;
1355ffd83dbSDimitry Andric 
136*0fca6ea1SDimitry Andric   Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic,
137*0fca6ea1SDimitry Andric         bool IsDead)
138*0fca6ea1SDimitry Andric       : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true),
139*0fca6ea1SDimitry Andric         IsDynamic(false), Desc(Desc) {
140*0fca6ea1SDimitry Andric     assert(Desc);
141*0fca6ea1SDimitry Andric   }
1425ffd83dbSDimitry Andric 
14306c3fb27SDimitry Andric   /// Deletes a dead block at the end of its lifetime.
1445ffd83dbSDimitry Andric   void cleanup();
1455ffd83dbSDimitry Andric 
14606c3fb27SDimitry Andric   /// Pointer chain management.
1475ffd83dbSDimitry Andric   void addPointer(Pointer *P);
1485ffd83dbSDimitry Andric   void removePointer(Pointer *P);
14906c3fb27SDimitry Andric   void replacePointer(Pointer *Old, Pointer *New);
15006c3fb27SDimitry Andric #ifndef NDEBUG
15106c3fb27SDimitry Andric   bool hasPointer(const Pointer *P) const;
15206c3fb27SDimitry Andric #endif
1535ffd83dbSDimitry Andric 
154*0fca6ea1SDimitry Andric   const unsigned EvalID = ~0u;
1555ffd83dbSDimitry Andric   /// Start of the chain of pointers.
1565ffd83dbSDimitry Andric   Pointer *Pointers = nullptr;
1575ffd83dbSDimitry Andric   /// Unique identifier of the declaration.
158bdd1243dSDimitry Andric   std::optional<unsigned> DeclID;
1595ffd83dbSDimitry Andric   /// Flag indicating if the block has static storage duration.
1605ffd83dbSDimitry Andric   bool IsStatic = false;
1615ffd83dbSDimitry Andric   /// Flag indicating if the block is an extern.
1625ffd83dbSDimitry Andric   bool IsExtern = false;
1635f757f3fSDimitry Andric   /// Flag indicating if the pointer is dead. This is only ever
1645f757f3fSDimitry Andric   /// set once, when converting the Block to a DeadBlock.
1655ffd83dbSDimitry Andric   bool IsDead = false;
1665f757f3fSDimitry Andric   /// Flag indicating if the block contents have been initialized
1675f757f3fSDimitry Andric   /// via invokeCtor.
1685f757f3fSDimitry Andric   bool IsInitialized = false;
169*0fca6ea1SDimitry Andric   /// Flag indicating if this block has been allocated via dynamic
170*0fca6ea1SDimitry Andric   /// memory allocation (e.g. malloc).
171*0fca6ea1SDimitry Andric   bool IsDynamic = false;
1725ffd83dbSDimitry Andric   /// Pointer to the stack slot descriptor.
1735f757f3fSDimitry Andric   const Descriptor *Desc;
1745ffd83dbSDimitry Andric };
1755ffd83dbSDimitry Andric 
1765ffd83dbSDimitry Andric /// Descriptor for a dead block.
1775ffd83dbSDimitry Andric ///
1785ffd83dbSDimitry Andric /// Dead blocks are chained in a double-linked list to deallocate them
1795ffd83dbSDimitry Andric /// whenever pointers become dead.
180bdd1243dSDimitry Andric class DeadBlock final {
1815ffd83dbSDimitry Andric public:
1825ffd83dbSDimitry Andric   /// Copies the block.
1835ffd83dbSDimitry Andric   DeadBlock(DeadBlock *&Root, Block *Blk);
1845ffd83dbSDimitry Andric 
1855ffd83dbSDimitry Andric   /// Returns a pointer to the stored data.
1865f757f3fSDimitry Andric   std::byte *data() { return B.data(); }
1875f757f3fSDimitry Andric   std::byte *rawData() { return B.rawData(); }
1885ffd83dbSDimitry Andric 
1895ffd83dbSDimitry Andric private:
1905ffd83dbSDimitry Andric   friend class Block;
1915ffd83dbSDimitry Andric   friend class InterpState;
1925ffd83dbSDimitry Andric 
1935ffd83dbSDimitry Andric   void free();
1945ffd83dbSDimitry Andric 
1955ffd83dbSDimitry Andric   /// Root pointer of the list.
1965ffd83dbSDimitry Andric   DeadBlock *&Root;
1975ffd83dbSDimitry Andric   /// Previous block in the list.
1985ffd83dbSDimitry Andric   DeadBlock *Prev;
1995ffd83dbSDimitry Andric   /// Next block in the list.
2005ffd83dbSDimitry Andric   DeadBlock *Next;
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric   /// Actual block storing data and tracking pointers.
2035ffd83dbSDimitry Andric   Block B;
2045ffd83dbSDimitry Andric };
2055ffd83dbSDimitry Andric 
2065ffd83dbSDimitry Andric } // namespace interp
2075ffd83dbSDimitry Andric } // namespace clang
2085ffd83dbSDimitry Andric 
2095ffd83dbSDimitry Andric #endif
210