xref: /llvm-project/clang/lib/AST/ByteCode/DynamicAllocator.cpp (revision 610b85395d233b5cbc5a1f112ac3039b888c0a88)
1a07aba5dSTimm Baeder //==-------- DynamicAllocator.cpp - Dynamic allocations ----------*- C++ -*-==//
2a07aba5dSTimm Baeder //
3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a07aba5dSTimm Baeder //
7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8a07aba5dSTimm Baeder 
9a07aba5dSTimm Baeder #include "DynamicAllocator.h"
10a07aba5dSTimm Baeder #include "InterpBlock.h"
11a07aba5dSTimm Baeder #include "InterpState.h"
12a07aba5dSTimm Baeder 
13a07aba5dSTimm Baeder using namespace clang;
14a07aba5dSTimm Baeder using namespace clang::interp;
15a07aba5dSTimm Baeder 
16a07aba5dSTimm Baeder DynamicAllocator::~DynamicAllocator() { cleanup(); }
17a07aba5dSTimm Baeder 
18a07aba5dSTimm Baeder void DynamicAllocator::cleanup() {
19a07aba5dSTimm Baeder   // Invoke destructors of all the blocks and as a last restort,
20a07aba5dSTimm Baeder   // reset all the pointers pointing to them to null pointees.
21a07aba5dSTimm Baeder   // This should never show up in diagnostics, but it's necessary
22a07aba5dSTimm Baeder   // for us to not cause use-after-free problems.
23a07aba5dSTimm Baeder   for (auto &Iter : AllocationSites) {
24a07aba5dSTimm Baeder     auto &AllocSite = Iter.second;
25a07aba5dSTimm Baeder     for (auto &Alloc : AllocSite.Allocations) {
26a07aba5dSTimm Baeder       Block *B = reinterpret_cast<Block *>(Alloc.Memory.get());
27a07aba5dSTimm Baeder       B->invokeDtor();
28a07aba5dSTimm Baeder       if (B->hasPointers()) {
29a07aba5dSTimm Baeder         while (B->Pointers) {
30a07aba5dSTimm Baeder           Pointer *Next = B->Pointers->Next;
31a07aba5dSTimm Baeder           B->Pointers->PointeeStorage.BS.Pointee = nullptr;
32a07aba5dSTimm Baeder           B->Pointers = Next;
33a07aba5dSTimm Baeder         }
34a07aba5dSTimm Baeder         B->Pointers = nullptr;
35a07aba5dSTimm Baeder       }
36a07aba5dSTimm Baeder     }
37a07aba5dSTimm Baeder   }
38a07aba5dSTimm Baeder 
39a07aba5dSTimm Baeder   AllocationSites.clear();
40a07aba5dSTimm Baeder }
41a07aba5dSTimm Baeder 
42a07aba5dSTimm Baeder Block *DynamicAllocator::allocate(const Expr *Source, PrimType T,
43*610b8539STimm Baeder                                   size_t NumElements, unsigned EvalID,
44*610b8539STimm Baeder                                   Form AllocForm) {
45a07aba5dSTimm Baeder   // Create a new descriptor for an array of the specified size and
46a07aba5dSTimm Baeder   // element type.
47a07aba5dSTimm Baeder   const Descriptor *D = allocateDescriptor(
48a07aba5dSTimm Baeder       Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false,
49a07aba5dSTimm Baeder       /*IsTemporary=*/false, /*IsMutable=*/false);
50a07aba5dSTimm Baeder 
51*610b8539STimm Baeder   return allocate(D, EvalID, AllocForm);
52a07aba5dSTimm Baeder }
53a07aba5dSTimm Baeder 
54a07aba5dSTimm Baeder Block *DynamicAllocator::allocate(const Descriptor *ElementDesc,
55*610b8539STimm Baeder                                   size_t NumElements, unsigned EvalID,
56*610b8539STimm Baeder                                   Form AllocForm) {
57a07aba5dSTimm Baeder   // Create a new descriptor for an array of the specified size and
58a07aba5dSTimm Baeder   // element type.
59a07aba5dSTimm Baeder   const Descriptor *D = allocateDescriptor(
60a07aba5dSTimm Baeder       ElementDesc->asExpr(), ElementDesc, Descriptor::InlineDescMD, NumElements,
61a07aba5dSTimm Baeder       /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false);
62*610b8539STimm Baeder   return allocate(D, EvalID, AllocForm);
63a07aba5dSTimm Baeder }
64a07aba5dSTimm Baeder 
65*610b8539STimm Baeder Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
66*610b8539STimm Baeder                                   Form AllocForm) {
67a07aba5dSTimm Baeder   assert(D);
68a07aba5dSTimm Baeder   assert(D->asExpr());
69a07aba5dSTimm Baeder 
70a07aba5dSTimm Baeder   auto Memory =
71a07aba5dSTimm Baeder       std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
72a07aba5dSTimm Baeder   auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);
73a07aba5dSTimm Baeder   B->invokeCtor();
74a07aba5dSTimm Baeder 
75a07aba5dSTimm Baeder   InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());
76a07aba5dSTimm Baeder   ID->Desc = D;
77a07aba5dSTimm Baeder   ID->IsActive = true;
78a07aba5dSTimm Baeder   ID->Offset = sizeof(InlineDescriptor);
79a07aba5dSTimm Baeder   ID->IsBase = false;
80a07aba5dSTimm Baeder   ID->IsFieldMutable = false;
81a07aba5dSTimm Baeder   ID->IsConst = false;
82a07aba5dSTimm Baeder   ID->IsInitialized = false;
83a07aba5dSTimm Baeder 
84a07aba5dSTimm Baeder   B->IsDynamic = true;
85a07aba5dSTimm Baeder 
86a07aba5dSTimm Baeder   if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
87a07aba5dSTimm Baeder     It->second.Allocations.emplace_back(std::move(Memory));
88a07aba5dSTimm Baeder   else
89a07aba5dSTimm Baeder     AllocationSites.insert(
90*610b8539STimm Baeder         {D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
91a07aba5dSTimm Baeder   return B;
92a07aba5dSTimm Baeder }
93a07aba5dSTimm Baeder 
94a07aba5dSTimm Baeder bool DynamicAllocator::deallocate(const Expr *Source,
95a07aba5dSTimm Baeder                                   const Block *BlockToDelete, InterpState &S) {
96a07aba5dSTimm Baeder   auto It = AllocationSites.find(Source);
97a07aba5dSTimm Baeder   if (It == AllocationSites.end())
98a07aba5dSTimm Baeder     return false;
99a07aba5dSTimm Baeder 
100a07aba5dSTimm Baeder   auto &Site = It->second;
101a07aba5dSTimm Baeder   assert(Site.size() > 0);
102a07aba5dSTimm Baeder 
103a07aba5dSTimm Baeder   // Find the Block to delete.
104a07aba5dSTimm Baeder   auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
105a07aba5dSTimm Baeder     const Block *B = reinterpret_cast<const Block *>(A.Memory.get());
106a07aba5dSTimm Baeder     return BlockToDelete == B;
107a07aba5dSTimm Baeder   });
108a07aba5dSTimm Baeder 
109a07aba5dSTimm Baeder   assert(AllocIt != Site.Allocations.end());
110a07aba5dSTimm Baeder 
111a07aba5dSTimm Baeder   Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get());
112a07aba5dSTimm Baeder   B->invokeDtor();
113a07aba5dSTimm Baeder 
114a07aba5dSTimm Baeder   S.deallocate(B);
115a07aba5dSTimm Baeder   Site.Allocations.erase(AllocIt);
116a07aba5dSTimm Baeder 
117a07aba5dSTimm Baeder   if (Site.size() == 0)
118a07aba5dSTimm Baeder     AllocationSites.erase(It);
119a07aba5dSTimm Baeder 
120a07aba5dSTimm Baeder   return true;
121a07aba5dSTimm Baeder }
122