diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h')
-rw-r--r-- | contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h | 129 |
1 files changed, 99 insertions, 30 deletions
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h b/contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h index 0ccdef221c83..3760ded7b13f 100644 --- a/contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h +++ b/contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h @@ -25,28 +25,46 @@ 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 { +/// The storage described by the block is immediately followed by +/// optional metadata, which is followed by the actual data. +/// +/// Block* rawData() data() +/// │ │ │ +/// │ │ │ +/// ▼ ▼ ▼ +/// ┌───────────────┬─────────────────────────┬─────────────────┐ +/// │ Block │ Metadata │ Data │ +/// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │ +/// └───────────────┴─────────────────────────┴─────────────────┘ +/// +/// Desc->getAllocSize() describes the size after the Block, i.e. +/// the data size and the metadata size. +/// +class Block final { public: - // Creates a new block. - Block(const llvm::Optional<unsigned> &DeclID, Descriptor *Desc, - bool IsStatic = false, bool IsExtern = false) - : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {} + /// Creates a new block. + Block(unsigned EvalID, const std::optional<unsigned> &DeclID, + const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false) + : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), + IsDynamic(false), Desc(Desc) { + assert(Desc); + } - Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false) - : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern), - Desc(Desc) {} + Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false, + bool IsExtern = false) + : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic), + IsExtern(IsExtern), IsDynamic(false), Desc(Desc) { + assert(Desc); + } /// Returns the block's descriptor. - Descriptor *getDescriptor() const { return Desc; } + const Descriptor *getDescriptor() const { return Desc; } /// Checks if the block has any live pointers. bool hasPointers() const { return Pointers; } /// Checks if the block is extern. @@ -55,67 +73,118 @@ public: bool isStatic() const { return IsStatic; } /// Checks if the block is temporary. bool isTemporary() const { return Desc->IsTemporary; } + bool isDynamic() const { return IsDynamic; } /// Returns the size of the block. - InterpSize getSize() const { return Desc->getAllocSize(); } + unsigned getSize() const { return Desc->getAllocSize(); } /// Returns the declaration ID. - llvm::Optional<unsigned> getDeclID() const { return DeclID; } + std::optional<unsigned> getDeclID() const { return DeclID; } + /// Returns whether the data of this block has been initialized via + /// invoking the Ctor func. + bool isInitialized() const { return IsInitialized; } + /// The Evaluation ID this block was created in. + unsigned getEvalID() const { return EvalID; } /// Returns a pointer to the stored data. - char *data() { return reinterpret_cast<char *>(this + 1); } + /// You are allowed to read Desc->getSize() bytes from this address. + std::byte *data() { + // rawData might contain metadata as well. + size_t DataOffset = Desc->getMetadataSize(); + return rawData() + DataOffset; + } + const std::byte *data() const { + // rawData might contain metadata as well. + size_t DataOffset = Desc->getMetadataSize(); + return rawData() + DataOffset; + } - /// Returns a view over the data. - template <typename T> - T &deref() { return *reinterpret_cast<T *>(data()); } + /// Returns a pointer to the raw data, including metadata. + /// You are allowed to read Desc->getAllocSize() bytes from this address. + std::byte *rawData() { + return reinterpret_cast<std::byte *>(this) + sizeof(Block); + } + const std::byte *rawData() const { + return reinterpret_cast<const std::byte *>(this) + sizeof(Block); + } /// Invokes the constructor. void invokeCtor() { - std::memset(data(), 0, getSize()); + assert(!IsInitialized); + std::memset(rawData(), 0, Desc->getAllocSize()); if (Desc->CtorFn) Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable, /*isActive=*/true, Desc); + IsInitialized = true; + } + + /// Invokes the Destructor. + void invokeDtor() { + assert(IsInitialized); + if (Desc->DtorFn) + Desc->DtorFn(this, data(), Desc); + IsInitialized = false; } -protected: + void dump() const { dump(llvm::errs()); } + void dump(llvm::raw_ostream &OS) const; + +private: friend class Pointer; friend class DeadBlock; friend class InterpState; + friend class DynamicAllocator; - Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead) - : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {} + Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic, + bool IsDead) + : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), + IsDynamic(false), Desc(Desc) { + assert(Desc); + } - // Deletes a dead block at the end of its lifetime. + /// Deletes a dead block at the end of its lifetime. void cleanup(); - // Pointer chain management. + /// Pointer chain management. void addPointer(Pointer *P); void removePointer(Pointer *P); - void movePointer(Pointer *From, Pointer *To); + void replacePointer(Pointer *Old, Pointer *New); +#ifndef NDEBUG + bool hasPointer(const Pointer *P) const; +#endif + const unsigned EvalID = ~0u; /// Start of the chain of pointers. Pointer *Pointers = nullptr; /// Unique identifier of the declaration. - llvm::Optional<unsigned> DeclID; + std::optional<unsigned> 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. + /// Flag indicating if the pointer is dead. This is only ever + /// set once, when converting the Block to a DeadBlock. bool IsDead = false; + /// Flag indicating if the block contents have been initialized + /// via invokeCtor. + bool IsInitialized = false; + /// Flag indicating if this block has been allocated via dynamic + /// memory allocation (e.g. malloc). + bool IsDynamic = false; /// Pointer to the stack slot descriptor. - Descriptor *Desc; + const 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 { +class DeadBlock final { public: /// Copies the block. DeadBlock(DeadBlock *&Root, Block *Blk); /// Returns a pointer to the stored data. - char *data() { return B.data(); } + std::byte *data() { return B.data(); } + std::byte *rawData() { return B.rawData(); } private: friend class Block; |