121 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H10#define LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H11 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 list27/// of allocations. This is called an AllocationSite. For each site, we28/// record whether it was allocated using new or new[], the29/// 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 Block *block() const { return reinterpret_cast<Block *>(Memory.get()); }47 };48 49 struct AllocationSite {50 llvm::SmallVector<Allocation> Allocations;51 unsigned NumAllocs = 0;52 Form AllocForm;53 54 AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm)55 : AllocForm(AllocForm) {56 Allocations.push_back({std::move(Memory)});57 ++NumAllocs;58 }59 60 size_t size() const { return Allocations.size(); }61 bool empty() const { return Allocations.empty(); }62 };63 64public:65 DynamicAllocator() = default;66 DynamicAllocator(DynamicAllocator &) = delete;67 DynamicAllocator(DynamicAllocator &&) = delete;68 ~DynamicAllocator();69 70 void cleanup();71 72 /// Allocate ONE element of the given descriptor.73 Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm);74 /// Allocate \p NumElements primitive elements of the given type.75 Block *allocate(const Expr *Source, PrimType T, size_t NumElements,76 unsigned EvalID, Form AllocForm);77 /// Allocate \p NumElements elements of the given descriptor.78 Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID,79 Form AllocForm);80 81 /// Deallocate the given source+block combination.82 /// Returns \c true if anything has been deallocatd, \c false otherwise.83 bool deallocate(const Expr *Source, const Block *BlockToDelete,84 InterpState &S);85 86 /// Checks whether the allocation done at the given source is an array87 /// allocation.88 std::optional<Form> getAllocationForm(const Expr *Source) const {89 if (auto It = AllocationSites.find(Source); It != AllocationSites.end())90 return It->second.AllocForm;91 return std::nullopt;92 }93 94 /// Allocation site iterator.95 using const_virtual_iter =96 llvm::DenseMap<const Expr *, AllocationSite>::const_iterator;97 llvm::iterator_range<const_virtual_iter> allocation_sites() const {98 return llvm::make_range(AllocationSites.begin(), AllocationSites.end());99 }100 101 bool hasAllocations() const { return !AllocationSites.empty(); }102 103private:104 llvm::DenseMap<const Expr *, AllocationSite> AllocationSites;105 // Allocations that have already been deallocated but had pointers106 // to them.107 llvm::SmallVector<Allocation> DeadAllocations;108 109 using PoolAllocTy = llvm::BumpPtrAllocator;110 PoolAllocTy DescAllocator;111 112 /// Allocates a new descriptor.113 template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) {114 return new (DescAllocator) Descriptor(std::forward<Ts>(Args)...);115 }116};117 118} // namespace interp119} // namespace clang120#endif121