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