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