|  | //==--------- DynamicAllocator.h - Dynamic allocations ------------*- 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 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H | 
|  | #define LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H | 
|  |  | 
|  | #include "Descriptor.h" | 
|  | #include "InterpBlock.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/ADT/iterator_range.h" | 
|  | #include "llvm/Support/Allocator.h" | 
|  |  | 
|  | namespace clang { | 
|  | class Expr; | 
|  | namespace interp { | 
|  | class Block; | 
|  | class InterpState; | 
|  |  | 
|  | /// Manages dynamic memory allocations done during bytecode interpretation. | 
|  | /// | 
|  | /// We manage allocations as a map from their new-expression to a list | 
|  | /// of allocations. This is called an AllocationSite. For each site, we | 
|  | /// record whether it was allocated using new or new[], the | 
|  | /// IsArrayAllocation flag. | 
|  | /// | 
|  | /// For all array allocations, we need to allocate new Descriptor instances, | 
|  | /// so the DynamicAllocator has a llvm::BumpPtrAllocator similar to Program. | 
|  | class DynamicAllocator final { | 
|  | public: | 
|  | enum class Form : uint8_t { | 
|  | NonArray, | 
|  | Array, | 
|  | Operator, | 
|  | }; | 
|  |  | 
|  | private: | 
|  | struct Allocation { | 
|  | std::unique_ptr<std::byte[]> Memory; | 
|  | Allocation(std::unique_ptr<std::byte[]> Memory) | 
|  | : Memory(std::move(Memory)) {} | 
|  | Block *block() const { return reinterpret_cast<Block *>(Memory.get()); } | 
|  | }; | 
|  |  | 
|  | struct AllocationSite { | 
|  | llvm::SmallVector<Allocation> Allocations; | 
|  | unsigned NumAllocs = 0; | 
|  | Form AllocForm; | 
|  |  | 
|  | AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm) | 
|  | : AllocForm(AllocForm) { | 
|  | Allocations.push_back({std::move(Memory)}); | 
|  | ++NumAllocs; | 
|  | } | 
|  |  | 
|  | size_t size() const { return Allocations.size(); } | 
|  | bool empty() const { return Allocations.empty(); } | 
|  | }; | 
|  |  | 
|  | public: | 
|  | DynamicAllocator() = default; | 
|  | DynamicAllocator(DynamicAllocator &) = delete; | 
|  | DynamicAllocator(DynamicAllocator &&) = delete; | 
|  | ~DynamicAllocator(); | 
|  |  | 
|  | void cleanup(); | 
|  |  | 
|  | /// Allocate ONE element of the given descriptor. | 
|  | Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm); | 
|  | /// Allocate \p NumElements primitive elements of the given type. | 
|  | Block *allocate(const Expr *Source, PrimType T, size_t NumElements, | 
|  | unsigned EvalID, Form AllocForm); | 
|  | /// Allocate \p NumElements elements of the given descriptor. | 
|  | Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID, | 
|  | Form AllocForm); | 
|  |  | 
|  | /// Deallocate the given source+block combination. | 
|  | /// Returns \c true if anything has been deallocatd, \c false otherwise. | 
|  | bool deallocate(const Expr *Source, const Block *BlockToDelete, | 
|  | InterpState &S); | 
|  |  | 
|  | /// Checks whether the allocation done at the given source is an array | 
|  | /// allocation. | 
|  | std::optional<Form> getAllocationForm(const Expr *Source) const { | 
|  | if (auto It = AllocationSites.find(Source); It != AllocationSites.end()) | 
|  | return It->second.AllocForm; | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | /// Allocation site iterator. | 
|  | using const_virtual_iter = | 
|  | llvm::DenseMap<const Expr *, AllocationSite>::const_iterator; | 
|  | llvm::iterator_range<const_virtual_iter> allocation_sites() const { | 
|  | return llvm::make_range(AllocationSites.begin(), AllocationSites.end()); | 
|  | } | 
|  |  | 
|  | bool hasAllocations() const { return !AllocationSites.empty(); } | 
|  |  | 
|  | private: | 
|  | llvm::DenseMap<const Expr *, AllocationSite> AllocationSites; | 
|  | // Allocations that have already been deallocated but had pointers | 
|  | // to them. | 
|  | llvm::SmallVector<Allocation> DeadAllocations; | 
|  |  | 
|  | using PoolAllocTy = llvm::BumpPtrAllocator; | 
|  | PoolAllocTy DescAllocator; | 
|  |  | 
|  | /// Allocates a new descriptor. | 
|  | template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) { | 
|  | return new (DescAllocator) Descriptor(std::forward<Ts>(Args)...); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // namespace interp | 
|  | } // namespace clang | 
|  | #endif |