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