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