1*0fca6ea1SDimitry Andric //==--------- DynamicAllocator.h - Dynamic allocations ------------*- C++ -*-=// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric 9*0fca6ea1SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H 10*0fca6ea1SDimitry Andric #define LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H 11*0fca6ea1SDimitry Andric 12*0fca6ea1SDimitry Andric #include "Descriptor.h" 13*0fca6ea1SDimitry Andric #include "InterpBlock.h" 14*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 15*0fca6ea1SDimitry Andric #include "llvm/ADT/iterator_range.h" 16*0fca6ea1SDimitry Andric #include "llvm/Support/Allocator.h" 17*0fca6ea1SDimitry Andric 18*0fca6ea1SDimitry Andric namespace clang { 19*0fca6ea1SDimitry Andric class Expr; 20*0fca6ea1SDimitry Andric namespace interp { 21*0fca6ea1SDimitry Andric class Block; 22*0fca6ea1SDimitry Andric class InterpState; 23*0fca6ea1SDimitry Andric 24*0fca6ea1SDimitry Andric /// Manages dynamic memory allocations done during bytecode interpretation. 25*0fca6ea1SDimitry Andric /// 26*0fca6ea1SDimitry Andric /// We manage allocations as a map from their new-expression to a list 27*0fca6ea1SDimitry Andric /// of allocations. This is called an AllocationSite. For each site, we 28*0fca6ea1SDimitry Andric /// record whether it was allocated using new or new[], the 29*0fca6ea1SDimitry Andric /// IsArrayAllocation flag. 30*0fca6ea1SDimitry Andric /// 31*0fca6ea1SDimitry Andric /// For all array allocations, we need to allocate new Descriptor instances, 32*0fca6ea1SDimitry Andric /// so the DynamicAllocator has a llvm::BumpPtrAllocator similar to Program. 33*0fca6ea1SDimitry Andric class DynamicAllocator final { 34*0fca6ea1SDimitry Andric struct Allocation { 35*0fca6ea1SDimitry Andric std::unique_ptr<std::byte[]> Memory; 36*0fca6ea1SDimitry Andric Allocation(std::unique_ptr<std::byte[]> Memory) 37*0fca6ea1SDimitry Andric : Memory(std::move(Memory)) {} 38*0fca6ea1SDimitry Andric }; 39*0fca6ea1SDimitry Andric 40*0fca6ea1SDimitry Andric struct AllocationSite { 41*0fca6ea1SDimitry Andric llvm::SmallVector<Allocation> Allocations; 42*0fca6ea1SDimitry Andric bool IsArrayAllocation = false; 43*0fca6ea1SDimitry Andric 44*0fca6ea1SDimitry Andric AllocationSite(std::unique_ptr<std::byte[]> Memory, bool Array) 45*0fca6ea1SDimitry Andric : IsArrayAllocation(Array) { 46*0fca6ea1SDimitry Andric Allocations.push_back({std::move(Memory)}); 47*0fca6ea1SDimitry Andric } 48*0fca6ea1SDimitry Andric 49*0fca6ea1SDimitry Andric size_t size() const { return Allocations.size(); } 50*0fca6ea1SDimitry Andric }; 51*0fca6ea1SDimitry Andric 52*0fca6ea1SDimitry Andric public: 53*0fca6ea1SDimitry Andric DynamicAllocator() = default; 54*0fca6ea1SDimitry Andric ~DynamicAllocator(); 55*0fca6ea1SDimitry Andric 56*0fca6ea1SDimitry Andric void cleanup(); 57*0fca6ea1SDimitry Andric 58*0fca6ea1SDimitry Andric unsigned getNumAllocations() const { return AllocationSites.size(); } 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric /// Allocate ONE element of the given descriptor. 61*0fca6ea1SDimitry Andric Block *allocate(const Descriptor *D, unsigned EvalID); 62*0fca6ea1SDimitry Andric /// Allocate \p NumElements primitive elements of the given type. 63*0fca6ea1SDimitry Andric Block *allocate(const Expr *Source, PrimType T, size_t NumElements, 64*0fca6ea1SDimitry Andric unsigned EvalID); 65*0fca6ea1SDimitry Andric /// Allocate \p NumElements elements of the given descriptor. 66*0fca6ea1SDimitry Andric Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID); 67*0fca6ea1SDimitry Andric 68*0fca6ea1SDimitry Andric /// Deallocate the given source+block combination. 69*0fca6ea1SDimitry Andric /// Returns \c true if anything has been deallocatd, \c false otherwise. 70*0fca6ea1SDimitry Andric bool deallocate(const Expr *Source, const Block *BlockToDelete, 71*0fca6ea1SDimitry Andric InterpState &S); 72*0fca6ea1SDimitry Andric 73*0fca6ea1SDimitry Andric /// Checks whether the allocation done at the given source is an array 74*0fca6ea1SDimitry Andric /// allocation. 75*0fca6ea1SDimitry Andric bool isArrayAllocation(const Expr *Source) const { 76*0fca6ea1SDimitry Andric if (auto It = AllocationSites.find(Source); It != AllocationSites.end()) 77*0fca6ea1SDimitry Andric return It->second.IsArrayAllocation; 78*0fca6ea1SDimitry Andric return false; 79*0fca6ea1SDimitry Andric } 80*0fca6ea1SDimitry Andric 81*0fca6ea1SDimitry Andric /// Allocation site iterator. 82*0fca6ea1SDimitry Andric using const_virtual_iter = 83*0fca6ea1SDimitry Andric llvm::DenseMap<const Expr *, AllocationSite>::const_iterator; 84*0fca6ea1SDimitry Andric llvm::iterator_range<const_virtual_iter> allocation_sites() const { 85*0fca6ea1SDimitry Andric return llvm::make_range(AllocationSites.begin(), AllocationSites.end()); 86*0fca6ea1SDimitry Andric } 87*0fca6ea1SDimitry Andric 88*0fca6ea1SDimitry Andric private: 89*0fca6ea1SDimitry Andric llvm::DenseMap<const Expr *, AllocationSite> AllocationSites; 90*0fca6ea1SDimitry Andric 91*0fca6ea1SDimitry Andric using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>; 92*0fca6ea1SDimitry Andric PoolAllocTy DescAllocator; 93*0fca6ea1SDimitry Andric 94*0fca6ea1SDimitry Andric /// Allocates a new descriptor. 95*0fca6ea1SDimitry Andric template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) { 96*0fca6ea1SDimitry Andric return new (DescAllocator) Descriptor(std::forward<Ts>(Args)...); 97*0fca6ea1SDimitry Andric } 98*0fca6ea1SDimitry Andric }; 99*0fca6ea1SDimitry Andric 100*0fca6ea1SDimitry Andric } // namespace interp 101*0fca6ea1SDimitry Andric } // namespace clang 102*0fca6ea1SDimitry Andric #endif 103