1 //==--------- DynamicAllocator.h - Dynamic allocations ------------*- 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 #ifndef LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H 10 #define LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H 11 12 #include "Descriptor.h" 13 #include "InterpBlock.h" 14 #include "llvm/ADT/SmallVector.h" 15 #include "llvm/ADT/iterator_range.h" 16 #include "llvm/Support/Allocator.h" 17 18 namespace clang { 19 class Expr; 20 namespace interp { 21 class Block; 22 class InterpState; 23 24 /// Manages dynamic memory allocations done during bytecode interpretation. 25 /// 26 /// We manage allocations as a map from their new-expression to a list 27 /// of allocations. This is called an AllocationSite. For each site, we 28 /// record whether it was allocated using new or new[], the 29 /// IsArrayAllocation flag. 30 /// 31 /// For all array allocations, we need to allocate new Descriptor instances, 32 /// so the DynamicAllocator has a llvm::BumpPtrAllocator similar to Program. 33 class DynamicAllocator final { 34 public: 35 enum class Form : uint8_t { 36 NonArray, 37 Array, 38 Operator, 39 }; 40 41 private: 42 struct Allocation { 43 std::unique_ptr<std::byte[]> Memory; AllocationAllocation44 Allocation(std::unique_ptr<std::byte[]> Memory) 45 : Memory(std::move(Memory)) {} 46 }; 47 48 struct AllocationSite { 49 llvm::SmallVector<Allocation> Allocations; 50 Form AllocForm; 51 AllocationSiteAllocationSite52 AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm) 53 : AllocForm(AllocForm) { 54 Allocations.push_back({std::move(Memory)}); 55 } 56 sizeAllocationSite57 size_t size() const { return Allocations.size(); } 58 }; 59 60 public: 61 DynamicAllocator() = default; 62 DynamicAllocator(DynamicAllocator &) = delete; 63 DynamicAllocator(DynamicAllocator &&) = delete; 64 ~DynamicAllocator(); 65 66 void cleanup(); 67 getNumAllocations()68 unsigned getNumAllocations() const { return AllocationSites.size(); } 69 70 /// Allocate ONE element of the given descriptor. 71 Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm); 72 /// Allocate \p NumElements primitive elements of the given type. 73 Block *allocate(const Expr *Source, PrimType T, size_t NumElements, 74 unsigned EvalID, Form AllocForm); 75 /// Allocate \p NumElements elements of the given descriptor. 76 Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID, 77 Form AllocForm); 78 79 /// Deallocate the given source+block combination. 80 /// Returns \c true if anything has been deallocatd, \c false otherwise. 81 bool deallocate(const Expr *Source, const Block *BlockToDelete, 82 InterpState &S); 83 84 /// Checks whether the allocation done at the given source is an array 85 /// allocation. getAllocationForm(const Expr * Source)86 std::optional<Form> getAllocationForm(const Expr *Source) const { 87 if (auto It = AllocationSites.find(Source); It != AllocationSites.end()) 88 return It->second.AllocForm; 89 return std::nullopt; 90 } 91 92 /// Allocation site iterator. 93 using const_virtual_iter = 94 llvm::DenseMap<const Expr *, AllocationSite>::const_iterator; allocation_sites()95 llvm::iterator_range<const_virtual_iter> allocation_sites() const { 96 return llvm::make_range(AllocationSites.begin(), AllocationSites.end()); 97 } 98 99 private: 100 llvm::DenseMap<const Expr *, AllocationSite> AllocationSites; 101 102 using PoolAllocTy = llvm::BumpPtrAllocator; 103 PoolAllocTy DescAllocator; 104 105 /// Allocates a new descriptor. allocateDescriptor(Ts &&...Args)106 template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) { 107 return new (DescAllocator) Descriptor(std::forward<Ts>(Args)...); 108 } 109 }; 110 111 } // namespace interp 112 } // namespace clang 113 #endif 114