Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/InterpBlock.h
35292 views
//===-- InterpBlock.h - Allocated blocks for the interpreter -*- C++ ----*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines the classes describing allocated blocks.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_BLOCK_H13#define LLVM_CLANG_AST_INTERP_BLOCK_H1415#include "Descriptor.h"16#include "clang/AST/Decl.h"17#include "clang/AST/DeclCXX.h"18#include "clang/AST/Expr.h"19#include "clang/AST/ComparisonCategories.h"20#include "llvm/ADT/PointerUnion.h"21#include "llvm/Support/raw_ostream.h"2223namespace clang {24namespace interp {25class Block;26class DeadBlock;27class InterpState;28class Pointer;29enum PrimType : unsigned;3031/// A memory block, either on the stack or in the heap.32///33/// The storage described by the block is immediately followed by34/// optional metadata, which is followed by the actual data.35///36/// Block* rawData() data()37/// │ │ │38/// │ │ │39/// ▼ ▼ ▼40/// ┌───────────────┬─────────────────────────┬─────────────────┐41/// │ Block │ Metadata │ Data │42/// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │43/// └───────────────┴─────────────────────────┴─────────────────┘44///45/// Desc->getAllocSize() describes the size after the Block, i.e.46/// the data size and the metadata size.47///48class Block final {49public:50/// Creates a new block.51Block(unsigned EvalID, const std::optional<unsigned> &DeclID,52const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)53: EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern),54IsDynamic(false), Desc(Desc) {55assert(Desc);56}5758Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,59bool IsExtern = false)60: EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic),61IsExtern(IsExtern), IsDynamic(false), Desc(Desc) {62assert(Desc);63}6465/// Returns the block's descriptor.66const Descriptor *getDescriptor() const { return Desc; }67/// Checks if the block has any live pointers.68bool hasPointers() const { return Pointers; }69/// Checks if the block is extern.70bool isExtern() const { return IsExtern; }71/// Checks if the block has static storage duration.72bool isStatic() const { return IsStatic; }73/// Checks if the block is temporary.74bool isTemporary() const { return Desc->IsTemporary; }75bool isDynamic() const { return IsDynamic; }76/// Returns the size of the block.77unsigned getSize() const { return Desc->getAllocSize(); }78/// Returns the declaration ID.79std::optional<unsigned> getDeclID() const { return DeclID; }80/// Returns whether the data of this block has been initialized via81/// invoking the Ctor func.82bool isInitialized() const { return IsInitialized; }83/// The Evaluation ID this block was created in.84unsigned getEvalID() const { return EvalID; }8586/// Returns a pointer to the stored data.87/// You are allowed to read Desc->getSize() bytes from this address.88std::byte *data() {89// rawData might contain metadata as well.90size_t DataOffset = Desc->getMetadataSize();91return rawData() + DataOffset;92}93const std::byte *data() const {94// rawData might contain metadata as well.95size_t DataOffset = Desc->getMetadataSize();96return rawData() + DataOffset;97}9899/// Returns a pointer to the raw data, including metadata.100/// You are allowed to read Desc->getAllocSize() bytes from this address.101std::byte *rawData() {102return reinterpret_cast<std::byte *>(this) + sizeof(Block);103}104const std::byte *rawData() const {105return reinterpret_cast<const std::byte *>(this) + sizeof(Block);106}107108/// Invokes the constructor.109void invokeCtor() {110assert(!IsInitialized);111std::memset(rawData(), 0, Desc->getAllocSize());112if (Desc->CtorFn)113Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,114/*isActive=*/true, Desc);115IsInitialized = true;116}117118/// Invokes the Destructor.119void invokeDtor() {120assert(IsInitialized);121if (Desc->DtorFn)122Desc->DtorFn(this, data(), Desc);123IsInitialized = false;124}125126void dump() const { dump(llvm::errs()); }127void dump(llvm::raw_ostream &OS) const;128129private:130friend class Pointer;131friend class DeadBlock;132friend class InterpState;133friend class DynamicAllocator;134135Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic,136bool IsDead)137: EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true),138IsDynamic(false), Desc(Desc) {139assert(Desc);140}141142/// Deletes a dead block at the end of its lifetime.143void cleanup();144145/// Pointer chain management.146void addPointer(Pointer *P);147void removePointer(Pointer *P);148void replacePointer(Pointer *Old, Pointer *New);149#ifndef NDEBUG150bool hasPointer(const Pointer *P) const;151#endif152153const unsigned EvalID = ~0u;154/// Start of the chain of pointers.155Pointer *Pointers = nullptr;156/// Unique identifier of the declaration.157std::optional<unsigned> DeclID;158/// Flag indicating if the block has static storage duration.159bool IsStatic = false;160/// Flag indicating if the block is an extern.161bool IsExtern = false;162/// Flag indicating if the pointer is dead. This is only ever163/// set once, when converting the Block to a DeadBlock.164bool IsDead = false;165/// Flag indicating if the block contents have been initialized166/// via invokeCtor.167bool IsInitialized = false;168/// Flag indicating if this block has been allocated via dynamic169/// memory allocation (e.g. malloc).170bool IsDynamic = false;171/// Pointer to the stack slot descriptor.172const Descriptor *Desc;173};174175/// Descriptor for a dead block.176///177/// Dead blocks are chained in a double-linked list to deallocate them178/// whenever pointers become dead.179class DeadBlock final {180public:181/// Copies the block.182DeadBlock(DeadBlock *&Root, Block *Blk);183184/// Returns a pointer to the stored data.185std::byte *data() { return B.data(); }186std::byte *rawData() { return B.rawData(); }187188private:189friend class Block;190friend class InterpState;191192void free();193194/// Root pointer of the list.195DeadBlock *&Root;196/// Previous block in the list.197DeadBlock *Prev;198/// Next block in the list.199DeadBlock *Next;200201/// Actual block storing data and tracking pointers.202Block B;203};204205} // namespace interp206} // namespace clang207208#endif209210211