//===--- InterpState.cpp - Interpreter for the constexpr VM -----*- 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
//
//===----------------------------------------------------------------------===//

#include "InterpState.h"
#include "EvalSettings.h"
#include "InterpFrame.h"
#include "InterpStack.h"
#include "Program.h"
#include "State.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"

using namespace clang;
using namespace clang::interp;

InterpState::InterpState(const EvalSettings &Settings, Program &P,
                         InterpStack &Stk, FrameAllocator &FrameAlloc,
                         Context &Ctx, SourceMapper *M)
    : State(Ctx.getASTContext(), Settings.EvalStatus), M(M),
      FrameAlloc(FrameAlloc), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
      Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
      InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) {
  InConstantContext = Settings.InConstantContext;
  CheckingPotentialConstantExpression =
      Settings.CheckingPotentialConstantExpression;
  CheckingForUndefinedBehavior = Settings.CheckingForUndefinedBehavior;
  EvalMode = Settings.EvalMode;
}

InterpState::InterpState(const EvalSettings &Settings, Program &P,
                         InterpStack &Stk, FrameAllocator &FrameAlloc,
                         Context &Ctx, const Function *Func)
    : State(Ctx.getASTContext(), Settings.EvalStatus), M(nullptr),
      FrameAlloc(FrameAlloc), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
      Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
      InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) {
  InConstantContext = Settings.InConstantContext;
  CheckingPotentialConstantExpression =
      Settings.CheckingPotentialConstantExpression;
  CheckingForUndefinedBehavior = Settings.CheckingForUndefinedBehavior;
  EvalMode = Settings.EvalMode;
}

InterpState::InterpState(Expr::EvalStatus &Status, Program &P, InterpStack &Stk,
                         FrameAllocator &FrameAlloc, Context &Ctx,
                         SourceMapper *M)
    : State(Ctx.getASTContext(), Status), M(M), FrameAlloc(FrameAlloc), P(P),
      Stk(Stk), Ctx(Ctx), BottomFrame(*this), Current(&BottomFrame),
      StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
      InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) {
  InConstantContext = true;
  CheckingPotentialConstantExpression = false;
  CheckingForUndefinedBehavior = true;
  EvalMode = EvaluationMode::ConstantExpression;
}

bool InterpState::inConstantContext() const {
  if (ConstantContextOverride)
    return *ConstantContextOverride;

  return InConstantContext;
}

InterpState::~InterpState() {
  assert(Current->isBottomFrame());

  while (DeadBlocks) {
    DeadBlock *Next = DeadBlocks->Next;

    // There might be a pointer in a global structure pointing to the dead
    // block.
    for (Pointer *P = DeadBlocks->B.Pointers; P; P = P->asBlockPointer().Next)
      DeadBlocks->B.removePointer(P);

    std::free(DeadBlocks);
    DeadBlocks = Next;
  }
}

void InterpState::cleanup() {
  // As a last resort, make sure all pointers still pointing to a dead block
  // don't point to it anymore.
  if (Alloc)
    Alloc->cleanup();
}

const Frame *InterpState::getCurrentFrame() { return Current; }

void InterpState::deallocate(Block *B) {
  assert(B);
  assert(!B->isDynamic());
  assert(!B->isStatic());
  assert(!B->isDead());

  // The block might have a pointer saved in a field in its data
  // that points to the block itself. We call the dtor first,
  // which will destroy all the data but leave InlineDescriptors
  // intact. If the block THEN still has pointers, we create a
  // DeadBlock for it.
  if (B->IsInitialized)
    B->invokeDtor();

  assert(!B->isInitialized());
  if (B->hasPointers()) {
    size_t Size = B->getSize();
    // Allocate a new block, transferring over pointers.
    char *Memory =
        reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size));
    auto *D = new (Memory) DeadBlock(DeadBlocks, B);
    // Since the block doesn't hold any actual data anymore, we can just
    // memcpy() everything over.
    std::memcpy(D->rawData(), B->rawData(), Size);
    D->B.IsInitialized = false;
  }
}

bool InterpState::maybeDiagnoseDanglingAllocations() {
  if (!Alloc)
    return true;

  bool NoAllocationsLeft = !Alloc->hasAllocations();

  if (!checkingPotentialConstantExpression()) {
    for (const auto &[Source, Site] : Alloc->allocation_sites()) {
      assert(!Site.empty());

      CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak)
          << (Site.size() - 1) << Source->getSourceRange();
    }
  }
  // Keep evaluating before C++20, since the CXXNewExpr wasn't valid there
  // in the first place.
  return NoAllocationsLeft || !getLangOpts().CPlusPlus20;
}

StdAllocatorCaller InterpState::getStdAllocatorCaller(StringRef Name) const {
  for (const InterpFrame *F = Current; F; F = F->Caller) {
    const Function *Func = F->getFunction();
    if (!Func)
      continue;
    const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
    if (!MD)
      continue;
    const IdentifierInfo *FnII = MD->getIdentifier();
    if (!FnII || !FnII->isStr(Name))
      continue;

    const auto *CTSD =
        dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
    if (!CTSD)
      continue;

    const IdentifierInfo *ClassII = CTSD->getIdentifier();
    const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
    if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
        TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
      QualType ElemType = TAL[0].getAsType();
      const auto *NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetOpPC()));
      return {NewCall, ElemType};
    }
  }

  return {};
}

bool InterpState::diagnoseStepLimitExceeded(CodePtr OpPC) {
  FFDiag(Current->getSource(OpPC), diag::note_constexpr_step_limit_exceeded, 1)
      << getLangOpts().ConstexprStepLimit;
  Note(Current->getSource(OpPC), diag::note_constexpr_steps);
  return false;
}
