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