xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/DynamicAllocator.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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