xref: /llvm-project/clang/lib/AST/ByteCode/InterpFrame.cpp (revision a07aba5d44204a7ca0d891a3da05af9960081e4c)
1*a07aba5dSTimm Baeder //===--- InterpFrame.cpp - Call Frame implementation for the VM -*- C++ -*-===//
2*a07aba5dSTimm Baeder //
3*a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5*a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*a07aba5dSTimm Baeder //
7*a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8*a07aba5dSTimm Baeder 
9*a07aba5dSTimm Baeder #include "InterpFrame.h"
10*a07aba5dSTimm Baeder #include "Boolean.h"
11*a07aba5dSTimm Baeder #include "Floating.h"
12*a07aba5dSTimm Baeder #include "Function.h"
13*a07aba5dSTimm Baeder #include "InterpStack.h"
14*a07aba5dSTimm Baeder #include "InterpState.h"
15*a07aba5dSTimm Baeder #include "MemberPointer.h"
16*a07aba5dSTimm Baeder #include "Pointer.h"
17*a07aba5dSTimm Baeder #include "PrimType.h"
18*a07aba5dSTimm Baeder #include "Program.h"
19*a07aba5dSTimm Baeder #include "clang/AST/ASTContext.h"
20*a07aba5dSTimm Baeder #include "clang/AST/DeclCXX.h"
21*a07aba5dSTimm Baeder #include "clang/AST/ExprCXX.h"
22*a07aba5dSTimm Baeder 
23*a07aba5dSTimm Baeder using namespace clang;
24*a07aba5dSTimm Baeder using namespace clang::interp;
25*a07aba5dSTimm Baeder 
26*a07aba5dSTimm Baeder InterpFrame::InterpFrame(InterpState &S, const Function *Func,
27*a07aba5dSTimm Baeder                          InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize)
28*a07aba5dSTimm Baeder     : Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func),
29*a07aba5dSTimm Baeder       RetPC(RetPC), ArgSize(ArgSize), Args(static_cast<char *>(S.Stk.top())),
30*a07aba5dSTimm Baeder       FrameOffset(S.Stk.size()) {
31*a07aba5dSTimm Baeder   if (!Func)
32*a07aba5dSTimm Baeder     return;
33*a07aba5dSTimm Baeder 
34*a07aba5dSTimm Baeder   unsigned FrameSize = Func->getFrameSize();
35*a07aba5dSTimm Baeder   if (FrameSize == 0)
36*a07aba5dSTimm Baeder     return;
37*a07aba5dSTimm Baeder 
38*a07aba5dSTimm Baeder   Locals = std::make_unique<char[]>(FrameSize);
39*a07aba5dSTimm Baeder   for (auto &Scope : Func->scopes()) {
40*a07aba5dSTimm Baeder     for (auto &Local : Scope.locals()) {
41*a07aba5dSTimm Baeder       new (localBlock(Local.Offset)) Block(S.Ctx.getEvalID(), Local.Desc);
42*a07aba5dSTimm Baeder       // Note that we are NOT calling invokeCtor() here, since that is done
43*a07aba5dSTimm Baeder       // via the InitScope op.
44*a07aba5dSTimm Baeder       new (localInlineDesc(Local.Offset)) InlineDescriptor(Local.Desc);
45*a07aba5dSTimm Baeder     }
46*a07aba5dSTimm Baeder   }
47*a07aba5dSTimm Baeder }
48*a07aba5dSTimm Baeder 
49*a07aba5dSTimm Baeder InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC,
50*a07aba5dSTimm Baeder                          unsigned VarArgSize)
51*a07aba5dSTimm Baeder     : InterpFrame(S, Func, S.Current, RetPC, Func->getArgSize() + VarArgSize) {
52*a07aba5dSTimm Baeder   // As per our calling convention, the this pointer is
53*a07aba5dSTimm Baeder   // part of the ArgSize.
54*a07aba5dSTimm Baeder   // If the function has RVO, the RVO pointer is first.
55*a07aba5dSTimm Baeder   // If the fuction has a This pointer, that one is next.
56*a07aba5dSTimm Baeder   // Then follow the actual arguments (but those are handled
57*a07aba5dSTimm Baeder   // in getParamPointer()).
58*a07aba5dSTimm Baeder   if (Func->hasRVO())
59*a07aba5dSTimm Baeder     RVOPtr = stackRef<Pointer>(0);
60*a07aba5dSTimm Baeder 
61*a07aba5dSTimm Baeder   if (Func->hasThisPointer()) {
62*a07aba5dSTimm Baeder     if (Func->hasRVO())
63*a07aba5dSTimm Baeder       This = stackRef<Pointer>(sizeof(Pointer));
64*a07aba5dSTimm Baeder     else
65*a07aba5dSTimm Baeder       This = stackRef<Pointer>(0);
66*a07aba5dSTimm Baeder   }
67*a07aba5dSTimm Baeder }
68*a07aba5dSTimm Baeder 
69*a07aba5dSTimm Baeder InterpFrame::~InterpFrame() {
70*a07aba5dSTimm Baeder   for (auto &Param : Params)
71*a07aba5dSTimm Baeder     S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
72*a07aba5dSTimm Baeder 
73*a07aba5dSTimm Baeder   // When destroying the InterpFrame, call the Dtor for all block
74*a07aba5dSTimm Baeder   // that haven't been destroyed via a destroy() op yet.
75*a07aba5dSTimm Baeder   // This happens when the execution is interruped midway-through.
76*a07aba5dSTimm Baeder   if (Func) {
77*a07aba5dSTimm Baeder     for (auto &Scope : Func->scopes()) {
78*a07aba5dSTimm Baeder       for (auto &Local : Scope.locals()) {
79*a07aba5dSTimm Baeder         S.deallocate(localBlock(Local.Offset));
80*a07aba5dSTimm Baeder       }
81*a07aba5dSTimm Baeder     }
82*a07aba5dSTimm Baeder   }
83*a07aba5dSTimm Baeder }
84*a07aba5dSTimm Baeder 
85*a07aba5dSTimm Baeder void InterpFrame::initScope(unsigned Idx) {
86*a07aba5dSTimm Baeder   if (!Func)
87*a07aba5dSTimm Baeder     return;
88*a07aba5dSTimm Baeder   for (auto &Local : Func->getScope(Idx).locals()) {
89*a07aba5dSTimm Baeder     localBlock(Local.Offset)->invokeCtor();
90*a07aba5dSTimm Baeder   }
91*a07aba5dSTimm Baeder }
92*a07aba5dSTimm Baeder 
93*a07aba5dSTimm Baeder void InterpFrame::destroy(unsigned Idx) {
94*a07aba5dSTimm Baeder   for (auto &Local : Func->getScope(Idx).locals()) {
95*a07aba5dSTimm Baeder     S.deallocate(localBlock(Local.Offset));
96*a07aba5dSTimm Baeder   }
97*a07aba5dSTimm Baeder }
98*a07aba5dSTimm Baeder 
99*a07aba5dSTimm Baeder void InterpFrame::popArgs() {
100*a07aba5dSTimm Baeder   for (PrimType Ty : Func->args_reverse())
101*a07aba5dSTimm Baeder     TYPE_SWITCH(Ty, S.Stk.discard<T>());
102*a07aba5dSTimm Baeder }
103*a07aba5dSTimm Baeder 
104*a07aba5dSTimm Baeder template <typename T>
105*a07aba5dSTimm Baeder static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx,
106*a07aba5dSTimm Baeder                   QualType Ty) {
107*a07aba5dSTimm Baeder   V.toAPValue(ASTCtx).printPretty(OS, ASTCtx, Ty);
108*a07aba5dSTimm Baeder }
109*a07aba5dSTimm Baeder 
110*a07aba5dSTimm Baeder template <>
111*a07aba5dSTimm Baeder void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
112*a07aba5dSTimm Baeder            QualType Ty) {
113*a07aba5dSTimm Baeder   if (P.isZero()) {
114*a07aba5dSTimm Baeder     OS << "nullptr";
115*a07aba5dSTimm Baeder     return;
116*a07aba5dSTimm Baeder   }
117*a07aba5dSTimm Baeder 
118*a07aba5dSTimm Baeder   auto printDesc = [&OS, &Ctx](const Descriptor *Desc) {
119*a07aba5dSTimm Baeder     if (const auto *D = Desc->asDecl()) {
120*a07aba5dSTimm Baeder       // Subfields or named values.
121*a07aba5dSTimm Baeder       if (const auto *VD = dyn_cast<ValueDecl>(D)) {
122*a07aba5dSTimm Baeder         OS << *VD;
123*a07aba5dSTimm Baeder         return;
124*a07aba5dSTimm Baeder       }
125*a07aba5dSTimm Baeder       // Base classes.
126*a07aba5dSTimm Baeder       if (isa<RecordDecl>(D))
127*a07aba5dSTimm Baeder         return;
128*a07aba5dSTimm Baeder     }
129*a07aba5dSTimm Baeder     // Temporary expression.
130*a07aba5dSTimm Baeder     if (const auto *E = Desc->asExpr()) {
131*a07aba5dSTimm Baeder       E->printPretty(OS, nullptr, Ctx.getPrintingPolicy());
132*a07aba5dSTimm Baeder       return;
133*a07aba5dSTimm Baeder     }
134*a07aba5dSTimm Baeder     llvm_unreachable("Invalid descriptor type");
135*a07aba5dSTimm Baeder   };
136*a07aba5dSTimm Baeder 
137*a07aba5dSTimm Baeder   if (!Ty->isReferenceType())
138*a07aba5dSTimm Baeder     OS << "&";
139*a07aba5dSTimm Baeder   llvm::SmallVector<Pointer, 2> Levels;
140*a07aba5dSTimm Baeder   for (Pointer F = P; !F.isRoot();) {
141*a07aba5dSTimm Baeder     Levels.push_back(F);
142*a07aba5dSTimm Baeder     F = F.isArrayElement() ? F.getArray().expand() : F.getBase();
143*a07aba5dSTimm Baeder   }
144*a07aba5dSTimm Baeder 
145*a07aba5dSTimm Baeder   // Drop the first pointer since we print it unconditionally anyway.
146*a07aba5dSTimm Baeder   if (!Levels.empty())
147*a07aba5dSTimm Baeder     Levels.erase(Levels.begin());
148*a07aba5dSTimm Baeder 
149*a07aba5dSTimm Baeder   printDesc(P.getDeclDesc());
150*a07aba5dSTimm Baeder   for (const auto &It : Levels) {
151*a07aba5dSTimm Baeder     if (It.inArray()) {
152*a07aba5dSTimm Baeder       OS << "[" << It.expand().getIndex() << "]";
153*a07aba5dSTimm Baeder       continue;
154*a07aba5dSTimm Baeder     }
155*a07aba5dSTimm Baeder     if (auto Index = It.getIndex()) {
156*a07aba5dSTimm Baeder       OS << " + " << Index;
157*a07aba5dSTimm Baeder       continue;
158*a07aba5dSTimm Baeder     }
159*a07aba5dSTimm Baeder     OS << ".";
160*a07aba5dSTimm Baeder     printDesc(It.getFieldDesc());
161*a07aba5dSTimm Baeder   }
162*a07aba5dSTimm Baeder }
163*a07aba5dSTimm Baeder 
164*a07aba5dSTimm Baeder void InterpFrame::describe(llvm::raw_ostream &OS) const {
165*a07aba5dSTimm Baeder   // We create frames for builtin functions as well, but we can't reliably
166*a07aba5dSTimm Baeder   // diagnose them. The 'in call to' diagnostics for them add no value to the
167*a07aba5dSTimm Baeder   // user _and_ it doesn't generally work since the argument types don't always
168*a07aba5dSTimm Baeder   // match the function prototype. Just ignore them.
169*a07aba5dSTimm Baeder   // Similarly, for lambda static invokers, we would just print __invoke().
170*a07aba5dSTimm Baeder   if (const auto *F = getFunction();
171*a07aba5dSTimm Baeder       F && (F->isBuiltin() || F->isLambdaStaticInvoker()))
172*a07aba5dSTimm Baeder     return;
173*a07aba5dSTimm Baeder 
174*a07aba5dSTimm Baeder   const Expr *CallExpr = Caller->getExpr(getRetPC());
175*a07aba5dSTimm Baeder   const FunctionDecl *F = getCallee();
176*a07aba5dSTimm Baeder   bool IsMemberCall = isa<CXXMethodDecl>(F) && !isa<CXXConstructorDecl>(F) &&
177*a07aba5dSTimm Baeder                       cast<CXXMethodDecl>(F)->isImplicitObjectMemberFunction();
178*a07aba5dSTimm Baeder   if (Func->hasThisPointer() && IsMemberCall) {
179*a07aba5dSTimm Baeder     if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) {
180*a07aba5dSTimm Baeder       const Expr *Object = MCE->getImplicitObjectArgument();
181*a07aba5dSTimm Baeder       Object->printPretty(OS, /*Helper=*/nullptr,
182*a07aba5dSTimm Baeder                           S.getCtx().getPrintingPolicy(),
183*a07aba5dSTimm Baeder                           /*Indentation=*/0);
184*a07aba5dSTimm Baeder       if (Object->getType()->isPointerType())
185*a07aba5dSTimm Baeder         OS << "->";
186*a07aba5dSTimm Baeder       else
187*a07aba5dSTimm Baeder         OS << ".";
188*a07aba5dSTimm Baeder     } else if (const auto *OCE =
189*a07aba5dSTimm Baeder                    dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
190*a07aba5dSTimm Baeder       OCE->getArg(0)->printPretty(OS, /*Helper=*/nullptr,
191*a07aba5dSTimm Baeder                                   S.getCtx().getPrintingPolicy(),
192*a07aba5dSTimm Baeder                                   /*Indentation=*/0);
193*a07aba5dSTimm Baeder       OS << ".";
194*a07aba5dSTimm Baeder     } else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) {
195*a07aba5dSTimm Baeder       print(OS, This, S.getCtx(),
196*a07aba5dSTimm Baeder             S.getCtx().getLValueReferenceType(
197*a07aba5dSTimm Baeder                 S.getCtx().getRecordType(M->getParent())));
198*a07aba5dSTimm Baeder       OS << ".";
199*a07aba5dSTimm Baeder     }
200*a07aba5dSTimm Baeder   }
201*a07aba5dSTimm Baeder 
202*a07aba5dSTimm Baeder   F->getNameForDiagnostic(OS, S.getCtx().getPrintingPolicy(),
203*a07aba5dSTimm Baeder                           /*Qualified=*/false);
204*a07aba5dSTimm Baeder   OS << '(';
205*a07aba5dSTimm Baeder   unsigned Off = 0;
206*a07aba5dSTimm Baeder 
207*a07aba5dSTimm Baeder   Off += Func->hasRVO() ? primSize(PT_Ptr) : 0;
208*a07aba5dSTimm Baeder   Off += Func->hasThisPointer() ? primSize(PT_Ptr) : 0;
209*a07aba5dSTimm Baeder 
210*a07aba5dSTimm Baeder   for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) {
211*a07aba5dSTimm Baeder     QualType Ty = F->getParamDecl(I)->getType();
212*a07aba5dSTimm Baeder 
213*a07aba5dSTimm Baeder     PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr);
214*a07aba5dSTimm Baeder 
215*a07aba5dSTimm Baeder     TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
216*a07aba5dSTimm Baeder     Off += align(primSize(PrimTy));
217*a07aba5dSTimm Baeder     if (I + 1 != N)
218*a07aba5dSTimm Baeder       OS << ", ";
219*a07aba5dSTimm Baeder   }
220*a07aba5dSTimm Baeder   OS << ")";
221*a07aba5dSTimm Baeder }
222*a07aba5dSTimm Baeder 
223*a07aba5dSTimm Baeder Frame *InterpFrame::getCaller() const {
224*a07aba5dSTimm Baeder   if (Caller->Caller)
225*a07aba5dSTimm Baeder     return Caller;
226*a07aba5dSTimm Baeder   return S.getSplitFrame();
227*a07aba5dSTimm Baeder }
228*a07aba5dSTimm Baeder 
229*a07aba5dSTimm Baeder SourceRange InterpFrame::getCallRange() const {
230*a07aba5dSTimm Baeder   if (!Caller->Func) {
231*a07aba5dSTimm Baeder     if (SourceRange NullRange = S.getRange(nullptr, {}); NullRange.isValid())
232*a07aba5dSTimm Baeder       return NullRange;
233*a07aba5dSTimm Baeder     return S.EvalLocation;
234*a07aba5dSTimm Baeder   }
235*a07aba5dSTimm Baeder   return S.getRange(Caller->Func, RetPC - sizeof(uintptr_t));
236*a07aba5dSTimm Baeder }
237*a07aba5dSTimm Baeder 
238*a07aba5dSTimm Baeder const FunctionDecl *InterpFrame::getCallee() const {
239*a07aba5dSTimm Baeder   if (!Func)
240*a07aba5dSTimm Baeder     return nullptr;
241*a07aba5dSTimm Baeder   return Func->getDecl();
242*a07aba5dSTimm Baeder }
243*a07aba5dSTimm Baeder 
244*a07aba5dSTimm Baeder Pointer InterpFrame::getLocalPointer(unsigned Offset) const {
245*a07aba5dSTimm Baeder   assert(Offset < Func->getFrameSize() && "Invalid local offset.");
246*a07aba5dSTimm Baeder   return Pointer(localBlock(Offset));
247*a07aba5dSTimm Baeder }
248*a07aba5dSTimm Baeder 
249*a07aba5dSTimm Baeder Pointer InterpFrame::getParamPointer(unsigned Off) {
250*a07aba5dSTimm Baeder   // Return the block if it was created previously.
251*a07aba5dSTimm Baeder   if (auto Pt = Params.find(Off); Pt != Params.end())
252*a07aba5dSTimm Baeder     return Pointer(reinterpret_cast<Block *>(Pt->second.get()));
253*a07aba5dSTimm Baeder 
254*a07aba5dSTimm Baeder   // Allocate memory to store the parameter and the block metadata.
255*a07aba5dSTimm Baeder   const auto &Desc = Func->getParamDescriptor(Off);
256*a07aba5dSTimm Baeder   size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize();
257*a07aba5dSTimm Baeder   auto Memory = std::make_unique<char[]>(BlockSize);
258*a07aba5dSTimm Baeder   auto *B = new (Memory.get()) Block(S.Ctx.getEvalID(), Desc.second);
259*a07aba5dSTimm Baeder   B->invokeCtor();
260*a07aba5dSTimm Baeder 
261*a07aba5dSTimm Baeder   // Copy the initial value.
262*a07aba5dSTimm Baeder   TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off)));
263*a07aba5dSTimm Baeder 
264*a07aba5dSTimm Baeder   // Record the param.
265*a07aba5dSTimm Baeder   Params.insert({Off, std::move(Memory)});
266*a07aba5dSTimm Baeder   return Pointer(B);
267*a07aba5dSTimm Baeder }
268*a07aba5dSTimm Baeder 
269*a07aba5dSTimm Baeder SourceInfo InterpFrame::getSource(CodePtr PC) const {
270*a07aba5dSTimm Baeder   // Implicitly created functions don't have any code we could point at,
271*a07aba5dSTimm Baeder   // so return the call site.
272*a07aba5dSTimm Baeder   if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
273*a07aba5dSTimm Baeder     return Caller->getSource(RetPC);
274*a07aba5dSTimm Baeder 
275*a07aba5dSTimm Baeder   return S.getSource(Func, PC);
276*a07aba5dSTimm Baeder }
277*a07aba5dSTimm Baeder 
278*a07aba5dSTimm Baeder const Expr *InterpFrame::getExpr(CodePtr PC) const {
279*a07aba5dSTimm Baeder   if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
280*a07aba5dSTimm Baeder     return Caller->getExpr(RetPC);
281*a07aba5dSTimm Baeder 
282*a07aba5dSTimm Baeder   return S.getExpr(Func, PC);
283*a07aba5dSTimm Baeder }
284*a07aba5dSTimm Baeder 
285*a07aba5dSTimm Baeder SourceLocation InterpFrame::getLocation(CodePtr PC) const {
286*a07aba5dSTimm Baeder   if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
287*a07aba5dSTimm Baeder     return Caller->getLocation(RetPC);
288*a07aba5dSTimm Baeder 
289*a07aba5dSTimm Baeder   return S.getLocation(Func, PC);
290*a07aba5dSTimm Baeder }
291*a07aba5dSTimm Baeder 
292*a07aba5dSTimm Baeder SourceRange InterpFrame::getRange(CodePtr PC) const {
293*a07aba5dSTimm Baeder   if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
294*a07aba5dSTimm Baeder     return Caller->getRange(RetPC);
295*a07aba5dSTimm Baeder 
296*a07aba5dSTimm Baeder   return S.getRange(Func, PC);
297*a07aba5dSTimm Baeder }
298