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