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