1*700637cbSDimitry Andric //===-- InterpBlock.h - Allocated blocks for the interpreter -*- C++ ----*-===// 2*700637cbSDimitry Andric // 3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*700637cbSDimitry Andric // 7*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 8*700637cbSDimitry Andric // 9*700637cbSDimitry Andric // Defines the classes describing allocated blocks. 10*700637cbSDimitry Andric // 11*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 12*700637cbSDimitry Andric 13*700637cbSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_BLOCK_H 14*700637cbSDimitry Andric #define LLVM_CLANG_AST_INTERP_BLOCK_H 15*700637cbSDimitry Andric 16*700637cbSDimitry Andric #include "Descriptor.h" 17*700637cbSDimitry Andric #include "clang/AST/ComparisonCategories.h" 18*700637cbSDimitry Andric #include "clang/AST/Decl.h" 19*700637cbSDimitry Andric #include "clang/AST/DeclCXX.h" 20*700637cbSDimitry Andric #include "clang/AST/Expr.h" 21*700637cbSDimitry Andric #include "llvm/ADT/PointerUnion.h" 22*700637cbSDimitry Andric #include "llvm/Support/raw_ostream.h" 23*700637cbSDimitry Andric 24*700637cbSDimitry Andric namespace clang { 25*700637cbSDimitry Andric namespace interp { 26*700637cbSDimitry Andric class Block; 27*700637cbSDimitry Andric class DeadBlock; 28*700637cbSDimitry Andric class InterpState; 29*700637cbSDimitry Andric class Pointer; 30*700637cbSDimitry Andric enum PrimType : unsigned; 31*700637cbSDimitry Andric 32*700637cbSDimitry Andric /// A memory block, either on the stack or in the heap. 33*700637cbSDimitry Andric /// 34*700637cbSDimitry Andric /// The storage described by the block is immediately followed by 35*700637cbSDimitry Andric /// optional metadata, which is followed by the actual data. 36*700637cbSDimitry Andric /// 37*700637cbSDimitry Andric /// Block* rawData() data() 38*700637cbSDimitry Andric /// │ │ │ 39*700637cbSDimitry Andric /// │ │ │ 40*700637cbSDimitry Andric /// ▼ ▼ ▼ 41*700637cbSDimitry Andric /// ┌───────────────┬─────────────────────────┬─────────────────┐ 42*700637cbSDimitry Andric /// │ Block │ Metadata │ Data │ 43*700637cbSDimitry Andric /// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │ 44*700637cbSDimitry Andric /// └───────────────┴─────────────────────────┴─────────────────┘ 45*700637cbSDimitry Andric /// 46*700637cbSDimitry Andric /// Desc->getAllocSize() describes the size after the Block, i.e. 47*700637cbSDimitry Andric /// the data size and the metadata size. 48*700637cbSDimitry Andric /// 49*700637cbSDimitry Andric class Block final { 50*700637cbSDimitry Andric public: 51*700637cbSDimitry Andric /// Creates a new block. 52*700637cbSDimitry Andric Block(unsigned EvalID, const std::optional<unsigned> &DeclID, 53*700637cbSDimitry Andric const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false, 54*700637cbSDimitry Andric bool IsWeak = false) EvalID(EvalID)55*700637cbSDimitry Andric : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), 56*700637cbSDimitry Andric IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { 57*700637cbSDimitry Andric assert(Desc); 58*700637cbSDimitry Andric } 59*700637cbSDimitry Andric 60*700637cbSDimitry Andric Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false, 61*700637cbSDimitry Andric bool IsExtern = false, bool IsWeak = false) EvalID(EvalID)62*700637cbSDimitry Andric : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic), 63*700637cbSDimitry Andric IsExtern(IsExtern), IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { 64*700637cbSDimitry Andric assert(Desc); 65*700637cbSDimitry Andric } 66*700637cbSDimitry Andric 67*700637cbSDimitry Andric /// Returns the block's descriptor. getDescriptor()68*700637cbSDimitry Andric const Descriptor *getDescriptor() const { return Desc; } 69*700637cbSDimitry Andric /// Checks if the block has any live pointers. hasPointers()70*700637cbSDimitry Andric bool hasPointers() const { return Pointers; } 71*700637cbSDimitry Andric /// Checks if the block is extern. isExtern()72*700637cbSDimitry Andric bool isExtern() const { return IsExtern; } 73*700637cbSDimitry Andric /// Checks if the block has static storage duration. isStatic()74*700637cbSDimitry Andric bool isStatic() const { return IsStatic; } 75*700637cbSDimitry Andric /// Checks if the block is temporary. isTemporary()76*700637cbSDimitry Andric bool isTemporary() const { return Desc->IsTemporary; } isWeak()77*700637cbSDimitry Andric bool isWeak() const { return IsWeak; } isDynamic()78*700637cbSDimitry Andric bool isDynamic() const { return IsDynamic; } 79*700637cbSDimitry Andric /// Returns the size of the block. getSize()80*700637cbSDimitry Andric unsigned getSize() const { return Desc->getAllocSize(); } 81*700637cbSDimitry Andric /// Returns the declaration ID. getDeclID()82*700637cbSDimitry Andric std::optional<unsigned> getDeclID() const { return DeclID; } 83*700637cbSDimitry Andric /// Returns whether the data of this block has been initialized via 84*700637cbSDimitry Andric /// invoking the Ctor func. isInitialized()85*700637cbSDimitry Andric bool isInitialized() const { return IsInitialized; } 86*700637cbSDimitry Andric /// The Evaluation ID this block was created in. getEvalID()87*700637cbSDimitry Andric unsigned getEvalID() const { return EvalID; } 88*700637cbSDimitry Andric 89*700637cbSDimitry Andric /// Returns a pointer to the stored data. 90*700637cbSDimitry Andric /// You are allowed to read Desc->getSize() bytes from this address. data()91*700637cbSDimitry Andric std::byte *data() { 92*700637cbSDimitry Andric // rawData might contain metadata as well. 93*700637cbSDimitry Andric size_t DataOffset = Desc->getMetadataSize(); 94*700637cbSDimitry Andric return rawData() + DataOffset; 95*700637cbSDimitry Andric } data()96*700637cbSDimitry Andric const std::byte *data() const { 97*700637cbSDimitry Andric // rawData might contain metadata as well. 98*700637cbSDimitry Andric size_t DataOffset = Desc->getMetadataSize(); 99*700637cbSDimitry Andric return rawData() + DataOffset; 100*700637cbSDimitry Andric } 101*700637cbSDimitry Andric 102*700637cbSDimitry Andric /// Returns a pointer to the raw data, including metadata. 103*700637cbSDimitry Andric /// You are allowed to read Desc->getAllocSize() bytes from this address. rawData()104*700637cbSDimitry Andric std::byte *rawData() { 105*700637cbSDimitry Andric return reinterpret_cast<std::byte *>(this) + sizeof(Block); 106*700637cbSDimitry Andric } rawData()107*700637cbSDimitry Andric const std::byte *rawData() const { 108*700637cbSDimitry Andric return reinterpret_cast<const std::byte *>(this) + sizeof(Block); 109*700637cbSDimitry Andric } 110*700637cbSDimitry Andric 111*700637cbSDimitry Andric /// Invokes the constructor. invokeCtor()112*700637cbSDimitry Andric void invokeCtor() { 113*700637cbSDimitry Andric assert(!IsInitialized); 114*700637cbSDimitry Andric std::memset(rawData(), 0, Desc->getAllocSize()); 115*700637cbSDimitry Andric if (Desc->CtorFn) { 116*700637cbSDimitry Andric Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable, 117*700637cbSDimitry Andric Desc->IsVolatile, 118*700637cbSDimitry Andric /*isActive=*/true, /*InUnion=*/false, Desc); 119*700637cbSDimitry Andric } 120*700637cbSDimitry Andric IsInitialized = true; 121*700637cbSDimitry Andric } 122*700637cbSDimitry Andric 123*700637cbSDimitry Andric /// Invokes the Destructor. invokeDtor()124*700637cbSDimitry Andric void invokeDtor() { 125*700637cbSDimitry Andric assert(IsInitialized); 126*700637cbSDimitry Andric if (Desc->DtorFn) 127*700637cbSDimitry Andric Desc->DtorFn(this, data(), Desc); 128*700637cbSDimitry Andric IsInitialized = false; 129*700637cbSDimitry Andric } 130*700637cbSDimitry Andric dump()131*700637cbSDimitry Andric void dump() const { dump(llvm::errs()); } 132*700637cbSDimitry Andric void dump(llvm::raw_ostream &OS) const; 133*700637cbSDimitry Andric 134*700637cbSDimitry Andric private: 135*700637cbSDimitry Andric friend class Pointer; 136*700637cbSDimitry Andric friend class DeadBlock; 137*700637cbSDimitry Andric friend class InterpState; 138*700637cbSDimitry Andric friend class DynamicAllocator; 139*700637cbSDimitry Andric Block(unsigned EvalID,const Descriptor * Desc,bool IsExtern,bool IsStatic,bool IsWeak,bool IsDead)140*700637cbSDimitry Andric Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic, 141*700637cbSDimitry Andric bool IsWeak, bool IsDead) 142*700637cbSDimitry Andric : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), 143*700637cbSDimitry Andric IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { 144*700637cbSDimitry Andric assert(Desc); 145*700637cbSDimitry Andric } 146*700637cbSDimitry Andric 147*700637cbSDimitry Andric /// Deletes a dead block at the end of its lifetime. 148*700637cbSDimitry Andric void cleanup(); 149*700637cbSDimitry Andric 150*700637cbSDimitry Andric /// Pointer chain management. 151*700637cbSDimitry Andric void addPointer(Pointer *P); 152*700637cbSDimitry Andric void removePointer(Pointer *P); 153*700637cbSDimitry Andric void replacePointer(Pointer *Old, Pointer *New); 154*700637cbSDimitry Andric #ifndef NDEBUG 155*700637cbSDimitry Andric bool hasPointer(const Pointer *P) const; 156*700637cbSDimitry Andric #endif 157*700637cbSDimitry Andric 158*700637cbSDimitry Andric const unsigned EvalID = ~0u; 159*700637cbSDimitry Andric /// Start of the chain of pointers. 160*700637cbSDimitry Andric Pointer *Pointers = nullptr; 161*700637cbSDimitry Andric /// Unique identifier of the declaration. 162*700637cbSDimitry Andric std::optional<unsigned> DeclID; 163*700637cbSDimitry Andric /// Flag indicating if the block has static storage duration. 164*700637cbSDimitry Andric bool IsStatic = false; 165*700637cbSDimitry Andric /// Flag indicating if the block is an extern. 166*700637cbSDimitry Andric bool IsExtern = false; 167*700637cbSDimitry Andric /// Flag indicating if the pointer is dead. This is only ever 168*700637cbSDimitry Andric /// set once, when converting the Block to a DeadBlock. 169*700637cbSDimitry Andric bool IsDead = false; 170*700637cbSDimitry Andric /// Flag indicating if the block contents have been initialized 171*700637cbSDimitry Andric /// via invokeCtor. 172*700637cbSDimitry Andric bool IsInitialized = false; 173*700637cbSDimitry Andric /// Flag indicating if this block has been allocated via dynamic 174*700637cbSDimitry Andric /// memory allocation (e.g. malloc). 175*700637cbSDimitry Andric bool IsDynamic = false; 176*700637cbSDimitry Andric bool IsWeak = false; 177*700637cbSDimitry Andric /// Pointer to the stack slot descriptor. 178*700637cbSDimitry Andric const Descriptor *Desc; 179*700637cbSDimitry Andric }; 180*700637cbSDimitry Andric 181*700637cbSDimitry Andric /// Descriptor for a dead block. 182*700637cbSDimitry Andric /// 183*700637cbSDimitry Andric /// Dead blocks are chained in a double-linked list to deallocate them 184*700637cbSDimitry Andric /// whenever pointers become dead. 185*700637cbSDimitry Andric class DeadBlock final { 186*700637cbSDimitry Andric public: 187*700637cbSDimitry Andric /// Copies the block. 188*700637cbSDimitry Andric DeadBlock(DeadBlock *&Root, Block *Blk); 189*700637cbSDimitry Andric 190*700637cbSDimitry Andric /// Returns a pointer to the stored data. data()191*700637cbSDimitry Andric std::byte *data() { return B.data(); } rawData()192*700637cbSDimitry Andric std::byte *rawData() { return B.rawData(); } 193*700637cbSDimitry Andric 194*700637cbSDimitry Andric private: 195*700637cbSDimitry Andric friend class Block; 196*700637cbSDimitry Andric friend class InterpState; 197*700637cbSDimitry Andric 198*700637cbSDimitry Andric void free(); 199*700637cbSDimitry Andric 200*700637cbSDimitry Andric /// Root pointer of the list. 201*700637cbSDimitry Andric DeadBlock *&Root; 202*700637cbSDimitry Andric /// Previous block in the list. 203*700637cbSDimitry Andric DeadBlock *Prev; 204*700637cbSDimitry Andric /// Next block in the list. 205*700637cbSDimitry Andric DeadBlock *Next; 206*700637cbSDimitry Andric 207*700637cbSDimitry Andric /// Actual block storing data and tracking pointers. 208*700637cbSDimitry Andric Block B; 209*700637cbSDimitry Andric }; 210*700637cbSDimitry Andric 211*700637cbSDimitry Andric } // namespace interp 212*700637cbSDimitry Andric } // namespace clang 213*700637cbSDimitry Andric 214*700637cbSDimitry Andric #endif 215