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; 44 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 52 AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm) 53 : AllocForm(AllocForm) { 54 Allocations.push_back({std::move(Memory)}); 55 } 56 57 size_t size() const { return Allocations.size(); } 58 }; 59 60 public: 61 DynamicAllocator() = default; 62 ~DynamicAllocator(); 63 64 void cleanup(); 65 66 unsigned getNumAllocations() const { return AllocationSites.size(); } 67 68 /// Allocate ONE element of the given descriptor. 69 Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm); 70 /// Allocate \p NumElements primitive elements of the given type. 71 Block *allocate(const Expr *Source, PrimType T, size_t NumElements, 72 unsigned EvalID, Form AllocForm); 73 /// Allocate \p NumElements elements of the given descriptor. 74 Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID, 75 Form AllocForm); 76 77 /// Deallocate the given source+block combination. 78 /// Returns \c true if anything has been deallocatd, \c false otherwise. 79 bool deallocate(const Expr *Source, const Block *BlockToDelete, 80 InterpState &S); 81 82 /// Checks whether the allocation done at the given source is an array 83 /// allocation. 84 std::optional<Form> getAllocationForm(const Expr *Source) const { 85 if (auto It = AllocationSites.find(Source); It != AllocationSites.end()) 86 return It->second.AllocForm; 87 return std::nullopt; 88 } 89 90 /// Allocation site iterator. 91 using const_virtual_iter = 92 llvm::DenseMap<const Expr *, AllocationSite>::const_iterator; 93 llvm::iterator_range<const_virtual_iter> allocation_sites() const { 94 return llvm::make_range(AllocationSites.begin(), AllocationSites.end()); 95 } 96 97 private: 98 llvm::DenseMap<const Expr *, AllocationSite> AllocationSites; 99 100 using PoolAllocTy = llvm::BumpPtrAllocator; 101 PoolAllocTy DescAllocator; 102 103 /// Allocates a new descriptor. 104 template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) { 105 return new (DescAllocator) Descriptor(std::forward<Ts>(Args)...); 106 } 107 }; 108 109 } // namespace interp 110 } // namespace clang 111 #endif 112