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