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" 15bdd1243dSDimitry Andric #include "Pointer.h" 16a7dea167SDimitry Andric #include "PrimType.h" 17a7dea167SDimitry Andric #include "Program.h" 18bdd1243dSDimitry Andric #include "clang/AST/ASTContext.h" 19a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h" 20a7dea167SDimitry Andric 21a7dea167SDimitry Andric using namespace clang; 22a7dea167SDimitry Andric using namespace clang::interp; 23a7dea167SDimitry Andric 24bdd1243dSDimitry Andric InterpFrame::InterpFrame(InterpState &S, const Function *Func, 25bdd1243dSDimitry Andric InterpFrame *Caller, CodePtr RetPC) 2606c3fb27SDimitry Andric : Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func), 2706c3fb27SDimitry Andric RetPC(RetPC), ArgSize(Func ? Func->getArgSize() : 0), 28a7dea167SDimitry Andric Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) { 29bdd1243dSDimitry Andric if (!Func) 30bdd1243dSDimitry Andric return; 31bdd1243dSDimitry Andric 32bdd1243dSDimitry Andric unsigned FrameSize = Func->getFrameSize(); 33bdd1243dSDimitry Andric if (FrameSize == 0) 34bdd1243dSDimitry Andric return; 35bdd1243dSDimitry Andric 36a7dea167SDimitry Andric Locals = std::make_unique<char[]>(FrameSize); 37a7dea167SDimitry Andric for (auto &Scope : Func->scopes()) { 38a7dea167SDimitry Andric for (auto &Local : Scope.locals()) { 39a7dea167SDimitry Andric Block *B = new (localBlock(Local.Offset)) Block(Local.Desc); 40a7dea167SDimitry Andric B->invokeCtor(); 41bdd1243dSDimitry Andric InlineDescriptor *ID = localInlineDesc(Local.Offset); 42bdd1243dSDimitry Andric ID->Desc = Local.Desc; 43bdd1243dSDimitry Andric ID->IsActive = true; 44bdd1243dSDimitry Andric ID->Offset = sizeof(InlineDescriptor); 45bdd1243dSDimitry Andric ID->IsBase = false; 46bdd1243dSDimitry Andric ID->IsFieldMutable = false; 47bdd1243dSDimitry Andric ID->IsConst = false; 48bdd1243dSDimitry Andric ID->IsInitialized = false; 49a7dea167SDimitry Andric } 50a7dea167SDimitry Andric } 51a7dea167SDimitry Andric } 52a7dea167SDimitry Andric 53bdd1243dSDimitry Andric InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC) 54bdd1243dSDimitry Andric : InterpFrame(S, Func, S.Current, RetPC) { 55bdd1243dSDimitry Andric // As per our calling convention, the this pointer is 56bdd1243dSDimitry Andric // part of the ArgSize. 57bdd1243dSDimitry Andric // If the function has RVO, the RVO pointer is first. 58bdd1243dSDimitry Andric // If the fuction has a This pointer, that one is next. 59bdd1243dSDimitry Andric // Then follow the actual arguments (but those are handled 60bdd1243dSDimitry Andric // in getParamPointer()). 61bdd1243dSDimitry Andric if (Func->hasRVO()) 62bdd1243dSDimitry Andric RVOPtr = stackRef<Pointer>(0); 63bdd1243dSDimitry Andric 64bdd1243dSDimitry Andric if (Func->hasThisPointer()) { 65bdd1243dSDimitry Andric if (Func->hasRVO()) 66bdd1243dSDimitry Andric This = stackRef<Pointer>(sizeof(Pointer)); 67bdd1243dSDimitry Andric else 68bdd1243dSDimitry Andric This = stackRef<Pointer>(0); 69bdd1243dSDimitry Andric } 70bdd1243dSDimitry Andric } 71bdd1243dSDimitry Andric 72a7dea167SDimitry Andric InterpFrame::~InterpFrame() { 73a7dea167SDimitry Andric for (auto &Param : Params) 74a7dea167SDimitry Andric S.deallocate(reinterpret_cast<Block *>(Param.second.get())); 75*5f757f3fSDimitry Andric 76*5f757f3fSDimitry Andric // When destroying the InterpFrame, call the Dtor for all block 77*5f757f3fSDimitry Andric // that haven't been destroyed via a destroy() op yet. 78*5f757f3fSDimitry Andric // This happens when the execution is interruped midway-through. 79*5f757f3fSDimitry Andric if (Func) { 80*5f757f3fSDimitry Andric for (auto &Scope : Func->scopes()) { 81*5f757f3fSDimitry Andric for (auto &Local : Scope.locals()) { 82*5f757f3fSDimitry Andric Block *B = localBlock(Local.Offset); 83*5f757f3fSDimitry Andric if (B->isInitialized()) 84*5f757f3fSDimitry Andric B->invokeDtor(); 85*5f757f3fSDimitry Andric } 86*5f757f3fSDimitry Andric } 87*5f757f3fSDimitry Andric } 88a7dea167SDimitry Andric } 89a7dea167SDimitry Andric 90a7dea167SDimitry Andric void InterpFrame::destroy(unsigned Idx) { 91a7dea167SDimitry Andric for (auto &Local : Func->getScope(Idx).locals()) { 9206c3fb27SDimitry Andric S.deallocate(localBlock(Local.Offset)); 93a7dea167SDimitry Andric } 94a7dea167SDimitry Andric } 95a7dea167SDimitry Andric 96a7dea167SDimitry Andric void InterpFrame::popArgs() { 97a7dea167SDimitry Andric for (PrimType Ty : Func->args_reverse()) 98a7dea167SDimitry Andric TYPE_SWITCH(Ty, S.Stk.discard<T>()); 99a7dea167SDimitry Andric } 100a7dea167SDimitry Andric 101a7dea167SDimitry Andric template <typename T> 102a7dea167SDimitry Andric static void print(llvm::raw_ostream &OS, const T &V, ASTContext &, QualType) { 103a7dea167SDimitry Andric OS << V; 104a7dea167SDimitry Andric } 105a7dea167SDimitry Andric 106a7dea167SDimitry Andric template <> 107a7dea167SDimitry Andric void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx, 108a7dea167SDimitry Andric QualType Ty) { 109a7dea167SDimitry Andric if (P.isZero()) { 110a7dea167SDimitry Andric OS << "nullptr"; 111a7dea167SDimitry Andric return; 112a7dea167SDimitry Andric } 113a7dea167SDimitry Andric 11406c3fb27SDimitry Andric auto printDesc = [&OS, &Ctx](const Descriptor *Desc) { 11506c3fb27SDimitry Andric if (const auto *D = Desc->asDecl()) { 116a7dea167SDimitry Andric // Subfields or named values. 11706c3fb27SDimitry Andric if (const auto *VD = dyn_cast<ValueDecl>(D)) { 118a7dea167SDimitry Andric OS << *VD; 119a7dea167SDimitry Andric return; 120a7dea167SDimitry Andric } 121a7dea167SDimitry Andric // Base classes. 12206c3fb27SDimitry Andric if (isa<RecordDecl>(D)) 123a7dea167SDimitry Andric return; 124a7dea167SDimitry Andric } 125a7dea167SDimitry Andric // Temporary expression. 12606c3fb27SDimitry Andric if (const auto *E = Desc->asExpr()) { 127a7dea167SDimitry Andric E->printPretty(OS, nullptr, Ctx.getPrintingPolicy()); 128a7dea167SDimitry Andric return; 129a7dea167SDimitry Andric } 130a7dea167SDimitry Andric llvm_unreachable("Invalid descriptor type"); 131a7dea167SDimitry Andric }; 132a7dea167SDimitry Andric 133a7dea167SDimitry Andric if (!Ty->isReferenceType()) 134a7dea167SDimitry Andric OS << "&"; 135a7dea167SDimitry Andric llvm::SmallVector<Pointer, 2> Levels; 136a7dea167SDimitry Andric for (Pointer F = P; !F.isRoot(); ) { 137a7dea167SDimitry Andric Levels.push_back(F); 138a7dea167SDimitry Andric F = F.isArrayElement() ? F.getArray().expand() : F.getBase(); 139a7dea167SDimitry Andric } 140a7dea167SDimitry Andric 14106c3fb27SDimitry Andric // Drop the first pointer since we print it unconditionally anyway. 14206c3fb27SDimitry Andric if (!Levels.empty()) 14306c3fb27SDimitry Andric Levels.erase(Levels.begin()); 14406c3fb27SDimitry Andric 145a7dea167SDimitry Andric printDesc(P.getDeclDesc()); 146bdd1243dSDimitry Andric for (const auto &It : Levels) { 147bdd1243dSDimitry Andric if (It.inArray()) { 148bdd1243dSDimitry Andric OS << "[" << It.expand().getIndex() << "]"; 149a7dea167SDimitry Andric continue; 150a7dea167SDimitry Andric } 151bdd1243dSDimitry Andric if (auto Index = It.getIndex()) { 152a7dea167SDimitry Andric OS << " + " << Index; 153a7dea167SDimitry Andric continue; 154a7dea167SDimitry Andric } 155a7dea167SDimitry Andric OS << "."; 156bdd1243dSDimitry Andric printDesc(It.getFieldDesc()); 157a7dea167SDimitry Andric } 158a7dea167SDimitry Andric } 159a7dea167SDimitry Andric 16006c3fb27SDimitry Andric void InterpFrame::describe(llvm::raw_ostream &OS) const { 161a7dea167SDimitry Andric const FunctionDecl *F = getCallee(); 16206c3fb27SDimitry Andric if (const auto *M = dyn_cast<CXXMethodDecl>(F); 16306c3fb27SDimitry Andric M && M->isInstance() && !isa<CXXConstructorDecl>(F)) { 164a7dea167SDimitry Andric print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent())); 165a7dea167SDimitry Andric OS << "->"; 166a7dea167SDimitry Andric } 167a7dea167SDimitry Andric OS << *F << "("; 168bdd1243dSDimitry Andric unsigned Off = 0; 169bdd1243dSDimitry Andric 170bdd1243dSDimitry Andric Off += Func->hasRVO() ? primSize(PT_Ptr) : 0; 171bdd1243dSDimitry Andric Off += Func->hasThisPointer() ? primSize(PT_Ptr) : 0; 172bdd1243dSDimitry Andric 173a7dea167SDimitry Andric for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) { 174a7dea167SDimitry Andric QualType Ty = F->getParamDecl(I)->getType(); 175a7dea167SDimitry Andric 176bdd1243dSDimitry Andric PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr); 177a7dea167SDimitry Andric 178a7dea167SDimitry Andric TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty)); 179a7dea167SDimitry Andric Off += align(primSize(PrimTy)); 180a7dea167SDimitry Andric if (I + 1 != N) 181a7dea167SDimitry Andric OS << ", "; 182a7dea167SDimitry Andric } 183a7dea167SDimitry Andric OS << ")"; 184a7dea167SDimitry Andric } 185a7dea167SDimitry Andric 186a7dea167SDimitry Andric Frame *InterpFrame::getCaller() const { 187a7dea167SDimitry Andric if (Caller->Caller) 188a7dea167SDimitry Andric return Caller; 189a7dea167SDimitry Andric return S.getSplitFrame(); 190a7dea167SDimitry Andric } 191a7dea167SDimitry Andric 192*5f757f3fSDimitry Andric SourceRange InterpFrame::getCallRange() const { 193a7dea167SDimitry Andric if (!Caller->Func) 194*5f757f3fSDimitry Andric return S.getRange(nullptr, {}); 195*5f757f3fSDimitry Andric return S.getRange(Caller->Func, RetPC - sizeof(uintptr_t)); 196a7dea167SDimitry Andric } 197a7dea167SDimitry Andric 198a7dea167SDimitry Andric const FunctionDecl *InterpFrame::getCallee() const { 199a7dea167SDimitry Andric return Func->getDecl(); 200a7dea167SDimitry Andric } 201a7dea167SDimitry Andric 202bdd1243dSDimitry Andric Pointer InterpFrame::getLocalPointer(unsigned Offset) const { 203a7dea167SDimitry Andric assert(Offset < Func->getFrameSize() && "Invalid local offset."); 20406c3fb27SDimitry Andric return Pointer(localBlock(Offset), sizeof(InlineDescriptor)); 205a7dea167SDimitry Andric } 206a7dea167SDimitry Andric 207a7dea167SDimitry Andric Pointer InterpFrame::getParamPointer(unsigned Off) { 208a7dea167SDimitry Andric // Return the block if it was created previously. 209a7dea167SDimitry Andric auto Pt = Params.find(Off); 210a7dea167SDimitry Andric if (Pt != Params.end()) { 211a7dea167SDimitry Andric return Pointer(reinterpret_cast<Block *>(Pt->second.get())); 212a7dea167SDimitry Andric } 213a7dea167SDimitry Andric 214a7dea167SDimitry Andric // Allocate memory to store the parameter and the block metadata. 215a7dea167SDimitry Andric const auto &Desc = Func->getParamDescriptor(Off); 216a7dea167SDimitry Andric size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize(); 217a7dea167SDimitry Andric auto Memory = std::make_unique<char[]>(BlockSize); 218a7dea167SDimitry Andric auto *B = new (Memory.get()) Block(Desc.second); 219a7dea167SDimitry Andric 220a7dea167SDimitry Andric // Copy the initial value. 221a7dea167SDimitry Andric TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off))); 222a7dea167SDimitry Andric 223a7dea167SDimitry Andric // Record the param. 224a7dea167SDimitry Andric Params.insert({Off, std::move(Memory)}); 225a7dea167SDimitry Andric return Pointer(B); 226a7dea167SDimitry Andric } 227a7dea167SDimitry Andric 228a7dea167SDimitry Andric SourceInfo InterpFrame::getSource(CodePtr PC) const { 22906c3fb27SDimitry Andric // Implicitly created functions don't have any code we could point at, 23006c3fb27SDimitry Andric // so return the call site. 231*5f757f3fSDimitry Andric if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller) 23206c3fb27SDimitry Andric return Caller->getSource(RetPC); 23306c3fb27SDimitry Andric 234a7dea167SDimitry Andric return S.getSource(Func, PC); 235a7dea167SDimitry Andric } 236a7dea167SDimitry Andric 237a7dea167SDimitry Andric const Expr *InterpFrame::getExpr(CodePtr PC) const { 238a7dea167SDimitry Andric return S.getExpr(Func, PC); 239a7dea167SDimitry Andric } 240a7dea167SDimitry Andric 241a7dea167SDimitry Andric SourceLocation InterpFrame::getLocation(CodePtr PC) const { 242a7dea167SDimitry Andric return S.getLocation(Func, PC); 243a7dea167SDimitry Andric } 244a7dea167SDimitry Andric 245*5f757f3fSDimitry Andric SourceRange InterpFrame::getRange(CodePtr PC) const { 246*5f757f3fSDimitry Andric if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller) 247*5f757f3fSDimitry Andric return Caller->getRange(RetPC); 248*5f757f3fSDimitry Andric 249*5f757f3fSDimitry Andric return S.getRange(Func, PC); 250*5f757f3fSDimitry Andric } 251