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