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 Context; 29 class InterpState; 30 class Pointer; 31 class Function; 32 enum PrimType : unsigned; 33 34 /// A memory block, either on the stack or in the heap. 35 /// 36 /// The storage described by the block immediately follows it in memory. 37 class Block { 38 public: 39 // Creates a new block. 40 Block(const llvm::Optional<unsigned> &DeclID, Descriptor *Desc, 41 bool IsStatic = false, bool IsExtern = false) DeclID(DeclID)42 : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {} 43 44 Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false) 45 : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern), 46 Desc(Desc) {} 47 48 /// Returns the block's descriptor. getDescriptor()49 Descriptor *getDescriptor() const { return Desc; } 50 /// Checks if the block has any live pointers. hasPointers()51 bool hasPointers() const { return Pointers; } 52 /// Checks if the block is extern. isExtern()53 bool isExtern() const { return IsExtern; } 54 /// Checks if the block has static storage duration. isStatic()55 bool isStatic() const { return IsStatic; } 56 /// Checks if the block is temporary. isTemporary()57 bool isTemporary() const { return Desc->IsTemporary; } 58 /// Returns the size of the block. getSize()59 InterpSize getSize() const { return Desc->getAllocSize(); } 60 /// Returns the declaration ID. getDeclID()61 llvm::Optional<unsigned> getDeclID() const { return DeclID; } 62 63 /// Returns a pointer to the stored data. data()64 char *data() { return reinterpret_cast<char *>(this + 1); } 65 66 /// Returns a view over the data. 67 template <typename T> deref()68 T &deref() { return *reinterpret_cast<T *>(data()); } 69 70 /// Invokes the constructor. invokeCtor()71 void invokeCtor() { 72 std::memset(data(), 0, getSize()); 73 if (Desc->CtorFn) 74 Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable, 75 /*isActive=*/true, Desc); 76 } 77 78 protected: 79 friend class Pointer; 80 friend class DeadBlock; 81 friend class InterpState; 82 Block(Descriptor * Desc,bool IsExtern,bool IsStatic,bool IsDead)83 Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead) 84 : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {} 85 86 // Deletes a dead block at the end of its lifetime. 87 void cleanup(); 88 89 // Pointer chain management. 90 void addPointer(Pointer *P); 91 void removePointer(Pointer *P); 92 void movePointer(Pointer *From, Pointer *To); 93 94 /// Start of the chain of pointers. 95 Pointer *Pointers = nullptr; 96 /// Unique identifier of the declaration. 97 llvm::Optional<unsigned> DeclID; 98 /// Flag indicating if the block has static storage duration. 99 bool IsStatic = false; 100 /// Flag indicating if the block is an extern. 101 bool IsExtern = false; 102 /// Flag indicating if the pointer is dead. 103 bool IsDead = false; 104 /// Pointer to the stack slot descriptor. 105 Descriptor *Desc; 106 }; 107 108 /// Descriptor for a dead block. 109 /// 110 /// Dead blocks are chained in a double-linked list to deallocate them 111 /// whenever pointers become dead. 112 class DeadBlock { 113 public: 114 /// Copies the block. 115 DeadBlock(DeadBlock *&Root, Block *Blk); 116 117 /// Returns a pointer to the stored data. data()118 char *data() { return B.data(); } 119 120 private: 121 friend class Block; 122 friend class InterpState; 123 124 void free(); 125 126 /// Root pointer of the list. 127 DeadBlock *&Root; 128 /// Previous block in the list. 129 DeadBlock *Prev; 130 /// Next block in the list. 131 DeadBlock *Next; 132 133 /// Actual block storing data and tracking pointers. 134 Block B; 135 }; 136 137 } // namespace interp 138 } // namespace clang 139 140 #endif 141