xref: /openbsd-src/gnu/llvm/clang/lib/AST/Interp/InterpFrame.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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