| //===----- CGObjCRuntime.h - Interface to ObjC Runtimes ---------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This provides an abstract class for Objective-C code generation. Concrete |
| // subclasses of this implement code generation for specific Objective-C |
| // runtime libraries. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H |
| #define LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H |
| #include "CGBuilder.h" |
| #include "CGCall.h" |
| #include "CGCleanup.h" |
| #include "CGValue.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/Basic/IdentifierTable.h" // Selector |
| #include "llvm/ADT/UniqueVector.h" |
| |
| namespace llvm { |
| class Constant; |
| class Function; |
| class Module; |
| class StructLayout; |
| class StructType; |
| class Type; |
| class Value; |
| } |
| |
| namespace clang { |
| namespace CodeGen { |
| class CodeGenFunction; |
| } |
| |
| class FieldDecl; |
| class ObjCAtTryStmt; |
| class ObjCAtThrowStmt; |
| class ObjCAtSynchronizedStmt; |
| class ObjCContainerDecl; |
| class ObjCCategoryImplDecl; |
| class ObjCImplementationDecl; |
| class ObjCInterfaceDecl; |
| class ObjCMessageExpr; |
| class ObjCMethodDecl; |
| class ObjCProtocolDecl; |
| class Selector; |
| class ObjCIvarDecl; |
| class ObjCStringLiteral; |
| class BlockDeclRefExpr; |
| |
| namespace CodeGen { |
| class CodeGenModule; |
| class CGBlockInfo; |
| |
| // FIXME: Several methods should be pure virtual but aren't to avoid the |
| // partially-implemented subclass breaking. |
| |
| /// Implements runtime-specific code generation functions. |
| class CGObjCRuntime { |
| protected: |
| CodeGen::CodeGenModule &CGM; |
| CGObjCRuntime(CodeGen::CodeGenModule &CGM) : CGM(CGM) {} |
| |
| // Utility functions for unified ivar access. These need to |
| // eventually be folded into other places (the structure layout |
| // code). |
| |
| /// Compute an offset to the given ivar, suitable for passing to |
| /// EmitValueForIvarAtOffset. Note that the correct handling of |
| /// bit-fields is carefully coordinated by these two, use caution! |
| /// |
| /// The latter overload is suitable for computing the offset of a |
| /// sythesized ivar. |
| uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
| const ObjCInterfaceDecl *OID, |
| const ObjCIvarDecl *Ivar); |
| uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
| const ObjCImplementationDecl *OID, |
| const ObjCIvarDecl *Ivar); |
| |
| LValue EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, |
| const ObjCInterfaceDecl *OID, |
| llvm::Value *BaseValue, |
| const ObjCIvarDecl *Ivar, |
| unsigned CVRQualifiers, |
| llvm::Value *Offset); |
| /// Emits a try / catch statement. This function is intended to be called by |
| /// subclasses, and provides a generic mechanism for generating these, which |
| /// should be usable by all runtimes. The caller must provide the functions |
| /// to call when entering and exiting a \@catch() block, and the function |
| /// used to rethrow exceptions. If the begin and end catch functions are |
| /// NULL, then the function assumes that the EH personality function provides |
| /// the thrown object directly. |
| void EmitTryCatchStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S, |
| llvm::FunctionCallee beginCatchFn, |
| llvm::FunctionCallee endCatchFn, |
| llvm::FunctionCallee exceptionRethrowFn); |
| |
| void EmitInitOfCatchParam(CodeGenFunction &CGF, llvm::Value *exn, |
| const VarDecl *paramDecl); |
| |
| /// Emits an \@synchronize() statement, using the \p syncEnterFn and |
| /// \p syncExitFn arguments as the functions called to lock and unlock |
| /// the object. This function can be called by subclasses that use |
| /// zero-cost exception handling. |
| void EmitAtSynchronizedStmt(CodeGenFunction &CGF, |
| const ObjCAtSynchronizedStmt &S, |
| llvm::FunctionCallee syncEnterFn, |
| llvm::FunctionCallee syncExitFn); |
| |
| public: |
| virtual ~CGObjCRuntime(); |
| |
| std::string getSymbolNameForMethod(const ObjCMethodDecl *method, |
| bool includeCategoryName = true); |
| |
| /// Generate the function required to register all Objective-C components in |
| /// this compilation unit with the runtime library. |
| virtual llvm::Function *ModuleInitFunction() = 0; |
| |
| /// Get a selector for the specified name and type values. |
| /// The result should have the LLVM type for ASTContext::getObjCSelType(). |
| virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) = 0; |
| |
| /// Get the address of a selector for the specified name and type values. |
| /// This is a rarely-used language extension, but sadly it exists. |
| /// |
| /// The result should have the LLVM type for a pointer to |
| /// ASTContext::getObjCSelType(). |
| virtual Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) = 0; |
| |
| /// Get a typed selector. |
| virtual llvm::Value *GetSelector(CodeGenFunction &CGF, |
| const ObjCMethodDecl *Method) = 0; |
| |
| /// Get the type constant to catch for the given ObjC pointer type. |
| /// This is used externally to implement catching ObjC types in C++. |
| /// Runtimes which don't support this should add the appropriate |
| /// error to Sema. |
| virtual llvm::Constant *GetEHType(QualType T) = 0; |
| |
| virtual CatchTypeInfo getCatchAllTypeInfo() { return { nullptr, 0 }; } |
| |
| /// Generate a constant string object. |
| virtual ConstantAddress GenerateConstantString(const StringLiteral *) = 0; |
| |
| /// Generate a category. A category contains a list of methods (and |
| /// accompanying metadata) and a list of protocols. |
| virtual void GenerateCategory(const ObjCCategoryImplDecl *OCD) = 0; |
| |
| /// Generate a class structure for this class. |
| virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0; |
| |
| /// Register an class alias. |
| virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) = 0; |
| |
| /// Generate an Objective-C message send operation. |
| /// |
| /// \param Method - The method being called, this may be null if synthesizing |
| /// a property setter or getter. |
| virtual CodeGen::RValue |
| GenerateMessageSend(CodeGen::CodeGenFunction &CGF, |
| ReturnValueSlot ReturnSlot, |
| QualType ResultType, |
| Selector Sel, |
| llvm::Value *Receiver, |
| const CallArgList &CallArgs, |
| const ObjCInterfaceDecl *Class = nullptr, |
| const ObjCMethodDecl *Method = nullptr) = 0; |
| |
| /// Generate an Objective-C message send operation. |
| /// |
| /// This variant allows for the call to be substituted with an optimized |
| /// variant. |
| CodeGen::RValue |
| GeneratePossiblySpecializedMessageSend(CodeGenFunction &CGF, |
| ReturnValueSlot Return, |
| QualType ResultType, |
| Selector Sel, |
| llvm::Value *Receiver, |
| const CallArgList& Args, |
| const ObjCInterfaceDecl *OID, |
| const ObjCMethodDecl *Method, |
| bool isClassMessage); |
| |
| /// Generate an Objective-C message send operation to the super |
| /// class initiated in a method for Class and with the given Self |
| /// object. |
| /// |
| /// \param Method - The method being called, this may be null if synthesizing |
| /// a property setter or getter. |
| virtual CodeGen::RValue |
| GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, |
| ReturnValueSlot ReturnSlot, |
| QualType ResultType, |
| Selector Sel, |
| const ObjCInterfaceDecl *Class, |
| bool isCategoryImpl, |
| llvm::Value *Self, |
| bool IsClassMessage, |
| const CallArgList &CallArgs, |
| const ObjCMethodDecl *Method = nullptr) = 0; |
| |
| /// Walk the list of protocol references from a class, category or |
| /// protocol to traverse the DAG formed from it's inheritance hierarchy. Find |
| /// the list of protocols that ends each walk at either a runtime |
| /// protocol or a non-runtime protocol with no parents. For the common case of |
| /// just a list of standard runtime protocols this just returns the same list |
| /// that was passed in. |
| std::vector<const ObjCProtocolDecl *> |
| GetRuntimeProtocolList(ObjCProtocolDecl::protocol_iterator begin, |
| ObjCProtocolDecl::protocol_iterator end); |
| |
| /// Emit the code to return the named protocol as an object, as in a |
| /// \@protocol expression. |
| virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF, |
| const ObjCProtocolDecl *OPD) = 0; |
| |
| /// Generate the named protocol. Protocols contain method metadata but no |
| /// implementations. |
| virtual void GenerateProtocol(const ObjCProtocolDecl *OPD) = 0; |
| |
| /// GetOrEmitProtocol - Get the protocol object for the given |
| /// declaration, emitting it if necessary. The return value has type |
| /// ProtocolPtrTy. |
| virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) = 0; |
| |
| /// Generate a function preamble for a method with the specified |
| /// types. |
| |
| // FIXME: Current this just generates the Function definition, but really this |
| // should also be generating the loads of the parameters, as the runtime |
| // should have full control over how parameters are passed. |
| virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, |
| const ObjCContainerDecl *CD) = 0; |
| |
| /// Generates prologue for direct Objective-C Methods. |
| virtual void GenerateDirectMethodPrologue(CodeGenFunction &CGF, |
| llvm::Function *Fn, |
| const ObjCMethodDecl *OMD, |
| const ObjCContainerDecl *CD) = 0; |
| |
| /// Return the runtime function for getting properties. |
| virtual llvm::FunctionCallee GetPropertyGetFunction() = 0; |
| |
| /// Return the runtime function for setting properties. |
| virtual llvm::FunctionCallee GetPropertySetFunction() = 0; |
| |
| /// Return the runtime function for optimized setting properties. |
| virtual llvm::FunctionCallee GetOptimizedPropertySetFunction(bool atomic, |
| bool copy) = 0; |
| |
| // API for atomic copying of qualified aggregates in getter. |
| virtual llvm::FunctionCallee GetGetStructFunction() = 0; |
| // API for atomic copying of qualified aggregates in setter. |
| virtual llvm::FunctionCallee GetSetStructFunction() = 0; |
| /// API for atomic copying of qualified aggregates with non-trivial copy |
| /// assignment (c++) in setter. |
| virtual llvm::FunctionCallee GetCppAtomicObjectSetFunction() = 0; |
| /// API for atomic copying of qualified aggregates with non-trivial copy |
| /// assignment (c++) in getter. |
| virtual llvm::FunctionCallee GetCppAtomicObjectGetFunction() = 0; |
| |
| /// GetClass - Return a reference to the class for the given |
| /// interface decl. |
| virtual llvm::Value *GetClass(CodeGenFunction &CGF, |
| const ObjCInterfaceDecl *OID) = 0; |
| |
| |
| virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) { |
| llvm_unreachable("autoreleasepool unsupported in this ABI"); |
| } |
| |
| /// EnumerationMutationFunction - Return the function that's called by the |
| /// compiler when a mutation is detected during foreach iteration. |
| virtual llvm::FunctionCallee EnumerationMutationFunction() = 0; |
| |
| virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, |
| const ObjCAtSynchronizedStmt &S) = 0; |
| virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF, |
| const ObjCAtTryStmt &S) = 0; |
| virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, |
| const ObjCAtThrowStmt &S, |
| bool ClearInsertionPoint=true) = 0; |
| virtual llvm::Value *EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, |
| Address AddrWeakObj) = 0; |
| virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, |
| llvm::Value *src, Address dest) = 0; |
| virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, |
| llvm::Value *src, Address dest, |
| bool threadlocal=false) = 0; |
| virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, |
| llvm::Value *src, Address dest, |
| llvm::Value *ivarOffset) = 0; |
| virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, |
| llvm::Value *src, Address dest) = 0; |
| |
| virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, |
| QualType ObjectTy, |
| llvm::Value *BaseValue, |
| const ObjCIvarDecl *Ivar, |
| unsigned CVRQualifiers) = 0; |
| virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF, |
| const ObjCInterfaceDecl *Interface, |
| const ObjCIvarDecl *Ivar) = 0; |
| virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, |
| Address DestPtr, |
| Address SrcPtr, |
| llvm::Value *Size) = 0; |
| virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, |
| const CodeGen::CGBlockInfo &blockInfo) = 0; |
| virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, |
| const CodeGen::CGBlockInfo &blockInfo) = 0; |
| virtual std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM, |
| const CGBlockInfo &blockInfo) { |
| return {}; |
| } |
| |
| /// Returns an i8* which points to the byref layout information. |
| virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM, |
| QualType T) = 0; |
| |
| struct MessageSendInfo { |
| const CGFunctionInfo &CallInfo; |
| llvm::PointerType *MessengerType; |
| |
| MessageSendInfo(const CGFunctionInfo &callInfo, |
| llvm::PointerType *messengerType) |
| : CallInfo(callInfo), MessengerType(messengerType) {} |
| }; |
| |
| MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method, |
| QualType resultType, |
| CallArgList &callArgs); |
| bool canMessageReceiverBeNull(CodeGenFunction &CGF, |
| const ObjCMethodDecl *method, |
| bool isSuper, |
| const ObjCInterfaceDecl *classReceiver, |
| llvm::Value *receiver); |
| static bool isWeakLinkedClass(const ObjCInterfaceDecl *cls); |
| |
| /// Destroy the callee-destroyed arguments of the given method, |
| /// if it has any. Used for nil-receiver paths in message sends. |
| /// Never does anything if the method does not satisfy |
| /// hasParamDestroyedInCallee(). |
| /// |
| /// \param callArgs - just the formal arguments, not including implicit |
| /// arguments such as self and cmd |
| static void destroyCalleeDestroyedArguments(CodeGenFunction &CGF, |
| const ObjCMethodDecl *method, |
| const CallArgList &callArgs); |
| |
| // FIXME: This probably shouldn't be here, but the code to compute |
| // it is here. |
| unsigned ComputeBitfieldBitOffset(CodeGen::CodeGenModule &CGM, |
| const ObjCInterfaceDecl *ID, |
| const ObjCIvarDecl *Ivar); |
| }; |
| |
| /// Creates an instance of an Objective-C runtime class. |
| //TODO: This should include some way of selecting which runtime to target. |
| CGObjCRuntime *CreateGNUObjCRuntime(CodeGenModule &CGM); |
| CGObjCRuntime *CreateMacObjCRuntime(CodeGenModule &CGM); |
| } |
| } |
| #endif |