xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 ///
34*bdd1243dSDimitry Andric /// The storage described by the block is immediately followed by
35*bdd1243dSDimitry Andric /// optional metadata, which is followed by the actual data.
36*bdd1243dSDimitry Andric ///
37*bdd1243dSDimitry Andric /// Block*        rawData()                  data()
38*bdd1243dSDimitry Andric /// │               │                         │
39*bdd1243dSDimitry Andric /// │               │                         │
40*bdd1243dSDimitry Andric /// ▼               ▼                         ▼
41*bdd1243dSDimitry Andric /// ┌───────────────┬─────────────────────────┬─────────────────┐
42*bdd1243dSDimitry Andric /// │ Block         │ Metadata                │ Data            │
43*bdd1243dSDimitry Andric /// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │
44*bdd1243dSDimitry Andric /// └───────────────┴─────────────────────────┴─────────────────┘
45*bdd1243dSDimitry Andric ///
46*bdd1243dSDimitry Andric /// Desc->getAllocSize() describes the size after the Block, i.e.
47*bdd1243dSDimitry Andric /// the data size and the metadata size.
48*bdd1243dSDimitry Andric ///
49*bdd1243dSDimitry Andric class Block final {
505ffd83dbSDimitry Andric public:
515ffd83dbSDimitry Andric   // Creates a new block.
52*bdd1243dSDimitry Andric   Block(const std::optional<unsigned> &DeclID, Descriptor *Desc,
535ffd83dbSDimitry Andric         bool IsStatic = false, bool IsExtern = false)
545ffd83dbSDimitry Andric       : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
555ffd83dbSDimitry Andric 
565ffd83dbSDimitry Andric   Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
575ffd83dbSDimitry Andric       : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern),
585ffd83dbSDimitry Andric         Desc(Desc) {}
595ffd83dbSDimitry Andric 
605ffd83dbSDimitry Andric   /// Returns the block's descriptor.
615ffd83dbSDimitry Andric   Descriptor *getDescriptor() const { return Desc; }
625ffd83dbSDimitry Andric   /// Checks if the block has any live pointers.
635ffd83dbSDimitry Andric   bool hasPointers() const { return Pointers; }
645ffd83dbSDimitry Andric   /// Checks if the block is extern.
655ffd83dbSDimitry Andric   bool isExtern() const { return IsExtern; }
665ffd83dbSDimitry Andric   /// Checks if the block has static storage duration.
675ffd83dbSDimitry Andric   bool isStatic() const { return IsStatic; }
685ffd83dbSDimitry Andric   /// Checks if the block is temporary.
695ffd83dbSDimitry Andric   bool isTemporary() const { return Desc->IsTemporary; }
705ffd83dbSDimitry Andric   /// Returns the size of the block.
715ffd83dbSDimitry Andric   InterpSize getSize() const { return Desc->getAllocSize(); }
725ffd83dbSDimitry Andric   /// Returns the declaration ID.
73*bdd1243dSDimitry Andric   std::optional<unsigned> getDeclID() const { return DeclID; }
745ffd83dbSDimitry Andric 
755ffd83dbSDimitry Andric   /// Returns a pointer to the stored data.
76*bdd1243dSDimitry Andric   /// You are allowed to read Desc->getSize() bytes from this address.
77*bdd1243dSDimitry Andric   char *data() {
78*bdd1243dSDimitry Andric     // rawData might contain metadata as well.
79*bdd1243dSDimitry Andric     size_t DataOffset = Desc->getMetadataSize();
80*bdd1243dSDimitry Andric     return rawData() + DataOffset;
81*bdd1243dSDimitry Andric   }
82*bdd1243dSDimitry Andric   const char *data() const {
83*bdd1243dSDimitry Andric     // rawData might contain metadata as well.
84*bdd1243dSDimitry Andric     size_t DataOffset = Desc->getMetadataSize();
85*bdd1243dSDimitry Andric     return rawData() + DataOffset;
86*bdd1243dSDimitry Andric   }
87*bdd1243dSDimitry Andric 
88*bdd1243dSDimitry Andric   /// Returns a pointer to the raw data, including metadata.
89*bdd1243dSDimitry Andric   /// You are allowed to read Desc->getAllocSize() bytes from this address.
90*bdd1243dSDimitry Andric   char *rawData() { return reinterpret_cast<char *>(this) + sizeof(Block); }
91*bdd1243dSDimitry Andric   const char *rawData() const {
92*bdd1243dSDimitry Andric     return reinterpret_cast<const char *>(this) + sizeof(Block);
93*bdd1243dSDimitry Andric   }
945ffd83dbSDimitry Andric 
955ffd83dbSDimitry Andric   /// Returns a view over the data.
965ffd83dbSDimitry Andric   template <typename T>
975ffd83dbSDimitry Andric   T &deref() { return *reinterpret_cast<T *>(data()); }
985ffd83dbSDimitry Andric 
995ffd83dbSDimitry Andric   /// Invokes the constructor.
1005ffd83dbSDimitry Andric   void invokeCtor() {
101*bdd1243dSDimitry Andric     std::memset(rawData(), 0, Desc->getAllocSize());
1025ffd83dbSDimitry Andric     if (Desc->CtorFn)
1035ffd83dbSDimitry Andric       Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
1045ffd83dbSDimitry Andric                    /*isActive=*/true, Desc);
1055ffd83dbSDimitry Andric   }
1065ffd83dbSDimitry Andric 
107*bdd1243dSDimitry Andric   // Invokes the Destructor.
108*bdd1243dSDimitry Andric   void invokeDtor() {
109*bdd1243dSDimitry Andric     if (Desc->DtorFn)
110*bdd1243dSDimitry Andric       Desc->DtorFn(this, data(), Desc);
111*bdd1243dSDimitry Andric   }
112*bdd1243dSDimitry Andric 
1135ffd83dbSDimitry Andric protected:
1145ffd83dbSDimitry Andric   friend class Pointer;
1155ffd83dbSDimitry Andric   friend class DeadBlock;
1165ffd83dbSDimitry Andric   friend class InterpState;
1175ffd83dbSDimitry Andric 
1185ffd83dbSDimitry Andric   Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead)
1195ffd83dbSDimitry Andric     : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {}
1205ffd83dbSDimitry Andric 
1215ffd83dbSDimitry Andric   // Deletes a dead block at the end of its lifetime.
1225ffd83dbSDimitry Andric   void cleanup();
1235ffd83dbSDimitry Andric 
1245ffd83dbSDimitry Andric   // Pointer chain management.
1255ffd83dbSDimitry Andric   void addPointer(Pointer *P);
1265ffd83dbSDimitry Andric   void removePointer(Pointer *P);
1275ffd83dbSDimitry Andric   void movePointer(Pointer *From, Pointer *To);
1285ffd83dbSDimitry Andric 
1295ffd83dbSDimitry Andric   /// Start of the chain of pointers.
1305ffd83dbSDimitry Andric   Pointer *Pointers = nullptr;
1315ffd83dbSDimitry Andric   /// Unique identifier of the declaration.
132*bdd1243dSDimitry Andric   std::optional<unsigned> DeclID;
1335ffd83dbSDimitry Andric   /// Flag indicating if the block has static storage duration.
1345ffd83dbSDimitry Andric   bool IsStatic = false;
1355ffd83dbSDimitry Andric   /// Flag indicating if the block is an extern.
1365ffd83dbSDimitry Andric   bool IsExtern = false;
1375ffd83dbSDimitry Andric   /// Flag indicating if the pointer is dead.
1385ffd83dbSDimitry Andric   bool IsDead = false;
1395ffd83dbSDimitry Andric   /// Pointer to the stack slot descriptor.
1405ffd83dbSDimitry Andric   Descriptor *Desc;
1415ffd83dbSDimitry Andric };
1425ffd83dbSDimitry Andric 
1435ffd83dbSDimitry Andric /// Descriptor for a dead block.
1445ffd83dbSDimitry Andric ///
1455ffd83dbSDimitry Andric /// Dead blocks are chained in a double-linked list to deallocate them
1465ffd83dbSDimitry Andric /// whenever pointers become dead.
147*bdd1243dSDimitry Andric class DeadBlock final {
1485ffd83dbSDimitry Andric public:
1495ffd83dbSDimitry Andric   /// Copies the block.
1505ffd83dbSDimitry Andric   DeadBlock(DeadBlock *&Root, Block *Blk);
1515ffd83dbSDimitry Andric 
1525ffd83dbSDimitry Andric   /// Returns a pointer to the stored data.
1535ffd83dbSDimitry Andric   char *data() { return B.data(); }
1545ffd83dbSDimitry Andric 
1555ffd83dbSDimitry Andric private:
1565ffd83dbSDimitry Andric   friend class Block;
1575ffd83dbSDimitry Andric   friend class InterpState;
1585ffd83dbSDimitry Andric 
1595ffd83dbSDimitry Andric   void free();
1605ffd83dbSDimitry Andric 
1615ffd83dbSDimitry Andric   /// Root pointer of the list.
1625ffd83dbSDimitry Andric   DeadBlock *&Root;
1635ffd83dbSDimitry Andric   /// Previous block in the list.
1645ffd83dbSDimitry Andric   DeadBlock *Prev;
1655ffd83dbSDimitry Andric   /// Next block in the list.
1665ffd83dbSDimitry Andric   DeadBlock *Next;
1675ffd83dbSDimitry Andric 
1685ffd83dbSDimitry Andric   /// Actual block storing data and tracking pointers.
1695ffd83dbSDimitry Andric   Block B;
1705ffd83dbSDimitry Andric };
1715ffd83dbSDimitry Andric 
1725ffd83dbSDimitry Andric } // namespace interp
1735ffd83dbSDimitry Andric } // namespace clang
1745ffd83dbSDimitry Andric 
1755ffd83dbSDimitry Andric #endif
176