1a7dea167SDimitry Andric //===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "InterpState.h" 10a7dea167SDimitry Andric #include "InterpFrame.h" 11a7dea167SDimitry Andric #include "InterpStack.h" 12a7dea167SDimitry Andric #include "Program.h" 13a7dea167SDimitry Andric #include "State.h" 14a7dea167SDimitry Andric 15a7dea167SDimitry Andric using namespace clang; 16a7dea167SDimitry Andric using namespace clang::interp; 17a7dea167SDimitry Andric 18a7dea167SDimitry Andric InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk, 19a7dea167SDimitry Andric Context &Ctx, SourceMapper *M) 2006c3fb27SDimitry Andric : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr) {} 21a7dea167SDimitry Andric 22a7dea167SDimitry Andric InterpState::~InterpState() { 23a7dea167SDimitry Andric while (Current) { 24a7dea167SDimitry Andric InterpFrame *Next = Current->Caller; 25a7dea167SDimitry Andric delete Current; 26a7dea167SDimitry Andric Current = Next; 27a7dea167SDimitry Andric } 28a7dea167SDimitry Andric 29a7dea167SDimitry Andric while (DeadBlocks) { 30a7dea167SDimitry Andric DeadBlock *Next = DeadBlocks->Next; 3106c3fb27SDimitry Andric std::free(DeadBlocks); 32a7dea167SDimitry Andric DeadBlocks = Next; 33a7dea167SDimitry Andric } 34a7dea167SDimitry Andric } 35a7dea167SDimitry Andric 36*0fca6ea1SDimitry Andric void InterpState::cleanup() { 37*0fca6ea1SDimitry Andric // As a last resort, make sure all pointers still pointing to a dead block 38*0fca6ea1SDimitry Andric // don't point to it anymore. 39*0fca6ea1SDimitry Andric for (DeadBlock *DB = DeadBlocks; DB; DB = DB->Next) { 40*0fca6ea1SDimitry Andric for (Pointer *P = DB->B.Pointers; P; P = P->Next) { 41*0fca6ea1SDimitry Andric P->PointeeStorage.BS.Pointee = nullptr; 42*0fca6ea1SDimitry Andric } 43*0fca6ea1SDimitry Andric } 44*0fca6ea1SDimitry Andric 45*0fca6ea1SDimitry Andric Alloc.cleanup(); 46*0fca6ea1SDimitry Andric } 47*0fca6ea1SDimitry Andric 48a7dea167SDimitry Andric Frame *InterpState::getCurrentFrame() { 4906c3fb27SDimitry Andric if (Current && Current->Caller) 50a7dea167SDimitry Andric return Current; 51a7dea167SDimitry Andric return Parent.getCurrentFrame(); 52a7dea167SDimitry Andric } 53a7dea167SDimitry Andric 54a7dea167SDimitry Andric bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) { 55a7dea167SDimitry Andric QualType Type = E->getType(); 56a7dea167SDimitry Andric CCEDiag(E, diag::note_constexpr_overflow) << Value << Type; 57a7dea167SDimitry Andric return noteUndefinedBehavior(); 58a7dea167SDimitry Andric } 59a7dea167SDimitry Andric 60a7dea167SDimitry Andric void InterpState::deallocate(Block *B) { 6106c3fb27SDimitry Andric assert(B); 6206c3fb27SDimitry Andric const Descriptor *Desc = B->getDescriptor(); 6306c3fb27SDimitry Andric assert(Desc); 6406c3fb27SDimitry Andric 65a7dea167SDimitry Andric if (B->hasPointers()) { 66a7dea167SDimitry Andric size_t Size = B->getSize(); 67a7dea167SDimitry Andric 68a7dea167SDimitry Andric // Allocate a new block, transferring over pointers. 6906c3fb27SDimitry Andric char *Memory = 7006c3fb27SDimitry Andric reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size)); 71a7dea167SDimitry Andric auto *D = new (Memory) DeadBlock(DeadBlocks, B); 72*0fca6ea1SDimitry Andric std::memset(D->B.rawData(), 0, D->B.getSize()); 73a7dea167SDimitry Andric 745f757f3fSDimitry Andric // Move data and metadata from the old block to the new (dead)block. 75*0fca6ea1SDimitry Andric if (B->IsInitialized && Desc->MoveFn) { 76a7dea167SDimitry Andric Desc->MoveFn(B, B->data(), D->data(), Desc); 775f757f3fSDimitry Andric if (Desc->getMetadataSize() > 0) 785f757f3fSDimitry Andric std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize()); 795f757f3fSDimitry Andric } 80*0fca6ea1SDimitry Andric D->B.IsInitialized = B->IsInitialized; 815f757f3fSDimitry Andric 825f757f3fSDimitry Andric // We moved the contents over to the DeadBlock. 835f757f3fSDimitry Andric B->IsInitialized = false; 84*0fca6ea1SDimitry Andric } else if (B->IsInitialized) { 855f757f3fSDimitry Andric B->invokeDtor(); 86a7dea167SDimitry Andric } 87a7dea167SDimitry Andric } 88*0fca6ea1SDimitry Andric 89*0fca6ea1SDimitry Andric bool InterpState::maybeDiagnoseDanglingAllocations() { 90*0fca6ea1SDimitry Andric bool NoAllocationsLeft = (Alloc.getNumAllocations() == 0); 91*0fca6ea1SDimitry Andric 92*0fca6ea1SDimitry Andric if (!checkingPotentialConstantExpression()) { 93*0fca6ea1SDimitry Andric for (const auto &It : Alloc.allocation_sites()) { 94*0fca6ea1SDimitry Andric assert(It.second.size() > 0); 95*0fca6ea1SDimitry Andric 96*0fca6ea1SDimitry Andric const Expr *Source = It.first; 97*0fca6ea1SDimitry Andric CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak) 98*0fca6ea1SDimitry Andric << (It.second.size() - 1) << Source->getSourceRange(); 99*0fca6ea1SDimitry Andric } 100*0fca6ea1SDimitry Andric } 101*0fca6ea1SDimitry Andric return NoAllocationsLeft; 102*0fca6ea1SDimitry Andric } 103