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
18namespace clang {
19class Expr;
20namespace interp {
21class Block;
22class 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.
33class DynamicAllocator final {
34public:
35 enum class Form : uint8_t {
36 NonArray,
37 Array,
38 Operator,
39 };
40
41private:
42 struct Allocation {
43 std::unique_ptr<std::byte[]> Memory;
44 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
52 AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm)
53 : AllocForm(AllocForm) {
54 Allocations.push_back(Elt: {std::move(Memory)});
55 }
56
57 size_t size() const { return Allocations.size(); }
58 };
59
60public:
61 DynamicAllocator() = default;
62 DynamicAllocator(DynamicAllocator &) = delete;
63 DynamicAllocator(DynamicAllocator &&) = delete;
64 ~DynamicAllocator();
65
66 void cleanup();
67
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.
86 std::optional<Form> getAllocationForm(const Expr *Source) const {
87 if (auto It = AllocationSites.find(Val: 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;
95 llvm::iterator_range<const_virtual_iter> allocation_sites() const {
96 return llvm::make_range(x: AllocationSites.begin(), y: AllocationSites.end());
97 }
98
99private:
100 llvm::DenseMap<const Expr *, AllocationSite> AllocationSites;
101
102 using PoolAllocTy = llvm::BumpPtrAllocator;
103 PoolAllocTy DescAllocator;
104
105 /// Allocates a new descriptor.
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