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