| //===--- Block.cpp - Allocated blocks for the interpreter -------*- 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Defines the classes describing allocated blocks. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "Block.h" | |
| #include "Pointer.h" | |
| using namespace clang; | |
| using namespace clang::interp; | |
| void Block::addPointer(Pointer *P) { | |
| assert(P); | |
| #ifndef NDEBUG | |
| assert(!hasPointer(P)); | |
| #endif | |
| if (Pointers) | |
| Pointers->BS.Prev = P; | |
| P->BS.Next = Pointers; | |
| P->BS.Prev = nullptr; | |
| Pointers = P; | |
| #ifndef NDEBUG | |
| assert(hasPointer(P)); | |
| #endif | |
| } | |
| void Block::removePointer(Pointer *P) { | |
| assert(P->isBlockPointer()); | |
| assert(P); | |
| #ifndef NDEBUG | |
| assert(hasPointer(P)); | |
| #endif | |
| BlockPointer &BP = P->BS; | |
| if (Pointers == P) | |
| Pointers = BP.Next; | |
| if (BP.Prev) | |
| BP.Prev->BS.Next = BP.Next; | |
| if (BP.Next) | |
| BP.Next->BS.Prev = BP.Prev; | |
| P->BS.Pointee = nullptr; | |
| #ifndef NDEBUG | |
| assert(!hasPointer(P)); | |
| #endif | |
| } | |
| void Block::cleanup() { | |
| if (Pointers == nullptr && !isDynamic() && isDead()) | |
| (reinterpret_cast<DeadBlock *>(this + 1) - 1)->free(); | |
| } | |
| void Block::replacePointer(Pointer *Old, Pointer *New) { | |
| assert(Old); | |
| assert(Old->isBlockPointer()); | |
| assert(New); | |
| assert(New->isBlockPointer()); | |
| assert(Old != New); | |
| #ifndef NDEBUG | |
| assert(hasPointer(Old)); | |
| #endif | |
| BlockPointer &OldBP = Old->BS; | |
| BlockPointer &NewBP = New->BS; | |
| if (OldBP.Prev) | |
| OldBP.Prev->BS.Next = New; | |
| if (OldBP.Next) | |
| OldBP.Next->BS.Prev = New; | |
| NewBP.Prev = OldBP.Prev; | |
| NewBP.Next = OldBP.Next; | |
| if (Pointers == Old) | |
| Pointers = New; | |
| OldBP.Pointee = nullptr; | |
| NewBP.Pointee = this; | |
| #ifndef NDEBUG | |
| assert(!hasPointer(Old)); | |
| assert(hasPointer(New)); | |
| #endif | |
| } | |
| #ifndef NDEBUG | |
| bool Block::hasPointer(const Pointer *P) const { | |
| for (const Pointer *C = Pointers; C; C = C->asBlockPointer().Next) { | |
| if (C == P) | |
| return true; | |
| } | |
| return false; | |
| } | |
| #endif | |
| void Block::movePointersTo(Block *B) { | |
| assert(B != this); | |
| while (Pointers) { | |
| Pointer *P = Pointers; | |
| this->removePointer(P); | |
| P->BS.Pointee = B; | |
| B->addPointer(P); | |
| } | |
| assert(!this->hasPointers()); | |
| } | |
| void Block::removePointers() { | |
| Pointer *P = Pointers; | |
| while (P) { | |
| Pointer *Next = P->BS.Next; | |
| P->BS.Pointee = nullptr; | |
| P->BS.Prev = nullptr; | |
| P->BS.Next = nullptr; | |
| P = Next; | |
| } | |
| Pointers = nullptr; | |
| } | |
| DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) | |
| : Root(Root), B(~0u, Blk->Desc, Blk->MDSize, Blk->isExtern(), Blk->IsStatic, | |
| Blk->isWeak(), | |
| /*IsDead=*/true) { | |
| // Add the block to the chain of dead blocks. | |
| if (Root) | |
| Root->Prev = this; | |
| Next = Root; | |
| Prev = nullptr; | |
| Root = this; | |
| B.DynAllocId = Blk->DynAllocId; | |
| // Transfer pointers. | |
| B.Pointers = Blk->Pointers; | |
| for (Pointer *P = Blk->Pointers; P; P = P->asBlockPointer().Next) | |
| P->BS.Pointee = &B; | |
| Blk->Pointers = nullptr; | |
| } | |
| void DeadBlock::free() { | |
| assert(!B.isInitialized()); | |
| if (Prev) | |
| Prev->Next = Next; | |
| if (Next) | |
| Next->Prev = Prev; | |
| if (Root == this) | |
| Root = Next; | |
| std::free(this); | |
| } |