1a07aba5dSTimm Baeder //===--- InterpState.cpp - Interpreter for the constexpr VM -----*- 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 "InterpState.h" 10a07aba5dSTimm Baeder #include "InterpFrame.h" 11a07aba5dSTimm Baeder #include "InterpStack.h" 12a07aba5dSTimm Baeder #include "Program.h" 13a07aba5dSTimm Baeder #include "State.h" 14a07aba5dSTimm Baeder 15a07aba5dSTimm Baeder using namespace clang; 16a07aba5dSTimm Baeder using namespace clang::interp; 17a07aba5dSTimm Baeder 18a07aba5dSTimm Baeder InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk, 19a07aba5dSTimm Baeder Context &Ctx, SourceMapper *M) 20a07aba5dSTimm Baeder : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr) {} 21a07aba5dSTimm Baeder 22*a024a0ceSTimm Baeder bool InterpState::inConstantContext() const { 23*a024a0ceSTimm Baeder if (ConstantContextOverride) 24*a024a0ceSTimm Baeder return *ConstantContextOverride; 25*a024a0ceSTimm Baeder 26*a024a0ceSTimm Baeder return Parent.InConstantContext; 27*a024a0ceSTimm Baeder } 28*a024a0ceSTimm Baeder 29a07aba5dSTimm Baeder InterpState::~InterpState() { 30a07aba5dSTimm Baeder while (Current) { 31a07aba5dSTimm Baeder InterpFrame *Next = Current->Caller; 32a07aba5dSTimm Baeder delete Current; 33a07aba5dSTimm Baeder Current = Next; 34a07aba5dSTimm Baeder } 35a07aba5dSTimm Baeder 36a07aba5dSTimm Baeder while (DeadBlocks) { 37a07aba5dSTimm Baeder DeadBlock *Next = DeadBlocks->Next; 38a07aba5dSTimm Baeder std::free(DeadBlocks); 39a07aba5dSTimm Baeder DeadBlocks = Next; 40a07aba5dSTimm Baeder } 41a07aba5dSTimm Baeder } 42a07aba5dSTimm Baeder 43a07aba5dSTimm Baeder void InterpState::cleanup() { 44a07aba5dSTimm Baeder // As a last resort, make sure all pointers still pointing to a dead block 45a07aba5dSTimm Baeder // don't point to it anymore. 46a07aba5dSTimm Baeder for (DeadBlock *DB = DeadBlocks; DB; DB = DB->Next) { 47a07aba5dSTimm Baeder for (Pointer *P = DB->B.Pointers; P; P = P->Next) { 48a07aba5dSTimm Baeder P->PointeeStorage.BS.Pointee = nullptr; 49a07aba5dSTimm Baeder } 50a07aba5dSTimm Baeder } 51a07aba5dSTimm Baeder 52a07aba5dSTimm Baeder Alloc.cleanup(); 53a07aba5dSTimm Baeder } 54a07aba5dSTimm Baeder 55a07aba5dSTimm Baeder Frame *InterpState::getCurrentFrame() { 56a07aba5dSTimm Baeder if (Current && Current->Caller) 57a07aba5dSTimm Baeder return Current; 58a07aba5dSTimm Baeder return Parent.getCurrentFrame(); 59a07aba5dSTimm Baeder } 60a07aba5dSTimm Baeder 61a07aba5dSTimm Baeder bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) { 62a07aba5dSTimm Baeder QualType Type = E->getType(); 63a07aba5dSTimm Baeder CCEDiag(E, diag::note_constexpr_overflow) << Value << Type; 64a07aba5dSTimm Baeder return noteUndefinedBehavior(); 65a07aba5dSTimm Baeder } 66a07aba5dSTimm Baeder 67a07aba5dSTimm Baeder void InterpState::deallocate(Block *B) { 68a07aba5dSTimm Baeder assert(B); 69a07aba5dSTimm Baeder const Descriptor *Desc = B->getDescriptor(); 70a07aba5dSTimm Baeder assert(Desc); 71a07aba5dSTimm Baeder 72a07aba5dSTimm Baeder if (B->hasPointers()) { 73a07aba5dSTimm Baeder size_t Size = B->getSize(); 74a07aba5dSTimm Baeder 75a07aba5dSTimm Baeder // Allocate a new block, transferring over pointers. 76a07aba5dSTimm Baeder char *Memory = 77a07aba5dSTimm Baeder reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size)); 78a07aba5dSTimm Baeder auto *D = new (Memory) DeadBlock(DeadBlocks, B); 79a07aba5dSTimm Baeder std::memset(D->B.rawData(), 0, D->B.getSize()); 80a07aba5dSTimm Baeder 81a07aba5dSTimm Baeder // Move data and metadata from the old block to the new (dead)block. 82a07aba5dSTimm Baeder if (B->IsInitialized && Desc->MoveFn) { 83a07aba5dSTimm Baeder Desc->MoveFn(B, B->data(), D->data(), Desc); 84a07aba5dSTimm Baeder if (Desc->getMetadataSize() > 0) 85a07aba5dSTimm Baeder std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize()); 86a07aba5dSTimm Baeder } 87a07aba5dSTimm Baeder D->B.IsInitialized = B->IsInitialized; 88a07aba5dSTimm Baeder 89a07aba5dSTimm Baeder // We moved the contents over to the DeadBlock. 90a07aba5dSTimm Baeder B->IsInitialized = false; 91a07aba5dSTimm Baeder } else if (B->IsInitialized) { 92a07aba5dSTimm Baeder B->invokeDtor(); 93a07aba5dSTimm Baeder } 94a07aba5dSTimm Baeder } 95a07aba5dSTimm Baeder 96a07aba5dSTimm Baeder bool InterpState::maybeDiagnoseDanglingAllocations() { 97a07aba5dSTimm Baeder bool NoAllocationsLeft = (Alloc.getNumAllocations() == 0); 98a07aba5dSTimm Baeder 99a07aba5dSTimm Baeder if (!checkingPotentialConstantExpression()) { 100a07aba5dSTimm Baeder for (const auto &It : Alloc.allocation_sites()) { 101a07aba5dSTimm Baeder assert(It.second.size() > 0); 102a07aba5dSTimm Baeder 103a07aba5dSTimm Baeder const Expr *Source = It.first; 104a07aba5dSTimm Baeder CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak) 105a07aba5dSTimm Baeder << (It.second.size() - 1) << Source->getSourceRange(); 106a07aba5dSTimm Baeder } 107a07aba5dSTimm Baeder } 108a07aba5dSTimm Baeder return NoAllocationsLeft; 109a07aba5dSTimm Baeder } 110