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