#include "DynamicAllocator.h"
#include "InterpBlock.h"
#include "InterpState.h"
using namespace clang;
using namespace clang::interp;
DynamicAllocator::~DynamicAllocator() { cleanup(); }
void DynamicAllocator::cleanup() {
for (auto &Iter : AllocationSites) {
auto &AllocSite = Iter.second;
for (auto &Alloc : AllocSite.Allocations) {
Block *B = reinterpret_cast<Block *>(Alloc.Memory.get());
B->invokeDtor();
if (B->hasPointers()) {
while (B->Pointers) {
Pointer *Next = B->Pointers->Next;
B->Pointers->PointeeStorage.BS.Pointee = nullptr;
B->Pointers = Next;
}
B->Pointers = nullptr;
}
}
}
AllocationSites.clear();
}
Block *DynamicAllocator::allocate(const Expr *Source, PrimType T,
size_t NumElements, unsigned EvalID) {
const Descriptor *D = allocateDescriptor(
Source, T, Descriptor::InlineDescMD, NumElements, false,
false, false);
return allocate(D, EvalID);
}
Block *DynamicAllocator::allocate(const Descriptor *ElementDesc,
size_t NumElements, unsigned EvalID) {
const Descriptor *D = allocateDescriptor(
ElementDesc->asExpr(), ElementDesc, Descriptor::InlineDescMD, NumElements,
false, false, false);
return allocate(D, EvalID);
}
Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID) {
assert(D);
assert(D->asExpr());
auto Memory =
std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
auto *B = new (Memory.get()) Block(EvalID, D, false);
B->invokeCtor();
InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());
ID->Desc = D;
ID->IsActive = true;
ID->Offset = sizeof(InlineDescriptor);
ID->IsBase = false;
ID->IsFieldMutable = false;
ID->IsConst = false;
ID->IsInitialized = false;
B->IsDynamic = true;
if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
It->second.Allocations.emplace_back(std::move(Memory));
else
AllocationSites.insert(
{D->asExpr(), AllocationSite(std::move(Memory), D->isArray())});
return B;
}
bool DynamicAllocator::deallocate(const Expr *Source,
const Block *BlockToDelete, InterpState &S) {
auto It = AllocationSites.find(Source);
if (It == AllocationSites.end())
return false;
auto &Site = It->second;
assert(Site.size() > 0);
auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
const Block *B = reinterpret_cast<const Block *>(A.Memory.get());
return BlockToDelete == B;
});
assert(AllocIt != Site.Allocations.end());
Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get());
B->invokeDtor();
S.deallocate(B);
Site.Allocations.erase(AllocIt);
if (Site.size() == 0)
AllocationSites.erase(It);
return true;
}