//===-- InterpBlock.h - Allocated blocks for the interpreter -*- C++ ----*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Defines the classes describing allocated blocks. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_INTERP_BLOCK_H #define LLVM_CLANG_AST_INTERP_BLOCK_H #include "Descriptor.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/ComparisonCategories.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/Support/raw_ostream.h" namespace clang { namespace interp { class Block; class DeadBlock; class Context; class InterpState; class Pointer; class Function; enum PrimType : unsigned; /// A memory block, either on the stack or in the heap. /// /// The storage described by the block immediately follows it in memory. class Block { public: // Creates a new block. Block(const llvm::Optional &DeclID, Descriptor *Desc, bool IsStatic = false, bool IsExtern = false) : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {} Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false) : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {} /// Returns the block's descriptor. Descriptor *getDescriptor() const { return Desc; } /// Checks if the block has any live pointers. bool hasPointers() const { return Pointers; } /// Checks if the block is extern. bool isExtern() const { return IsExtern; } /// Checks if the block has static storage duration. bool isStatic() const { return IsStatic; } /// Checks if the block is temporary. bool isTemporary() const { return Desc->IsTemporary; } /// Returns the size of the block. InterpSize getSize() const { return Desc->getAllocSize(); } /// Returns the declaration ID. llvm::Optional getDeclID() const { return DeclID; } /// Returns a pointer to the stored data. char *data() { return reinterpret_cast(this + 1); } /// Returns a view over the data. template T &deref() { return *reinterpret_cast(data()); } /// Invokes the constructor. void invokeCtor() { std::memset(data(), 0, getSize()); if (Desc->CtorFn) Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable, /*isActive=*/true, Desc); } protected: friend class Pointer; friend class DeadBlock; friend class InterpState; Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead) : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {} // Deletes a dead block at the end of its lifetime. void cleanup(); // Pointer chain management. void addPointer(Pointer *P); void removePointer(Pointer *P); void movePointer(Pointer *From, Pointer *To); /// Start of the chain of pointers. Pointer *Pointers = nullptr; /// Unique identifier of the declaration. llvm::Optional DeclID; /// Flag indicating if the block has static storage duration. bool IsStatic = false; /// Flag indicating if the block is an extern. bool IsExtern = false; /// Flag indicating if the pointer is dead. bool IsDead = false; /// Pointer to the stack slot descriptor. Descriptor *Desc; }; /// Descriptor for a dead block. /// /// Dead blocks are chained in a double-linked list to deallocate them /// whenever pointers become dead. class DeadBlock { public: /// Copies the block. DeadBlock(DeadBlock *&Root, Block *Blk); /// Returns a pointer to the stored data. char *data() { return B.data(); } private: friend class Block; friend class InterpState; void free(); /// Root pointer of the list. DeadBlock *&Root; /// Previous block in the list. DeadBlock *Prev; /// Next block in the list. DeadBlock *Next; /// Actual block storing data and tracking pointers. Block B; }; } // namespace interp } // namespace clang #endif