xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1a7dea167SDimitry Andric //===--- InterpFrame.cpp - Call Frame implementation for the 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 "InterpFrame.h"
10bdd1243dSDimitry Andric #include "Boolean.h"
1106c3fb27SDimitry Andric #include "Floating.h"
12a7dea167SDimitry Andric #include "Function.h"
13a7dea167SDimitry Andric #include "InterpStack.h"
14bdd1243dSDimitry Andric #include "InterpState.h"
15*0fca6ea1SDimitry Andric #include "MemberPointer.h"
16bdd1243dSDimitry Andric #include "Pointer.h"
17a7dea167SDimitry Andric #include "PrimType.h"
18a7dea167SDimitry Andric #include "Program.h"
19bdd1243dSDimitry Andric #include "clang/AST/ASTContext.h"
20a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h"
21a7dea167SDimitry Andric 
22a7dea167SDimitry Andric using namespace clang;
23a7dea167SDimitry Andric using namespace clang::interp;
24a7dea167SDimitry Andric 
InterpFrame(InterpState & S,const Function * Func,InterpFrame * Caller,CodePtr RetPC,unsigned ArgSize)25bdd1243dSDimitry Andric InterpFrame::InterpFrame(InterpState &S, const Function *Func,
26*0fca6ea1SDimitry Andric                          InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize)
2706c3fb27SDimitry Andric     : Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func),
28*0fca6ea1SDimitry Andric       RetPC(RetPC), ArgSize(ArgSize), Args(static_cast<char *>(S.Stk.top())),
29*0fca6ea1SDimitry Andric       FrameOffset(S.Stk.size()) {
30bdd1243dSDimitry Andric   if (!Func)
31bdd1243dSDimitry Andric     return;
32bdd1243dSDimitry Andric 
33bdd1243dSDimitry Andric   unsigned FrameSize = Func->getFrameSize();
34bdd1243dSDimitry Andric   if (FrameSize == 0)
35bdd1243dSDimitry Andric     return;
36bdd1243dSDimitry Andric 
37a7dea167SDimitry Andric   Locals = std::make_unique<char[]>(FrameSize);
38a7dea167SDimitry Andric   for (auto &Scope : Func->scopes()) {
39a7dea167SDimitry Andric     for (auto &Local : Scope.locals()) {
40*0fca6ea1SDimitry Andric       Block *B =
41*0fca6ea1SDimitry Andric           new (localBlock(Local.Offset)) Block(S.Ctx.getEvalID(), Local.Desc);
42a7dea167SDimitry Andric       B->invokeCtor();
43*0fca6ea1SDimitry Andric       new (localInlineDesc(Local.Offset)) InlineDescriptor(Local.Desc);
44a7dea167SDimitry Andric     }
45a7dea167SDimitry Andric   }
46a7dea167SDimitry Andric }
47a7dea167SDimitry Andric 
InterpFrame(InterpState & S,const Function * Func,CodePtr RetPC,unsigned VarArgSize)48*0fca6ea1SDimitry Andric InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC,
49*0fca6ea1SDimitry Andric                          unsigned VarArgSize)
50*0fca6ea1SDimitry Andric     : InterpFrame(S, Func, S.Current, RetPC, Func->getArgSize() + VarArgSize) {
51bdd1243dSDimitry Andric   // As per our calling convention, the this pointer is
52bdd1243dSDimitry Andric   // part of the ArgSize.
53bdd1243dSDimitry Andric   // If the function has RVO, the RVO pointer is first.
54bdd1243dSDimitry Andric   // If the fuction has a This pointer, that one is next.
55bdd1243dSDimitry Andric   // Then follow the actual arguments (but those are handled
56bdd1243dSDimitry Andric   // in getParamPointer()).
57bdd1243dSDimitry Andric   if (Func->hasRVO())
58bdd1243dSDimitry Andric     RVOPtr = stackRef<Pointer>(0);
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric   if (Func->hasThisPointer()) {
61bdd1243dSDimitry Andric     if (Func->hasRVO())
62bdd1243dSDimitry Andric       This = stackRef<Pointer>(sizeof(Pointer));
63bdd1243dSDimitry Andric     else
64bdd1243dSDimitry Andric       This = stackRef<Pointer>(0);
65bdd1243dSDimitry Andric   }
66bdd1243dSDimitry Andric }
67bdd1243dSDimitry Andric 
~InterpFrame()68a7dea167SDimitry Andric InterpFrame::~InterpFrame() {
69a7dea167SDimitry Andric   for (auto &Param : Params)
70a7dea167SDimitry Andric     S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
715f757f3fSDimitry Andric 
725f757f3fSDimitry Andric   // When destroying the InterpFrame, call the Dtor for all block
735f757f3fSDimitry Andric   // that haven't been destroyed via a destroy() op yet.
745f757f3fSDimitry Andric   // This happens when the execution is interruped midway-through.
755f757f3fSDimitry Andric   if (Func) {
765f757f3fSDimitry Andric     for (auto &Scope : Func->scopes()) {
775f757f3fSDimitry Andric       for (auto &Local : Scope.locals()) {
785f757f3fSDimitry Andric         Block *B = localBlock(Local.Offset);
795f757f3fSDimitry Andric         if (B->isInitialized())
805f757f3fSDimitry Andric           B->invokeDtor();
815f757f3fSDimitry Andric       }
825f757f3fSDimitry Andric     }
835f757f3fSDimitry Andric   }
84a7dea167SDimitry Andric }
85a7dea167SDimitry Andric 
destroy(unsigned Idx)86a7dea167SDimitry Andric void InterpFrame::destroy(unsigned Idx) {
87a7dea167SDimitry Andric   for (auto &Local : Func->getScope(Idx).locals()) {
8806c3fb27SDimitry Andric     S.deallocate(localBlock(Local.Offset));
89a7dea167SDimitry Andric   }
90a7dea167SDimitry Andric }
91a7dea167SDimitry Andric 
popArgs()92a7dea167SDimitry Andric void InterpFrame::popArgs() {
93a7dea167SDimitry Andric   for (PrimType Ty : Func->args_reverse())
94a7dea167SDimitry Andric     TYPE_SWITCH(Ty, S.Stk.discard<T>());
95a7dea167SDimitry Andric }
96a7dea167SDimitry Andric 
97a7dea167SDimitry Andric template <typename T>
print(llvm::raw_ostream & OS,const T & V,ASTContext &,QualType)98a7dea167SDimitry Andric static void print(llvm::raw_ostream &OS, const T &V, ASTContext &, QualType) {
99a7dea167SDimitry Andric   OS << V;
100a7dea167SDimitry Andric }
101a7dea167SDimitry Andric 
102a7dea167SDimitry Andric template <>
print(llvm::raw_ostream & OS,const Pointer & P,ASTContext & Ctx,QualType Ty)103a7dea167SDimitry Andric void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
104a7dea167SDimitry Andric            QualType Ty) {
105a7dea167SDimitry Andric   if (P.isZero()) {
106a7dea167SDimitry Andric     OS << "nullptr";
107a7dea167SDimitry Andric     return;
108a7dea167SDimitry Andric   }
109a7dea167SDimitry Andric 
11006c3fb27SDimitry Andric   auto printDesc = [&OS, &Ctx](const Descriptor *Desc) {
11106c3fb27SDimitry Andric     if (const auto *D = Desc->asDecl()) {
112a7dea167SDimitry Andric       // Subfields or named values.
11306c3fb27SDimitry Andric       if (const auto *VD = dyn_cast<ValueDecl>(D)) {
114a7dea167SDimitry Andric         OS << *VD;
115a7dea167SDimitry Andric         return;
116a7dea167SDimitry Andric       }
117a7dea167SDimitry Andric       // Base classes.
11806c3fb27SDimitry Andric       if (isa<RecordDecl>(D))
119a7dea167SDimitry Andric         return;
120a7dea167SDimitry Andric     }
121a7dea167SDimitry Andric     // Temporary expression.
12206c3fb27SDimitry Andric     if (const auto *E = Desc->asExpr()) {
123a7dea167SDimitry Andric       E->printPretty(OS, nullptr, Ctx.getPrintingPolicy());
124a7dea167SDimitry Andric       return;
125a7dea167SDimitry Andric     }
126a7dea167SDimitry Andric     llvm_unreachable("Invalid descriptor type");
127a7dea167SDimitry Andric   };
128a7dea167SDimitry Andric 
129a7dea167SDimitry Andric   if (!Ty->isReferenceType())
130a7dea167SDimitry Andric     OS << "&";
131a7dea167SDimitry Andric   llvm::SmallVector<Pointer, 2> Levels;
132a7dea167SDimitry Andric   for (Pointer F = P; !F.isRoot(); ) {
133a7dea167SDimitry Andric     Levels.push_back(F);
134a7dea167SDimitry Andric     F = F.isArrayElement() ? F.getArray().expand() : F.getBase();
135a7dea167SDimitry Andric   }
136a7dea167SDimitry Andric 
13706c3fb27SDimitry Andric   // Drop the first pointer since we print it unconditionally anyway.
13806c3fb27SDimitry Andric   if (!Levels.empty())
13906c3fb27SDimitry Andric     Levels.erase(Levels.begin());
14006c3fb27SDimitry Andric 
141a7dea167SDimitry Andric   printDesc(P.getDeclDesc());
142bdd1243dSDimitry Andric   for (const auto &It : Levels) {
143bdd1243dSDimitry Andric     if (It.inArray()) {
144bdd1243dSDimitry Andric       OS << "[" << It.expand().getIndex() << "]";
145a7dea167SDimitry Andric       continue;
146a7dea167SDimitry Andric     }
147bdd1243dSDimitry Andric     if (auto Index = It.getIndex()) {
148a7dea167SDimitry Andric       OS << " + " << Index;
149a7dea167SDimitry Andric       continue;
150a7dea167SDimitry Andric     }
151a7dea167SDimitry Andric     OS << ".";
152bdd1243dSDimitry Andric     printDesc(It.getFieldDesc());
153a7dea167SDimitry Andric   }
154a7dea167SDimitry Andric }
155a7dea167SDimitry Andric 
describe(llvm::raw_ostream & OS) const15606c3fb27SDimitry Andric void InterpFrame::describe(llvm::raw_ostream &OS) const {
157*0fca6ea1SDimitry Andric   // We create frames for builtin functions as well, but we can't reliably
158*0fca6ea1SDimitry Andric   // diagnose them. The 'in call to' diagnostics for them add no value to the
159*0fca6ea1SDimitry Andric   // user _and_ it doesn't generally work since the argument types don't always
160*0fca6ea1SDimitry Andric   // match the function prototype. Just ignore them.
161*0fca6ea1SDimitry Andric   // Similarly, for lambda static invokers, we would just print __invoke().
162*0fca6ea1SDimitry Andric   if (const auto *F = getFunction();
163*0fca6ea1SDimitry Andric       F && (F->isBuiltin() || F->isLambdaStaticInvoker()))
164*0fca6ea1SDimitry Andric     return;
165*0fca6ea1SDimitry Andric 
166a7dea167SDimitry Andric   const FunctionDecl *F = getCallee();
16706c3fb27SDimitry Andric   if (const auto *M = dyn_cast<CXXMethodDecl>(F);
16806c3fb27SDimitry Andric       M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
169a7dea167SDimitry Andric     print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
170a7dea167SDimitry Andric     OS << "->";
171a7dea167SDimitry Andric   }
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric   F->getNameForDiagnostic(OS, S.getCtx().getPrintingPolicy(),
174*0fca6ea1SDimitry Andric                           /*Qualified=*/false);
175*0fca6ea1SDimitry Andric   OS << '(';
176bdd1243dSDimitry Andric   unsigned Off = 0;
177bdd1243dSDimitry Andric 
178bdd1243dSDimitry Andric   Off += Func->hasRVO() ? primSize(PT_Ptr) : 0;
179bdd1243dSDimitry Andric   Off += Func->hasThisPointer() ? primSize(PT_Ptr) : 0;
180bdd1243dSDimitry Andric 
181a7dea167SDimitry Andric   for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) {
182a7dea167SDimitry Andric     QualType Ty = F->getParamDecl(I)->getType();
183a7dea167SDimitry Andric 
184bdd1243dSDimitry Andric     PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr);
185a7dea167SDimitry Andric 
186a7dea167SDimitry Andric     TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
187a7dea167SDimitry Andric     Off += align(primSize(PrimTy));
188a7dea167SDimitry Andric     if (I + 1 != N)
189a7dea167SDimitry Andric       OS << ", ";
190a7dea167SDimitry Andric   }
191a7dea167SDimitry Andric   OS << ")";
192a7dea167SDimitry Andric }
193a7dea167SDimitry Andric 
getCaller() const194a7dea167SDimitry Andric Frame *InterpFrame::getCaller() const {
195a7dea167SDimitry Andric   if (Caller->Caller)
196a7dea167SDimitry Andric     return Caller;
197a7dea167SDimitry Andric   return S.getSplitFrame();
198a7dea167SDimitry Andric }
199a7dea167SDimitry Andric 
getCallRange() const2005f757f3fSDimitry Andric SourceRange InterpFrame::getCallRange() const {
201*0fca6ea1SDimitry Andric   if (!Caller->Func) {
202*0fca6ea1SDimitry Andric     if (SourceRange NullRange = S.getRange(nullptr, {}); NullRange.isValid())
203*0fca6ea1SDimitry Andric       return NullRange;
204*0fca6ea1SDimitry Andric     return S.EvalLocation;
205*0fca6ea1SDimitry Andric   }
2065f757f3fSDimitry Andric   return S.getRange(Caller->Func, RetPC - sizeof(uintptr_t));
207a7dea167SDimitry Andric }
208a7dea167SDimitry Andric 
getCallee() const209a7dea167SDimitry Andric const FunctionDecl *InterpFrame::getCallee() const {
210*0fca6ea1SDimitry Andric   if (!Func)
211*0fca6ea1SDimitry Andric     return nullptr;
212a7dea167SDimitry Andric   return Func->getDecl();
213a7dea167SDimitry Andric }
214a7dea167SDimitry Andric 
getLocalPointer(unsigned Offset) const215bdd1243dSDimitry Andric Pointer InterpFrame::getLocalPointer(unsigned Offset) const {
216a7dea167SDimitry Andric   assert(Offset < Func->getFrameSize() && "Invalid local offset.");
217*0fca6ea1SDimitry Andric   return Pointer(localBlock(Offset));
218a7dea167SDimitry Andric }
219a7dea167SDimitry Andric 
getParamPointer(unsigned Off)220a7dea167SDimitry Andric Pointer InterpFrame::getParamPointer(unsigned Off) {
221a7dea167SDimitry Andric   // Return the block if it was created previously.
222*0fca6ea1SDimitry Andric   if (auto Pt = Params.find(Off); Pt != Params.end())
223a7dea167SDimitry Andric     return Pointer(reinterpret_cast<Block *>(Pt->second.get()));
224a7dea167SDimitry Andric 
225a7dea167SDimitry Andric   // Allocate memory to store the parameter and the block metadata.
226a7dea167SDimitry Andric   const auto &Desc = Func->getParamDescriptor(Off);
227a7dea167SDimitry Andric   size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize();
228a7dea167SDimitry Andric   auto Memory = std::make_unique<char[]>(BlockSize);
229*0fca6ea1SDimitry Andric   auto *B = new (Memory.get()) Block(S.Ctx.getEvalID(), Desc.second);
230*0fca6ea1SDimitry Andric   B->invokeCtor();
231a7dea167SDimitry Andric 
232a7dea167SDimitry Andric   // Copy the initial value.
233a7dea167SDimitry Andric   TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off)));
234a7dea167SDimitry Andric 
235a7dea167SDimitry Andric   // Record the param.
236a7dea167SDimitry Andric   Params.insert({Off, std::move(Memory)});
237a7dea167SDimitry Andric   return Pointer(B);
238a7dea167SDimitry Andric }
239a7dea167SDimitry Andric 
getSource(CodePtr PC) const240a7dea167SDimitry Andric SourceInfo InterpFrame::getSource(CodePtr PC) const {
24106c3fb27SDimitry Andric   // Implicitly created functions don't have any code we could point at,
24206c3fb27SDimitry Andric   // so return the call site.
2435f757f3fSDimitry Andric   if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
24406c3fb27SDimitry Andric     return Caller->getSource(RetPC);
24506c3fb27SDimitry Andric 
246a7dea167SDimitry Andric   return S.getSource(Func, PC);
247a7dea167SDimitry Andric }
248a7dea167SDimitry Andric 
getExpr(CodePtr PC) const249a7dea167SDimitry Andric const Expr *InterpFrame::getExpr(CodePtr PC) const {
250*0fca6ea1SDimitry Andric   if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
251*0fca6ea1SDimitry Andric     return Caller->getExpr(RetPC);
252*0fca6ea1SDimitry Andric 
253a7dea167SDimitry Andric   return S.getExpr(Func, PC);
254a7dea167SDimitry Andric }
255a7dea167SDimitry Andric 
getLocation(CodePtr PC) const256a7dea167SDimitry Andric SourceLocation InterpFrame::getLocation(CodePtr PC) const {
257*0fca6ea1SDimitry Andric   if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
258*0fca6ea1SDimitry Andric     return Caller->getLocation(RetPC);
259*0fca6ea1SDimitry Andric 
260a7dea167SDimitry Andric   return S.getLocation(Func, PC);
261a7dea167SDimitry Andric }
262a7dea167SDimitry Andric 
getRange(CodePtr PC) const2635f757f3fSDimitry Andric SourceRange InterpFrame::getRange(CodePtr PC) const {
2645f757f3fSDimitry Andric   if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
2655f757f3fSDimitry Andric     return Caller->getRange(RetPC);
2665f757f3fSDimitry Andric 
2675f757f3fSDimitry Andric   return S.getRange(Func, PC);
2685f757f3fSDimitry Andric }
269