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