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(Elt: {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(Val: 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(x: AllocationSites.begin(), y: 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 | |