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*5f757f3fSDimitry Andric Block(const std::optional<unsigned> &DeclID, const Descriptor *Desc, 535ffd83dbSDimitry Andric bool IsStatic = false, bool IsExtern = false) DeclID(DeclID)545ffd83dbSDimitry Andric : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {} 555ffd83dbSDimitry Andric 56*5f757f3fSDimitry Andric Block(const 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. getDescriptor()6106c3fb27SDimitry Andric const Descriptor *getDescriptor() const { return Desc; } 625ffd83dbSDimitry Andric /// Checks if the block has any live pointers. hasPointers()635ffd83dbSDimitry Andric bool hasPointers() const { return Pointers; } 645ffd83dbSDimitry Andric /// Checks if the block is extern. isExtern()655ffd83dbSDimitry Andric bool isExtern() const { return IsExtern; } 665ffd83dbSDimitry Andric /// Checks if the block has static storage duration. isStatic()675ffd83dbSDimitry Andric bool isStatic() const { return IsStatic; } 685ffd83dbSDimitry Andric /// Checks if the block is temporary. isTemporary()695ffd83dbSDimitry Andric bool isTemporary() const { return Desc->IsTemporary; } 705ffd83dbSDimitry Andric /// Returns the size of the block. getSize()7106c3fb27SDimitry Andric unsigned getSize() const { return Desc->getAllocSize(); } 725ffd83dbSDimitry Andric /// Returns the declaration ID. getDeclID()73bdd1243dSDimitry Andric std::optional<unsigned> getDeclID() const { return DeclID; } isInitialized()74*5f757f3fSDimitry Andric bool isInitialized() const { return IsInitialized; } 755ffd83dbSDimitry Andric 765ffd83dbSDimitry Andric /// Returns a pointer to the stored data. 77bdd1243dSDimitry Andric /// You are allowed to read Desc->getSize() bytes from this address. data()78*5f757f3fSDimitry Andric std::byte *data() { 79bdd1243dSDimitry Andric // rawData might contain metadata as well. 80bdd1243dSDimitry Andric size_t DataOffset = Desc->getMetadataSize(); 81bdd1243dSDimitry Andric return rawData() + DataOffset; 82bdd1243dSDimitry Andric } data()83*5f757f3fSDimitry Andric const std::byte *data() const { 84bdd1243dSDimitry Andric // rawData might contain metadata as well. 85bdd1243dSDimitry Andric size_t DataOffset = Desc->getMetadataSize(); 86bdd1243dSDimitry Andric return rawData() + DataOffset; 87bdd1243dSDimitry Andric } 88bdd1243dSDimitry Andric 89bdd1243dSDimitry Andric /// Returns a pointer to the raw data, including metadata. 90bdd1243dSDimitry Andric /// You are allowed to read Desc->getAllocSize() bytes from this address. rawData()91*5f757f3fSDimitry Andric std::byte *rawData() { 92*5f757f3fSDimitry Andric return reinterpret_cast<std::byte *>(this) + sizeof(Block); 93*5f757f3fSDimitry Andric } rawData()94*5f757f3fSDimitry Andric const std::byte *rawData() const { 95*5f757f3fSDimitry Andric return reinterpret_cast<const std::byte *>(this) + sizeof(Block); 96bdd1243dSDimitry Andric } 975ffd83dbSDimitry Andric 985ffd83dbSDimitry Andric /// Returns a view over the data. 995ffd83dbSDimitry Andric template <typename T> deref()1005ffd83dbSDimitry Andric T &deref() { return *reinterpret_cast<T *>(data()); } deref()101*5f757f3fSDimitry Andric template <typename T> const T &deref() const { 102*5f757f3fSDimitry Andric return *reinterpret_cast<const T *>(data()); 103*5f757f3fSDimitry Andric } 1045ffd83dbSDimitry Andric 1055ffd83dbSDimitry Andric /// Invokes the constructor. invokeCtor()1065ffd83dbSDimitry Andric void invokeCtor() { 107bdd1243dSDimitry Andric std::memset(rawData(), 0, Desc->getAllocSize()); 1085ffd83dbSDimitry Andric if (Desc->CtorFn) 1095ffd83dbSDimitry Andric Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable, 1105ffd83dbSDimitry Andric /*isActive=*/true, Desc); 111*5f757f3fSDimitry Andric IsInitialized = true; 1125ffd83dbSDimitry Andric } 1135ffd83dbSDimitry Andric 11406c3fb27SDimitry Andric /// Invokes the Destructor. invokeDtor()115bdd1243dSDimitry Andric void invokeDtor() { 116bdd1243dSDimitry Andric if (Desc->DtorFn) 117bdd1243dSDimitry Andric Desc->DtorFn(this, data(), Desc); 118*5f757f3fSDimitry Andric IsInitialized = false; 119bdd1243dSDimitry Andric } 120bdd1243dSDimitry Andric 1215ffd83dbSDimitry Andric protected: 1225ffd83dbSDimitry Andric friend class Pointer; 1235ffd83dbSDimitry Andric friend class DeadBlock; 1245ffd83dbSDimitry Andric friend class InterpState; 1255ffd83dbSDimitry Andric Block(const Descriptor * Desc,bool IsExtern,bool IsStatic,bool IsDead)126*5f757f3fSDimitry Andric Block(const Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead) 1275ffd83dbSDimitry Andric : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {} 1285ffd83dbSDimitry Andric 12906c3fb27SDimitry Andric /// Deletes a dead block at the end of its lifetime. 1305ffd83dbSDimitry Andric void cleanup(); 1315ffd83dbSDimitry Andric 13206c3fb27SDimitry Andric /// Pointer chain management. 1335ffd83dbSDimitry Andric void addPointer(Pointer *P); 1345ffd83dbSDimitry Andric void removePointer(Pointer *P); 13506c3fb27SDimitry Andric void replacePointer(Pointer *Old, Pointer *New); 13606c3fb27SDimitry Andric #ifndef NDEBUG 13706c3fb27SDimitry Andric bool hasPointer(const Pointer *P) const; 13806c3fb27SDimitry Andric #endif 1395ffd83dbSDimitry Andric 1405ffd83dbSDimitry Andric /// Start of the chain of pointers. 1415ffd83dbSDimitry Andric Pointer *Pointers = nullptr; 1425ffd83dbSDimitry Andric /// Unique identifier of the declaration. 143bdd1243dSDimitry Andric std::optional<unsigned> DeclID; 1445ffd83dbSDimitry Andric /// Flag indicating if the block has static storage duration. 1455ffd83dbSDimitry Andric bool IsStatic = false; 1465ffd83dbSDimitry Andric /// Flag indicating if the block is an extern. 1475ffd83dbSDimitry Andric bool IsExtern = false; 148*5f757f3fSDimitry Andric /// Flag indicating if the pointer is dead. This is only ever 149*5f757f3fSDimitry Andric /// set once, when converting the Block to a DeadBlock. 1505ffd83dbSDimitry Andric bool IsDead = false; 151*5f757f3fSDimitry Andric /// Flag indicating if the block contents have been initialized 152*5f757f3fSDimitry Andric /// via invokeCtor. 153*5f757f3fSDimitry Andric bool IsInitialized = false; 1545ffd83dbSDimitry Andric /// Pointer to the stack slot descriptor. 155*5f757f3fSDimitry Andric const Descriptor *Desc; 1565ffd83dbSDimitry Andric }; 1575ffd83dbSDimitry Andric 1585ffd83dbSDimitry Andric /// Descriptor for a dead block. 1595ffd83dbSDimitry Andric /// 1605ffd83dbSDimitry Andric /// Dead blocks are chained in a double-linked list to deallocate them 1615ffd83dbSDimitry Andric /// whenever pointers become dead. 162bdd1243dSDimitry Andric class DeadBlock final { 1635ffd83dbSDimitry Andric public: 1645ffd83dbSDimitry Andric /// Copies the block. 1655ffd83dbSDimitry Andric DeadBlock(DeadBlock *&Root, Block *Blk); 1665ffd83dbSDimitry Andric 1675ffd83dbSDimitry Andric /// Returns a pointer to the stored data. data()168*5f757f3fSDimitry Andric std::byte *data() { return B.data(); } rawData()169*5f757f3fSDimitry Andric std::byte *rawData() { return B.rawData(); } 1705ffd83dbSDimitry Andric 1715ffd83dbSDimitry Andric private: 1725ffd83dbSDimitry Andric friend class Block; 1735ffd83dbSDimitry Andric friend class InterpState; 1745ffd83dbSDimitry Andric 1755ffd83dbSDimitry Andric void free(); 1765ffd83dbSDimitry Andric 1775ffd83dbSDimitry Andric /// Root pointer of the list. 1785ffd83dbSDimitry Andric DeadBlock *&Root; 1795ffd83dbSDimitry Andric /// Previous block in the list. 1805ffd83dbSDimitry Andric DeadBlock *Prev; 1815ffd83dbSDimitry Andric /// Next block in the list. 1825ffd83dbSDimitry Andric DeadBlock *Next; 1835ffd83dbSDimitry Andric 1845ffd83dbSDimitry Andric /// Actual block storing data and tracking pointers. 1855ffd83dbSDimitry Andric Block B; 1865ffd83dbSDimitry Andric }; 1875ffd83dbSDimitry Andric 1885ffd83dbSDimitry Andric } // namespace interp 1895ffd83dbSDimitry Andric } // namespace clang 1905ffd83dbSDimitry Andric 1915ffd83dbSDimitry Andric #endif 192