1 | //===--- Function.h - Bytecode function 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 Function class which holds all bytecode function-specific data. |
10 | // |
11 | // The scope class which describes local variables is also defined here. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H |
16 | #define LLVM_CLANG_AST_INTERP_FUNCTION_H |
17 | |
18 | #include "Descriptor.h" |
19 | #include "Source.h" |
20 | #include "clang/AST/ASTLambda.h" |
21 | #include "clang/AST/Attr.h" |
22 | #include "clang/AST/Decl.h" |
23 | #include "llvm/ADT/PointerUnion.h" |
24 | #include "llvm/Support/raw_ostream.h" |
25 | |
26 | namespace clang { |
27 | namespace interp { |
28 | class Program; |
29 | class ByteCodeEmitter; |
30 | class Pointer; |
31 | enum PrimType : uint32_t; |
32 | |
33 | /// Describes a scope block. |
34 | /// |
35 | /// The block gathers all the descriptors of the locals defined in this block. |
36 | class Scope final { |
37 | public: |
38 | /// Information about a local's storage. |
39 | struct Local { |
40 | /// Offset of the local in frame. |
41 | unsigned Offset; |
42 | /// Descriptor of the local. |
43 | Descriptor *Desc; |
44 | }; |
45 | |
46 | using LocalVectorTy = llvm::SmallVector<Local, 8>; |
47 | |
48 | Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {} |
49 | |
50 | llvm::iterator_range<LocalVectorTy::const_iterator> locals() const { |
51 | return llvm::make_range(x: Descriptors.begin(), y: Descriptors.end()); |
52 | } |
53 | |
54 | llvm::iterator_range<LocalVectorTy::const_reverse_iterator> |
55 | locals_reverse() const { |
56 | return llvm::reverse(C: Descriptors); |
57 | } |
58 | |
59 | private: |
60 | /// Object descriptors in this block. |
61 | LocalVectorTy Descriptors; |
62 | }; |
63 | |
64 | using FunctionDeclTy = |
65 | llvm::PointerUnion<const FunctionDecl *, const BlockExpr *>; |
66 | |
67 | /// Bytecode function. |
68 | /// |
69 | /// Contains links to the bytecode of the function, as well as metadata |
70 | /// describing all arguments and stack-local variables. |
71 | /// |
72 | /// # Calling Convention |
73 | /// |
74 | /// When calling a function, all argument values must be on the stack. |
75 | /// |
76 | /// If the function has a This pointer (i.e. hasThisPointer() returns true, |
77 | /// the argument values need to be preceeded by a Pointer for the This object. |
78 | /// |
79 | /// If the function uses Return Value Optimization, the arguments (and |
80 | /// potentially the This pointer) need to be preceeded by a Pointer pointing |
81 | /// to the location to construct the returned value. |
82 | /// |
83 | /// After the function has been called, it will remove all arguments, |
84 | /// including RVO and This pointer, from the stack. |
85 | /// |
86 | class Function final { |
87 | public: |
88 | enum class FunctionKind { |
89 | Normal, |
90 | Ctor, |
91 | Dtor, |
92 | LambdaStaticInvoker, |
93 | LambdaCallOperator, |
94 | CopyOrMoveOperator, |
95 | }; |
96 | using ParamDescriptor = std::pair<PrimType, Descriptor *>; |
97 | |
98 | /// Returns the size of the function's local stack. |
99 | unsigned getFrameSize() const { return FrameSize; } |
100 | /// Returns the size of the argument stack. |
101 | unsigned getArgSize() const { return ArgSize; } |
102 | |
103 | /// Returns a pointer to the start of the code. |
104 | CodePtr getCodeBegin() const { return Code.data(); } |
105 | /// Returns a pointer to the end of the code. |
106 | CodePtr getCodeEnd() const { return Code.data() + Code.size(); } |
107 | |
108 | /// Returns the original FunctionDecl. |
109 | const FunctionDecl *getDecl() const { |
110 | return dyn_cast<const FunctionDecl *>(Val: Source); |
111 | } |
112 | const BlockExpr *getExpr() const { |
113 | return dyn_cast<const BlockExpr *>(Val: Source); |
114 | } |
115 | |
116 | /// Returns the name of the function decl this code |
117 | /// was generated for. |
118 | std::string getName() const { |
119 | if (!Source || !getDecl()) |
120 | return "<<expr>>" ; |
121 | |
122 | return getDecl()->getQualifiedNameAsString(); |
123 | } |
124 | |
125 | /// Returns a parameter descriptor. |
126 | ParamDescriptor getParamDescriptor(unsigned Offset) const; |
127 | |
128 | /// Checks if the first argument is a RVO pointer. |
129 | bool hasRVO() const { return HasRVO; } |
130 | |
131 | bool hasNonNullAttr() const { return getDecl()->hasAttr<NonNullAttr>(); } |
132 | |
133 | /// Range over the scope blocks. |
134 | llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator> |
135 | scopes() const { |
136 | return llvm::make_range(x: Scopes.begin(), y: Scopes.end()); |
137 | } |
138 | |
139 | /// Range over argument types. |
140 | using arg_reverse_iterator = |
141 | SmallVectorImpl<PrimType>::const_reverse_iterator; |
142 | llvm::iterator_range<arg_reverse_iterator> args_reverse() const { |
143 | return llvm::reverse(C: ParamTypes); |
144 | } |
145 | |
146 | /// Returns a specific scope. |
147 | Scope &getScope(unsigned Idx) { return Scopes[Idx]; } |
148 | const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; } |
149 | |
150 | /// Returns the source information at a given PC. |
151 | SourceInfo getSource(CodePtr PC) const; |
152 | |
153 | /// Checks if the function is valid to call. |
154 | bool isValid() const { return IsValid || isLambdaStaticInvoker(); } |
155 | |
156 | /// Checks if the function is virtual. |
157 | bool isVirtual() const { return Virtual; }; |
158 | bool isImmediate() const { return Immediate; } |
159 | bool isConstexpr() const { return Constexpr; } |
160 | |
161 | /// Checks if the function is a constructor. |
162 | bool isConstructor() const { return Kind == FunctionKind::Ctor; } |
163 | /// Checks if the function is a destructor. |
164 | bool isDestructor() const { return Kind == FunctionKind::Dtor; } |
165 | /// Checks if the function is copy or move operator. |
166 | bool isCopyOrMoveOperator() const { |
167 | return Kind == FunctionKind::CopyOrMoveOperator; |
168 | } |
169 | |
170 | /// Returns whether this function is a lambda static invoker, |
171 | /// which we generate custom byte code for. |
172 | bool isLambdaStaticInvoker() const { |
173 | return Kind == FunctionKind::LambdaStaticInvoker; |
174 | } |
175 | |
176 | /// Returns whether this function is the call operator |
177 | /// of a lambda record decl. |
178 | bool isLambdaCallOperator() const { |
179 | return Kind == FunctionKind::LambdaCallOperator; |
180 | } |
181 | |
182 | /// Returns the parent record decl, if any. |
183 | const CXXRecordDecl *getParentDecl() const { |
184 | if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>( |
185 | Val: dyn_cast<const FunctionDecl *>(Val: Source))) |
186 | return MD->getParent(); |
187 | return nullptr; |
188 | } |
189 | |
190 | /// Checks if the function is fully done compiling. |
191 | bool isFullyCompiled() const { return IsFullyCompiled; } |
192 | |
193 | bool hasThisPointer() const { return HasThisPointer; } |
194 | |
195 | /// Checks if the function already has a body attached. |
196 | bool hasBody() const { return HasBody; } |
197 | |
198 | /// Checks if the function is defined. |
199 | bool isDefined() const { return Defined; } |
200 | |
201 | bool isVariadic() const { return Variadic; } |
202 | |
203 | unsigned getNumParams() const { return ParamTypes.size(); } |
204 | |
205 | /// Returns the number of parameter this function takes when it's called, |
206 | /// i.e excluding the instance pointer and the RVO pointer. |
207 | unsigned getNumWrittenParams() const { |
208 | assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO())); |
209 | return getNumParams() - hasThisPointer() - hasRVO(); |
210 | } |
211 | unsigned getWrittenArgSize() const { |
212 | return ArgSize - (align(Size: primSize(Type: PT_Ptr)) * (hasThisPointer() + hasRVO())); |
213 | } |
214 | |
215 | bool isThisPointerExplicit() const { |
216 | if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>( |
217 | Val: dyn_cast<const FunctionDecl *>(Val: Source))) |
218 | return MD->isExplicitObjectMemberFunction(); |
219 | return false; |
220 | } |
221 | |
222 | unsigned getParamOffset(unsigned ParamIndex) const { |
223 | return ParamOffsets[ParamIndex]; |
224 | } |
225 | |
226 | PrimType getParamType(unsigned ParamIndex) const { |
227 | return ParamTypes[ParamIndex]; |
228 | } |
229 | |
230 | private: |
231 | /// Construct a function representing an actual function. |
232 | Function(Program &P, FunctionDeclTy Source, unsigned ArgSize, |
233 | llvm::SmallVectorImpl<PrimType> &&ParamTypes, |
234 | llvm::DenseMap<unsigned, ParamDescriptor> &&Params, |
235 | llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer, |
236 | bool HasRVO, bool IsLambdaStaticInvoker); |
237 | |
238 | /// Sets the code of a function. |
239 | void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode, |
240 | SourceMap &&NewSrcMap, llvm::SmallVector<Scope, 2> &&NewScopes, |
241 | bool NewHasBody) { |
242 | FrameSize = NewFrameSize; |
243 | Code = std::move(NewCode); |
244 | SrcMap = std::move(NewSrcMap); |
245 | Scopes = std::move(NewScopes); |
246 | IsValid = true; |
247 | HasBody = NewHasBody; |
248 | } |
249 | |
250 | void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; } |
251 | void setDefined(bool D) { Defined = D; } |
252 | |
253 | private: |
254 | friend class Program; |
255 | friend class ByteCodeEmitter; |
256 | friend class Context; |
257 | |
258 | /// Program reference. |
259 | Program &P; |
260 | /// Function Kind. |
261 | FunctionKind Kind; |
262 | /// Declaration this function was compiled from. |
263 | FunctionDeclTy Source; |
264 | /// Local area size: storage + metadata. |
265 | unsigned FrameSize = 0; |
266 | /// Size of the argument stack. |
267 | unsigned ArgSize; |
268 | /// Program code. |
269 | std::vector<std::byte> Code; |
270 | /// Opcode-to-expression mapping. |
271 | SourceMap SrcMap; |
272 | /// List of block descriptors. |
273 | llvm::SmallVector<Scope, 2> Scopes; |
274 | /// List of argument types. |
275 | llvm::SmallVector<PrimType, 8> ParamTypes; |
276 | /// Map from byte offset to parameter descriptor. |
277 | llvm::DenseMap<unsigned, ParamDescriptor> Params; |
278 | /// List of parameter offsets. |
279 | llvm::SmallVector<unsigned, 8> ParamOffsets; |
280 | /// Flag to indicate if the function is valid. |
281 | LLVM_PREFERRED_TYPE(bool) |
282 | unsigned IsValid : 1; |
283 | /// Flag to indicate if the function is done being |
284 | /// compiled to bytecode. |
285 | LLVM_PREFERRED_TYPE(bool) |
286 | unsigned IsFullyCompiled : 1; |
287 | /// Flag indicating if this function takes the this pointer |
288 | /// as the first implicit argument |
289 | LLVM_PREFERRED_TYPE(bool) |
290 | unsigned HasThisPointer : 1; |
291 | /// Whether this function has Return Value Optimization, i.e. |
292 | /// the return value is constructed in the caller's stack frame. |
293 | /// This is done for functions that return non-primive values. |
294 | LLVM_PREFERRED_TYPE(bool) |
295 | unsigned HasRVO : 1; |
296 | /// If we've already compiled the function's body. |
297 | LLVM_PREFERRED_TYPE(bool) |
298 | unsigned HasBody : 1; |
299 | LLVM_PREFERRED_TYPE(bool) |
300 | unsigned Defined : 1; |
301 | LLVM_PREFERRED_TYPE(bool) |
302 | unsigned Variadic : 1; |
303 | LLVM_PREFERRED_TYPE(bool) |
304 | unsigned Virtual : 1; |
305 | LLVM_PREFERRED_TYPE(bool) |
306 | unsigned Immediate : 1; |
307 | LLVM_PREFERRED_TYPE(bool) |
308 | unsigned Constexpr : 1; |
309 | |
310 | public: |
311 | /// Dumps the disassembled bytecode to \c llvm::errs(). |
312 | void dump() const; |
313 | void dump(llvm::raw_ostream &OS) const; |
314 | }; |
315 | |
316 | } // namespace interp |
317 | } // namespace clang |
318 | |
319 | #endif |
320 | |