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