Skip to content
CGObjCMac.cpp 187 KiB
Newer Older
//===------- CGObjCMac.cpp - Interface to Apple Objective-C Runtime -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This provides Objective-C code generation targetting the Apple runtime.
//
//===----------------------------------------------------------------------===//

#include "CGObjCRuntime.h"

#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
Daniel Dunbar's avatar
Daniel Dunbar committed
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"

#include "llvm/Module.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Target/TargetData.h"
#include <sstream>

using namespace clang;
using namespace CodeGen;
  typedef std::vector<llvm::Constant*> ConstantVector;

  // FIXME: We should find a nicer way to make the labels for
  // metadata, string concatenation is lame.

class ObjCCommonTypesHelper {
protected:
  CodeGen::CodeGenModule &CGM;
  const llvm::Type *ShortTy, *IntTy, *LongTy;
  const llvm::Type *Int8PtrTy;
  /// ObjectPtrTy - LLVM type for object handles (typeof(id))
  const llvm::Type *ObjectPtrTy;
  
  /// PtrObjectPtrTy - LLVM type for id *
  const llvm::Type *PtrObjectPtrTy;
  
  /// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
  const llvm::Type *SelectorPtrTy;
  /// ProtocolPtrTy - LLVM type for external protocol handles
  /// (typeof(Protocol))
  const llvm::Type *ExternalProtocolPtrTy;
  // SuperCTy - clang type for struct objc_super.
  QualType SuperCTy;
  // SuperPtrCTy - clang type for struct objc_super *.
  QualType SuperPtrCTy;
  /// SuperTy - LLVM type for struct objc_super.
  const llvm::StructType *SuperTy;
  /// SuperPtrTy - LLVM type for struct objc_super *.
  const llvm::Type *SuperPtrTy;
  /// PropertyTy - LLVM type for struct objc_property (struct _prop_t
  /// in GCC parlance).
  const llvm::StructType *PropertyTy;
  
  /// PropertyListTy - LLVM type for struct objc_property_list
  /// (_prop_list_t in GCC parlance).
  const llvm::StructType *PropertyListTy;
  /// PropertyListPtrTy - LLVM type for struct objc_property_list*.
  const llvm::Type *PropertyListPtrTy;
  
  // MethodTy - LLVM type for struct objc_method.
  const llvm::StructType *MethodTy;
  
  /// CacheTy - LLVM type for struct objc_cache.
  const llvm::Type *CacheTy;
  /// CachePtrTy - LLVM type for struct objc_cache *.
  const llvm::Type *CachePtrTy;
  
  llvm::Function *GetPropertyFn, *SetPropertyFn;
  
  llvm::Function *EnumerationMutationFn;
  
  /// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
  llvm::Function *GcReadWeakFn;
  
  /// GcAssignWeakFn -- LLVM objc_assign_weak function.
  llvm::Function *GcAssignWeakFn;
  
  /// GcAssignGlobalFn -- LLVM objc_assign_global function.
  llvm::Function *GcAssignGlobalFn;
  
  /// GcAssignIvarFn -- LLVM objc_assign_ivar function.
  llvm::Function *GcAssignIvarFn;
  
  /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
  llvm::Function *GcAssignStrongCastFn;

  /// ExceptionThrowFn - LLVM objc_exception_throw function.
  llvm::Function *ExceptionThrowFn;
  
  ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
  ~ObjCCommonTypesHelper(){}
};
/// ObjCTypesHelper - Helper class that encapsulates lazy
/// construction of varies types used during ObjC generation.
class ObjCTypesHelper : public ObjCCommonTypesHelper {
private:
  
  llvm::Function *MessageSendFn, *MessageSendStretFn, *MessageSendFpretFn;
  llvm::Function *MessageSendSuperFn, *MessageSendSuperStretFn, 
    *MessageSendSuperFpretFn;

public:
  /// SymtabTy - LLVM type for struct objc_symtab.
  const llvm::StructType *SymtabTy;
  /// SymtabPtrTy - LLVM type for struct objc_symtab *.
  const llvm::Type *SymtabPtrTy;
  /// ModuleTy - LLVM type for struct objc_module.
  const llvm::StructType *ModuleTy;
  /// ProtocolTy - LLVM type for struct objc_protocol.
  const llvm::StructType *ProtocolTy;
  /// ProtocolPtrTy - LLVM type for struct objc_protocol *.
  const llvm::Type *ProtocolPtrTy;
  /// ProtocolExtensionTy - LLVM type for struct
  /// objc_protocol_extension.
  const llvm::StructType *ProtocolExtensionTy;
  /// ProtocolExtensionTy - LLVM type for struct
  /// objc_protocol_extension *.
  const llvm::Type *ProtocolExtensionPtrTy;
  /// MethodDescriptionTy - LLVM type for struct
  /// objc_method_description.
  const llvm::StructType *MethodDescriptionTy;
  /// MethodDescriptionListTy - LLVM type for struct
  /// objc_method_description_list.
  const llvm::StructType *MethodDescriptionListTy;
  /// MethodDescriptionListPtrTy - LLVM type for struct
  /// objc_method_description_list *.
  const llvm::Type *MethodDescriptionListPtrTy;
  /// ProtocolListTy - LLVM type for struct objc_property_list.
  const llvm::Type *ProtocolListTy;
  /// ProtocolListPtrTy - LLVM type for struct objc_property_list*.
  const llvm::Type *ProtocolListPtrTy;
  /// CategoryTy - LLVM type for struct objc_category.
  const llvm::StructType *CategoryTy;
  /// ClassTy - LLVM type for struct objc_class.
  const llvm::StructType *ClassTy;
  /// ClassPtrTy - LLVM type for struct objc_class *.
  const llvm::Type *ClassPtrTy;
  /// ClassExtensionTy - LLVM type for struct objc_class_ext.
  const llvm::StructType *ClassExtensionTy;
  /// ClassExtensionPtrTy - LLVM type for struct objc_class_ext *.
  const llvm::Type *ClassExtensionPtrTy;
  // IvarTy - LLVM type for struct objc_ivar.
  const llvm::StructType *IvarTy;
  /// IvarListTy - LLVM type for struct objc_ivar_list.
  const llvm::Type *IvarListTy;
  /// IvarListPtrTy - LLVM type for struct objc_ivar_list *.
  const llvm::Type *IvarListPtrTy;
  /// MethodListTy - LLVM type for struct objc_method_list.
  const llvm::Type *MethodListTy;
  /// MethodListPtrTy - LLVM type for struct objc_method_list *.
  const llvm::Type *MethodListPtrTy;
  
  /// ExceptionDataTy - LLVM type for struct _objc_exception_data.
  const llvm::Type *ExceptionDataTy;
  
  /// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
  llvm::Function *ExceptionTryEnterFn;

  /// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
  llvm::Function *ExceptionTryExitFn;

  /// ExceptionExtractFn - LLVM objc_exception_extract function.
  llvm::Function *ExceptionExtractFn;
  
  /// ExceptionMatchFn - LLVM objc_exception_match function.
  llvm::Function *ExceptionMatchFn;
  
  /// SetJmpFn - LLVM _setjmp function.
  llvm::Function *SetJmpFn;
  
  /// SyncEnterFn - LLVM object_sync_enter function.
  llvm::Function *SyncEnterFn;
  
  /// SyncExitFn - LLVM object_sync_exit function.
  llvm::Function *SyncExitFn;
  
public:
  ObjCTypesHelper(CodeGen::CodeGenModule &cgm);


  llvm::Function *getSendFn(bool IsSuper) {
    return IsSuper ? MessageSendSuperFn : MessageSendFn;
  }

  llvm::Function *getSendStretFn(bool IsSuper) {
    return IsSuper ? MessageSendSuperStretFn : MessageSendStretFn;
  }

  llvm::Function *getSendFpretFn(bool IsSuper) {
    return IsSuper ? MessageSendSuperFpretFn : MessageSendFpretFn;
  }
/// ObjCNonFragileABITypesHelper - will have all types needed by objective-c's
class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper {
  llvm::Function *MessageSendFixupFn, *MessageSendFpretFixupFn,
                 *MessageSendStretFixupFn, *MessageSendIdFixupFn,
                 *MessageSendIdStretFixupFn, *MessageSendSuper2FixupFn,
                 *MessageSendSuper2StretFixupFn;
          
  // MethodListnfABITy - LLVM for struct _method_list_t
  const llvm::StructType *MethodListnfABITy;
  
  // MethodListnfABIPtrTy - LLVM for struct _method_list_t*
  const llvm::Type *MethodListnfABIPtrTy;
  
  // ProtocolnfABITy = LLVM for struct _protocol_t
  const llvm::StructType *ProtocolnfABITy;
  
  // ProtocolnfABIPtrTy = LLVM for struct _protocol_t*
  const llvm::Type *ProtocolnfABIPtrTy;

  // ProtocolListnfABITy - LLVM for struct _objc_protocol_list
  const llvm::StructType *ProtocolListnfABITy;
  
  // ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list*
  const llvm::Type *ProtocolListnfABIPtrTy;
  
  // ClassnfABITy - LLVM for struct _class_t
  const llvm::StructType *ClassnfABITy;
  
  // ClassnfABIPtrTy - LLVM for struct _class_t*
  const llvm::Type *ClassnfABIPtrTy;
  
  // IvarnfABITy - LLVM for struct _ivar_t
  const llvm::StructType *IvarnfABITy;
  
  // IvarListnfABITy - LLVM for struct _ivar_list_t
  const llvm::StructType *IvarListnfABITy;
  
  // IvarListnfABIPtrTy = LLVM for struct _ivar_list_t*
  const llvm::Type *IvarListnfABIPtrTy;
  
  // ClassRonfABITy - LLVM for struct _class_ro_t
  const llvm::StructType *ClassRonfABITy;
  
  // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
  const llvm::Type *ImpnfABITy;
  
  // CategorynfABITy - LLVM for struct _category_t
  const llvm::StructType *CategorynfABITy;
  
  // New types for nonfragile abi messaging.
  
  // MessageRefTy - LLVM for:
  // struct _message_ref_t {
  //   IMP messenger;
  //   SEL name;
  // };
  const llvm::StructType *MessageRefTy;
  // MessageRefCTy - clang type for struct _message_ref_t
  QualType MessageRefCTy;
  
  // MessageRefPtrTy - LLVM for struct _message_ref_t*
  const llvm::Type *MessageRefPtrTy;
  // MessageRefCPtrTy - clang type for struct _message_ref_t*
  QualType MessageRefCPtrTy;
  // MessengerTy - Type of the messenger (shown as IMP above)
  const llvm::FunctionType *MessengerTy;
  
  // SuperMessageRefTy - LLVM for:
  // struct _super_message_ref_t {
  //   SUPER_IMP messenger;
  //   SEL name;
  // };
  const llvm::StructType *SuperMessageRefTy;
  
  // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
  const llvm::Type *SuperMessageRefPtrTy;
  
  ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
  ~ObjCNonFragileABITypesHelper(){}
};
  
class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
protected:
  CodeGen::CodeGenModule &CGM;
  // FIXME! May not be needing this after all.
  unsigned ObjCABI;
  /// LazySymbols - Symbols to generate a lazy reference for. See
  /// DefinedSymbols and FinishModule().
  std::set<IdentifierInfo*> LazySymbols;
  
  /// DefinedSymbols - External symbols which are defined by this
  /// module. The symbols in this list and LazySymbols are used to add
  /// special linker symbols which ensure that Objective-C modules are
  /// linked properly.
  std::set<IdentifierInfo*> DefinedSymbols;
  /// ClassNames - uniqued class names.
  llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassNames;
  /// MethodVarNames - uniqued method variable names.
  llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
  /// MethodVarTypes - uniqued method type signatures. We have to use
  /// a StringMap here because have no other unique reference.
  llvm::StringMap<llvm::GlobalVariable*> MethodVarTypes;
  /// MethodDefinitions - map of methods which have been defined in
  /// this translation unit.
  llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
  /// PropertyNames - uniqued method variable names.
  llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
  /// ClassReferences - uniqued class references.
  llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassReferences;
  /// SelectorReferences - uniqued selector references.
  llvm::DenseMap<Selector, llvm::GlobalVariable*> SelectorReferences;
  /// Protocols - Protocols for which an objc_protocol structure has
  /// been emitted. Forward declarations are handled by creating an
  /// empty structure whose initializer is filled in when/if defined.
  llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> Protocols;
  /// DefinedProtocols - Protocols which have actually been
  /// defined. We should not need this, see FIXME in GenerateProtocol.
  llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
  /// DefinedClasses - List of defined classes.
  std::vector<llvm::GlobalValue*> DefinedClasses;
  /// DefinedCategories - List of defined categories.
  std::vector<llvm::GlobalValue*> DefinedCategories;
  /// UsedGlobals - List of globals to pack into the llvm.used metadata
  /// to prevent them from being clobbered.
  std::vector<llvm::GlobalVariable*> UsedGlobals;
  /// GetNameForMethod - Return a name for the given method.
  /// \param[out] NameOut - The return value.
  void GetNameForMethod(const ObjCMethodDecl *OMD,
                        const ObjCContainerDecl *CD,
                        std::string &NameOut);
  
  /// GetMethodVarName - Return a unique constant for the given
  /// selector's name. The return value has type char *.
  llvm::Constant *GetMethodVarName(Selector Sel);
  llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
  llvm::Constant *GetMethodVarName(const std::string &Name);
  
  /// GetMethodVarType - Return a unique constant for the given
  /// selector's name. The return value has type char *.
  
  // FIXME: This is a horrible name.
  llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D);
  llvm::Constant *GetMethodVarType(const std::string &Name);
  
  /// GetPropertyName - Return a unique constant for the given
  /// name. The return value has type char *.
  llvm::Constant *GetPropertyName(IdentifierInfo *Ident);
  
  // FIXME: This can be dropped once string functions are unified.
  llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD,
                                        const Decl *Container);
  
  /// GetClassName - Return a unique constant for the given selector's
  /// name. The return value has type char *.
  llvm::Constant *GetClassName(IdentifierInfo *Ident);
  
  const RecordDecl *GetFirstIvarInRecord(const ObjCInterfaceDecl *OID,
                                         RecordDecl::field_iterator &FIV,
                                         RecordDecl::field_iterator &PIV);  
  /// EmitPropertyList - Emit the given property list. The return
  /// value has type PropertyListPtrTy.
  llvm::Constant *EmitPropertyList(const std::string &Name,
                                   const Decl *Container, 
                                   const ObjCContainerDecl *OCD,
                                   const ObjCCommonTypesHelper &ObjCTypes);
  
  /// GetProtocolRef - Return a reference to the internal protocol
  /// description, creating an empty one if it has not been
  /// defined. The return value has type ProtocolPtrTy.
  llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
  
public:
  CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm)
  { }
  
  virtual llvm::Constant *GenerateConstantString(const std::string &String);
  
  virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
                                         const ObjCContainerDecl *CD=0);
  
  virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
  
  /// 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;
  
  /// GetOrEmitProtocolRef - Get a forward reference to the protocol
  /// object for the given declaration, emitting it if needed. These
  /// forward references will be filled in with empty bodies if no
  /// definition is seen. The return value has type ProtocolPtrTy.
  virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
};
  
class CGObjCMac : public CGObjCCommonMac {
private:
  ObjCTypesHelper ObjCTypes;
  /// EmitImageInfo - Emit the image info marker used to encode some module
  /// level information.
  void EmitImageInfo();

  /// EmitModuleInfo - Another marker encoding module level
  /// information. 
  void EmitModuleInfo();

  /// EmitModuleSymols - Emit module symbols, the list of defined
  /// classes and categories. The result has type SymtabPtrTy.
  llvm::Constant *EmitModuleSymbols();

  /// FinishModule - Write out global data structures at the end of
  /// processing a translation unit.
  void FinishModule();
  /// EmitClassExtension - Generate the class extension structure used
  /// to store the weak ivar layout and properties. The return value
  /// has type ClassExtensionPtrTy.
  llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID);

  /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
  /// for the given class.
  llvm::Value *EmitClassRef(CGBuilderTy &Builder, 
                            const ObjCInterfaceDecl *ID);

  CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
                                  QualType ResultType,
                                  Selector Sel,
                                  QualType Arg0Ty,
                                  bool IsSuper,
                                  const CallArgList &CallArgs);
  /// EmitIvarList - Emit the ivar list for the given
  /// implementation. If ForClass is true the list of class ivars
  /// (i.e. metaclass ivars) is emitted, otherwise the list of
  /// interface ivars will be emitted. The return value has type
  /// IvarListPtrTy.
  llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID,
  /// EmitMetaClass - Emit a forward reference to the class structure
  /// for the metaclass of the given interface. The return value has
  /// type ClassPtrTy.
  llvm::Constant *EmitMetaClassRef(const ObjCInterfaceDecl *ID);

  /// EmitMetaClass - Emit a class structure for the metaclass of the
  /// given implementation. The return value has type ClassPtrTy.
  llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
                                llvm::Constant *Protocols,
                                const llvm::Type *InterfaceTy,
                                const ConstantVector &Methods);
  llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
  llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD);

  /// EmitMethodList - Emit the method list for the given
  /// implementation. The return value has type MethodListPtrTy.
  llvm::Constant *EmitMethodList(const std::string &Name,
                                 const char *Section,
                                 const ConstantVector &Methods);

  /// EmitMethodDescList - Emit a method description list for a list of
  /// method declarations. 
  ///  - TypeName: The name for the type containing the methods.
  ///  - IsProtocol: True iff these methods are for a protocol.
  ///  - ClassMethds: True iff these are class methods.
  ///  - Required: When true, only "required" methods are
  ///    listed. Similarly, when false only "optional" methods are
  ///    listed. For classes this should always be true.
  ///  - begin, end: The method list to output.
  ///
  /// The return value has type MethodDescriptionListPtrTy.
  llvm::Constant *EmitMethodDescList(const std::string &Name,
                                     const char *Section,
                                     const ConstantVector &Methods);
  /// 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);

  /// GetOrEmitProtocolRef - Get a forward reference to the protocol
  /// object for the given declaration, emitting it if needed. These
  /// forward references will be filled in with empty bodies if no
  /// definition is seen. The return value has type ProtocolPtrTy.
  virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
  /// EmitProtocolExtension - Generate the protocol extension
  /// structure used to store optional instance and class methods, and
  /// protocol properties. The return value has type
  /// ProtocolExtensionPtrTy.
  llvm::Constant *
  EmitProtocolExtension(const ObjCProtocolDecl *PD,
                        const ConstantVector &OptInstanceMethods,
                        const ConstantVector &OptClassMethods);

  /// EmitProtocolList - Generate the list of referenced
  /// protocols. The return value has type ProtocolListPtrTy.
  llvm::Constant *EmitProtocolList(const std::string &Name,
                                   ObjCProtocolDecl::protocol_iterator begin,
                                   ObjCProtocolDecl::protocol_iterator end);
  /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
  /// for the given selector.
  llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel);
  CGObjCMac(CodeGen::CodeGenModule &cgm);

  virtual llvm::Function *ModuleInitFunction();
  
  virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                                              QualType ResultType,
                                              Selector Sel,
                                              llvm::Value *Receiver,
                                              bool IsClassMessage,
                                              const CallArgList &CallArgs);

  virtual CodeGen::RValue 
  GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
                           QualType ResultType,
                           Selector Sel,
                           const ObjCInterfaceDecl *Class,
                           llvm::Value *Receiver,
                           bool IsClassMessage,
                           const CallArgList &CallArgs);
  virtual llvm::Value *GetClass(CGBuilderTy &Builder,
                                const ObjCInterfaceDecl *ID);
  virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel);
  virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);

  virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
  virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
                                           const ObjCProtocolDecl *PD);
  virtual llvm::Function *GetPropertyGetFunction();
  virtual llvm::Function *GetPropertySetFunction();
  virtual llvm::Function *EnumerationMutationFunction();
  virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
                                         const Stmt &S);
  virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
                             const ObjCAtThrowStmt &S);
  virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
                                         llvm::Value *AddrWeakObj); 
  virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
                                  llvm::Value *src, llvm::Value *dst); 
  virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
                                    llvm::Value *src, llvm::Value *dest);
  virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
                                  llvm::Value *src, llvm::Value *dest);
  virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
                                        llvm::Value *src, llvm::Value *dest);
  virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
                                      QualType ObjectTy,
                                      llvm::Value *BaseValue,
                                      const ObjCIvarDecl *Ivar,
                                      const FieldDecl *Field,
                                      unsigned CVRQualifiers);
  virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
                                      ObjCInterfaceDecl *Interface,
                                      const ObjCIvarDecl *Ivar);
class CGObjCNonFragileABIMac : public CGObjCCommonMac {
  ObjCNonFragileABITypesHelper ObjCTypes;
  llvm::GlobalVariable* ObjCEmptyCacheVar;
  llvm::GlobalVariable* ObjCEmptyVtableVar;
  /// MetaClassReferences - uniqued meta class references.
  llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> MetaClassReferences;
  
  /// FinishNonFragileABIModule - Write out global data structures at the end of
  /// processing a translation unit.
  void FinishNonFragileABIModule();
  
  llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags, 
                                unsigned InstanceStart,
                                unsigned InstanceSize,
                                const ObjCImplementationDecl *ID);
  llvm::GlobalVariable * BuildClassMetaData(std::string &ClassName,
                                            llvm::Constant *IsAGV, 
                                            llvm::Constant *SuperClassGV,
                                            llvm::Constant *ClassRoGV,
                                            bool HiddenVisibility);
  
  llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
  
  llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD);
  
  /// EmitMethodList - Emit the method list for the given
  /// implementation. The return value has type MethodListnfABITy.
  llvm::Constant *EmitMethodList(const std::string &Name,
                                 const char *Section,
                                 const ConstantVector &Methods);
  /// EmitIvarList - Emit the ivar list for the given
  /// implementation. If ForClass is true the list of class ivars
  /// (i.e. metaclass ivars) is emitted, otherwise the list of
  /// interface ivars will be emitted. The return value has type
  /// IvarListnfABIPtrTy.
  llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID);
  llvm::Constant *EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
                                    const ObjCIvarDecl *Ivar,
  /// 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);
    
  /// GetOrEmitProtocolRef - Get a forward reference to the protocol
  /// object for the given declaration, emitting it if needed. These
  /// forward references will be filled in with empty bodies if no
  /// definition is seen. The return value has type ProtocolPtrTy.
  virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
    
  /// EmitProtocolList - Generate the list of referenced
  /// protocols. The return value has type ProtocolListPtrTy.
  llvm::Constant *EmitProtocolList(const std::string &Name,
                                   ObjCProtocolDecl::protocol_iterator begin,
                                   ObjCProtocolDecl::protocol_iterator end);
  
  CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
                                  QualType ResultType,
                                  Selector Sel,
                                  QualType Arg0Ty,
                                  bool IsSuper,
                                  const CallArgList &CallArgs);
  /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
  /// for the given class.
  llvm::Value *EmitClassRef(CGBuilderTy &Builder, 
                            const ObjCInterfaceDecl *ID,
                            bool IsSuper = false);
  
  /// EmitMetaClassRef - Return a Value * of the address of _class_t
  /// meta-data
  llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder, 
                                const ObjCInterfaceDecl *ID);

  /// ObjCIvarOffsetVariable - Returns the ivar offset variable for
  /// the given ivar.
  ///
  llvm::GlobalVariable * ObjCIvarOffsetVariable(std::string &Name, 
                              const ObjCIvarDecl *Ivar);
  /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
  /// for the given selector.
  llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel);
  
  CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
  // FIXME. All stubs for now!
  virtual llvm::Function *ModuleInitFunction();
  
  virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                                              QualType ResultType,
                                              Selector Sel,
                                              llvm::Value *Receiver,
                                              bool IsClassMessage,
                                              const CallArgList &CallArgs);
  
  virtual CodeGen::RValue 
  GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
                           QualType ResultType,
                           Selector Sel,
                           const ObjCInterfaceDecl *Class,
                           llvm::Value *Receiver,
                           bool IsClassMessage,
                           const CallArgList &CallArgs);
  
  virtual llvm::Value *GetClass(CGBuilderTy &Builder,
  
  virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel)
    { return EmitSelector(Builder, Sel); }
  virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
  
  virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
  virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
  virtual llvm::Function *GetPropertyGetFunction(){ 
    return ObjCTypes.GetPropertyFn;
  }
  virtual llvm::Function *GetPropertySetFunction(){ 
    return ObjCTypes.SetPropertyFn; 
  }
  virtual llvm::Function *EnumerationMutationFunction() {
    return ObjCTypes.EnumerationMutationFn;
  }
  
  virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
                                         const Stmt &S) {
    CGF.ErrorUnsupported(&S, "try or synchronized statement");
  }
  virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
                             const ObjCAtThrowStmt &S);
  virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
                                         llvm::Value *AddrWeakObj);
  virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
                                  llvm::Value *src, llvm::Value *dst);
  virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
                                    llvm::Value *src, llvm::Value *dest);
  virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
                                  llvm::Value *src, llvm::Value *dest);
  virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
                                        llvm::Value *src, llvm::Value *dest);
  virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
                                      QualType ObjectTy,
                                      llvm::Value *BaseValue,
                                      const ObjCIvarDecl *Ivar,
                                      const FieldDecl *Field,
                                      unsigned CVRQualifiers);
  virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
                                      ObjCInterfaceDecl *Interface,
                                      const ObjCIvarDecl *Ivar);
} // end anonymous namespace

/* *** Helper Functions *** */

/// getConstantGEP() - Help routine to construct simple GEPs.
static llvm::Constant *getConstantGEP(llvm::Constant *C, 
                                      unsigned idx0,
                                      unsigned idx1) {
  llvm::Value *Idxs[] = {
    llvm::ConstantInt::get(llvm::Type::Int32Ty, idx0),
    llvm::ConstantInt::get(llvm::Type::Int32Ty, idx1)
  };
  return llvm::ConstantExpr::getGetElementPtr(C, Idxs, 2);
}

/* *** CGObjCMac Public Interface *** */
CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
                                                    ObjCTypes(cgm)
  EmitImageInfo();  
/// GetClass - Return a reference to the class for the given interface
/// decl.
llvm::Value *CGObjCMac::GetClass(CGBuilderTy &Builder,
                                 const ObjCInterfaceDecl *ID) {
  return EmitClassRef(Builder, ID);
}

/// GetSelector - Return the pointer to the unique'd string for this selector.
llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, Selector Sel) {
  return EmitSelector(Builder, Sel);
/// Generate a constant CFString object.
/* 
   struct __builtin_CFString {
     const int *isa; // point to __CFConstantStringClassReference
     int flags;
     const char *str;
     long length;
   };
*/

llvm::Constant *CGObjCCommonMac::GenerateConstantString(
                                                  const std::string &String) {
  return CGM.GetAddrOfConstantCFString(String);
}

/// Generates a message send where the super is the receiver.  This is
/// a message send to self with special delivery semantics indicating
/// which class's method should be called.
CodeGen::RValue
CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
                                    QualType ResultType,
                                    Selector Sel,
                                    const ObjCInterfaceDecl *Class,
                                    llvm::Value *Receiver,
                                    bool IsClassMessage,
                                    const CodeGen::CallArgList &CallArgs) {
  // Create and init a super structure; this is a (receiver, class)
  // pair we will pass to objc_msgSendSuper.
  llvm::Value *ObjCSuper = 
    CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super");
  llvm::Value *ReceiverAsObject = 
    CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
  CGF.Builder.CreateStore(ReceiverAsObject, 
                          CGF.Builder.CreateStructGEP(ObjCSuper, 0));

  // If this is a class message the metaclass is passed as the target.
  llvm::Value *Target;
  if (IsClassMessage) {
    llvm::Value *MetaClassPtr = EmitMetaClassRef(Class);
    llvm::Value *SuperPtr = CGF.Builder.CreateStructGEP(MetaClassPtr, 1);
    llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr);
    Target = Super;
  } else {
    Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
  }
  // FIXME: We shouldn't need to do this cast, rectify the ASTContext
  // and ObjCTypes types.
  const llvm::Type *ClassTy = 
    CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
  Target = CGF.Builder.CreateBitCast(Target, ClassTy);
  CGF.Builder.CreateStore(Target, 
                          CGF.Builder.CreateStructGEP(ObjCSuper, 1));
    
  return EmitMessageSend(CGF, ResultType, Sel, 
                         ObjCSuper, ObjCTypes.SuperPtrCTy,
                         true, CallArgs);
/// Generate code for a message send expression.  
CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                                               QualType ResultType,
                                               Selector Sel,
                                               llvm::Value *Receiver,
                                               bool IsClassMessage,
                                               const CallArgList &CallArgs) {
  llvm::Value *Arg0 = 
    CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy, "tmp");
  return EmitMessageSend(CGF, ResultType, Sel,
                         Arg0, CGF.getContext().getObjCIdType(),
                         false, CallArgs);
}

CodeGen::RValue CGObjCMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
                                           QualType ResultType,
                                           Selector Sel,
                                           QualType Arg0Ty,
                                           bool IsSuper,
                                           const CallArgList &CallArgs) {
  CallArgList ActualArgs;
  ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty));
  ActualArgs.push_back(std::make_pair(RValue::get(EmitSelector(CGF.Builder, 
                                                               Sel)),
                                      CGF.getContext().getObjCSelType()));
  ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
  CodeGenTypes &Types = CGM.getTypes();
  const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
  const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, false);
Daniel Dunbar's avatar
Daniel Dunbar committed
  if (CGM.ReturnTypeUsesSret(FnInfo)) {
    Fn = ObjCTypes.getSendStretFn(IsSuper);
  } else if (ResultType->isFloatingType()) {
    // FIXME: Sadly, this is wrong. This actually depends on the
    // architecture. This happens to be right for x86-32 though.
    Fn = ObjCTypes.getSendFpretFn(IsSuper);
  } else {
    Fn = ObjCTypes.getSendFn(IsSuper);
  }
  Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
Daniel Dunbar's avatar
Daniel Dunbar committed
  return CGF.EmitCall(FnInfo, Fn, ActualArgs);
llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, 
                                            const ObjCProtocolDecl *PD) {
  // FIXME: I don't understand why gcc generates this, or where it is
  // resolved. Investigate. Its also wasteful to look this up over and
  // over.
  LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));

  return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
                                        ObjCTypes.ExternalProtocolPtrTy);
}

void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
  // FIXME: We shouldn't need this, the protocol decl should contain
  // enough information to tell us whether this was a declaration or a
  // definition.
  DefinedProtocols.insert(PD->getIdentifier());

  // If we have generated a forward reference to this protocol, emit
  // it now. Otherwise do nothing, the protocol objects are lazily
  // emitted.
  if (Protocols.count(PD->getIdentifier())) 
    GetOrEmitProtocol(PD);
}

llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
  if (DefinedProtocols.count(PD->getIdentifier()))
    return GetOrEmitProtocol(PD);
  return GetOrEmitProtocolRef(PD);
}

/*
     // APPLE LOCAL radar 4585769 - Objective-C 1.0 extensions
  struct _objc_protocol {
    struct _objc_protocol_extension *isa;
    char *protocol_name;
    struct _objc_protocol_list *protocol_list;
    struct _objc__method_prototype_list *instance_methods;
    struct _objc__method_prototype_list *class_methods
  };

  See EmitProtocolExtension().
*/
llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
  llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];

  // Early exit if a defining object has already been generated.
  if (Entry && Entry->hasInitializer())
    return Entry;

  // FIXME: I don't understand why gcc generates this, or where it is
  // resolved. Investigate. Its also wasteful to look this up over and
  // over.
  LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));

  const char *ProtocolName = PD->getNameAsCString();

  // Construct method lists.
  std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
  std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
  for (ObjCProtocolDecl::instmeth_iterator i = PD->instmeth_begin(),
         e = PD->instmeth_end(); i != e; ++i) {
    ObjCMethodDecl *MD = *i;
    llvm::Constant *C = GetMethodDescriptionConstant(MD);
    if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
      OptInstanceMethods.push_back(C);
    } else {
      InstanceMethods.push_back(C);
    }      
  }

  for (ObjCProtocolDecl::classmeth_iterator i = PD->classmeth_begin(),
         e = PD->classmeth_end(); i != e; ++i) {
    ObjCMethodDecl *MD = *i;
    llvm::Constant *C = GetMethodDescriptionConstant(MD);
    if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
      OptClassMethods.push_back(C);
    } else {
      ClassMethods.push_back(C);
    }      
  }

  std::vector<llvm::Constant*> Values(5);
  Values[0] = EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods);
  Values[1] = GetClassName(PD->getIdentifier());
    EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getNameAsString(),
                     PD->protocol_begin(),
                     PD->protocol_end());
    EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_"
                          + PD->getNameAsString(),
                       "__OBJC,__cat_inst_meth,regular,no_dead_strip",
                       InstanceMethods);
  Values[4] = 
    EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" 
                            + PD->getNameAsString(),
                       "__OBJC,__cat_cls_meth,regular,no_dead_strip",
                       ClassMethods);
  llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
                                                   Values);