1353942Sdim//===--- InterpFrame.cpp - Call Frame implementation for the VM -*- C++ -*-===//
2353942Sdim//
3353942Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353942Sdim// See https://llvm.org/LICENSE.txt for license information.
5353942Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353942Sdim//
7353942Sdim//===----------------------------------------------------------------------===//
8353942Sdim
9353942Sdim#include "InterpFrame.h"
10353942Sdim#include "Function.h"
11353942Sdim#include "Interp.h"
12353942Sdim#include "InterpStack.h"
13353942Sdim#include "PrimType.h"
14353942Sdim#include "Program.h"
15353942Sdim#include "clang/AST/DeclCXX.h"
16353942Sdim
17353942Sdimusing namespace clang;
18353942Sdimusing namespace clang::interp;
19353942Sdim
20353942SdimInterpFrame::InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
21353942Sdim                         CodePtr RetPC, Pointer &&This)
22353942Sdim    : Caller(Caller), S(S), Func(Func), This(std::move(This)), RetPC(RetPC),
23353942Sdim      ArgSize(Func ? Func->getArgSize() : 0),
24353942Sdim      Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
25353942Sdim  if (Func) {
26353942Sdim    if (unsigned FrameSize = Func->getFrameSize()) {
27353942Sdim      Locals = std::make_unique<char[]>(FrameSize);
28353942Sdim      for (auto &Scope : Func->scopes()) {
29353942Sdim        for (auto &Local : Scope.locals()) {
30353942Sdim          Block *B = new (localBlock(Local.Offset)) Block(Local.Desc);
31353942Sdim          B->invokeCtor();
32353942Sdim        }
33353942Sdim      }
34353942Sdim    }
35353942Sdim  }
36353942Sdim}
37353942Sdim
38353942SdimInterpFrame::~InterpFrame() {
39353942Sdim  if (Func && Func->isConstructor() && This.isBaseClass())
40353942Sdim    This.initialize();
41353942Sdim  for (auto &Param : Params)
42353942Sdim    S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
43353942Sdim}
44353942Sdim
45353942Sdimvoid InterpFrame::destroy(unsigned Idx) {
46353942Sdim  for (auto &Local : Func->getScope(Idx).locals()) {
47353942Sdim    S.deallocate(reinterpret_cast<Block *>(localBlock(Local.Offset)));
48353942Sdim  }
49353942Sdim}
50353942Sdim
51353942Sdimvoid InterpFrame::popArgs() {
52353942Sdim  for (PrimType Ty : Func->args_reverse())
53353942Sdim    TYPE_SWITCH(Ty, S.Stk.discard<T>());
54353942Sdim}
55353942Sdim
56353942Sdimtemplate <typename T>
57353942Sdimstatic void print(llvm::raw_ostream &OS, const T &V, ASTContext &, QualType) {
58353942Sdim  OS << V;
59353942Sdim}
60353942Sdim
61353942Sdimtemplate <>
62353942Sdimvoid print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
63353942Sdim           QualType Ty) {
64353942Sdim  if (P.isZero()) {
65353942Sdim    OS << "nullptr";
66353942Sdim    return;
67353942Sdim  }
68353942Sdim
69353942Sdim  auto printDesc = [&OS, &Ctx](Descriptor *Desc) {
70353942Sdim    if (auto *D = Desc->asDecl()) {
71353942Sdim      // Subfields or named values.
72353942Sdim      if (auto *VD = dyn_cast<ValueDecl>(D)) {
73353942Sdim        OS << *VD;
74353942Sdim        return;
75353942Sdim      }
76353942Sdim      // Base classes.
77353942Sdim      if (isa<RecordDecl>(D)) {
78353942Sdim        return;
79353942Sdim      }
80353942Sdim    }
81353942Sdim    // Temporary expression.
82353942Sdim    if (auto *E = Desc->asExpr()) {
83353942Sdim      E->printPretty(OS, nullptr, Ctx.getPrintingPolicy());
84353942Sdim      return;
85353942Sdim    }
86353942Sdim    llvm_unreachable("Invalid descriptor type");
87353942Sdim  };
88353942Sdim
89353942Sdim  if (!Ty->isReferenceType())
90353942Sdim    OS << "&";
91353942Sdim  llvm::SmallVector<Pointer, 2> Levels;
92353942Sdim  for (Pointer F = P; !F.isRoot(); ) {
93353942Sdim    Levels.push_back(F);
94353942Sdim    F = F.isArrayElement() ? F.getArray().expand() : F.getBase();
95353942Sdim  }
96353942Sdim
97353942Sdim  printDesc(P.getDeclDesc());
98353942Sdim  for (auto It = Levels.rbegin(); It != Levels.rend(); ++It) {
99353942Sdim    if (It->inArray()) {
100353942Sdim      OS << "[" << It->expand().getIndex() << "]";
101353942Sdim      continue;
102353942Sdim    }
103353942Sdim    if (auto Index = It->getIndex()) {
104353942Sdim      OS << " + " << Index;
105353942Sdim      continue;
106353942Sdim    }
107353942Sdim    OS << ".";
108353942Sdim    printDesc(It->getFieldDesc());
109353942Sdim  }
110353942Sdim}
111353942Sdim
112353942Sdimvoid InterpFrame::describe(llvm::raw_ostream &OS) {
113353942Sdim  const FunctionDecl *F = getCallee();
114353942Sdim  auto *M = dyn_cast<CXXMethodDecl>(F);
115353942Sdim  if (M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
116353942Sdim    print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
117353942Sdim    OS << "->";
118353942Sdim  }
119353942Sdim  OS << *F << "(";
120353942Sdim  unsigned Off = Func->hasRVO() ? primSize(PT_Ptr) : 0;
121353942Sdim  for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) {
122353942Sdim    QualType Ty = F->getParamDecl(I)->getType();
123353942Sdim
124353942Sdim    PrimType PrimTy;
125353942Sdim    if (llvm::Optional<PrimType> T = S.Ctx.classify(Ty)) {
126353942Sdim      PrimTy = *T;
127353942Sdim    } else {
128353942Sdim      PrimTy = PT_Ptr;
129353942Sdim    }
130353942Sdim
131353942Sdim    TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
132353942Sdim    Off += align(primSize(PrimTy));
133353942Sdim    if (I + 1 != N)
134353942Sdim      OS << ", ";
135353942Sdim  }
136353942Sdim  OS << ")";
137353942Sdim}
138353942Sdim
139353942SdimFrame *InterpFrame::getCaller() const {
140353942Sdim  if (Caller->Caller)
141353942Sdim    return Caller;
142353942Sdim  return S.getSplitFrame();
143353942Sdim}
144353942Sdim
145353942SdimSourceLocation InterpFrame::getCallLocation() const {
146353942Sdim  if (!Caller->Func)
147353942Sdim    return S.getLocation(nullptr, {});
148353942Sdim  return S.getLocation(Caller->Func, RetPC - sizeof(uintptr_t));
149353942Sdim}
150353942Sdim
151353942Sdimconst FunctionDecl *InterpFrame::getCallee() const {
152353942Sdim  return Func->getDecl();
153353942Sdim}
154353942Sdim
155353942SdimPointer InterpFrame::getLocalPointer(unsigned Offset) {
156353942Sdim  assert(Offset < Func->getFrameSize() && "Invalid local offset.");
157353942Sdim  return Pointer(
158353942Sdim      reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block)));
159353942Sdim}
160353942Sdim
161353942SdimPointer InterpFrame::getParamPointer(unsigned Off) {
162353942Sdim  // Return the block if it was created previously.
163353942Sdim  auto Pt = Params.find(Off);
164353942Sdim  if (Pt != Params.end()) {
165353942Sdim    return Pointer(reinterpret_cast<Block *>(Pt->second.get()));
166353942Sdim  }
167353942Sdim
168353942Sdim  // Allocate memory to store the parameter and the block metadata.
169353942Sdim  const auto &Desc = Func->getParamDescriptor(Off);
170353942Sdim  size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize();
171353942Sdim  auto Memory = std::make_unique<char[]>(BlockSize);
172353942Sdim  auto *B = new (Memory.get()) Block(Desc.second);
173353942Sdim
174353942Sdim  // Copy the initial value.
175353942Sdim  TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off)));
176353942Sdim
177353942Sdim  // Record the param.
178353942Sdim  Params.insert({Off, std::move(Memory)});
179353942Sdim  return Pointer(B);
180353942Sdim}
181353942Sdim
182353942SdimSourceInfo InterpFrame::getSource(CodePtr PC) const {
183353942Sdim  return S.getSource(Func, PC);
184353942Sdim}
185353942Sdim
186353942Sdimconst Expr *InterpFrame::getExpr(CodePtr PC) const {
187353942Sdim  return S.getExpr(Func, PC);
188353942Sdim}
189353942Sdim
190353942SdimSourceLocation InterpFrame::getLocation(CodePtr PC) const {
191353942Sdim  return S.getLocation(Func, PC);
192353942Sdim}
193353942Sdim
194