1a07aba5dSTimm Baeder //===--- InterpFrame.cpp - Call Frame implementation for the VM -*- C++ -*-===// 2a07aba5dSTimm Baeder // 3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a07aba5dSTimm Baeder // 7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 8a07aba5dSTimm Baeder 9a07aba5dSTimm Baeder #include "InterpFrame.h" 10a07aba5dSTimm Baeder #include "Boolean.h" 11a07aba5dSTimm Baeder #include "Floating.h" 12a07aba5dSTimm Baeder #include "Function.h" 13a07aba5dSTimm Baeder #include "InterpStack.h" 14a07aba5dSTimm Baeder #include "InterpState.h" 15a07aba5dSTimm Baeder #include "MemberPointer.h" 16a07aba5dSTimm Baeder #include "Pointer.h" 17a07aba5dSTimm Baeder #include "PrimType.h" 18a07aba5dSTimm Baeder #include "Program.h" 19a07aba5dSTimm Baeder #include "clang/AST/ASTContext.h" 20a07aba5dSTimm Baeder #include "clang/AST/DeclCXX.h" 21a07aba5dSTimm Baeder #include "clang/AST/ExprCXX.h" 22a07aba5dSTimm Baeder 23a07aba5dSTimm Baeder using namespace clang; 24a07aba5dSTimm Baeder using namespace clang::interp; 25a07aba5dSTimm Baeder 26a07aba5dSTimm Baeder InterpFrame::InterpFrame(InterpState &S, const Function *Func, 27a07aba5dSTimm Baeder InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize) 28a07aba5dSTimm Baeder : Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func), 29a07aba5dSTimm Baeder RetPC(RetPC), ArgSize(ArgSize), Args(static_cast<char *>(S.Stk.top())), 30a07aba5dSTimm Baeder FrameOffset(S.Stk.size()) { 31a07aba5dSTimm Baeder if (!Func) 32a07aba5dSTimm Baeder return; 33a07aba5dSTimm Baeder 34a07aba5dSTimm Baeder unsigned FrameSize = Func->getFrameSize(); 35a07aba5dSTimm Baeder if (FrameSize == 0) 36a07aba5dSTimm Baeder return; 37a07aba5dSTimm Baeder 38a07aba5dSTimm Baeder Locals = std::make_unique<char[]>(FrameSize); 39a07aba5dSTimm Baeder for (auto &Scope : Func->scopes()) { 40a07aba5dSTimm Baeder for (auto &Local : Scope.locals()) { 41a07aba5dSTimm Baeder new (localBlock(Local.Offset)) Block(S.Ctx.getEvalID(), Local.Desc); 42a07aba5dSTimm Baeder // Note that we are NOT calling invokeCtor() here, since that is done 43a07aba5dSTimm Baeder // via the InitScope op. 44a07aba5dSTimm Baeder new (localInlineDesc(Local.Offset)) InlineDescriptor(Local.Desc); 45a07aba5dSTimm Baeder } 46a07aba5dSTimm Baeder } 47a07aba5dSTimm Baeder } 48a07aba5dSTimm Baeder 49a07aba5dSTimm Baeder InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC, 50a07aba5dSTimm Baeder unsigned VarArgSize) 51a07aba5dSTimm Baeder : InterpFrame(S, Func, S.Current, RetPC, Func->getArgSize() + VarArgSize) { 52a07aba5dSTimm Baeder // As per our calling convention, the this pointer is 53a07aba5dSTimm Baeder // part of the ArgSize. 54a07aba5dSTimm Baeder // If the function has RVO, the RVO pointer is first. 55a07aba5dSTimm Baeder // If the fuction has a This pointer, that one is next. 56a07aba5dSTimm Baeder // Then follow the actual arguments (but those are handled 57a07aba5dSTimm Baeder // in getParamPointer()). 58a07aba5dSTimm Baeder if (Func->hasRVO()) 59a07aba5dSTimm Baeder RVOPtr = stackRef<Pointer>(0); 60a07aba5dSTimm Baeder 61a07aba5dSTimm Baeder if (Func->hasThisPointer()) { 62a07aba5dSTimm Baeder if (Func->hasRVO()) 63a07aba5dSTimm Baeder This = stackRef<Pointer>(sizeof(Pointer)); 64a07aba5dSTimm Baeder else 65a07aba5dSTimm Baeder This = stackRef<Pointer>(0); 66a07aba5dSTimm Baeder } 67a07aba5dSTimm Baeder } 68a07aba5dSTimm Baeder 69a07aba5dSTimm Baeder InterpFrame::~InterpFrame() { 70a07aba5dSTimm Baeder for (auto &Param : Params) 71a07aba5dSTimm Baeder S.deallocate(reinterpret_cast<Block *>(Param.second.get())); 72a07aba5dSTimm Baeder 73a07aba5dSTimm Baeder // When destroying the InterpFrame, call the Dtor for all block 74a07aba5dSTimm Baeder // that haven't been destroyed via a destroy() op yet. 75a07aba5dSTimm Baeder // This happens when the execution is interruped midway-through. 76a07aba5dSTimm Baeder if (Func) { 77a07aba5dSTimm Baeder for (auto &Scope : Func->scopes()) { 78a07aba5dSTimm Baeder for (auto &Local : Scope.locals()) { 79a07aba5dSTimm Baeder S.deallocate(localBlock(Local.Offset)); 80a07aba5dSTimm Baeder } 81a07aba5dSTimm Baeder } 82a07aba5dSTimm Baeder } 83a07aba5dSTimm Baeder } 84a07aba5dSTimm Baeder 85a07aba5dSTimm Baeder void InterpFrame::initScope(unsigned Idx) { 86a07aba5dSTimm Baeder if (!Func) 87a07aba5dSTimm Baeder return; 88a07aba5dSTimm Baeder for (auto &Local : Func->getScope(Idx).locals()) { 89a07aba5dSTimm Baeder localBlock(Local.Offset)->invokeCtor(); 90a07aba5dSTimm Baeder } 91a07aba5dSTimm Baeder } 92a07aba5dSTimm Baeder 93a07aba5dSTimm Baeder void InterpFrame::destroy(unsigned Idx) { 94a07aba5dSTimm Baeder for (auto &Local : Func->getScope(Idx).locals()) { 95a07aba5dSTimm Baeder S.deallocate(localBlock(Local.Offset)); 96a07aba5dSTimm Baeder } 97a07aba5dSTimm Baeder } 98a07aba5dSTimm Baeder 99a07aba5dSTimm Baeder template <typename T> 100a07aba5dSTimm Baeder static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, 101a07aba5dSTimm Baeder QualType Ty) { 102a07aba5dSTimm Baeder V.toAPValue(ASTCtx).printPretty(OS, ASTCtx, Ty); 103a07aba5dSTimm Baeder } 104a07aba5dSTimm Baeder 105898fd396STimm Baeder static bool shouldSkipInBacktrace(const Function *F) { 106898fd396STimm Baeder if (F->isBuiltin()) 107898fd396STimm Baeder return true; 108898fd396STimm Baeder if (F->isLambdaStaticInvoker()) 109898fd396STimm Baeder return true; 110898fd396STimm Baeder 111898fd396STimm Baeder const FunctionDecl *FD = F->getDecl(); 112898fd396STimm Baeder if (FD->getDeclName().getCXXOverloadedOperator() == OO_New || 113898fd396STimm Baeder FD->getDeclName().getCXXOverloadedOperator() == OO_Array_New) 114898fd396STimm Baeder return true; 115898fd396STimm Baeder return false; 116898fd396STimm Baeder } 117898fd396STimm Baeder 118a07aba5dSTimm Baeder void InterpFrame::describe(llvm::raw_ostream &OS) const { 119a07aba5dSTimm Baeder // We create frames for builtin functions as well, but we can't reliably 120a07aba5dSTimm Baeder // diagnose them. The 'in call to' diagnostics for them add no value to the 121a07aba5dSTimm Baeder // user _and_ it doesn't generally work since the argument types don't always 122a07aba5dSTimm Baeder // match the function prototype. Just ignore them. 123a07aba5dSTimm Baeder // Similarly, for lambda static invokers, we would just print __invoke(). 124898fd396STimm Baeder if (const auto *F = getFunction(); F && shouldSkipInBacktrace(F)) 125a07aba5dSTimm Baeder return; 126a07aba5dSTimm Baeder 127a07aba5dSTimm Baeder const Expr *CallExpr = Caller->getExpr(getRetPC()); 128a07aba5dSTimm Baeder const FunctionDecl *F = getCallee(); 129a07aba5dSTimm Baeder bool IsMemberCall = isa<CXXMethodDecl>(F) && !isa<CXXConstructorDecl>(F) && 130a07aba5dSTimm Baeder cast<CXXMethodDecl>(F)->isImplicitObjectMemberFunction(); 131a07aba5dSTimm Baeder if (Func->hasThisPointer() && IsMemberCall) { 132a07aba5dSTimm Baeder if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) { 133a07aba5dSTimm Baeder const Expr *Object = MCE->getImplicitObjectArgument(); 134a07aba5dSTimm Baeder Object->printPretty(OS, /*Helper=*/nullptr, 135d9e72860Syronglin S.getASTContext().getPrintingPolicy(), 136a07aba5dSTimm Baeder /*Indentation=*/0); 137a07aba5dSTimm Baeder if (Object->getType()->isPointerType()) 138a07aba5dSTimm Baeder OS << "->"; 139a07aba5dSTimm Baeder else 140a07aba5dSTimm Baeder OS << "."; 141a07aba5dSTimm Baeder } else if (const auto *OCE = 142a07aba5dSTimm Baeder dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) { 143a07aba5dSTimm Baeder OCE->getArg(0)->printPretty(OS, /*Helper=*/nullptr, 144d9e72860Syronglin S.getASTContext().getPrintingPolicy(), 145a07aba5dSTimm Baeder /*Indentation=*/0); 146a07aba5dSTimm Baeder OS << "."; 147a07aba5dSTimm Baeder } else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) { 148d9e72860Syronglin print(OS, This, S.getASTContext(), 149d9e72860Syronglin S.getASTContext().getLValueReferenceType( 150d9e72860Syronglin S.getASTContext().getRecordType(M->getParent()))); 151a07aba5dSTimm Baeder OS << "."; 152a07aba5dSTimm Baeder } 153a07aba5dSTimm Baeder } 154a07aba5dSTimm Baeder 155d9e72860Syronglin F->getNameForDiagnostic(OS, S.getASTContext().getPrintingPolicy(), 156a07aba5dSTimm Baeder /*Qualified=*/false); 157a07aba5dSTimm Baeder OS << '('; 158a07aba5dSTimm Baeder unsigned Off = 0; 159a07aba5dSTimm Baeder 160a07aba5dSTimm Baeder Off += Func->hasRVO() ? primSize(PT_Ptr) : 0; 161a07aba5dSTimm Baeder Off += Func->hasThisPointer() ? primSize(PT_Ptr) : 0; 162a07aba5dSTimm Baeder 163a07aba5dSTimm Baeder for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) { 164a07aba5dSTimm Baeder QualType Ty = F->getParamDecl(I)->getType(); 165a07aba5dSTimm Baeder 166a07aba5dSTimm Baeder PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr); 167a07aba5dSTimm Baeder 168d9e72860Syronglin TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getASTContext(), Ty)); 169a07aba5dSTimm Baeder Off += align(primSize(PrimTy)); 170a07aba5dSTimm Baeder if (I + 1 != N) 171a07aba5dSTimm Baeder OS << ", "; 172a07aba5dSTimm Baeder } 173a07aba5dSTimm Baeder OS << ")"; 174a07aba5dSTimm Baeder } 175a07aba5dSTimm Baeder 176a07aba5dSTimm Baeder Frame *InterpFrame::getCaller() const { 177a07aba5dSTimm Baeder if (Caller->Caller) 178a07aba5dSTimm Baeder return Caller; 179a07aba5dSTimm Baeder return S.getSplitFrame(); 180a07aba5dSTimm Baeder } 181a07aba5dSTimm Baeder 182a07aba5dSTimm Baeder SourceRange InterpFrame::getCallRange() const { 183a07aba5dSTimm Baeder if (!Caller->Func) { 184a07aba5dSTimm Baeder if (SourceRange NullRange = S.getRange(nullptr, {}); NullRange.isValid()) 185a07aba5dSTimm Baeder return NullRange; 186a07aba5dSTimm Baeder return S.EvalLocation; 187a07aba5dSTimm Baeder } 188a07aba5dSTimm Baeder return S.getRange(Caller->Func, RetPC - sizeof(uintptr_t)); 189a07aba5dSTimm Baeder } 190a07aba5dSTimm Baeder 191a07aba5dSTimm Baeder const FunctionDecl *InterpFrame::getCallee() const { 192a07aba5dSTimm Baeder if (!Func) 193a07aba5dSTimm Baeder return nullptr; 194a07aba5dSTimm Baeder return Func->getDecl(); 195a07aba5dSTimm Baeder } 196a07aba5dSTimm Baeder 197a07aba5dSTimm Baeder Pointer InterpFrame::getLocalPointer(unsigned Offset) const { 198a07aba5dSTimm Baeder assert(Offset < Func->getFrameSize() && "Invalid local offset."); 199a07aba5dSTimm Baeder return Pointer(localBlock(Offset)); 200a07aba5dSTimm Baeder } 201a07aba5dSTimm Baeder 202a07aba5dSTimm Baeder Pointer InterpFrame::getParamPointer(unsigned Off) { 203a07aba5dSTimm Baeder // Return the block if it was created previously. 204a07aba5dSTimm Baeder if (auto Pt = Params.find(Off); Pt != Params.end()) 205a07aba5dSTimm Baeder return Pointer(reinterpret_cast<Block *>(Pt->second.get())); 206a07aba5dSTimm Baeder 207a07aba5dSTimm Baeder // Allocate memory to store the parameter and the block metadata. 208a07aba5dSTimm Baeder const auto &Desc = Func->getParamDescriptor(Off); 209a07aba5dSTimm Baeder size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize(); 210a07aba5dSTimm Baeder auto Memory = std::make_unique<char[]>(BlockSize); 211a07aba5dSTimm Baeder auto *B = new (Memory.get()) Block(S.Ctx.getEvalID(), Desc.second); 212a07aba5dSTimm Baeder B->invokeCtor(); 213a07aba5dSTimm Baeder 214a07aba5dSTimm Baeder // Copy the initial value. 215a07aba5dSTimm Baeder TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off))); 216a07aba5dSTimm Baeder 217a07aba5dSTimm Baeder // Record the param. 218a07aba5dSTimm Baeder Params.insert({Off, std::move(Memory)}); 219a07aba5dSTimm Baeder return Pointer(B); 220a07aba5dSTimm Baeder } 221a07aba5dSTimm Baeder 222d03822d8STimm Baeder static bool funcHasUsableBody(const Function *F) { 223d03822d8STimm Baeder assert(F); 224d03822d8STimm Baeder 225d03822d8STimm Baeder if (F->isConstructor() || F->isDestructor()) 226d03822d8STimm Baeder return true; 227d03822d8STimm Baeder 228d03822d8STimm Baeder return !F->getDecl()->isImplicit(); 229d03822d8STimm Baeder } 230d03822d8STimm Baeder 231a07aba5dSTimm Baeder SourceInfo InterpFrame::getSource(CodePtr PC) const { 232a07aba5dSTimm Baeder // Implicitly created functions don't have any code we could point at, 233a07aba5dSTimm Baeder // so return the call site. 234d03822d8STimm Baeder if (Func && !funcHasUsableBody(Func) && Caller) 235a07aba5dSTimm Baeder return Caller->getSource(RetPC); 236a07aba5dSTimm Baeder 237*ceaf6e91STimm Baeder // Similarly, if the resulting source location is invalid anyway, 238*ceaf6e91STimm Baeder // point to the caller instead. 239*ceaf6e91STimm Baeder SourceInfo Result = S.getSource(Func, PC); 240*ceaf6e91STimm Baeder if (Result.getLoc().isInvalid() && Caller) 241*ceaf6e91STimm Baeder return Caller->getSource(RetPC); 242*ceaf6e91STimm Baeder return Result; 243a07aba5dSTimm Baeder } 244a07aba5dSTimm Baeder 245a07aba5dSTimm Baeder const Expr *InterpFrame::getExpr(CodePtr PC) const { 246d03822d8STimm Baeder if (Func && !funcHasUsableBody(Func) && Caller) 247d03822d8STimm Baeder return Caller->getExpr(PC); 248a07aba5dSTimm Baeder 249a07aba5dSTimm Baeder return S.getExpr(Func, PC); 250a07aba5dSTimm Baeder } 251a07aba5dSTimm Baeder 252a07aba5dSTimm Baeder SourceLocation InterpFrame::getLocation(CodePtr PC) const { 253d03822d8STimm Baeder if (Func && !funcHasUsableBody(Func) && Caller) 254a07aba5dSTimm Baeder return Caller->getLocation(RetPC); 255a07aba5dSTimm Baeder 256a07aba5dSTimm Baeder return S.getLocation(Func, PC); 257a07aba5dSTimm Baeder } 258a07aba5dSTimm Baeder 259a07aba5dSTimm Baeder SourceRange InterpFrame::getRange(CodePtr PC) const { 260d03822d8STimm Baeder if (Func && !funcHasUsableBody(Func) && Caller) 261a07aba5dSTimm Baeder return Caller->getRange(RetPC); 262a07aba5dSTimm Baeder 263a07aba5dSTimm Baeder return S.getRange(Func, PC); 264a07aba5dSTimm Baeder } 2654b964002STimm Baeder 2664b964002STimm Baeder bool InterpFrame::isStdFunction() const { 2674b964002STimm Baeder if (!Func) 2684b964002STimm Baeder return false; 2694b964002STimm Baeder for (const DeclContext *DC = Func->getDecl(); DC; DC = DC->getParent()) 2704b964002STimm Baeder if (DC->isStdNamespace()) 2714b964002STimm Baeder return true; 2724b964002STimm Baeder 2734b964002STimm Baeder return false; 2744b964002STimm Baeder } 275