1 //===--- InterpFrame.cpp - Call Frame implementation for the VM -*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "InterpFrame.h"
13 #include "InterpStack.h"
14 #include "InterpState.h"
18 #include "clang/AST/ASTContext.h"
19 #include "clang/AST/DeclCXX.h"
21 using namespace clang
;
22 using namespace clang::interp
;
24 InterpFrame::InterpFrame(InterpState
&S
, const Function
*Func
,
25 InterpFrame
*Caller
, CodePtr RetPC
)
26 : Caller(Caller
), S(S
), Depth(Caller
? Caller
->Depth
+ 1 : 0), Func(Func
),
27 RetPC(RetPC
), ArgSize(Func
? Func
->getArgSize() : 0),
28 Args(static_cast<char *>(S
.Stk
.top())), FrameOffset(S
.Stk
.size()) {
32 unsigned FrameSize
= Func
->getFrameSize();
36 Locals
= std::make_unique
<char[]>(FrameSize
);
37 for (auto &Scope
: Func
->scopes()) {
38 for (auto &Local
: Scope
.locals()) {
39 Block
*B
= new (localBlock(Local
.Offset
)) Block(Local
.Desc
);
41 InlineDescriptor
*ID
= localInlineDesc(Local
.Offset
);
42 ID
->Desc
= Local
.Desc
;
44 ID
->Offset
= sizeof(InlineDescriptor
);
46 ID
->IsFieldMutable
= false;
48 ID
->IsInitialized
= false;
53 InterpFrame::InterpFrame(InterpState
&S
, const Function
*Func
, CodePtr RetPC
)
54 : InterpFrame(S
, Func
, S
.Current
, RetPC
) {
55 // As per our calling convention, the this pointer is
56 // part of the ArgSize.
57 // If the function has RVO, the RVO pointer is first.
58 // If the fuction has a This pointer, that one is next.
59 // Then follow the actual arguments (but those are handled
60 // in getParamPointer()).
62 RVOPtr
= stackRef
<Pointer
>(0);
64 if (Func
->hasThisPointer()) {
66 This
= stackRef
<Pointer
>(sizeof(Pointer
));
68 This
= stackRef
<Pointer
>(0);
72 InterpFrame::~InterpFrame() {
73 for (auto &Param
: Params
)
74 S
.deallocate(reinterpret_cast<Block
*>(Param
.second
.get()));
76 // When destroying the InterpFrame, call the Dtor for all block
77 // that haven't been destroyed via a destroy() op yet.
78 // This happens when the execution is interruped midway-through.
80 for (auto &Scope
: Func
->scopes()) {
81 for (auto &Local
: Scope
.locals()) {
82 Block
*B
= localBlock(Local
.Offset
);
83 if (B
->isInitialized())
90 void InterpFrame::destroy(unsigned Idx
) {
91 for (auto &Local
: Func
->getScope(Idx
).locals()) {
92 S
.deallocate(localBlock(Local
.Offset
));
96 void InterpFrame::popArgs() {
97 for (PrimType Ty
: Func
->args_reverse())
98 TYPE_SWITCH(Ty
, S
.Stk
.discard
<T
>());
101 template <typename T
>
102 static void print(llvm::raw_ostream
&OS
, const T
&V
, ASTContext
&, QualType
) {
107 void print(llvm::raw_ostream
&OS
, const Pointer
&P
, ASTContext
&Ctx
,
114 auto printDesc
= [&OS
, &Ctx
](const Descriptor
*Desc
) {
115 if (const auto *D
= Desc
->asDecl()) {
116 // Subfields or named values.
117 if (const auto *VD
= dyn_cast
<ValueDecl
>(D
)) {
122 if (isa
<RecordDecl
>(D
))
125 // Temporary expression.
126 if (const auto *E
= Desc
->asExpr()) {
127 E
->printPretty(OS
, nullptr, Ctx
.getPrintingPolicy());
130 llvm_unreachable("Invalid descriptor type");
133 if (!Ty
->isReferenceType())
135 llvm::SmallVector
<Pointer
, 2> Levels
;
136 for (Pointer F
= P
; !F
.isRoot(); ) {
138 F
= F
.isArrayElement() ? F
.getArray().expand() : F
.getBase();
141 // Drop the first pointer since we print it unconditionally anyway.
143 Levels
.erase(Levels
.begin());
145 printDesc(P
.getDeclDesc());
146 for (const auto &It
: Levels
) {
148 OS
<< "[" << It
.expand().getIndex() << "]";
151 if (auto Index
= It
.getIndex()) {
152 OS
<< " + " << Index
;
156 printDesc(It
.getFieldDesc());
160 void InterpFrame::describe(llvm::raw_ostream
&OS
) const {
161 const FunctionDecl
*F
= getCallee();
162 if (const auto *M
= dyn_cast
<CXXMethodDecl
>(F
);
163 M
&& M
->isInstance() && !isa
<CXXConstructorDecl
>(F
)) {
164 print(OS
, This
, S
.getCtx(), S
.getCtx().getRecordType(M
->getParent()));
170 Off
+= Func
->hasRVO() ? primSize(PT_Ptr
) : 0;
171 Off
+= Func
->hasThisPointer() ? primSize(PT_Ptr
) : 0;
173 for (unsigned I
= 0, N
= F
->getNumParams(); I
< N
; ++I
) {
174 QualType Ty
= F
->getParamDecl(I
)->getType();
176 PrimType PrimTy
= S
.Ctx
.classify(Ty
).value_or(PT_Ptr
);
178 TYPE_SWITCH(PrimTy
, print(OS
, stackRef
<T
>(Off
), S
.getCtx(), Ty
));
179 Off
+= align(primSize(PrimTy
));
186 Frame
*InterpFrame::getCaller() const {
189 return S
.getSplitFrame();
192 SourceRange
InterpFrame::getCallRange() const {
194 return S
.getRange(nullptr, {});
195 return S
.getRange(Caller
->Func
, RetPC
- sizeof(uintptr_t));
198 const FunctionDecl
*InterpFrame::getCallee() const {
199 return Func
->getDecl();
202 Pointer
InterpFrame::getLocalPointer(unsigned Offset
) const {
203 assert(Offset
< Func
->getFrameSize() && "Invalid local offset.");
204 return Pointer(localBlock(Offset
), sizeof(InlineDescriptor
));
207 Pointer
InterpFrame::getParamPointer(unsigned Off
) {
208 // Return the block if it was created previously.
209 auto Pt
= Params
.find(Off
);
210 if (Pt
!= Params
.end()) {
211 return Pointer(reinterpret_cast<Block
*>(Pt
->second
.get()));
214 // Allocate memory to store the parameter and the block metadata.
215 const auto &Desc
= Func
->getParamDescriptor(Off
);
216 size_t BlockSize
= sizeof(Block
) + Desc
.second
->getAllocSize();
217 auto Memory
= std::make_unique
<char[]>(BlockSize
);
218 auto *B
= new (Memory
.get()) Block(Desc
.second
);
220 // Copy the initial value.
221 TYPE_SWITCH(Desc
.first
, new (B
->data()) T(stackRef
<T
>(Off
)));
224 Params
.insert({Off
, std::move(Memory
)});
228 SourceInfo
InterpFrame::getSource(CodePtr PC
) const {
229 // Implicitly created functions don't have any code we could point at,
230 // so return the call site.
231 if (Func
&& Func
->getDecl()->isImplicit() && Caller
)
232 return Caller
->getSource(RetPC
);
234 return S
.getSource(Func
, PC
);
237 const Expr
*InterpFrame::getExpr(CodePtr PC
) const {
238 return S
.getExpr(Func
, PC
);
241 SourceLocation
InterpFrame::getLocation(CodePtr PC
) const {
242 return S
.getLocation(Func
, PC
);
245 SourceRange
InterpFrame::getRange(CodePtr PC
) const {
246 if (Func
&& Func
->getDecl()->isImplicit() && Caller
)
247 return Caller
->getRange(RetPC
);
249 return S
.getRange(Func
, PC
);