156 lines · cpp
1//===--- Block.cpp - Allocated blocks for the interpreter -------*- 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// Defines the classes describing allocated blocks.10//11//===----------------------------------------------------------------------===//12 13#include "InterpBlock.h"14#include "Pointer.h"15 16using namespace clang;17using namespace clang::interp;18 19void Block::addPointer(Pointer *P) {20 assert(P);21 22#ifndef NDEBUG23 assert(!hasPointer(P));24#endif25 if (Pointers)26 Pointers->BS.Prev = P;27 P->BS.Next = Pointers;28 P->BS.Prev = nullptr;29 Pointers = P;30#ifndef NDEBUG31 assert(hasPointer(P));32#endif33}34 35void Block::removePointer(Pointer *P) {36 assert(P->isBlockPointer());37 assert(P);38 39#ifndef NDEBUG40 assert(hasPointer(P));41#endif42 43 BlockPointer &BP = P->BS;44 45 if (Pointers == P)46 Pointers = BP.Next;47 48 if (BP.Prev)49 BP.Prev->BS.Next = BP.Next;50 if (BP.Next)51 BP.Next->BS.Prev = BP.Prev;52 P->BS.Pointee = nullptr;53#ifndef NDEBUG54 assert(!hasPointer(P));55#endif56}57 58void Block::cleanup() {59 if (Pointers == nullptr && !isDynamic() && isDead())60 (reinterpret_cast<DeadBlock *>(this + 1) - 1)->free();61}62 63void Block::replacePointer(Pointer *Old, Pointer *New) {64 assert(Old);65 assert(Old->isBlockPointer());66 assert(New);67 assert(New->isBlockPointer());68 assert(Old != New);69#ifndef NDEBUG70 assert(hasPointer(Old));71#endif72 73 BlockPointer &OldBP = Old->BS;74 BlockPointer &NewBP = New->BS;75 76 if (OldBP.Prev)77 OldBP.Prev->BS.Next = New;78 if (OldBP.Next)79 OldBP.Next->BS.Prev = New;80 NewBP.Prev = OldBP.Prev;81 NewBP.Next = OldBP.Next;82 if (Pointers == Old)83 Pointers = New;84 85 OldBP.Pointee = nullptr;86 NewBP.Pointee = this;87#ifndef NDEBUG88 assert(!hasPointer(Old));89 assert(hasPointer(New));90#endif91}92 93#ifndef NDEBUG94bool Block::hasPointer(const Pointer *P) const {95 for (const Pointer *C = Pointers; C; C = C->asBlockPointer().Next) {96 if (C == P)97 return true;98 }99 return false;100}101#endif102 103void Block::movePointersTo(Block *B) {104 assert(B != this);105 unsigned MDDiff = static_cast<int>(B->Desc->getMetadataSize()) -106 static_cast<int>(Desc->getMetadataSize());107 108 while (Pointers) {109 Pointer *P = Pointers;110 111 this->removePointer(P);112 P->BS.Pointee = B;113 114 // If the metadata size changed between the two blocks, move the pointer115 // base/offset. Realistically, this should only happen when we move pointers116 // from a dummy pointer to a global one.117 P->BS.Base += MDDiff;118 P->Offset += MDDiff;119 120 B->addPointer(P);121 }122 assert(!this->hasPointers());123}124 125DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)126 : Root(Root), B(~0u, Blk->Desc, Blk->isExtern(), Blk->IsStatic,127 Blk->isWeak(), Blk->isDummy(), /*IsDead=*/true) {128 // Add the block to the chain of dead blocks.129 if (Root)130 Root->Prev = this;131 132 Next = Root;133 Prev = nullptr;134 Root = this;135 136 B.DynAllocId = Blk->DynAllocId;137 138 // Transfer pointers.139 B.Pointers = Blk->Pointers;140 for (Pointer *P = Blk->Pointers; P; P = P->asBlockPointer().Next)141 P->BS.Pointee = &B;142 Blk->Pointers = nullptr;143}144 145void DeadBlock::free() {146 assert(!B.isInitialized());147 148 if (Prev)149 Prev->Next = Next;150 if (Next)151 Next->Prev = Prev;152 if (Root == this)153 Root = Next;154 std::free(this);155}156