InterpBlock.h 5.7 KB

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