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 "Pointer.h"
19 #include "Source.h"
20 #include "clang/AST/Decl.h"
21 #include "llvm/Support/raw_ostream.h"
22 
23 namespace clang {
24 namespace interp {
25 class Program;
26 class ByteCodeEmitter;
27 enum PrimType : uint32_t;
28 
29 /// Describes a scope block.
30 ///
31 /// The block gathers all the descriptors of the locals defined in this block.
32 class Scope final {
33 public:
34   /// Information about a local's storage.
35   struct Local {
36     /// Offset of the local in frame.
37     unsigned Offset;
38     /// Descriptor of the local.
39     Descriptor *Desc;
40   };
41 
42   using LocalVectorTy = llvm::SmallVector<Local, 8>;
43 
44   Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
45 
46   llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
47     return llvm::make_range(Descriptors.begin(), Descriptors.end());
48   }
49 
50 private:
51   /// Object descriptors in this block.
52   LocalVectorTy Descriptors;
53 };
54 
55 /// Bytecode function.
56 ///
57 /// Contains links to the bytecode of the function, as well as metadata
58 /// describing all arguments and stack-local variables.
59 ///
60 /// # Calling Convention
61 ///
62 /// When calling a function, all argument values must be on the stack.
63 ///
64 /// If the function has a This pointer (i.e. hasThisPointer() returns true,
65 /// the argument values need to be preceeded by a Pointer for the This object.
66 ///
67 /// If the function uses Return Value Optimization, the arguments (and
68 /// potentially the This pointer) need to be proceeded by a Pointer pointing
69 /// to the location to construct the returned value.
70 ///
71 /// After the function has been called, it will remove all arguments,
72 /// including RVO and This pointer, from the stack.
73 ///
74 class Function final {
75 public:
76   using ParamDescriptor = std::pair<PrimType, Descriptor *>;
77 
78   /// Returns the size of the function's local stack.
79   unsigned getFrameSize() const { return FrameSize; }
80   /// Returns the size of the argument stack.
81   unsigned getArgSize() const { return ArgSize; }
82 
83   /// Returns a pointer to the start of the code.
84   CodePtr getCodeBegin() const { return Code.data(); }
85   /// Returns a pointer to the end of the code.
86   CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
87 
88   /// Returns the original FunctionDecl.
89   const FunctionDecl *getDecl() const { return F; }
90 
91   /// Returns the name of the function decl this code
92   /// was generated for.
93   const std::string getName() const {
94     if (!F)
95       return "<<expr>>";
96 
97     return F->getQualifiedNameAsString();
98   }
99 
100   /// Returns the location.
101   SourceLocation getLoc() const { return Loc; }
102 
103   /// Returns a parameter descriptor.
104   ParamDescriptor getParamDescriptor(unsigned Offset) const;
105 
106   /// Checks if the first argument is a RVO pointer.
107   bool hasRVO() const { return HasRVO; }
108 
109   /// Range over the scope blocks.
110   llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
111   scopes() const {
112     return llvm::make_range(Scopes.begin(), Scopes.end());
113   }
114 
115   /// Range over argument types.
116   using arg_reverse_iterator =
117       SmallVectorImpl<PrimType>::const_reverse_iterator;
118   llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
119     return llvm::reverse(ParamTypes);
120   }
121 
122   /// Returns a specific scope.
123   Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
124   const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; }
125 
126   /// Returns the source information at a given PC.
127   SourceInfo getSource(CodePtr PC) const;
128 
129   /// Checks if the function is valid to call in constexpr.
130   bool isConstexpr() const { return IsValid; }
131 
132   /// Checks if the function is virtual.
133   bool isVirtual() const;
134 
135   /// Checks if the function is a constructor.
136   bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
137   /// Checks if the function is a destructor.
138   bool isDestructor() const { return isa<CXXDestructorDecl>(F); }
139 
140   /// Returns the parent record decl, if any.
141   const CXXRecordDecl *getParentDecl() const {
142     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
143       return MD->getParent();
144     return nullptr;
145   }
146 
147   /// Checks if the function is fully done compiling.
148   bool isFullyCompiled() const { return IsFullyCompiled; }
149 
150   bool hasThisPointer() const { return HasThisPointer; }
151 
152   /// Checks if the function already has a body attached.
153   bool hasBody() const { return HasBody; }
154 
155   unsigned getBuiltinID() const { return F->getBuiltinID(); }
156 
157   unsigned getNumParams() const { return ParamTypes.size(); }
158 
159   unsigned getParamOffset(unsigned ParamIndex) const {
160     return ParamOffsets[ParamIndex];
161   }
162 
163 private:
164   /// Construct a function representing an actual function.
165   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
166            llvm::SmallVectorImpl<PrimType> &&ParamTypes,
167            llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
168            llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer,
169            bool HasRVO);
170 
171   /// Sets the code of a function.
172   void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode,
173                SourceMap &&NewSrcMap, llvm::SmallVector<Scope, 2> &&NewScopes,
174                bool NewHasBody) {
175     FrameSize = NewFrameSize;
176     Code = std::move(NewCode);
177     SrcMap = std::move(NewSrcMap);
178     Scopes = std::move(NewScopes);
179     IsValid = true;
180     HasBody = NewHasBody;
181   }
182 
183   void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
184 
185 private:
186   friend class Program;
187   friend class ByteCodeEmitter;
188 
189   /// Program reference.
190   Program &P;
191   /// Location of the executed code.
192   SourceLocation Loc;
193   /// Declaration this function was compiled from.
194   const FunctionDecl *F;
195   /// Local area size: storage + metadata.
196   unsigned FrameSize = 0;
197   /// Size of the argument stack.
198   unsigned ArgSize;
199   /// Program code.
200   std::vector<std::byte> Code;
201   /// Opcode-to-expression mapping.
202   SourceMap SrcMap;
203   /// List of block descriptors.
204   llvm::SmallVector<Scope, 2> Scopes;
205   /// List of argument types.
206   llvm::SmallVector<PrimType, 8> ParamTypes;
207   /// Map from byte offset to parameter descriptor.
208   llvm::DenseMap<unsigned, ParamDescriptor> Params;
209   /// List of parameter offsets.
210   llvm::SmallVector<unsigned, 8> ParamOffsets;
211   /// Flag to indicate if the function is valid.
212   bool IsValid = false;
213   /// Flag to indicate if the function is done being
214   /// compiled to bytecode.
215   bool IsFullyCompiled = false;
216   /// Flag indicating if this function takes the this pointer
217   /// as the first implicit argument
218   bool HasThisPointer = false;
219   /// Whether this function has Return Value Optimization, i.e.
220   /// the return value is constructed in the caller's stack frame.
221   /// This is done for functions that return non-primive values.
222   bool HasRVO = false;
223   /// If we've already compiled the function's body.
224   bool HasBody = false;
225 
226 public:
227   /// Dumps the disassembled bytecode to \c llvm::errs().
228   void dump() const;
229   void dump(llvm::raw_ostream &OS) const;
230 };
231 
232 } // namespace interp
233 } // namespace clang
234 
235 #endif
236