1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
//==--------- DynamicAllocator.h - Dynamic allocations ------------*- C++ -*-=//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H
#define LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H
#include "Descriptor.h"
#include "InterpBlock.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Allocator.h"
namespace clang {
class Expr;
namespace interp {
class Block;
class InterpState;
/// Manages dynamic memory allocations done during bytecode interpretation.
///
/// We manage allocations as a map from their new-expression to a list
/// of allocations. This is called an AllocationSite. For each site, we
/// record whether it was allocated using new or new[], the
/// IsArrayAllocation flag.
///
/// For all array allocations, we need to allocate new Descriptor instances,
/// so the DynamicAllocator has a llvm::BumpPtrAllocator similar to Program.
class DynamicAllocator final {
public:
enum class Form : uint8_t {
NonArray,
Array,
Operator,
};
private:
struct Allocation {
std::unique_ptr<std::byte[]> Memory;
Allocation(std::unique_ptr<std::byte[]> Memory)
: Memory(std::move(Memory)) {}
};
struct AllocationSite {
llvm::SmallVector<Allocation> Allocations;
Form AllocForm;
AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm)
: AllocForm(AllocForm) {
Allocations.push_back({std::move(Memory)});
}
size_t size() const { return Allocations.size(); }
};
public:
DynamicAllocator() = default;
DynamicAllocator(DynamicAllocator &) = delete;
DynamicAllocator(DynamicAllocator &&) = delete;
~DynamicAllocator();
void cleanup();
unsigned getNumAllocations() const { return AllocationSites.size(); }
/// Allocate ONE element of the given descriptor.
Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm);
/// Allocate \p NumElements primitive elements of the given type.
Block *allocate(const Expr *Source, PrimType T, size_t NumElements,
unsigned EvalID, Form AllocForm);
/// Allocate \p NumElements elements of the given descriptor.
Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID,
Form AllocForm);
/// Deallocate the given source+block combination.
/// Returns \c true if anything has been deallocatd, \c false otherwise.
bool deallocate(const Expr *Source, const Block *BlockToDelete,
InterpState &S);
/// Checks whether the allocation done at the given source is an array
/// allocation.
std::optional<Form> getAllocationForm(const Expr *Source) const {
if (auto It = AllocationSites.find(Source); It != AllocationSites.end())
return It->second.AllocForm;
return std::nullopt;
}
/// Allocation site iterator.
using const_virtual_iter =
llvm::DenseMap<const Expr *, AllocationSite>::const_iterator;
llvm::iterator_range<const_virtual_iter> allocation_sites() const {
return llvm::make_range(AllocationSites.begin(), AllocationSites.end());
}
private:
llvm::DenseMap<const Expr *, AllocationSite> AllocationSites;
using PoolAllocTy = llvm::BumpPtrAllocator;
PoolAllocTy DescAllocator;
/// Allocates a new descriptor.
template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) {
return new (DescAllocator) Descriptor(std::forward<Ts>(Args)...);
}
};
} // namespace interp
} // namespace clang
#endif
|