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 Scope(LocalVectorTy && Descriptors)48 Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {} 49 locals()50 llvm::iterator_range<LocalVectorTy::const_iterator> locals() const { 51 return llvm::make_range(Descriptors.begin(), Descriptors.end()); 52 } 53 54 llvm::iterator_range<LocalVectorTy::const_reverse_iterator> locals_reverse()55 locals_reverse() const { 56 return llvm::reverse(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. getFrameSize()99 unsigned getFrameSize() const { return FrameSize; } 100 /// Returns the size of the argument stack. getArgSize()101 unsigned getArgSize() const { return ArgSize; } 102 103 /// Returns a pointer to the start of the code. getCodeBegin()104 CodePtr getCodeBegin() const { return Code.data(); } 105 /// Returns a pointer to the end of the code. getCodeEnd()106 CodePtr getCodeEnd() const { return Code.data() + Code.size(); } 107 108 /// Returns the original FunctionDecl. getDecl()109 const FunctionDecl *getDecl() const { 110 return dyn_cast<const FunctionDecl *>(Source); 111 } getExpr()112 const BlockExpr *getExpr() const { 113 return dyn_cast<const BlockExpr *>(Source); 114 } 115 116 /// Returns the name of the function decl this code 117 /// was generated for. getName()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. hasRVO()129 bool hasRVO() const { return HasRVO; } 130 hasNonNullAttr()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> scopes()135 scopes() const { 136 return llvm::make_range(Scopes.begin(), Scopes.end()); 137 } 138 139 /// Range over argument types. 140 using arg_reverse_iterator = 141 SmallVectorImpl<PrimType>::const_reverse_iterator; args_reverse()142 llvm::iterator_range<arg_reverse_iterator> args_reverse() const { 143 return llvm::reverse(ParamTypes); 144 } 145 146 /// Returns a specific scope. getScope(unsigned Idx)147 Scope &getScope(unsigned Idx) { return Scopes[Idx]; } getScope(unsigned 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. isValid()154 bool isValid() const { return IsValid || isLambdaStaticInvoker(); } 155 156 /// Checks if the function is virtual. isVirtual()157 bool isVirtual() const { return Virtual; }; isImmediate()158 bool isImmediate() const { return Immediate; } isConstexpr()159 bool isConstexpr() const { return Constexpr; } 160 161 /// Checks if the function is a constructor. isConstructor()162 bool isConstructor() const { return Kind == FunctionKind::Ctor; } 163 /// Checks if the function is a destructor. isDestructor()164 bool isDestructor() const { return Kind == FunctionKind::Dtor; } 165 /// Checks if the function is copy or move operator. isCopyOrMoveOperator()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. isLambdaStaticInvoker()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. isLambdaCallOperator()178 bool isLambdaCallOperator() const { 179 return Kind == FunctionKind::LambdaCallOperator; 180 } 181 182 /// Returns the parent record decl, if any. getParentDecl()183 const CXXRecordDecl *getParentDecl() const { 184 if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>( 185 dyn_cast<const FunctionDecl *>(Source))) 186 return MD->getParent(); 187 return nullptr; 188 } 189 190 /// Checks if the function is fully done compiling. isFullyCompiled()191 bool isFullyCompiled() const { return IsFullyCompiled; } 192 hasThisPointer()193 bool hasThisPointer() const { return HasThisPointer; } 194 195 /// Checks if the function already has a body attached. hasBody()196 bool hasBody() const { return HasBody; } 197 198 /// Checks if the function is defined. isDefined()199 bool isDefined() const { return Defined; } 200 isVariadic()201 bool isVariadic() const { return Variadic; } 202 getNumParams()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. getNumWrittenParams()207 unsigned getNumWrittenParams() const { 208 assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO())); 209 return getNumParams() - hasThisPointer() - hasRVO(); 210 } getWrittenArgSize()211 unsigned getWrittenArgSize() const { 212 return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO())); 213 } 214 isThisPointerExplicit()215 bool isThisPointerExplicit() const { 216 if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>( 217 dyn_cast<const FunctionDecl *>(Source))) 218 return MD->isExplicitObjectMemberFunction(); 219 return false; 220 } 221 getParamOffset(unsigned ParamIndex)222 unsigned getParamOffset(unsigned ParamIndex) const { 223 return ParamOffsets[ParamIndex]; 224 } 225 getParamType(unsigned ParamIndex)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. setCode(unsigned NewFrameSize,std::vector<std::byte> && NewCode,SourceMap && NewSrcMap,llvm::SmallVector<Scope,2> && NewScopes,bool NewHasBody)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 setIsFullyCompiled(bool FC)250 void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; } setDefined(bool D)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