1e5dd7070Spatrick //===--- InterpFrame.cpp - Call Frame implementation for the VM -*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick
9e5dd7070Spatrick #include "InterpFrame.h"
10*12c85518Srobert #include "Boolean.h"
11e5dd7070Spatrick #include "Function.h"
12e5dd7070Spatrick #include "InterpStack.h"
13*12c85518Srobert #include "InterpState.h"
14*12c85518Srobert #include "Pointer.h"
15e5dd7070Spatrick #include "PrimType.h"
16e5dd7070Spatrick #include "Program.h"
17*12c85518Srobert #include "clang/AST/ASTContext.h"
18e5dd7070Spatrick #include "clang/AST/DeclCXX.h"
19e5dd7070Spatrick
20e5dd7070Spatrick using namespace clang;
21e5dd7070Spatrick using namespace clang::interp;
22e5dd7070Spatrick
InterpFrame(InterpState & S,const Function * Func,InterpFrame * Caller,CodePtr RetPC)23*12c85518Srobert InterpFrame::InterpFrame(InterpState &S, const Function *Func,
24*12c85518Srobert InterpFrame *Caller, CodePtr RetPC)
25*12c85518Srobert : Caller(Caller), S(S), Func(Func), RetPC(RetPC),
26e5dd7070Spatrick ArgSize(Func ? Func->getArgSize() : 0),
27e5dd7070Spatrick Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
28*12c85518Srobert if (!Func)
29*12c85518Srobert return;
30*12c85518Srobert
31*12c85518Srobert unsigned FrameSize = Func->getFrameSize();
32*12c85518Srobert if (FrameSize == 0)
33*12c85518Srobert return;
34*12c85518Srobert
35e5dd7070Spatrick Locals = std::make_unique<char[]>(FrameSize);
36e5dd7070Spatrick for (auto &Scope : Func->scopes()) {
37e5dd7070Spatrick for (auto &Local : Scope.locals()) {
38e5dd7070Spatrick Block *B = new (localBlock(Local.Offset)) Block(Local.Desc);
39e5dd7070Spatrick B->invokeCtor();
40*12c85518Srobert InlineDescriptor *ID = localInlineDesc(Local.Offset);
41*12c85518Srobert ID->Desc = Local.Desc;
42*12c85518Srobert ID->IsActive = true;
43*12c85518Srobert ID->Offset = sizeof(InlineDescriptor);
44*12c85518Srobert ID->IsBase = false;
45*12c85518Srobert ID->IsFieldMutable = false;
46*12c85518Srobert ID->IsConst = false;
47*12c85518Srobert ID->IsInitialized = false;
48e5dd7070Spatrick }
49e5dd7070Spatrick }
50e5dd7070Spatrick }
51e5dd7070Spatrick
InterpFrame(InterpState & S,const Function * Func,CodePtr RetPC)52*12c85518Srobert InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC)
53*12c85518Srobert : InterpFrame(S, Func, S.Current, RetPC) {
54*12c85518Srobert // As per our calling convention, the this pointer is
55*12c85518Srobert // part of the ArgSize.
56*12c85518Srobert // If the function has RVO, the RVO pointer is first.
57*12c85518Srobert // If the fuction has a This pointer, that one is next.
58*12c85518Srobert // Then follow the actual arguments (but those are handled
59*12c85518Srobert // in getParamPointer()).
60*12c85518Srobert if (Func->hasRVO())
61*12c85518Srobert RVOPtr = stackRef<Pointer>(0);
62*12c85518Srobert
63*12c85518Srobert if (Func->hasThisPointer()) {
64*12c85518Srobert if (Func->hasRVO())
65*12c85518Srobert This = stackRef<Pointer>(sizeof(Pointer));
66*12c85518Srobert else
67*12c85518Srobert This = stackRef<Pointer>(0);
68*12c85518Srobert }
69*12c85518Srobert }
70*12c85518Srobert
~InterpFrame()71e5dd7070Spatrick InterpFrame::~InterpFrame() {
72e5dd7070Spatrick for (auto &Param : Params)
73e5dd7070Spatrick S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
74e5dd7070Spatrick }
75e5dd7070Spatrick
destroy(unsigned Idx)76e5dd7070Spatrick void InterpFrame::destroy(unsigned Idx) {
77e5dd7070Spatrick for (auto &Local : Func->getScope(Idx).locals()) {
78e5dd7070Spatrick S.deallocate(reinterpret_cast<Block *>(localBlock(Local.Offset)));
79e5dd7070Spatrick }
80e5dd7070Spatrick }
81e5dd7070Spatrick
popArgs()82e5dd7070Spatrick void InterpFrame::popArgs() {
83e5dd7070Spatrick for (PrimType Ty : Func->args_reverse())
84e5dd7070Spatrick TYPE_SWITCH(Ty, S.Stk.discard<T>());
85e5dd7070Spatrick }
86e5dd7070Spatrick
87e5dd7070Spatrick template <typename T>
print(llvm::raw_ostream & OS,const T & V,ASTContext &,QualType)88e5dd7070Spatrick static void print(llvm::raw_ostream &OS, const T &V, ASTContext &, QualType) {
89e5dd7070Spatrick OS << V;
90e5dd7070Spatrick }
91e5dd7070Spatrick
92e5dd7070Spatrick template <>
print(llvm::raw_ostream & OS,const Pointer & P,ASTContext & Ctx,QualType Ty)93e5dd7070Spatrick void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
94e5dd7070Spatrick QualType Ty) {
95e5dd7070Spatrick if (P.isZero()) {
96e5dd7070Spatrick OS << "nullptr";
97e5dd7070Spatrick return;
98e5dd7070Spatrick }
99e5dd7070Spatrick
100e5dd7070Spatrick auto printDesc = [&OS, &Ctx](Descriptor *Desc) {
101e5dd7070Spatrick if (auto *D = Desc->asDecl()) {
102e5dd7070Spatrick // Subfields or named values.
103e5dd7070Spatrick if (auto *VD = dyn_cast<ValueDecl>(D)) {
104e5dd7070Spatrick OS << *VD;
105e5dd7070Spatrick return;
106e5dd7070Spatrick }
107e5dd7070Spatrick // Base classes.
108e5dd7070Spatrick if (isa<RecordDecl>(D)) {
109e5dd7070Spatrick return;
110e5dd7070Spatrick }
111e5dd7070Spatrick }
112e5dd7070Spatrick // Temporary expression.
113e5dd7070Spatrick if (auto *E = Desc->asExpr()) {
114e5dd7070Spatrick E->printPretty(OS, nullptr, Ctx.getPrintingPolicy());
115e5dd7070Spatrick return;
116e5dd7070Spatrick }
117e5dd7070Spatrick llvm_unreachable("Invalid descriptor type");
118e5dd7070Spatrick };
119e5dd7070Spatrick
120e5dd7070Spatrick if (!Ty->isReferenceType())
121e5dd7070Spatrick OS << "&";
122e5dd7070Spatrick llvm::SmallVector<Pointer, 2> Levels;
123e5dd7070Spatrick for (Pointer F = P; !F.isRoot(); ) {
124e5dd7070Spatrick Levels.push_back(F);
125e5dd7070Spatrick F = F.isArrayElement() ? F.getArray().expand() : F.getBase();
126e5dd7070Spatrick }
127e5dd7070Spatrick
128e5dd7070Spatrick printDesc(P.getDeclDesc());
129*12c85518Srobert for (const auto &It : Levels) {
130*12c85518Srobert if (It.inArray()) {
131*12c85518Srobert OS << "[" << It.expand().getIndex() << "]";
132e5dd7070Spatrick continue;
133e5dd7070Spatrick }
134*12c85518Srobert if (auto Index = It.getIndex()) {
135e5dd7070Spatrick OS << " + " << Index;
136e5dd7070Spatrick continue;
137e5dd7070Spatrick }
138e5dd7070Spatrick OS << ".";
139*12c85518Srobert printDesc(It.getFieldDesc());
140e5dd7070Spatrick }
141e5dd7070Spatrick }
142e5dd7070Spatrick
describe(llvm::raw_ostream & OS)143e5dd7070Spatrick void InterpFrame::describe(llvm::raw_ostream &OS) {
144e5dd7070Spatrick const FunctionDecl *F = getCallee();
145e5dd7070Spatrick auto *M = dyn_cast<CXXMethodDecl>(F);
146e5dd7070Spatrick if (M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
147e5dd7070Spatrick print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
148e5dd7070Spatrick OS << "->";
149e5dd7070Spatrick }
150e5dd7070Spatrick OS << *F << "(";
151*12c85518Srobert unsigned Off = 0;
152*12c85518Srobert
153*12c85518Srobert Off += Func->hasRVO() ? primSize(PT_Ptr) : 0;
154*12c85518Srobert Off += Func->hasThisPointer() ? primSize(PT_Ptr) : 0;
155*12c85518Srobert
156e5dd7070Spatrick for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) {
157e5dd7070Spatrick QualType Ty = F->getParamDecl(I)->getType();
158e5dd7070Spatrick
159*12c85518Srobert PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr);
160e5dd7070Spatrick
161e5dd7070Spatrick TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
162e5dd7070Spatrick Off += align(primSize(PrimTy));
163e5dd7070Spatrick if (I + 1 != N)
164e5dd7070Spatrick OS << ", ";
165e5dd7070Spatrick }
166e5dd7070Spatrick OS << ")";
167e5dd7070Spatrick }
168e5dd7070Spatrick
getCaller() const169e5dd7070Spatrick Frame *InterpFrame::getCaller() const {
170e5dd7070Spatrick if (Caller->Caller)
171e5dd7070Spatrick return Caller;
172e5dd7070Spatrick return S.getSplitFrame();
173e5dd7070Spatrick }
174e5dd7070Spatrick
getCallLocation() const175e5dd7070Spatrick SourceLocation InterpFrame::getCallLocation() const {
176e5dd7070Spatrick if (!Caller->Func)
177e5dd7070Spatrick return S.getLocation(nullptr, {});
178e5dd7070Spatrick return S.getLocation(Caller->Func, RetPC - sizeof(uintptr_t));
179e5dd7070Spatrick }
180e5dd7070Spatrick
getCallee() const181e5dd7070Spatrick const FunctionDecl *InterpFrame::getCallee() const {
182e5dd7070Spatrick return Func->getDecl();
183e5dd7070Spatrick }
184e5dd7070Spatrick
getLocalPointer(unsigned Offset) const185*12c85518Srobert Pointer InterpFrame::getLocalPointer(unsigned Offset) const {
186e5dd7070Spatrick assert(Offset < Func->getFrameSize() && "Invalid local offset.");
187*12c85518Srobert return Pointer(reinterpret_cast<Block *>(localBlock(Offset)),
188*12c85518Srobert sizeof(InlineDescriptor));
189e5dd7070Spatrick }
190e5dd7070Spatrick
getParamPointer(unsigned Off)191e5dd7070Spatrick Pointer InterpFrame::getParamPointer(unsigned Off) {
192e5dd7070Spatrick // Return the block if it was created previously.
193e5dd7070Spatrick auto Pt = Params.find(Off);
194e5dd7070Spatrick if (Pt != Params.end()) {
195e5dd7070Spatrick return Pointer(reinterpret_cast<Block *>(Pt->second.get()));
196e5dd7070Spatrick }
197e5dd7070Spatrick
198e5dd7070Spatrick // Allocate memory to store the parameter and the block metadata.
199e5dd7070Spatrick const auto &Desc = Func->getParamDescriptor(Off);
200e5dd7070Spatrick size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize();
201e5dd7070Spatrick auto Memory = std::make_unique<char[]>(BlockSize);
202e5dd7070Spatrick auto *B = new (Memory.get()) Block(Desc.second);
203e5dd7070Spatrick
204e5dd7070Spatrick // Copy the initial value.
205e5dd7070Spatrick TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off)));
206e5dd7070Spatrick
207e5dd7070Spatrick // Record the param.
208e5dd7070Spatrick Params.insert({Off, std::move(Memory)});
209e5dd7070Spatrick return Pointer(B);
210e5dd7070Spatrick }
211e5dd7070Spatrick
getSource(CodePtr PC) const212e5dd7070Spatrick SourceInfo InterpFrame::getSource(CodePtr PC) const {
213e5dd7070Spatrick return S.getSource(Func, PC);
214e5dd7070Spatrick }
215e5dd7070Spatrick
getExpr(CodePtr PC) const216e5dd7070Spatrick const Expr *InterpFrame::getExpr(CodePtr PC) const {
217e5dd7070Spatrick return S.getExpr(Func, PC);
218e5dd7070Spatrick }
219e5dd7070Spatrick
getLocation(CodePtr PC) const220e5dd7070Spatrick SourceLocation InterpFrame::getLocation(CodePtr PC) const {
221e5dd7070Spatrick return S.getLocation(Func, PC);
222e5dd7070Spatrick }
223e5dd7070Spatrick
224