1*700637cbSDimitry Andric //===--- InterpFrame.h - Call Frame implementation for the VM ---*- C++ -*-===// 2*700637cbSDimitry Andric // 3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*700637cbSDimitry Andric // 7*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 8*700637cbSDimitry Andric // 9*700637cbSDimitry Andric // Defines the class storing information about stack frames in the interpreter. 10*700637cbSDimitry Andric // 11*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 12*700637cbSDimitry Andric 13*700637cbSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTERPFRAME_H 14*700637cbSDimitry Andric #define LLVM_CLANG_AST_INTERP_INTERPFRAME_H 15*700637cbSDimitry Andric 16*700637cbSDimitry Andric #include "Frame.h" 17*700637cbSDimitry Andric #include "Program.h" 18*700637cbSDimitry Andric 19*700637cbSDimitry Andric namespace clang { 20*700637cbSDimitry Andric namespace interp { 21*700637cbSDimitry Andric class Function; 22*700637cbSDimitry Andric class InterpState; 23*700637cbSDimitry Andric class Pointer; 24*700637cbSDimitry Andric 25*700637cbSDimitry Andric /// Frame storing local variables. 26*700637cbSDimitry Andric class InterpFrame final : public Frame { 27*700637cbSDimitry Andric public: 28*700637cbSDimitry Andric /// The frame of the previous function. 29*700637cbSDimitry Andric InterpFrame *Caller; 30*700637cbSDimitry Andric 31*700637cbSDimitry Andric /// Bottom Frame. 32*700637cbSDimitry Andric InterpFrame(InterpState &S); 33*700637cbSDimitry Andric 34*700637cbSDimitry Andric /// Creates a new frame for a method call. 35*700637cbSDimitry Andric InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller, 36*700637cbSDimitry Andric CodePtr RetPC, unsigned ArgSize); 37*700637cbSDimitry Andric 38*700637cbSDimitry Andric /// Creates a new frame with the values that make sense. 39*700637cbSDimitry Andric /// I.e., the caller is the current frame of S, 40*700637cbSDimitry Andric /// the This() pointer is the current Pointer on the top of S's stack, 41*700637cbSDimitry Andric /// and the RVO pointer is before that. 42*700637cbSDimitry Andric InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC, 43*700637cbSDimitry Andric unsigned VarArgSize = 0); 44*700637cbSDimitry Andric 45*700637cbSDimitry Andric /// Destroys the frame, killing all live pointers to stack slots. 46*700637cbSDimitry Andric ~InterpFrame(); 47*700637cbSDimitry Andric free(InterpFrame * F)48*700637cbSDimitry Andric static void free(InterpFrame *F) { 49*700637cbSDimitry Andric if (!F->isBottomFrame()) 50*700637cbSDimitry Andric delete F; 51*700637cbSDimitry Andric } 52*700637cbSDimitry Andric 53*700637cbSDimitry Andric /// Invokes the destructors for a scope. 54*700637cbSDimitry Andric void destroy(unsigned Idx); 55*700637cbSDimitry Andric void initScope(unsigned Idx); 56*700637cbSDimitry Andric void destroyScopes(); 57*700637cbSDimitry Andric 58*700637cbSDimitry Andric /// Describes the frame with arguments for diagnostic purposes. 59*700637cbSDimitry Andric void describe(llvm::raw_ostream &OS) const override; 60*700637cbSDimitry Andric 61*700637cbSDimitry Andric /// Returns the parent frame object. 62*700637cbSDimitry Andric Frame *getCaller() const override; 63*700637cbSDimitry Andric 64*700637cbSDimitry Andric /// Returns the location of the call to the frame. 65*700637cbSDimitry Andric SourceRange getCallRange() const override; 66*700637cbSDimitry Andric 67*700637cbSDimitry Andric /// Returns the caller. 68*700637cbSDimitry Andric const FunctionDecl *getCallee() const override; 69*700637cbSDimitry Andric 70*700637cbSDimitry Andric /// Returns the current function. getFunction()71*700637cbSDimitry Andric const Function *getFunction() const { return Func; } 72*700637cbSDimitry Andric 73*700637cbSDimitry Andric /// Returns the offset on the stack at which the frame starts. getFrameOffset()74*700637cbSDimitry Andric size_t getFrameOffset() const { return FrameOffset; } 75*700637cbSDimitry Andric 76*700637cbSDimitry Andric /// Returns the value of a local variable. getLocal(unsigned Offset)77*700637cbSDimitry Andric template <typename T> const T &getLocal(unsigned Offset) const { 78*700637cbSDimitry Andric return localRef<T>(Offset); 79*700637cbSDimitry Andric } 80*700637cbSDimitry Andric 81*700637cbSDimitry Andric /// Mutates a local variable. setLocal(unsigned Offset,const T & Value)82*700637cbSDimitry Andric template <typename T> void setLocal(unsigned Offset, const T &Value) { 83*700637cbSDimitry Andric localRef<T>(Offset) = Value; 84*700637cbSDimitry Andric localInlineDesc(Offset)->IsInitialized = true; 85*700637cbSDimitry Andric } 86*700637cbSDimitry Andric 87*700637cbSDimitry Andric /// Returns a pointer to a local variables. 88*700637cbSDimitry Andric Pointer getLocalPointer(unsigned Offset) const; 89*700637cbSDimitry Andric 90*700637cbSDimitry Andric /// Returns the value of an argument. getParam(unsigned Offset)91*700637cbSDimitry Andric template <typename T> const T &getParam(unsigned Offset) const { 92*700637cbSDimitry Andric auto Pt = Params.find(Offset); 93*700637cbSDimitry Andric if (Pt == Params.end()) 94*700637cbSDimitry Andric return stackRef<T>(Offset); 95*700637cbSDimitry Andric return Pointer(reinterpret_cast<Block *>(Pt->second.get())).deref<T>(); 96*700637cbSDimitry Andric } 97*700637cbSDimitry Andric 98*700637cbSDimitry Andric /// Mutates a local copy of a parameter. setParam(unsigned Offset,const T & Value)99*700637cbSDimitry Andric template <typename T> void setParam(unsigned Offset, const T &Value) { 100*700637cbSDimitry Andric getParamPointer(Offset).deref<T>() = Value; 101*700637cbSDimitry Andric } 102*700637cbSDimitry Andric 103*700637cbSDimitry Andric /// Returns a pointer to an argument - lazily creates a block. 104*700637cbSDimitry Andric Pointer getParamPointer(unsigned Offset); 105*700637cbSDimitry Andric 106*700637cbSDimitry Andric /// Returns the 'this' pointer. getThis()107*700637cbSDimitry Andric const Pointer &getThis() const { return This; } 108*700637cbSDimitry Andric 109*700637cbSDimitry Andric /// Returns the RVO pointer, if the Function has one. getRVOPtr()110*700637cbSDimitry Andric const Pointer &getRVOPtr() const { return RVOPtr; } 111*700637cbSDimitry Andric 112*700637cbSDimitry Andric /// Checks if the frame is a root frame - return should quit the interpreter. isRoot()113*700637cbSDimitry Andric bool isRoot() const { return !Func; } 114*700637cbSDimitry Andric 115*700637cbSDimitry Andric /// Returns the PC of the frame's code start. getPC()116*700637cbSDimitry Andric CodePtr getPC() const { return Func->getCodeBegin(); } 117*700637cbSDimitry Andric 118*700637cbSDimitry Andric /// Returns the return address of the frame. getRetPC()119*700637cbSDimitry Andric CodePtr getRetPC() const { return RetPC; } 120*700637cbSDimitry Andric 121*700637cbSDimitry Andric /// Map a location to a source. 122*700637cbSDimitry Andric SourceInfo getSource(CodePtr PC) const; 123*700637cbSDimitry Andric const Expr *getExpr(CodePtr PC) const; 124*700637cbSDimitry Andric SourceLocation getLocation(CodePtr PC) const; 125*700637cbSDimitry Andric SourceRange getRange(CodePtr PC) const; 126*700637cbSDimitry Andric getDepth()127*700637cbSDimitry Andric unsigned getDepth() const { return Depth; } 128*700637cbSDimitry Andric 129*700637cbSDimitry Andric bool isStdFunction() const; 130*700637cbSDimitry Andric isBottomFrame()131*700637cbSDimitry Andric bool isBottomFrame() const { return IsBottom; } 132*700637cbSDimitry Andric dump()133*700637cbSDimitry Andric void dump() const { dump(llvm::errs(), 0); } 134*700637cbSDimitry Andric void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const; 135*700637cbSDimitry Andric 136*700637cbSDimitry Andric private: 137*700637cbSDimitry Andric /// Returns an original argument from the stack. stackRef(unsigned Offset)138*700637cbSDimitry Andric template <typename T> const T &stackRef(unsigned Offset) const { 139*700637cbSDimitry Andric assert(Args); 140*700637cbSDimitry Andric return *reinterpret_cast<const T *>(Args - ArgSize + Offset); 141*700637cbSDimitry Andric } 142*700637cbSDimitry Andric 143*700637cbSDimitry Andric /// Returns an offset to a local. localRef(unsigned Offset)144*700637cbSDimitry Andric template <typename T> T &localRef(unsigned Offset) const { 145*700637cbSDimitry Andric return getLocalPointer(Offset).deref<T>(); 146*700637cbSDimitry Andric } 147*700637cbSDimitry Andric 148*700637cbSDimitry Andric /// Returns a pointer to a local's block. localBlock(unsigned Offset)149*700637cbSDimitry Andric Block *localBlock(unsigned Offset) const { 150*700637cbSDimitry Andric return reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block)); 151*700637cbSDimitry Andric } 152*700637cbSDimitry Andric 153*700637cbSDimitry Andric /// Returns the inline descriptor of the local. localInlineDesc(unsigned Offset)154*700637cbSDimitry Andric InlineDescriptor *localInlineDesc(unsigned Offset) const { 155*700637cbSDimitry Andric return reinterpret_cast<InlineDescriptor *>(Locals.get() + Offset); 156*700637cbSDimitry Andric } 157*700637cbSDimitry Andric 158*700637cbSDimitry Andric private: 159*700637cbSDimitry Andric /// Reference to the interpreter state. 160*700637cbSDimitry Andric InterpState &S; 161*700637cbSDimitry Andric /// Depth of this frame. 162*700637cbSDimitry Andric unsigned Depth; 163*700637cbSDimitry Andric /// Reference to the function being executed. 164*700637cbSDimitry Andric const Function *Func; 165*700637cbSDimitry Andric /// Current object pointer for methods. 166*700637cbSDimitry Andric Pointer This; 167*700637cbSDimitry Andric /// Pointer the non-primitive return value gets constructed in. 168*700637cbSDimitry Andric Pointer RVOPtr; 169*700637cbSDimitry Andric /// Return address. 170*700637cbSDimitry Andric CodePtr RetPC; 171*700637cbSDimitry Andric /// The size of all the arguments. 172*700637cbSDimitry Andric const unsigned ArgSize; 173*700637cbSDimitry Andric /// Pointer to the arguments in the callee's frame. 174*700637cbSDimitry Andric char *Args = nullptr; 175*700637cbSDimitry Andric /// Fixed, initial storage for known local variables. 176*700637cbSDimitry Andric std::unique_ptr<char[]> Locals; 177*700637cbSDimitry Andric /// Offset on the stack at entry. 178*700637cbSDimitry Andric const size_t FrameOffset; 179*700637cbSDimitry Andric /// Mapping from arg offsets to their argument blocks. 180*700637cbSDimitry Andric llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Params; 181*700637cbSDimitry Andric bool IsBottom = false; 182*700637cbSDimitry Andric }; 183*700637cbSDimitry Andric 184*700637cbSDimitry Andric } // namespace interp 185*700637cbSDimitry Andric } // namespace clang 186*700637cbSDimitry Andric 187*700637cbSDimitry Andric #endif 188