Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/InterpBlock.h
213799 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/ComparisonCategories.h"17#include "clang/AST/Decl.h"18#include "clang/AST/DeclCXX.h"19#include "clang/AST/Expr.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,53bool IsWeak = false)54: EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern),55IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {56assert(Desc);57}5859Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,60bool IsExtern = false, bool IsWeak = false)61: EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic),62IsExtern(IsExtern), IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {63assert(Desc);64}6566/// Returns the block's descriptor.67const Descriptor *getDescriptor() const { return Desc; }68/// Checks if the block has any live pointers.69bool hasPointers() const { return Pointers; }70/// Checks if the block is extern.71bool isExtern() const { return IsExtern; }72/// Checks if the block has static storage duration.73bool isStatic() const { return IsStatic; }74/// Checks if the block is temporary.75bool isTemporary() const { return Desc->IsTemporary; }76bool isWeak() const { return IsWeak; }77bool isDynamic() const { return IsDynamic; }78/// Returns the size of the block.79unsigned getSize() const { return Desc->getAllocSize(); }80/// Returns the declaration ID.81std::optional<unsigned> getDeclID() const { return DeclID; }82/// Returns whether the data of this block has been initialized via83/// invoking the Ctor func.84bool isInitialized() const { return IsInitialized; }85/// The Evaluation ID this block was created in.86unsigned getEvalID() const { return EvalID; }8788/// Returns a pointer to the stored data.89/// You are allowed to read Desc->getSize() bytes from this address.90std::byte *data() {91// rawData might contain metadata as well.92size_t DataOffset = Desc->getMetadataSize();93return rawData() + DataOffset;94}95const std::byte *data() const {96// rawData might contain metadata as well.97size_t DataOffset = Desc->getMetadataSize();98return rawData() + DataOffset;99}100101/// Returns a pointer to the raw data, including metadata.102/// You are allowed to read Desc->getAllocSize() bytes from this address.103std::byte *rawData() {104return reinterpret_cast<std::byte *>(this) + sizeof(Block);105}106const std::byte *rawData() const {107return reinterpret_cast<const std::byte *>(this) + sizeof(Block);108}109110/// Invokes the constructor.111void invokeCtor() {112assert(!IsInitialized);113std::memset(rawData(), 0, Desc->getAllocSize());114if (Desc->CtorFn) {115Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,116Desc->IsVolatile,117/*isActive=*/true, /*InUnion=*/false, Desc);118}119IsInitialized = true;120}121122/// Invokes the Destructor.123void invokeDtor() {124assert(IsInitialized);125if (Desc->DtorFn)126Desc->DtorFn(this, data(), Desc);127IsInitialized = false;128}129130void dump() const { dump(llvm::errs()); }131void dump(llvm::raw_ostream &OS) const;132133private:134friend class Pointer;135friend class DeadBlock;136friend class InterpState;137friend class DynamicAllocator;138139Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic,140bool IsWeak, bool IsDead)141: EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true),142IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {143assert(Desc);144}145146/// Deletes a dead block at the end of its lifetime.147void cleanup();148149/// Pointer chain management.150void addPointer(Pointer *P);151void removePointer(Pointer *P);152void replacePointer(Pointer *Old, Pointer *New);153#ifndef NDEBUG154bool hasPointer(const Pointer *P) const;155#endif156157const unsigned EvalID = ~0u;158/// Start of the chain of pointers.159Pointer *Pointers = nullptr;160/// Unique identifier of the declaration.161std::optional<unsigned> DeclID;162/// Flag indicating if the block has static storage duration.163bool IsStatic = false;164/// Flag indicating if the block is an extern.165bool IsExtern = false;166/// Flag indicating if the pointer is dead. This is only ever167/// set once, when converting the Block to a DeadBlock.168bool IsDead = false;169/// Flag indicating if the block contents have been initialized170/// via invokeCtor.171bool IsInitialized = false;172/// Flag indicating if this block has been allocated via dynamic173/// memory allocation (e.g. malloc).174bool IsDynamic = false;175bool IsWeak = false;176/// Pointer to the stack slot descriptor.177const Descriptor *Desc;178};179180/// Descriptor for a dead block.181///182/// Dead blocks are chained in a double-linked list to deallocate them183/// whenever pointers become dead.184class DeadBlock final {185public:186/// Copies the block.187DeadBlock(DeadBlock *&Root, Block *Blk);188189/// Returns a pointer to the stored data.190std::byte *data() { return B.data(); }191std::byte *rawData() { return B.rawData(); }192193private:194friend class Block;195friend class InterpState;196197void free();198199/// Root pointer of the list.200DeadBlock *&Root;201/// Previous block in the list.202DeadBlock *Prev;203/// Next block in the list.204DeadBlock *Next;205206/// Actual block storing data and tracking pointers.207Block B;208};209210} // namespace interp211} // namespace clang212213#endif214215216