xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/InterpFrame.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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