2008-08-11 10:45:11 +08:00
|
|
|
//===------- 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"
|
2008-08-12 05:35:06 +08:00
|
|
|
|
|
|
|
#include "CodeGenModule.h"
|
2008-08-16 11:19:19 +08:00
|
|
|
#include "CodeGenFunction.h"
|
2008-08-12 08:12:39 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 12:54:23 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
2008-08-13 11:21:16 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2008-08-12 05:35:06 +08:00
|
|
|
#include "clang/Basic/LangOptions.h"
|
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
#include "llvm/Module.h"
|
2008-08-11 10:45:11 +08:00
|
|
|
#include "llvm/Support/IRBuilder.h"
|
2008-08-12 14:48:42 +08:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2008-08-16 11:19:19 +08:00
|
|
|
#include <sstream>
|
2008-08-11 10:45:11 +08:00
|
|
|
|
|
|
|
using namespace clang;
|
2008-09-09 09:06:48 +08:00
|
|
|
using namespace CodeGen;
|
2008-08-11 10:45:11 +08:00
|
|
|
|
|
|
|
namespace {
|
2008-08-12 08:12:39 +08:00
|
|
|
|
2008-08-27 10:31:56 +08:00
|
|
|
typedef std::vector<llvm::Constant*> ConstantVector;
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
// FIXME: We should find a nicer way to make the labels for
|
|
|
|
// metadata, string concatenation is lame.
|
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
/// ObjCTypesHelper - Helper class that encapsulates lazy
|
|
|
|
/// construction of varies types used during ObjC generation.
|
|
|
|
class ObjCTypesHelper {
|
|
|
|
private:
|
|
|
|
CodeGen::CodeGenModule &CGM;
|
|
|
|
|
2008-08-23 17:25:55 +08:00
|
|
|
llvm::Function *MessageSendFn, *MessageSendStretFn;
|
|
|
|
llvm::Function *MessageSendSuperFn, *MessageSendSuperStretFn;
|
2008-08-12 11:39:23 +08:00
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
public:
|
2008-08-21 12:36:09 +08:00
|
|
|
const llvm::Type *ShortTy, *IntTy, *LongTy;
|
|
|
|
const llvm::Type *Int8PtrTy;
|
2008-08-12 11:39:23 +08:00
|
|
|
|
2008-08-12 13:28:47 +08:00
|
|
|
/// ObjectPtrTy - LLVM type for object handles (typeof(id))
|
|
|
|
const llvm::Type *ObjectPtrTy;
|
2008-08-12 14:48:42 +08:00
|
|
|
/// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
|
2008-08-12 13:28:47 +08:00
|
|
|
const llvm::Type *SelectorPtrTy;
|
2008-08-13 11:21:16 +08:00
|
|
|
/// ProtocolPtrTy - LLVM type for external protocol handles
|
|
|
|
/// (typeof(Protocol))
|
|
|
|
const llvm::Type *ExternalProtocolPtrTy;
|
2008-08-12 14:48:42 +08:00
|
|
|
|
2008-08-30 11:02:31 +08:00
|
|
|
// SuperCTy - clang type for struct objc_super.
|
|
|
|
QualType SuperCTy;
|
|
|
|
// SuperPtrCTy - clang type for struct objc_super *.
|
|
|
|
QualType SuperPtrCTy;
|
|
|
|
|
2008-08-23 12:28:29 +08:00
|
|
|
/// SuperTy - LLVM type for struct objc_super.
|
|
|
|
const llvm::StructType *SuperTy;
|
2008-08-23 17:25:55 +08:00
|
|
|
/// SuperPtrTy - LLVM type for struct objc_super *.
|
|
|
|
const llvm::Type *SuperPtrTy;
|
2008-08-23 12:28:29 +08:00
|
|
|
|
2008-08-12 14:48:42 +08:00
|
|
|
/// SymtabTy - LLVM type for struct objc_symtab.
|
|
|
|
const llvm::StructType *SymtabTy;
|
2008-08-21 12:36:09 +08:00
|
|
|
/// SymtabPtrTy - LLVM type for struct objc_symtab *.
|
|
|
|
const llvm::Type *SymtabPtrTy;
|
2008-08-12 14:48:42 +08:00
|
|
|
/// ModuleTy - LLVM type for struct objc_module.
|
|
|
|
const llvm::StructType *ModuleTy;
|
2008-08-12 11:39:23 +08:00
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
/// 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;
|
2008-08-23 08:19:03 +08:00
|
|
|
/// 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;
|
2008-08-13 11:21:16 +08:00
|
|
|
/// PropertyListPtrTy - LLVM type for struct objc_property_list*.
|
|
|
|
const llvm::Type *PropertyListPtrTy;
|
|
|
|
/// ProtocolListTy - LLVM type for struct objc_property_list.
|
|
|
|
const llvm::Type *ProtocolListTy;
|
|
|
|
/// ProtocolListPtrTy - LLVM type for struct objc_property_list*.
|
|
|
|
const llvm::Type *ProtocolListPtrTy;
|
2008-08-23 04:34:54 +08:00
|
|
|
/// CategoryTy - LLVM type for struct objc_category.
|
|
|
|
const llvm::StructType *CategoryTy;
|
2008-08-21 12:36:09 +08:00
|
|
|
/// 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;
|
|
|
|
/// CacheTy - LLVM type for struct objc_cache.
|
|
|
|
const llvm::Type *CacheTy;
|
|
|
|
/// CachePtrTy - LLVM type for struct objc_cache *.
|
|
|
|
const llvm::Type *CachePtrTy;
|
|
|
|
// 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;
|
|
|
|
// MethodTy - LLVM type for struct objc_method.
|
|
|
|
const llvm::StructType *MethodTy;
|
|
|
|
/// MethodListTy - LLVM type for struct objc_method_list.
|
|
|
|
const llvm::Type *MethodListTy;
|
|
|
|
/// MethodListPtrTy - LLVM type for struct objc_method_list *.
|
|
|
|
const llvm::Type *MethodListPtrTy;
|
2008-08-13 11:21:16 +08:00
|
|
|
|
2008-09-24 11:38:44 +08:00
|
|
|
llvm::Function *GetPropertyFn, *SetPropertyFn;
|
2008-08-31 12:05:03 +08:00
|
|
|
llvm::Function *EnumerationMutationFn;
|
2008-09-09 18:10:21 +08:00
|
|
|
|
|
|
|
/// ExceptionDataTy - LLVM type for struct _objc_exception_data.
|
|
|
|
const llvm::Type *ExceptionDataTy;
|
|
|
|
|
|
|
|
/// ExceptionThrowFn - LLVM objc_exception_throw function.
|
|
|
|
llvm::Function *ExceptionThrowFn;
|
|
|
|
|
|
|
|
/// 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;
|
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
public:
|
|
|
|
ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
|
|
|
|
~ObjCTypesHelper();
|
|
|
|
|
2008-09-10 15:00:50 +08:00
|
|
|
llvm::Constant *getMessageSendFn(bool IsSuper, bool isStret);
|
2008-08-12 08:12:39 +08:00
|
|
|
};
|
|
|
|
|
2008-08-11 10:45:11 +08:00
|
|
|
class CGObjCMac : public CodeGen::CGObjCRuntime {
|
|
|
|
private:
|
2008-08-12 08:12:39 +08:00
|
|
|
CodeGen::CodeGenModule &CGM;
|
|
|
|
ObjCTypesHelper ObjCTypes;
|
|
|
|
/// ObjCABI - FIXME: Not sure yet.
|
|
|
|
unsigned ObjCABI;
|
2008-08-11 10:45:11 +08:00
|
|
|
|
2008-08-25 14:02:07 +08:00
|
|
|
/// 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;
|
|
|
|
|
2008-08-12 14:48:42 +08:00
|
|
|
/// ClassNames - uniqued class names.
|
2008-08-13 11:21:16 +08:00
|
|
|
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassNames;
|
2008-08-12 14:48:42 +08:00
|
|
|
|
2008-08-12 11:39:23 +08:00
|
|
|
/// MethodVarNames - uniqued method variable names.
|
|
|
|
llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
/// MethodVarTypes - uniqued method type signatures. We have to use
|
|
|
|
/// a StringMap here because have no other unique reference.
|
|
|
|
llvm::StringMap<llvm::GlobalVariable*> MethodVarTypes;
|
|
|
|
|
2008-08-27 05:51:14 +08:00
|
|
|
/// MethodDefinitions - map of methods which have been defined in
|
|
|
|
/// this translation unit.
|
|
|
|
llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
|
|
|
|
|
2008-08-23 08:19:03 +08:00
|
|
|
/// PropertyNames - uniqued method variable names.
|
|
|
|
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
/// ClassReferences - uniqued class references.
|
|
|
|
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassReferences;
|
|
|
|
|
2008-08-12 11:39:23 +08:00
|
|
|
/// SelectorReferences - uniqued selector references.
|
|
|
|
llvm::DenseMap<Selector, llvm::GlobalVariable*> SelectorReferences;
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
/// 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;
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
/// DefinedClasses - List of defined classes.
|
|
|
|
std::vector<llvm::GlobalValue*> DefinedClasses;
|
|
|
|
|
|
|
|
/// DefinedCategories - List of defined categories.
|
|
|
|
std::vector<llvm::GlobalValue*> DefinedCategories;
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
/// UsedGlobals - List of globals to pack into the llvm.used metadata
|
2008-08-12 05:35:06 +08:00
|
|
|
/// to prevent them from being clobbered.
|
2008-08-12 14:48:42 +08:00
|
|
|
std::vector<llvm::GlobalVariable*> UsedGlobals;
|
2008-08-12 05:35:06 +08:00
|
|
|
|
|
|
|
/// EmitImageInfo - Emit the image info marker used to encode some module
|
|
|
|
/// level information.
|
|
|
|
void EmitImageInfo();
|
|
|
|
|
2008-08-12 14:48:42 +08:00
|
|
|
/// EmitModuleInfo - Another marker encoding module level
|
|
|
|
/// information.
|
|
|
|
void EmitModuleInfo();
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
/// EmitModuleSymols - Emit module symbols, the list of defined
|
|
|
|
/// classes and categories. The result has type SymtabPtrTy.
|
2008-08-12 14:48:42 +08:00
|
|
|
llvm::Constant *EmitModuleSymbols();
|
|
|
|
|
2008-08-12 05:35:06 +08:00
|
|
|
/// FinishModule - Write out global data structures at the end of
|
|
|
|
/// processing a translation unit.
|
|
|
|
void FinishModule();
|
2008-08-13 11:21:16 +08:00
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
/// 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(llvm::IRBuilder<> &Builder,
|
|
|
|
const ObjCInterfaceDecl *ID);
|
|
|
|
|
2008-08-23 17:25:55 +08:00
|
|
|
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-23 17:25:55 +08:00
|
|
|
llvm::Value *Arg0,
|
2008-08-30 11:02:31 +08:00
|
|
|
QualType Arg0Ty,
|
|
|
|
bool IsSuper,
|
|
|
|
const CallArgList &CallArgs);
|
2008-08-23 17:25:55 +08:00
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
/// 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,
|
|
|
|
bool ForClass,
|
|
|
|
const llvm::Type *InterfaceTy);
|
2008-08-25 16:19:24 +08:00
|
|
|
|
|
|
|
/// 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);
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
/// EmitMetaClass - Emit a class structure for the metaclass of the
|
2008-08-25 16:19:24 +08:00
|
|
|
/// given implementation. The return value has type ClassPtrTy.
|
2008-08-21 12:36:09 +08:00
|
|
|
llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
|
|
|
|
llvm::Constant *Protocols,
|
2008-08-27 05:51:14 +08:00
|
|
|
const llvm::Type *InterfaceTy,
|
2008-08-27 10:31:56 +08:00
|
|
|
const ConstantVector &Methods);
|
|
|
|
|
|
|
|
llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
|
|
|
|
|
|
|
|
llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD);
|
2008-08-21 12:36:09 +08:00
|
|
|
|
|
|
|
/// EmitMethodList - Emit the method list for the given
|
2008-08-26 16:29:31 +08:00
|
|
|
/// implementation. The return value has type MethodListPtrTy.
|
2008-08-23 04:34:54 +08:00
|
|
|
llvm::Constant *EmitMethodList(const std::string &Name,
|
|
|
|
const char *Section,
|
2008-08-27 10:31:56 +08:00
|
|
|
const ConstantVector &Methods);
|
2008-08-21 12:36:09 +08:00
|
|
|
|
|
|
|
/// EmitMethodDescList - Emit a method description list for a list of
|
2008-08-13 11:21:16 +08:00
|
|
|
/// 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.
|
2008-08-27 10:31:56 +08:00
|
|
|
llvm::Constant *EmitMethodDescList(const std::string &Name,
|
|
|
|
const char *Section,
|
|
|
|
const ConstantVector &Methods);
|
2008-08-13 11:21:16 +08:00
|
|
|
|
2008-08-23 08:19:03 +08:00
|
|
|
/// EmitPropertyList - Emit the given property list. The return
|
|
|
|
/// value has type PropertyListPtrTy.
|
|
|
|
llvm::Constant *EmitPropertyList(const std::string &Name,
|
2008-08-28 12:38:10 +08:00
|
|
|
const Decl *Container,
|
2008-08-23 08:19:03 +08:00
|
|
|
ObjCPropertyDecl * const *begin,
|
|
|
|
ObjCPropertyDecl * const *end);
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
/// EmitProtocolExtension - Generate the protocol extension
|
|
|
|
/// structure used to store optional instance and class methods, and
|
|
|
|
/// protocol properties. The return value has type
|
|
|
|
/// ProtocolExtensionPtrTy.
|
2008-08-27 10:31:56 +08:00
|
|
|
llvm::Constant *
|
|
|
|
EmitProtocolExtension(const ObjCProtocolDecl *PD,
|
|
|
|
const ConstantVector &OptInstanceMethods,
|
|
|
|
const ConstantVector &OptClassMethods);
|
2008-08-13 11:21:16 +08:00
|
|
|
|
|
|
|
/// EmitProtocolList - Generate the list of referenced
|
|
|
|
/// protocols. The return value has type ProtocolListPtrTy.
|
2008-08-22 05:57:41 +08:00
|
|
|
llvm::Constant *EmitProtocolList(const std::string &Name,
|
|
|
|
ObjCProtocolDecl::protocol_iterator begin,
|
|
|
|
ObjCProtocolDecl::protocol_iterator end);
|
2008-08-13 11:21:16 +08:00
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
|
|
|
|
/// for the given selector.
|
|
|
|
llvm::Value *EmitSelector(llvm::IRBuilder<> &Builder, Selector Sel);
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
/// GetProtocolRef - Return a reference to the internal protocol
|
|
|
|
/// description, creating an empty one if it has not been
|
|
|
|
/// defined. The return value has type pointer-to ProtocolTy.
|
|
|
|
llvm::GlobalVariable *GetProtocolRef(const ObjCProtocolDecl *PD);
|
|
|
|
|
2008-08-12 14:48:42 +08:00
|
|
|
/// GetClassName - Return a unique constant for the given selector's
|
2008-08-21 12:36:09 +08:00
|
|
|
/// name. The return value has type char *.
|
2008-08-13 11:21:16 +08:00
|
|
|
llvm::Constant *GetClassName(IdentifierInfo *Ident);
|
2008-08-12 14:48:42 +08:00
|
|
|
|
2008-08-12 11:39:23 +08:00
|
|
|
/// GetMethodVarName - Return a unique constant for the given
|
2008-08-23 08:19:03 +08:00
|
|
|
/// selector's name. The return value has type char *.
|
2008-08-12 11:39:23 +08:00
|
|
|
llvm::Constant *GetMethodVarName(Selector Sel);
|
2008-08-23 08:19:03 +08:00
|
|
|
llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
|
2008-08-21 12:36:09 +08:00
|
|
|
llvm::Constant *GetMethodVarName(const std::string &Name);
|
2008-08-12 05:35:06 +08:00
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
/// GetMethodVarType - Return a unique constant for the given
|
2008-08-23 08:19:03 +08:00
|
|
|
/// selector's name. The return value has type char *.
|
|
|
|
|
|
|
|
// FIXME: This is a horrible name.
|
2008-08-27 05:51:14 +08:00
|
|
|
llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D);
|
2008-08-21 12:36:09 +08:00
|
|
|
llvm::Constant *GetMethodVarType(const std::string &Name);
|
2008-08-13 11:21:16 +08:00
|
|
|
|
2008-08-23 08:19:03 +08:00
|
|
|
/// GetPropertyName - Return a unique constant for the given
|
|
|
|
/// name. The return value has type char *.
|
|
|
|
llvm::Constant *GetPropertyName(IdentifierInfo *Ident);
|
|
|
|
|
2008-08-28 12:38:10 +08:00
|
|
|
// FIXME: This can be dropped once string functions are unified.
|
|
|
|
llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD,
|
|
|
|
const Decl *Container);
|
2008-08-23 08:19:03 +08:00
|
|
|
|
2008-08-16 11:19:19 +08:00
|
|
|
/// GetNameForMethod - Return a name for the given method.
|
|
|
|
/// \param[out] NameOut - The return value.
|
|
|
|
void GetNameForMethod(const ObjCMethodDecl *OMD,
|
|
|
|
std::string &NameOut);
|
|
|
|
|
2008-08-11 10:45:11 +08:00
|
|
|
public:
|
|
|
|
CGObjCMac(CodeGen::CodeGenModule &cgm);
|
2008-08-12 08:12:39 +08:00
|
|
|
virtual llvm::Constant *GenerateConstantString(const std::string &String);
|
2008-08-11 10:45:11 +08:00
|
|
|
|
2008-08-23 11:46:30 +08:00
|
|
|
virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-25 16:19:24 +08:00
|
|
|
llvm::Value *Receiver,
|
2008-08-30 11:02:31 +08:00
|
|
|
bool IsClassMessage,
|
|
|
|
const CallArgList &CallArgs);
|
2008-08-23 11:46:30 +08:00
|
|
|
|
|
|
|
virtual CodeGen::RValue
|
|
|
|
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-25 16:19:24 +08:00
|
|
|
const ObjCInterfaceDecl *Class,
|
|
|
|
llvm::Value *Receiver,
|
2008-08-30 11:02:31 +08:00
|
|
|
bool IsClassMessage,
|
|
|
|
const CallArgList &CallArgs);
|
2008-08-16 08:25:02 +08:00
|
|
|
|
|
|
|
virtual llvm::Value *GetClass(llvm::IRBuilder<> &Builder,
|
2008-08-21 12:36:09 +08:00
|
|
|
const ObjCInterfaceDecl *ID);
|
2008-08-11 10:45:11 +08:00
|
|
|
|
|
|
|
virtual llvm::Value *GetSelector(llvm::IRBuilder<> &Builder, Selector Sel);
|
|
|
|
|
2008-08-16 06:20:32 +08:00
|
|
|
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD);
|
|
|
|
|
|
|
|
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
|
|
|
|
|
|
|
|
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
|
2008-08-11 10:45:11 +08:00
|
|
|
|
|
|
|
virtual llvm::Value *GenerateProtocolRef(llvm::IRBuilder<> &Builder,
|
2008-08-13 08:59:25 +08:00
|
|
|
const ObjCProtocolDecl *PD);
|
2008-08-11 10:45:11 +08:00
|
|
|
|
2008-08-13 08:59:25 +08:00
|
|
|
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
|
2008-08-11 10:45:11 +08:00
|
|
|
|
|
|
|
virtual llvm::Function *ModuleInitFunction();
|
2008-09-24 11:38:44 +08:00
|
|
|
virtual llvm::Function *GetPropertyGetFunction();
|
|
|
|
virtual llvm::Function *GetPropertySetFunction();
|
2008-08-31 12:05:03 +08:00
|
|
|
virtual llvm::Function *EnumerationMutationFunction();
|
2008-09-09 18:04:29 +08:00
|
|
|
|
|
|
|
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
|
|
|
|
const ObjCAtTryStmt &S);
|
|
|
|
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
|
|
|
|
const ObjCAtThrowStmt &S);
|
|
|
|
|
2008-08-11 10:45:11 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
2008-08-12 08:12:39 +08:00
|
|
|
|
|
|
|
/* *** 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 *** */
|
2008-08-11 10:45:11 +08:00
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm)
|
|
|
|
: CGM(cgm),
|
|
|
|
ObjCTypes(cgm),
|
|
|
|
ObjCABI(1)
|
|
|
|
{
|
|
|
|
// FIXME: How does this get set in GCC? And what does it even mean?
|
|
|
|
if (ObjCTypes.LongTy != CGM.getTypes().ConvertType(CGM.getContext().IntTy))
|
|
|
|
ObjCABI = 2;
|
|
|
|
|
|
|
|
EmitImageInfo();
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
2008-08-16 08:25:02 +08:00
|
|
|
/// GetClass - Return a reference to the class for the given interface
|
|
|
|
/// decl.
|
|
|
|
llvm::Value *CGObjCMac::GetClass(llvm::IRBuilder<> &Builder,
|
2008-08-21 12:36:09 +08:00
|
|
|
const ObjCInterfaceDecl *ID) {
|
|
|
|
return EmitClassRef(Builder, ID);
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// GetSelector - Return the pointer to the unique'd string for this selector.
|
|
|
|
llvm::Value *CGObjCMac::GetSelector(llvm::IRBuilder<> &Builder, Selector Sel) {
|
2008-08-12 11:39:23 +08:00
|
|
|
return EmitSelector(Builder, Sel);
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
/// Generate a constant CFString object.
|
|
|
|
/*
|
|
|
|
struct __builtin_CFString {
|
|
|
|
const int *isa; // point to __CFConstantStringClassReference
|
|
|
|
int flags;
|
|
|
|
const char *str;
|
|
|
|
long length;
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
|
|
|
llvm::Constant *CGObjCMac::GenerateConstantString(const std::string &String) {
|
2008-08-24 02:37:06 +08:00
|
|
|
return CGM.GetAddrOfConstantCFString(String);
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
2008-08-23 11:46:30 +08:00
|
|
|
CodeGen::RValue
|
|
|
|
CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-25 16:19:24 +08:00
|
|
|
const ObjCInterfaceDecl *Class,
|
|
|
|
llvm::Value *Receiver,
|
2008-08-30 11:02:31 +08:00
|
|
|
bool IsClassMessage,
|
2008-09-09 09:06:48 +08:00
|
|
|
const CodeGen::CallArgList &CallArgs) {
|
2008-08-23 12:28:29 +08:00
|
|
|
// 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));
|
|
|
|
|
2008-08-25 16:19:24 +08:00
|
|
|
// 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());
|
|
|
|
}
|
2008-08-30 11:02:31 +08:00
|
|
|
// 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);
|
2008-08-25 16:19:24 +08:00
|
|
|
CGF.Builder.CreateStore(Target,
|
|
|
|
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
|
|
|
|
|
2008-08-30 13:35:15 +08:00
|
|
|
return EmitMessageSend(CGF, ResultType, Sel,
|
2008-08-30 11:02:31 +08:00
|
|
|
ObjCSuper, ObjCTypes.SuperPtrCTy,
|
|
|
|
true, CallArgs);
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
2008-08-23 17:25:55 +08:00
|
|
|
|
2008-08-11 10:45:11 +08:00
|
|
|
/// Generate code for a message send expression.
|
2008-08-23 11:46:30 +08:00
|
|
|
CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-25 16:19:24 +08:00
|
|
|
llvm::Value *Receiver,
|
2008-08-30 11:02:31 +08:00
|
|
|
bool IsClassMessage,
|
|
|
|
const CallArgList &CallArgs) {
|
2008-08-23 17:25:55 +08:00
|
|
|
llvm::Value *Arg0 =
|
|
|
|
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy, "tmp");
|
2008-08-30 13:35:15 +08:00
|
|
|
return EmitMessageSend(CGF, ResultType, Sel,
|
2008-08-30 11:02:31 +08:00
|
|
|
Arg0, CGF.getContext().getObjCIdType(),
|
|
|
|
false, CallArgs);
|
2008-08-23 17:25:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CodeGen::RValue CGObjCMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-23 17:25:55 +08:00
|
|
|
llvm::Value *Arg0,
|
2008-08-30 11:02:31 +08:00
|
|
|
QualType Arg0Ty,
|
|
|
|
bool IsSuper,
|
|
|
|
const CallArgList &CallArgs) {
|
|
|
|
CallArgList ActualArgs;
|
2008-09-09 09:06:48 +08:00
|
|
|
ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty));
|
|
|
|
ActualArgs.push_back(std::make_pair(RValue::get(EmitSelector(CGF.Builder,
|
|
|
|
Sel)),
|
2008-08-30 11:02:31 +08:00
|
|
|
CGF.getContext().getObjCSelType()));
|
|
|
|
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
|
2008-08-16 06:20:32 +08:00
|
|
|
|
2008-09-10 15:00:50 +08:00
|
|
|
const llvm::FunctionType *FTy =
|
|
|
|
CGM.getTypes().GetFunctionType(CGCallInfo(ResultType, ActualArgs),
|
|
|
|
false);
|
|
|
|
llvm::Constant *Fn =
|
|
|
|
ObjCTypes.getMessageSendFn(IsSuper, CGM.ReturnTypeUsesSret(ResultType));
|
|
|
|
Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
|
2008-09-10 07:48:28 +08:00
|
|
|
return CGF.EmitCall(Fn, ResultType, ActualArgs);
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Value *CGObjCMac::GenerateProtocolRef(llvm::IRBuilder<> &Builder,
|
2008-08-13 08:59:25 +08:00
|
|
|
const ObjCProtocolDecl *PD) {
|
2008-09-04 12:33:15 +08:00
|
|
|
// 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"));
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
|
|
|
|
ObjCTypes.ExternalProtocolPtrTy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
// 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().
|
|
|
|
*/
|
|
|
|
void CGObjCMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
|
2008-08-25 14:02:07 +08:00
|
|
|
// 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"));
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
const char *ProtocolName = PD->getName();
|
2008-08-27 10:31:56 +08:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
std::vector<llvm::Constant*> Values(5);
|
2008-08-27 10:31:56 +08:00
|
|
|
Values[0] = EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods);
|
2008-08-13 11:21:16 +08:00
|
|
|
Values[1] = GetClassName(PD->getIdentifier());
|
2008-08-22 05:57:41 +08:00
|
|
|
Values[2] =
|
|
|
|
EmitProtocolList(std::string("\01L_OBJC_PROTOCOL_REFS_")+PD->getName(),
|
|
|
|
PD->protocol_begin(),
|
|
|
|
PD->protocol_end());
|
2008-08-27 10:31:56 +08:00
|
|
|
Values[3] =
|
|
|
|
EmitMethodDescList(std::string("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_")
|
|
|
|
+ PD->getName(),
|
|
|
|
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
|
|
|
|
InstanceMethods);
|
|
|
|
Values[4] =
|
|
|
|
EmitMethodDescList(std::string("\01L_OBJC_PROTOCOL_CLASS_METHODS_")
|
|
|
|
+ PD->getName(),
|
|
|
|
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
|
|
|
|
ClassMethods);
|
2008-08-13 11:21:16 +08:00
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
|
|
|
|
Values);
|
|
|
|
|
|
|
|
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
|
|
|
|
if (Entry) {
|
|
|
|
// Already created, just update the initializer
|
|
|
|
Entry->setInitializer(Init);
|
|
|
|
} else {
|
|
|
|
Entry =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.ProtocolTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
|
|
|
std::string("\01L_OBJC_PROTOCOL_")+ProtocolName,
|
|
|
|
&CGM.getModule());
|
|
|
|
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(Entry);
|
|
|
|
// FIXME: Is this necessary? Why only for protocol?
|
|
|
|
Entry->setAlignment(4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::GlobalVariable *CGObjCMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
|
|
|
|
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
|
|
|
|
|
|
|
|
if (!Entry) {
|
|
|
|
std::vector<llvm::Constant*> Values(5);
|
|
|
|
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
|
|
|
|
Values[1] = GetClassName(PD->getIdentifier());
|
|
|
|
Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
|
|
|
|
Values[3] = Values[4] =
|
|
|
|
llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
|
|
|
|
Values);
|
|
|
|
|
|
|
|
Entry =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.ProtocolTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
|
|
|
std::string("\01L_OBJC_PROTOCOL_")+PD->getName(),
|
|
|
|
&CGM.getModule());
|
|
|
|
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(Entry);
|
|
|
|
// FIXME: Is this necessary? Why only for protocol?
|
|
|
|
Entry->setAlignment(4);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
struct _objc_protocol_extension {
|
|
|
|
uint32_t size;
|
|
|
|
struct objc_method_description_list *optional_instance_methods;
|
|
|
|
struct objc_method_description_list *optional_class_methods;
|
|
|
|
struct objc_property_list *instance_properties;
|
|
|
|
};
|
|
|
|
*/
|
2008-08-27 10:31:56 +08:00
|
|
|
llvm::Constant *
|
|
|
|
CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
|
|
|
|
const ConstantVector &OptInstanceMethods,
|
|
|
|
const ConstantVector &OptClassMethods) {
|
2008-08-13 11:21:16 +08:00
|
|
|
uint64_t Size =
|
|
|
|
CGM.getTargetData().getABITypeSize(ObjCTypes.ProtocolExtensionTy);
|
|
|
|
std::vector<llvm::Constant*> Values(4);
|
|
|
|
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
|
2008-08-27 10:31:56 +08:00
|
|
|
Values[1] =
|
|
|
|
EmitMethodDescList(std::string("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_")
|
|
|
|
+ PD->getName(),
|
|
|
|
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
|
|
|
|
OptInstanceMethods);
|
|
|
|
Values[2] =
|
|
|
|
EmitMethodDescList(std::string("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_")
|
|
|
|
+ PD->getName(),
|
|
|
|
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
|
|
|
|
OptClassMethods);
|
2008-08-23 08:19:03 +08:00
|
|
|
Values[3] = EmitPropertyList(std::string("\01L_OBJC_$_PROP_PROTO_LIST_") +
|
|
|
|
PD->getName(),
|
2008-08-28 12:38:10 +08:00
|
|
|
0,
|
2008-08-23 08:19:03 +08:00
|
|
|
PD->classprop_begin(),
|
|
|
|
PD->classprop_end());
|
2008-08-13 11:21:16 +08:00
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
// Return null if no extension bits are used.
|
2008-08-13 11:21:16 +08:00
|
|
|
if (Values[1]->isNullValue() && Values[2]->isNullValue() &&
|
|
|
|
Values[3]->isNullValue())
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
|
|
|
|
|
|
|
|
llvm::Constant *Init =
|
|
|
|
llvm::ConstantStruct::get(ObjCTypes.ProtocolExtensionTy, Values);
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.ProtocolExtensionTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
|
|
|
(std::string("\01L_OBJC_PROTOCOLEXT_") +
|
|
|
|
PD->getName()),
|
|
|
|
&CGM.getModule());
|
|
|
|
// No special section, but goes in llvm.used
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
struct objc_protocol_list {
|
|
|
|
struct objc_protocol_list *next;
|
|
|
|
long count;
|
|
|
|
Protocol *list[];
|
|
|
|
};
|
|
|
|
*/
|
2008-08-22 05:57:41 +08:00
|
|
|
llvm::Constant *
|
|
|
|
CGObjCMac::EmitProtocolList(const std::string &Name,
|
|
|
|
ObjCProtocolDecl::protocol_iterator begin,
|
|
|
|
ObjCProtocolDecl::protocol_iterator end) {
|
2008-08-13 11:21:16 +08:00
|
|
|
std::vector<llvm::Constant*> ProtocolRefs;
|
|
|
|
|
2008-08-22 05:57:41 +08:00
|
|
|
for (; begin != end; ++begin)
|
|
|
|
ProtocolRefs.push_back(GetProtocolRef(*begin));
|
2008-08-13 11:21:16 +08:00
|
|
|
|
|
|
|
// Just return null for empty protocol lists
|
|
|
|
if (ProtocolRefs.empty())
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
// This list is null terminated.
|
2008-08-13 11:21:16 +08:00
|
|
|
ProtocolRefs.push_back(llvm::Constant::getNullValue(ObjCTypes.ProtocolPtrTy));
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Values(3);
|
2008-08-21 12:36:09 +08:00
|
|
|
// This field is only used by the runtime.
|
2008-08-13 11:21:16 +08:00
|
|
|
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
|
|
|
|
Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1);
|
|
|
|
Values[2] =
|
|
|
|
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolPtrTy,
|
|
|
|
ProtocolRefs.size()),
|
|
|
|
ProtocolRefs);
|
|
|
|
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(Values);
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(Init->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
2008-08-22 05:57:41 +08:00
|
|
|
Name,
|
2008-08-13 11:21:16 +08:00
|
|
|
&CGM.getModule());
|
|
|
|
GV->setSection("__OBJC,__cat_cls_meth,regular,no_dead_strip");
|
|
|
|
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
2008-08-23 08:19:03 +08:00
|
|
|
/*
|
|
|
|
struct _objc_property {
|
|
|
|
const char * const name;
|
|
|
|
const char * const attributes;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _objc_property_list {
|
|
|
|
uint32_t entsize; // sizeof (struct _objc_property)
|
|
|
|
uint32_t prop_count;
|
|
|
|
struct _objc_property[prop_count];
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
llvm::Constant *CGObjCMac::EmitPropertyList(const std::string &Name,
|
2008-08-28 12:38:10 +08:00
|
|
|
const Decl *Container,
|
2008-08-23 08:19:03 +08:00
|
|
|
ObjCPropertyDecl * const *begin,
|
|
|
|
ObjCPropertyDecl * const *end) {
|
|
|
|
std::vector<llvm::Constant*> Properties, Prop(2);
|
|
|
|
for (; begin != end; ++begin) {
|
|
|
|
const ObjCPropertyDecl *PD = *begin;
|
|
|
|
Prop[0] = GetPropertyName(PD->getIdentifier());
|
2008-08-28 12:38:10 +08:00
|
|
|
Prop[1] = GetPropertyTypeString(PD, Container);
|
2008-08-23 08:19:03 +08:00
|
|
|
Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy,
|
|
|
|
Prop));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return null for empty list.
|
|
|
|
if (Properties.empty())
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
|
|
|
|
|
|
|
|
unsigned PropertySize =
|
|
|
|
CGM.getTargetData().getABITypeSize(ObjCTypes.PropertyTy);
|
|
|
|
std::vector<llvm::Constant*> Values(3);
|
|
|
|
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize);
|
|
|
|
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size());
|
|
|
|
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.PropertyTy,
|
|
|
|
Properties.size());
|
|
|
|
Values[2] = llvm::ConstantArray::get(AT, Properties);
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(Values);
|
|
|
|
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(Init->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
|
|
|
Name,
|
|
|
|
&CGM.getModule());
|
|
|
|
// No special section on property lists?
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
return llvm::ConstantExpr::getBitCast(GV,
|
|
|
|
ObjCTypes.PropertyListPtrTy);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
/*
|
|
|
|
struct objc_method_description_list {
|
|
|
|
int count;
|
|
|
|
struct objc_method_description list[];
|
|
|
|
};
|
|
|
|
*/
|
2008-08-27 10:31:56 +08:00
|
|
|
llvm::Constant *
|
|
|
|
CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
|
|
|
|
std::vector<llvm::Constant*> Desc(2);
|
|
|
|
Desc[0] = llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
|
|
|
|
ObjCTypes.SelectorPtrTy);
|
|
|
|
Desc[1] = GetMethodVarType(MD);
|
|
|
|
return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy,
|
|
|
|
Desc);
|
|
|
|
}
|
2008-08-13 11:21:16 +08:00
|
|
|
|
2008-08-27 10:31:56 +08:00
|
|
|
llvm::Constant *CGObjCMac::EmitMethodDescList(const std::string &Name,
|
|
|
|
const char *Section,
|
|
|
|
const ConstantVector &Methods) {
|
2008-08-13 11:21:16 +08:00
|
|
|
// Return null for empty list.
|
|
|
|
if (Methods.empty())
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Values(2);
|
|
|
|
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
|
|
|
|
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodDescriptionTy,
|
|
|
|
Methods.size());
|
|
|
|
Values[1] = llvm::ConstantArray::get(AT, Methods);
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(Values);
|
|
|
|
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(Init->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
2008-08-27 10:31:56 +08:00
|
|
|
Init, Name, &CGM.getModule());
|
|
|
|
GV->setSection(Section);
|
2008-08-13 11:21:16 +08:00
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
return llvm::ConstantExpr::getBitCast(GV,
|
|
|
|
ObjCTypes.MethodDescriptionListPtrTy);
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
2008-08-23 04:34:54 +08:00
|
|
|
/*
|
|
|
|
struct _objc_category {
|
|
|
|
char *category_name;
|
|
|
|
char *class_name;
|
|
|
|
struct _objc_method_list *instance_methods;
|
|
|
|
struct _objc_method_list *class_methods;
|
|
|
|
struct _objc_protocol_list *protocols;
|
|
|
|
uint32_t size; // <rdar://4585769>
|
|
|
|
struct _objc_property_list *instance_properties;
|
|
|
|
};
|
|
|
|
*/
|
2008-08-16 06:20:32 +08:00
|
|
|
void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
|
2008-08-23 04:34:54 +08:00
|
|
|
unsigned Size = CGM.getTargetData().getABITypeSize(ObjCTypes.CategoryTy);
|
|
|
|
|
2008-08-27 07:03:11 +08:00
|
|
|
// FIXME: This is poor design, the OCD should have a pointer to the
|
|
|
|
// category decl. Additionally, note that Category can be null for
|
|
|
|
// the @implementation w/o an @interface case. Sema should just
|
|
|
|
// create one for us as it does for @implementation so everyone else
|
|
|
|
// can live life under a clear blue sky.
|
2008-08-23 04:34:54 +08:00
|
|
|
const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
|
2008-08-27 07:03:11 +08:00
|
|
|
const ObjCCategoryDecl *Category =
|
|
|
|
Interface->FindCategoryDeclaration(OCD->getIdentifier());
|
2008-08-23 04:34:54 +08:00
|
|
|
std::string ExtName(std::string(Interface->getName()) +
|
|
|
|
"_" +
|
|
|
|
OCD->getName());
|
|
|
|
|
2008-08-27 05:51:14 +08:00
|
|
|
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
|
|
|
|
for (ObjCCategoryImplDecl::instmeth_iterator i = OCD->instmeth_begin(),
|
|
|
|
e = OCD->instmeth_end(); i != e; ++i) {
|
|
|
|
// Instance methods should always be defined.
|
|
|
|
InstanceMethods.push_back(GetMethodConstant(*i));
|
|
|
|
}
|
|
|
|
for (ObjCCategoryImplDecl::classmeth_iterator i = OCD->classmeth_begin(),
|
|
|
|
e = OCD->classmeth_end(); i != e; ++i) {
|
|
|
|
// Class methods should always be defined.
|
|
|
|
ClassMethods.push_back(GetMethodConstant(*i));
|
|
|
|
}
|
|
|
|
|
2008-08-23 04:34:54 +08:00
|
|
|
std::vector<llvm::Constant*> Values(7);
|
|
|
|
Values[0] = GetClassName(OCD->getIdentifier());
|
|
|
|
Values[1] = GetClassName(Interface->getIdentifier());
|
2008-08-23 08:19:03 +08:00
|
|
|
Values[2] =
|
|
|
|
EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") +
|
|
|
|
ExtName,
|
|
|
|
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
|
2008-08-27 05:51:14 +08:00
|
|
|
InstanceMethods);
|
2008-08-23 08:19:03 +08:00
|
|
|
Values[3] =
|
|
|
|
EmitMethodList(std::string("\01L_OBJC_CATEGORY_CLASS_METHODS_") + ExtName,
|
|
|
|
"__OBJC,__cat_class_meth,regular,no_dead_strip",
|
2008-08-27 05:51:14 +08:00
|
|
|
ClassMethods);
|
2008-08-27 10:31:56 +08:00
|
|
|
if (Category) {
|
|
|
|
Values[4] =
|
|
|
|
EmitProtocolList(std::string("\01L_OBJC_CATEGORY_PROTOCOLS_") + ExtName,
|
|
|
|
Category->protocol_begin(),
|
|
|
|
Category->protocol_end());
|
|
|
|
} else {
|
|
|
|
Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
|
|
|
|
}
|
2008-08-23 04:34:54 +08:00
|
|
|
Values[5] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
|
2008-08-27 07:03:11 +08:00
|
|
|
|
|
|
|
// If there is no category @interface then there can be no properties.
|
|
|
|
if (Category) {
|
|
|
|
Values[6] = EmitPropertyList(std::string("\01L_OBJC_$_PROP_LIST_") + ExtName,
|
2008-08-28 12:38:10 +08:00
|
|
|
OCD,
|
2008-08-27 07:03:11 +08:00
|
|
|
Category->classprop_begin(),
|
|
|
|
Category->classprop_end());
|
|
|
|
} else {
|
|
|
|
Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
|
|
|
|
}
|
2008-08-23 04:34:54 +08:00
|
|
|
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.CategoryTy,
|
|
|
|
Values);
|
|
|
|
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.CategoryTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
|
|
|
std::string("\01L_OBJC_CATEGORY_")+ExtName,
|
|
|
|
&CGM.getModule());
|
|
|
|
GV->setSection("__OBJC,__category,regular,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
DefinedCategories.push_back(GV);
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
// FIXME: Get from somewhere?
|
|
|
|
enum ClassFlags {
|
|
|
|
eClassFlags_Factory = 0x00001,
|
|
|
|
eClassFlags_Meta = 0x00002,
|
|
|
|
// <rdr://5142207>
|
|
|
|
eClassFlags_HasCXXStructors = 0x02000,
|
|
|
|
eClassFlags_Hidden = 0x20000,
|
|
|
|
eClassFlags_ABI2_Hidden = 0x00010,
|
|
|
|
eClassFlags_ABI2_HasCXXStructors = 0x00004 // <rdr://4923634>
|
|
|
|
};
|
|
|
|
|
|
|
|
// <rdr://5142207&4705298&4843145>
|
|
|
|
static bool IsClassHidden(const ObjCInterfaceDecl *ID) {
|
|
|
|
if (const VisibilityAttr *attr = ID->getAttr<VisibilityAttr>()) {
|
|
|
|
// FIXME: Support -fvisibility
|
|
|
|
switch (attr->getVisibility()) {
|
|
|
|
default:
|
|
|
|
assert(0 && "Unknown visibility");
|
|
|
|
return false;
|
|
|
|
case VisibilityAttr::DefaultVisibility:
|
|
|
|
case VisibilityAttr::ProtectedVisibility: // FIXME: What do we do here?
|
|
|
|
return false;
|
|
|
|
case VisibilityAttr::HiddenVisibility:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false; // FIXME: Support -fvisibility
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
struct _objc_class {
|
|
|
|
Class isa;
|
|
|
|
Class super_class;
|
|
|
|
const char *name;
|
|
|
|
long version;
|
|
|
|
long info;
|
|
|
|
long instance_size;
|
|
|
|
struct _objc_ivar_list *ivars;
|
|
|
|
struct _objc_method_list *methods;
|
|
|
|
struct _objc_cache *cache;
|
|
|
|
struct _objc_protocol_list *protocols;
|
|
|
|
// Objective-C 1.0 extensions (<rdr://4585769>)
|
|
|
|
const char *ivar_layout;
|
|
|
|
struct _objc_class_ext *ext;
|
|
|
|
};
|
|
|
|
|
|
|
|
See EmitClassExtension();
|
|
|
|
*/
|
|
|
|
void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
|
2008-08-25 14:02:07 +08:00
|
|
|
DefinedSymbols.insert(ID->getIdentifier());
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
const char *ClassName = ID->getName();
|
|
|
|
// FIXME: Gross
|
|
|
|
ObjCInterfaceDecl *Interface =
|
|
|
|
const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
|
2008-08-22 05:57:41 +08:00
|
|
|
llvm::Constant *Protocols =
|
|
|
|
EmitProtocolList(std::string("\01L_OBJC_CLASS_PROTOCOLS_") + ID->getName(),
|
|
|
|
Interface->protocol_begin(),
|
|
|
|
Interface->protocol_end());
|
2008-08-21 12:36:09 +08:00
|
|
|
const llvm::Type *InterfaceTy =
|
|
|
|
CGM.getTypes().ConvertType(CGM.getContext().getObjCInterfaceType(Interface));
|
|
|
|
unsigned Flags = eClassFlags_Factory;
|
|
|
|
unsigned Size = CGM.getTargetData().getABITypeSize(InterfaceTy);
|
|
|
|
|
|
|
|
// FIXME: Set CXX-structors flag.
|
|
|
|
if (IsClassHidden(ID->getClassInterface()))
|
|
|
|
Flags |= eClassFlags_Hidden;
|
|
|
|
|
2008-08-27 05:51:14 +08:00
|
|
|
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
|
|
|
|
for (ObjCImplementationDecl::instmeth_iterator i = ID->instmeth_begin(),
|
|
|
|
e = ID->instmeth_end(); i != e; ++i) {
|
|
|
|
// Instance methods should always be defined.
|
|
|
|
InstanceMethods.push_back(GetMethodConstant(*i));
|
|
|
|
}
|
|
|
|
for (ObjCImplementationDecl::classmeth_iterator i = ID->classmeth_begin(),
|
|
|
|
e = ID->classmeth_end(); i != e; ++i) {
|
|
|
|
// Class methods should always be defined.
|
|
|
|
ClassMethods.push_back(GetMethodConstant(*i));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ObjCImplementationDecl::propimpl_iterator i = ID->propimpl_begin(),
|
|
|
|
e = ID->propimpl_end(); i != e; ++i) {
|
|
|
|
ObjCPropertyImplDecl *PID = *i;
|
|
|
|
|
|
|
|
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
|
|
|
|
ObjCPropertyDecl *PD = PID->getPropertyDecl();
|
|
|
|
|
|
|
|
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
|
|
|
|
if (llvm::Constant *C = GetMethodConstant(MD))
|
|
|
|
InstanceMethods.push_back(C);
|
|
|
|
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl())
|
|
|
|
if (llvm::Constant *C = GetMethodConstant(MD))
|
|
|
|
InstanceMethods.push_back(C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
std::vector<llvm::Constant*> Values(12);
|
2008-08-27 05:51:14 +08:00
|
|
|
Values[ 0] = EmitMetaClass(ID, Protocols, InterfaceTy, ClassMethods);
|
2008-08-21 12:36:09 +08:00
|
|
|
if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) {
|
2008-08-25 14:02:07 +08:00
|
|
|
// Record a reference to the super class.
|
|
|
|
LazySymbols.insert(Super->getIdentifier());
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
Values[ 1] =
|
|
|
|
llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()),
|
|
|
|
ObjCTypes.ClassPtrTy);
|
|
|
|
} else {
|
|
|
|
Values[ 1] = llvm::Constant::getNullValue(ObjCTypes.ClassPtrTy);
|
|
|
|
}
|
|
|
|
Values[ 2] = GetClassName(ID->getIdentifier());
|
|
|
|
// Version is always 0.
|
|
|
|
Values[ 3] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
|
|
|
|
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
|
|
|
|
Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
|
|
|
|
Values[ 6] = EmitIvarList(ID, false, InterfaceTy);
|
2008-08-23 08:19:03 +08:00
|
|
|
Values[ 7] =
|
|
|
|
EmitMethodList(std::string("\01L_OBJC_INSTANCE_METHODS_") + ID->getName(),
|
|
|
|
"__OBJC,__inst_meth,regular,no_dead_strip",
|
2008-08-27 05:51:14 +08:00
|
|
|
InstanceMethods);
|
2008-08-21 12:36:09 +08:00
|
|
|
// cache is always NULL.
|
|
|
|
Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
|
|
|
|
Values[ 9] = Protocols;
|
2008-08-23 04:34:54 +08:00
|
|
|
// FIXME: Set ivar_layout
|
|
|
|
Values[10] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
|
2008-08-21 12:36:09 +08:00
|
|
|
Values[11] = EmitClassExtension(ID);
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
|
|
|
|
Values);
|
|
|
|
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
|
|
|
std::string("\01L_OBJC_CLASS_")+ClassName,
|
|
|
|
&CGM.getModule());
|
|
|
|
GV->setSection("__OBJC,__class,regular,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
// FIXME: Why?
|
|
|
|
GV->setAlignment(32);
|
|
|
|
DefinedClasses.push_back(GV);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
|
|
|
|
llvm::Constant *Protocols,
|
2008-08-27 05:51:14 +08:00
|
|
|
const llvm::Type *InterfaceTy,
|
2008-08-27 10:31:56 +08:00
|
|
|
const ConstantVector &Methods) {
|
2008-08-21 12:36:09 +08:00
|
|
|
const char *ClassName = ID->getName();
|
|
|
|
unsigned Flags = eClassFlags_Meta;
|
|
|
|
unsigned Size = CGM.getTargetData().getABITypeSize(ObjCTypes.ClassTy);
|
|
|
|
|
|
|
|
if (IsClassHidden(ID->getClassInterface()))
|
|
|
|
Flags |= eClassFlags_Hidden;
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Values(12);
|
|
|
|
// The isa for the metaclass is the root of the hierarchy.
|
|
|
|
const ObjCInterfaceDecl *Root = ID->getClassInterface();
|
|
|
|
while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
|
|
|
|
Root = Super;
|
|
|
|
Values[ 0] =
|
|
|
|
llvm::ConstantExpr::getBitCast(GetClassName(Root->getIdentifier()),
|
|
|
|
ObjCTypes.ClassPtrTy);
|
2008-08-23 04:34:54 +08:00
|
|
|
// The super class for the metaclass is emitted as the name of the
|
|
|
|
// super class. The runtime fixes this up to point to the
|
|
|
|
// *metaclass* for the super class.
|
2008-08-21 12:36:09 +08:00
|
|
|
if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) {
|
|
|
|
Values[ 1] =
|
|
|
|
llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()),
|
|
|
|
ObjCTypes.ClassPtrTy);
|
|
|
|
} else {
|
|
|
|
Values[ 1] = llvm::Constant::getNullValue(ObjCTypes.ClassPtrTy);
|
|
|
|
}
|
|
|
|
Values[ 2] = GetClassName(ID->getIdentifier());
|
|
|
|
// Version is always 0.
|
|
|
|
Values[ 3] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
|
|
|
|
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
|
|
|
|
Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
|
|
|
|
Values[ 6] = EmitIvarList(ID, true, InterfaceTy);
|
2008-08-23 08:19:03 +08:00
|
|
|
Values[ 7] =
|
|
|
|
EmitMethodList(std::string("\01L_OBJC_CLASS_METHODS_") + ID->getName(),
|
|
|
|
"__OBJC,__inst_meth,regular,no_dead_strip",
|
2008-08-27 05:51:14 +08:00
|
|
|
Methods);
|
2008-08-21 12:36:09 +08:00
|
|
|
// cache is always NULL.
|
|
|
|
Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
|
|
|
|
Values[ 9] = Protocols;
|
|
|
|
// ivar_layout for metaclass is always NULL.
|
|
|
|
Values[10] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
|
|
|
|
// The class extension is always unused for metaclasses.
|
|
|
|
Values[11] = llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
|
|
|
|
Values);
|
|
|
|
|
2008-08-25 16:19:24 +08:00
|
|
|
std::string Name("\01L_OBJC_METACLASS_");
|
|
|
|
Name += ClassName;
|
|
|
|
|
|
|
|
// Check for a forward reference.
|
|
|
|
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
|
|
|
|
if (GV) {
|
|
|
|
assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
|
|
|
|
"Forward metaclass reference has incorrect type.");
|
|
|
|
GV->setLinkage(llvm::GlobalValue::InternalLinkage);
|
|
|
|
GV->setInitializer(Init);
|
|
|
|
} else {
|
|
|
|
GV = new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init, Name,
|
|
|
|
&CGM.getModule());
|
|
|
|
}
|
2008-08-21 12:36:09 +08:00
|
|
|
GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
// FIXME: Why?
|
|
|
|
GV->setAlignment(32);
|
|
|
|
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2008-08-25 16:19:24 +08:00
|
|
|
llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
|
|
|
|
std::string Name("\01L_OBJC_METACLASS_");
|
|
|
|
Name += ID->getName();
|
|
|
|
|
|
|
|
// FIXME: Should we look these up somewhere other than the
|
|
|
|
// module. Its a bit silly since we only generate these while
|
|
|
|
// processing an implementation, so exactly one pointer would work
|
|
|
|
// if know when we entered/exitted an implementation block.
|
|
|
|
|
|
|
|
// Check for an existing forward reference.
|
|
|
|
if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name)) {
|
|
|
|
assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
|
|
|
|
"Forward metaclass reference has incorrect type.");
|
|
|
|
return GV;
|
|
|
|
} else {
|
|
|
|
// Generate as an external reference to keep a consistent
|
|
|
|
// module. This will be patched up when we emit the metaclass.
|
|
|
|
return new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
|
|
|
|
llvm::GlobalValue::ExternalLinkage,
|
|
|
|
0,
|
|
|
|
Name,
|
|
|
|
&CGM.getModule());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
/*
|
|
|
|
struct objc_class_ext {
|
|
|
|
uint32_t size;
|
|
|
|
const char *weak_ivar_layout;
|
|
|
|
struct _objc_property_list *properties;
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
llvm::Constant *
|
|
|
|
CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
|
|
|
|
uint64_t Size =
|
|
|
|
CGM.getTargetData().getABITypeSize(ObjCTypes.ClassExtensionTy);
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Values(3);
|
|
|
|
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
|
2008-08-23 04:34:54 +08:00
|
|
|
// FIXME: Output weak_ivar_layout string.
|
2008-08-21 12:36:09 +08:00
|
|
|
Values[1] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
|
2008-08-23 08:19:03 +08:00
|
|
|
Values[2] = EmitPropertyList(std::string("\01L_OBJC_$_PROP_LIST_") +
|
|
|
|
ID->getName(),
|
2008-08-28 12:38:10 +08:00
|
|
|
ID,
|
2008-08-23 08:19:03 +08:00
|
|
|
ID->getClassInterface()->classprop_begin(),
|
|
|
|
ID->getClassInterface()->classprop_end());
|
2008-08-21 12:36:09 +08:00
|
|
|
|
|
|
|
// Return null if no extension bits are used.
|
|
|
|
if (Values[1]->isNullValue() && Values[2]->isNullValue())
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
|
|
|
|
|
|
|
|
llvm::Constant *Init =
|
|
|
|
llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values);
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.ClassExtensionTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
|
|
|
(std::string("\01L_OBJC_CLASSEXT_") +
|
|
|
|
ID->getName()),
|
|
|
|
&CGM.getModule());
|
|
|
|
// No special section, but goes in llvm.used
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
struct objc_ivar {
|
|
|
|
char *ivar_name;
|
|
|
|
char *ivar_type;
|
|
|
|
int ivar_offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct objc_ivar_list {
|
|
|
|
int ivar_count;
|
|
|
|
struct objc_ivar list[count];
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
|
|
|
|
bool ForClass,
|
|
|
|
const llvm::Type *InterfaceTy) {
|
|
|
|
std::vector<llvm::Constant*> Ivars, Ivar(3);
|
|
|
|
|
|
|
|
// When emitting the root class GCC emits ivar entries for the
|
|
|
|
// actual class structure. It is not clear if we need to follow this
|
|
|
|
// behavior; for now lets try and get away with not doing it. If so,
|
|
|
|
// the cleanest solution would be to make up an ObjCInterfaceDecl
|
|
|
|
// for the class.
|
|
|
|
if (ForClass)
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
|
|
|
|
|
|
|
|
const llvm::StructLayout *Layout =
|
|
|
|
CGM.getTargetData().getStructLayout(cast<llvm::StructType>(InterfaceTy));
|
|
|
|
for (ObjCInterfaceDecl::ivar_iterator
|
|
|
|
i = ID->getClassInterface()->ivar_begin(),
|
|
|
|
e = ID->getClassInterface()->ivar_end(); i != e; ++i) {
|
|
|
|
ObjCIvarDecl *V = *i;
|
|
|
|
unsigned Offset =
|
|
|
|
Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(V));
|
|
|
|
std::string TypeStr;
|
|
|
|
llvm::SmallVector<const RecordType *, 8> EncodingRecordTypes;
|
|
|
|
Ivar[0] = GetMethodVarName(V->getIdentifier());
|
|
|
|
CGM.getContext().getObjCEncodingForType(V->getType(), TypeStr,
|
|
|
|
EncodingRecordTypes);
|
|
|
|
Ivar[1] = GetMethodVarType(TypeStr);
|
|
|
|
Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy, Offset);
|
|
|
|
Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy,
|
|
|
|
Ivar));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return null for empty list.
|
|
|
|
if (Ivars.empty())
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Values(2);
|
|
|
|
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
|
|
|
|
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarTy,
|
|
|
|
Ivars.size());
|
|
|
|
Values[1] = llvm::ConstantArray::get(AT, Ivars);
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(Values);
|
|
|
|
|
|
|
|
const char *Prefix = (ForClass ? "\01L_OBJC_CLASS_VARIABLES_" :
|
|
|
|
"\01L_OBJC_INSTANCE_VARIABLES_");
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(Init->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
|
|
|
std::string(Prefix) + ID->getName(),
|
|
|
|
&CGM.getModule());
|
|
|
|
if (ForClass) {
|
|
|
|
GV->setSection("__OBJC,__cls_vars,regular,no_dead_strip");
|
|
|
|
// FIXME: Why is this only here?
|
|
|
|
GV->setAlignment(32);
|
|
|
|
} else {
|
|
|
|
GV->setSection("__OBJC,__instance_vars,regular,no_dead_strip");
|
|
|
|
}
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
return llvm::ConstantExpr::getBitCast(GV,
|
|
|
|
ObjCTypes.IvarListPtrTy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
struct objc_method {
|
|
|
|
SEL method_name;
|
|
|
|
char *method_types;
|
|
|
|
void *method;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct objc_method_list {
|
|
|
|
struct objc_method_list *obsolete;
|
|
|
|
int count;
|
|
|
|
struct objc_method methods_list[count];
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
2008-08-27 05:51:14 +08:00
|
|
|
/// GetMethodConstant - Return a struct objc_method constant for the
|
|
|
|
/// given method if it has been defined. The result is null if the
|
|
|
|
/// method has not been defined. The return value has type MethodPtrTy.
|
2008-08-27 10:31:56 +08:00
|
|
|
llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) {
|
2008-08-27 05:51:14 +08:00
|
|
|
// FIXME: Use DenseMap::lookup
|
|
|
|
llvm::Function *Fn = MethodDefinitions[MD];
|
|
|
|
if (!Fn)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Method(3);
|
|
|
|
Method[0] =
|
|
|
|
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
|
|
|
|
ObjCTypes.SelectorPtrTy);
|
|
|
|
Method[1] = GetMethodVarType(MD);
|
|
|
|
Method[2] = llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy);
|
|
|
|
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method);
|
|
|
|
}
|
2008-08-21 12:36:09 +08:00
|
|
|
|
2008-08-27 05:51:14 +08:00
|
|
|
llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name,
|
|
|
|
const char *Section,
|
2008-08-27 10:31:56 +08:00
|
|
|
const ConstantVector &Methods) {
|
2008-08-21 12:36:09 +08:00
|
|
|
// Return null for empty list.
|
|
|
|
if (Methods.empty())
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.MethodListPtrTy);
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Values(3);
|
|
|
|
Values[0] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
|
|
|
|
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
|
|
|
|
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy,
|
|
|
|
Methods.size());
|
|
|
|
Values[2] = llvm::ConstantArray::get(AT, Methods);
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(Values);
|
|
|
|
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(Init->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Init,
|
2008-08-23 04:34:54 +08:00
|
|
|
Name,
|
2008-08-21 12:36:09 +08:00
|
|
|
&CGM.getModule());
|
2008-08-23 04:34:54 +08:00
|
|
|
GV->setSection(Section);
|
2008-08-21 12:36:09 +08:00
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
return llvm::ConstantExpr::getBitCast(GV,
|
|
|
|
ObjCTypes.MethodListPtrTy);
|
2008-08-16 11:19:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Function *CGObjCMac::GenerateMethod(const ObjCMethodDecl *OMD) {
|
|
|
|
std::string Name;
|
|
|
|
GetNameForMethod(OMD, Name);
|
|
|
|
|
2008-09-10 12:01:49 +08:00
|
|
|
const llvm::FunctionType *MethodTy =
|
|
|
|
CGM.getTypes().GetFunctionType(CGFunctionInfo(OMD, CGM.getContext()));
|
2008-08-16 11:19:19 +08:00
|
|
|
llvm::Function *Method =
|
2008-09-10 12:01:49 +08:00
|
|
|
llvm::Function::Create(MethodTy,
|
2008-08-16 11:19:19 +08:00
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Name,
|
|
|
|
&CGM.getModule());
|
2008-08-27 05:51:14 +08:00
|
|
|
MethodDefinitions.insert(std::make_pair(OMD, Method));
|
2008-08-16 11:19:19 +08:00
|
|
|
|
|
|
|
return Method;
|
2008-08-11 10:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Function *CGObjCMac::ModuleInitFunction() {
|
2008-08-12 05:35:06 +08:00
|
|
|
// Abuse this interface function as a place to finalize.
|
|
|
|
FinishModule();
|
|
|
|
|
2008-08-11 10:45:11 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-09-24 11:38:44 +08:00
|
|
|
llvm::Function *CGObjCMac::GetPropertyGetFunction() {
|
|
|
|
return ObjCTypes.GetPropertyFn;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Function *CGObjCMac::GetPropertySetFunction() {
|
|
|
|
return ObjCTypes.SetPropertyFn;
|
|
|
|
}
|
|
|
|
|
2008-08-31 12:05:03 +08:00
|
|
|
llvm::Function *CGObjCMac::EnumerationMutationFunction()
|
|
|
|
{
|
|
|
|
return ObjCTypes.EnumerationMutationFn;
|
|
|
|
}
|
|
|
|
|
2008-09-28 09:03:14 +08:00
|
|
|
/*
|
|
|
|
|
|
|
|
Objective-C setjmp-longjmp (sjlj) Exception Handling
|
|
|
|
--
|
|
|
|
|
|
|
|
The basic framework for a @try-catch-finally is as follows:
|
|
|
|
{
|
|
|
|
objc_exception_data d;
|
|
|
|
id _rethrow = null;
|
|
|
|
|
|
|
|
objc_exception_try_enter(&d);
|
|
|
|
if (!setjmp(d.jmp_buf)) {
|
|
|
|
... try body ...
|
|
|
|
} else {
|
|
|
|
// exception path
|
|
|
|
id _caught = objc_exception_extract(&d);
|
|
|
|
|
|
|
|
// enter new try scope for handlers
|
|
|
|
if (!setjmp(d.jmp_buf)) {
|
|
|
|
... match exception and execute catch blocks ...
|
|
|
|
|
|
|
|
// fell off end, rethrow.
|
|
|
|
_rethrow = _caught;
|
2008-09-30 09:06:03 +08:00
|
|
|
... jump-through-finally to finally_rethrow ...
|
2008-09-28 09:03:14 +08:00
|
|
|
} else {
|
|
|
|
// exception in catch block
|
|
|
|
_rethrow = objc_exception_extract(&d);
|
2008-09-30 09:06:03 +08:00
|
|
|
... jump-through-finally_no_exit to finally_rethrow ...
|
2008-09-28 09:03:14 +08:00
|
|
|
}
|
|
|
|
}
|
2008-09-30 09:06:03 +08:00
|
|
|
... jump-through-finally to finally_end ...
|
2008-09-28 09:03:14 +08:00
|
|
|
|
|
|
|
finally:
|
|
|
|
// match either the initial try_enter or the catch try_enter,
|
|
|
|
// depending on the path followed.
|
|
|
|
objc_exception_try_exit(&d);
|
|
|
|
finally_no_exit:
|
|
|
|
... finally block ....
|
2008-09-30 09:06:03 +08:00
|
|
|
... dispatch to finally destination ...
|
|
|
|
|
|
|
|
finally_rethrow:
|
|
|
|
objc_exception_throw(_rethrow);
|
|
|
|
|
|
|
|
finally_end:
|
2008-09-28 09:03:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
This framework differs slightly from the one gcc uses, in that gcc
|
2008-09-30 09:06:03 +08:00
|
|
|
uses _rethrow to determine if objc_exception_try_exit should be called
|
|
|
|
and if the object should be rethrown. This breaks in the face of
|
|
|
|
throwing nil and introduces unnecessary branches.
|
2008-09-28 09:03:14 +08:00
|
|
|
|
|
|
|
We specialize this framework for a few particular circumstances:
|
|
|
|
|
|
|
|
- If there are no catch blocks, then we avoid emitting the second
|
|
|
|
exception handling context.
|
|
|
|
|
|
|
|
- If there is a catch-all catch block (i.e. @catch(...) or @catch(id
|
|
|
|
e)) we avoid emitting the code to rethrow an uncaught exception.
|
|
|
|
|
|
|
|
- FIXME: If there is no @finally block we can do a few more
|
|
|
|
simplifications.
|
|
|
|
|
|
|
|
Rethrows and Jumps-Through-Finally
|
|
|
|
--
|
|
|
|
|
|
|
|
Support for implicit rethrows and jumping through the finally block is
|
|
|
|
handled by storing the current exception-handling context in
|
|
|
|
ObjCEHStack.
|
|
|
|
|
2008-09-30 09:06:03 +08:00
|
|
|
In order to implement proper @finally semantics, we support one basic
|
|
|
|
mechanism for jumping through the finally block to an arbitrary
|
|
|
|
destination. Constructs which generate exits from a @try or @catch
|
|
|
|
block use this mechanism to implement the proper semantics by chaining
|
|
|
|
jumps, as necessary.
|
|
|
|
|
|
|
|
This mechanism works like the one used for indirect goto: we
|
|
|
|
arbitrarily assign an ID to each destination and store the ID for the
|
|
|
|
destination in a variable prior to entering the finally block. At the
|
|
|
|
end of the finally block we simply create a switch to the proper
|
|
|
|
destination.
|
|
|
|
|
2008-09-28 09:03:14 +08:00
|
|
|
*/
|
|
|
|
|
2008-09-09 18:04:29 +08:00
|
|
|
void CGObjCMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
|
2008-09-30 09:06:03 +08:00
|
|
|
const ObjCAtTryStmt &S) {
|
|
|
|
// Create various blocks we refer to for handling @finally.
|
|
|
|
llvm::BasicBlock *FinallyBlock = llvm::BasicBlock::Create("finally");
|
|
|
|
llvm::BasicBlock *FinallyNoExit = llvm::BasicBlock::Create("finally.noexit");
|
|
|
|
llvm::BasicBlock *FinallyRethrow = llvm::BasicBlock::Create("finally.throw");
|
|
|
|
llvm::BasicBlock *FinallyEnd = llvm::BasicBlock::Create("finally.end");
|
|
|
|
llvm::Value *DestCode =
|
|
|
|
CGF.CreateTempAlloca(llvm::Type::Int32Ty, "finally.dst");
|
|
|
|
|
|
|
|
// Generate jump code. Done here so we can directly add things to
|
|
|
|
// the switch instruction.
|
|
|
|
llvm::BasicBlock *FinallyJump = llvm::BasicBlock::Create("finally.jump");
|
|
|
|
llvm::SwitchInst *FinallySwitch =
|
|
|
|
llvm::SwitchInst::Create(new llvm::LoadInst(DestCode, "", FinallyJump),
|
|
|
|
FinallyEnd, 10, FinallyJump);
|
|
|
|
|
|
|
|
// Push an EH context entry, used for handling rethrows and jumps
|
|
|
|
// through finally.
|
|
|
|
CodeGenFunction::ObjCEHEntry EHEntry(FinallyBlock, FinallyNoExit,
|
|
|
|
FinallySwitch, DestCode);
|
|
|
|
CGF.ObjCEHStack.push_back(&EHEntry);
|
|
|
|
|
|
|
|
// Allocate memory for the exception data and rethrow pointer.
|
2008-09-10 01:59:25 +08:00
|
|
|
llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
|
|
|
|
"exceptiondata.ptr");
|
2008-09-30 09:06:03 +08:00
|
|
|
llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy, "_rethrow");
|
2008-09-10 01:59:25 +08:00
|
|
|
|
|
|
|
// Enter a new try block and call setjmp.
|
|
|
|
CGF.Builder.CreateCall(ObjCTypes.ExceptionTryEnterFn, ExceptionData);
|
|
|
|
llvm::Value *JmpBufPtr = CGF.Builder.CreateStructGEP(ExceptionData, 0,
|
|
|
|
"jmpbufarray");
|
|
|
|
JmpBufPtr = CGF.Builder.CreateStructGEP(JmpBufPtr, 0, "tmp");
|
|
|
|
llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.SetJmpFn,
|
|
|
|
JmpBufPtr, "result");
|
2008-09-30 09:06:03 +08:00
|
|
|
|
2008-09-10 01:59:25 +08:00
|
|
|
llvm::BasicBlock *TryBlock = llvm::BasicBlock::Create("try");
|
2008-09-28 07:30:04 +08:00
|
|
|
llvm::BasicBlock *TryHandler = llvm::BasicBlock::Create("try.handler");
|
|
|
|
CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNonNull(SetJmpResult, "threw"),
|
|
|
|
TryHandler, TryBlock);
|
2008-09-10 01:59:25 +08:00
|
|
|
|
|
|
|
// Emit the @try block.
|
|
|
|
CGF.EmitBlock(TryBlock);
|
|
|
|
CGF.EmitStmt(S.getTryBody());
|
2008-09-30 09:06:03 +08:00
|
|
|
CGF.EmitJumpThroughFinally(&EHEntry, FinallyEnd);
|
2008-09-10 01:59:25 +08:00
|
|
|
|
|
|
|
// Emit the "exception in @try" block.
|
2008-09-28 07:30:04 +08:00
|
|
|
CGF.EmitBlock(TryHandler);
|
2008-09-27 15:03:52 +08:00
|
|
|
|
|
|
|
// Retrieve the exception object. We may emit multiple blocks but
|
|
|
|
// nothing can cross this so the value is already in SSA form.
|
|
|
|
llvm::Value *Caught = CGF.Builder.CreateCall(ObjCTypes.ExceptionExtractFn,
|
|
|
|
ExceptionData,
|
|
|
|
"caught");
|
2008-09-30 09:06:03 +08:00
|
|
|
EHEntry.Exception = Caught;
|
2008-09-27 15:03:52 +08:00
|
|
|
if (const ObjCAtCatchStmt* CatchStmt = S.getCatchStmts()) {
|
|
|
|
// Enter a new exception try block (in case a @catch block throws
|
|
|
|
// an exception).
|
2008-09-10 01:59:25 +08:00
|
|
|
CGF.Builder.CreateCall(ObjCTypes.ExceptionTryEnterFn, ExceptionData);
|
2008-09-27 15:03:52 +08:00
|
|
|
|
2008-09-10 01:59:25 +08:00
|
|
|
llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.SetJmpFn,
|
|
|
|
JmpBufPtr, "result");
|
2008-09-28 07:30:04 +08:00
|
|
|
llvm::Value *Threw = CGF.Builder.CreateIsNonNull(SetJmpResult, "threw");
|
2008-09-10 01:59:25 +08:00
|
|
|
|
|
|
|
llvm::BasicBlock *CatchBlock = llvm::BasicBlock::Create("catch");
|
2008-09-28 07:30:04 +08:00
|
|
|
llvm::BasicBlock *CatchHandler = llvm::BasicBlock::Create("catch.handler");
|
|
|
|
CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock);
|
2008-09-10 01:59:25 +08:00
|
|
|
|
|
|
|
CGF.EmitBlock(CatchBlock);
|
|
|
|
|
2008-09-27 15:03:52 +08:00
|
|
|
// Handle catch list. As a special case we check if everything is
|
|
|
|
// matched and avoid generating code for falling off the end if
|
|
|
|
// so.
|
|
|
|
bool AllMatched = false;
|
2008-09-10 01:59:25 +08:00
|
|
|
for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
|
2008-09-30 09:06:03 +08:00
|
|
|
llvm::BasicBlock *NextCatchBlock = llvm::BasicBlock::Create("catch");
|
2008-09-10 01:59:25 +08:00
|
|
|
|
2008-09-11 17:15:33 +08:00
|
|
|
const DeclStmt *CatchParam =
|
|
|
|
cast_or_null<DeclStmt>(CatchStmt->getCatchParamStmt());
|
2008-09-27 15:36:24 +08:00
|
|
|
const VarDecl *VD = 0;
|
|
|
|
const PointerType *PT = 0;
|
|
|
|
|
2008-09-10 01:59:25 +08:00
|
|
|
// catch(...) always matches.
|
2008-09-27 15:03:52 +08:00
|
|
|
if (!CatchParam) {
|
|
|
|
AllMatched = true;
|
|
|
|
} else {
|
2008-09-27 15:36:24 +08:00
|
|
|
VD = cast<VarDecl>(CatchParam->getDecl());
|
|
|
|
PT = VD->getType()->getAsPointerType();
|
2008-09-10 01:59:25 +08:00
|
|
|
|
2008-09-28 06:21:14 +08:00
|
|
|
// catch(id e) always matches.
|
|
|
|
// FIXME: For the time being we also match id<X>; this should
|
|
|
|
// be rejected by Sema instead.
|
|
|
|
if ((PT && CGF.getContext().isObjCIdType(PT->getPointeeType())) ||
|
|
|
|
VD->getType()->isObjCQualifiedIdType())
|
2008-09-27 15:03:52 +08:00
|
|
|
AllMatched = true;
|
2008-09-10 01:59:25 +08:00
|
|
|
}
|
|
|
|
|
2008-09-27 15:03:52 +08:00
|
|
|
if (AllMatched) {
|
2008-09-11 17:15:33 +08:00
|
|
|
if (CatchParam) {
|
|
|
|
CGF.EmitStmt(CatchParam);
|
2008-09-27 15:36:24 +08:00
|
|
|
CGF.Builder.CreateStore(Caught, CGF.GetAddrOfLocalVar(VD));
|
2008-09-11 17:15:33 +08:00
|
|
|
}
|
2008-09-11 16:21:54 +08:00
|
|
|
|
2008-09-11 17:15:33 +08:00
|
|
|
CGF.EmitStmt(CatchStmt->getCatchBody());
|
2008-09-30 09:06:03 +08:00
|
|
|
CGF.EmitJumpThroughFinally(&EHEntry, FinallyEnd);
|
2008-09-10 01:59:25 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-09-27 15:36:24 +08:00
|
|
|
assert(PT && "Unexpected non-pointer type in @catch");
|
|
|
|
QualType T = PT->getPointeeType();
|
2008-09-11 14:35:14 +08:00
|
|
|
const ObjCInterfaceType *ObjCType = T->getAsObjCInterfaceType();
|
2008-09-10 01:59:25 +08:00
|
|
|
assert(ObjCType && "Catch parameter must have Objective-C type!");
|
|
|
|
|
|
|
|
// Check if the @catch block matches the exception object.
|
|
|
|
llvm::Value *Class = EmitClassRef(CGF.Builder, ObjCType->getDecl());
|
|
|
|
|
|
|
|
llvm::Value *Match = CGF.Builder.CreateCall2(ObjCTypes.ExceptionMatchFn,
|
|
|
|
Class, Caught, "match");
|
|
|
|
|
|
|
|
llvm::BasicBlock *MatchedBlock = llvm::BasicBlock::Create("matched");
|
|
|
|
|
2008-09-28 07:30:04 +08:00
|
|
|
CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNonNull(Match, "matched"),
|
|
|
|
MatchedBlock, NextCatchBlock);
|
2008-09-10 01:59:25 +08:00
|
|
|
|
|
|
|
// Emit the @catch block.
|
|
|
|
CGF.EmitBlock(MatchedBlock);
|
2008-09-28 09:03:14 +08:00
|
|
|
CGF.EmitStmt(CatchParam);
|
|
|
|
|
|
|
|
llvm::Value *Tmp =
|
|
|
|
CGF.Builder.CreateBitCast(Caught, CGF.ConvertType(VD->getType()),
|
|
|
|
"tmp");
|
|
|
|
CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(VD));
|
2008-09-11 17:15:33 +08:00
|
|
|
|
|
|
|
CGF.EmitStmt(CatchStmt->getCatchBody());
|
2008-09-30 09:06:03 +08:00
|
|
|
CGF.EmitJumpThroughFinally(&EHEntry, FinallyEnd);
|
2008-09-10 01:59:25 +08:00
|
|
|
|
|
|
|
CGF.EmitBlock(NextCatchBlock);
|
|
|
|
}
|
|
|
|
|
2008-09-27 15:03:52 +08:00
|
|
|
if (!AllMatched) {
|
|
|
|
// None of the handlers caught the exception, so store it to be
|
|
|
|
// rethrown at the end of the @finally block.
|
|
|
|
CGF.Builder.CreateStore(Caught, RethrowPtr);
|
2008-09-30 09:06:03 +08:00
|
|
|
CGF.EmitJumpThroughFinally(&EHEntry, FinallyRethrow);
|
2008-09-27 15:03:52 +08:00
|
|
|
}
|
2008-09-10 01:59:25 +08:00
|
|
|
|
2008-09-27 15:03:52 +08:00
|
|
|
// Emit the exception handler for the @catch blocks.
|
2008-09-28 07:30:04 +08:00
|
|
|
CGF.EmitBlock(CatchHandler);
|
2008-09-27 15:03:52 +08:00
|
|
|
CGF.Builder.CreateStore(CGF.Builder.CreateCall(ObjCTypes.ExceptionExtractFn,
|
|
|
|
ExceptionData),
|
|
|
|
RethrowPtr);
|
2008-09-30 09:06:03 +08:00
|
|
|
CGF.EmitJumpThroughFinally(&EHEntry, FinallyRethrow, false);
|
2008-09-27 15:03:52 +08:00
|
|
|
} else {
|
|
|
|
CGF.Builder.CreateStore(Caught, RethrowPtr);
|
2008-09-30 09:06:03 +08:00
|
|
|
CGF.EmitJumpThroughFinally(&EHEntry, FinallyRethrow, false);
|
2008-09-10 01:59:25 +08:00
|
|
|
}
|
|
|
|
|
2008-09-30 09:06:03 +08:00
|
|
|
// Pop the exception-handling stack entry. It is important to do
|
|
|
|
// this now, because the code in the @finally block is not in this
|
|
|
|
// context.
|
|
|
|
CGF.ObjCEHStack.pop_back();
|
|
|
|
|
2008-09-10 01:59:25 +08:00
|
|
|
// Emit the @finally block.
|
|
|
|
CGF.EmitBlock(FinallyBlock);
|
2008-09-27 15:36:24 +08:00
|
|
|
CGF.Builder.CreateCall(ObjCTypes.ExceptionTryExitFn, ExceptionData);
|
2008-09-10 01:59:25 +08:00
|
|
|
|
2008-09-27 15:36:24 +08:00
|
|
|
CGF.EmitBlock(FinallyNoExit);
|
2008-09-10 01:59:25 +08:00
|
|
|
if (const ObjCAtFinallyStmt* FinallyStmt = S.getFinallyStmt())
|
|
|
|
CGF.EmitStmt(FinallyStmt->getFinallyBody());
|
|
|
|
|
2008-09-30 09:06:03 +08:00
|
|
|
CGF.EmitBlock(FinallyJump);
|
|
|
|
|
|
|
|
CGF.EmitBlock(FinallyRethrow);
|
|
|
|
CGF.Builder.CreateCall(ObjCTypes.ExceptionThrowFn,
|
|
|
|
CGF.Builder.CreateLoad(RethrowPtr));
|
2008-09-28 07:30:04 +08:00
|
|
|
CGF.Builder.CreateUnreachable();
|
2008-09-30 09:06:03 +08:00
|
|
|
|
|
|
|
CGF.EmitBlock(FinallyEnd);
|
2008-09-09 18:04:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
|
2008-09-30 09:06:03 +08:00
|
|
|
const ObjCAtThrowStmt &S) {
|
2008-09-10 00:16:55 +08:00
|
|
|
llvm::Value *ExceptionAsObject;
|
|
|
|
|
|
|
|
if (const Expr *ThrowExpr = S.getThrowExpr()) {
|
|
|
|
llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
|
|
|
|
ExceptionAsObject =
|
|
|
|
CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp");
|
|
|
|
} else {
|
2008-09-30 09:06:03 +08:00
|
|
|
assert((!CGF.ObjCEHStack.empty() && CGF.ObjCEHStack.back()->Exception) &&
|
2008-09-28 09:03:14 +08:00
|
|
|
"Unexpected rethrow outside @catch block.");
|
2008-09-30 09:06:03 +08:00
|
|
|
ExceptionAsObject = CGF.ObjCEHStack.back()->Exception;
|
2008-09-10 00:16:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CGF.Builder.CreateCall(ObjCTypes.ExceptionThrowFn, ExceptionAsObject);
|
2008-09-10 01:59:25 +08:00
|
|
|
CGF.Builder.CreateUnreachable();
|
|
|
|
CGF.EmitBlock(llvm::BasicBlock::Create("bb"));
|
2008-09-09 18:04:29 +08:00
|
|
|
}
|
|
|
|
|
2008-09-30 09:06:03 +08:00
|
|
|
void CodeGenFunction::EmitJumpThroughFinally(ObjCEHEntry *E,
|
|
|
|
llvm::BasicBlock *Dst,
|
|
|
|
bool ExecuteTryExit) {
|
|
|
|
llvm::BasicBlock *Src = Builder.GetInsertBlock();
|
|
|
|
|
|
|
|
if (isDummyBlock(Src))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Find the destination code for this block. We always use 0 for the
|
|
|
|
// fallthrough block (default destination).
|
|
|
|
llvm::SwitchInst *SI = E->FinallySwitch;
|
|
|
|
llvm::ConstantInt *ID;
|
|
|
|
if (Dst == SI->getDefaultDest()) {
|
|
|
|
ID = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
|
|
|
} else {
|
|
|
|
ID = SI->findCaseDest(Dst);
|
|
|
|
if (!ID) {
|
|
|
|
// No code found, get a new unique one by just using the number
|
|
|
|
// of switch successors.
|
|
|
|
ID = llvm::ConstantInt::get(llvm::Type::Int32Ty, SI->getNumSuccessors());
|
|
|
|
SI->addCase(ID, Dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the destination code and branch.
|
|
|
|
Builder.CreateStore(ID, E->DestCode);
|
|
|
|
Builder.CreateBr(ExecuteTryExit ? E->FinallyBlock : E->FinallyNoExit);
|
|
|
|
}
|
|
|
|
|
2008-08-12 05:35:06 +08:00
|
|
|
/* *** Private Interface *** */
|
|
|
|
|
|
|
|
/// EmitImageInfo - Emit the image info marker used to encode some module
|
|
|
|
/// level information.
|
|
|
|
///
|
|
|
|
/// See: <rdr://4810609&4810587&4810587>
|
|
|
|
/// struct IMAGE_INFO {
|
|
|
|
/// unsigned version;
|
|
|
|
/// unsigned flags;
|
|
|
|
/// };
|
|
|
|
enum ImageInfoFlags {
|
|
|
|
eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what this implies
|
|
|
|
eImageInfo_GarbageCollected = (1 << 1),
|
|
|
|
eImageInfo_GCOnly = (1 << 2)
|
|
|
|
};
|
|
|
|
|
|
|
|
void CGObjCMac::EmitImageInfo() {
|
|
|
|
unsigned version = 0; // Version is unused?
|
|
|
|
unsigned flags = 0;
|
|
|
|
|
|
|
|
// FIXME: Fix and continue?
|
|
|
|
if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC)
|
|
|
|
flags |= eImageInfo_GarbageCollected;
|
|
|
|
if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly)
|
|
|
|
flags |= eImageInfo_GCOnly;
|
|
|
|
|
|
|
|
// Emitted as int[2];
|
|
|
|
llvm::Constant *values[2] = {
|
|
|
|
llvm::ConstantInt::get(llvm::Type::Int32Ty, version),
|
|
|
|
llvm::ConstantInt::get(llvm::Type::Int32Ty, flags)
|
|
|
|
};
|
|
|
|
llvm::ArrayType *AT = llvm::ArrayType::get(llvm::Type::Int32Ty, 2);
|
2008-08-12 14:48:42 +08:00
|
|
|
llvm::GlobalVariable *GV =
|
2008-08-12 05:35:06 +08:00
|
|
|
new llvm::GlobalVariable(AT, true,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
llvm::ConstantArray::get(AT, values, 2),
|
|
|
|
"\01L_OBJC_IMAGE_INFO",
|
|
|
|
&CGM.getModule());
|
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
if (ObjCABI == 1) {
|
|
|
|
GV->setSection("__OBJC, __image_info,regular");
|
|
|
|
} else {
|
|
|
|
GV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip");
|
|
|
|
}
|
2008-08-12 05:35:06 +08:00
|
|
|
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
}
|
|
|
|
|
2008-08-12 14:48:42 +08:00
|
|
|
|
|
|
|
// struct objc_module {
|
|
|
|
// unsigned long version;
|
|
|
|
// unsigned long size;
|
|
|
|
// const char *name;
|
|
|
|
// Symtab symtab;
|
|
|
|
// };
|
|
|
|
|
|
|
|
// FIXME: Get from somewhere
|
|
|
|
static const int ModuleVersion = 7;
|
|
|
|
|
|
|
|
void CGObjCMac::EmitModuleInfo() {
|
|
|
|
uint64_t Size = CGM.getTargetData().getABITypeSize(ObjCTypes.ModuleTy);
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Values(4);
|
|
|
|
Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion);
|
|
|
|
Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
|
2008-08-16 06:20:32 +08:00
|
|
|
// This used to be the filename, now it is unused. <rdr://4327263>
|
2008-08-13 11:21:16 +08:00
|
|
|
Values[2] = GetClassName(&CGM.getContext().Idents.get(""));
|
2008-08-12 14:48:42 +08:00
|
|
|
Values[3] = EmitModuleSymbols();
|
|
|
|
|
|
|
|
llvm::GlobalVariable *GV =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.ModuleTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
llvm::ConstantStruct::get(ObjCTypes.ModuleTy,
|
|
|
|
Values),
|
2008-08-13 11:21:16 +08:00
|
|
|
"\01L_OBJC_MODULES",
|
2008-08-12 14:48:42 +08:00
|
|
|
&CGM.getModule());
|
|
|
|
GV->setSection("__OBJC,__module_info,regular,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(GV);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Constant *CGObjCMac::EmitModuleSymbols() {
|
2008-08-21 12:36:09 +08:00
|
|
|
unsigned NumClasses = DefinedClasses.size();
|
|
|
|
unsigned NumCategories = DefinedCategories.size();
|
|
|
|
|
2008-08-25 14:02:07 +08:00
|
|
|
// Return null if no symbols were defined.
|
|
|
|
if (!NumClasses && !NumCategories)
|
|
|
|
return llvm::Constant::getNullValue(ObjCTypes.SymtabPtrTy);
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Values(5);
|
2008-08-21 12:36:09 +08:00
|
|
|
Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
|
|
|
|
Values[1] = llvm::Constant::getNullValue(ObjCTypes.SelectorPtrTy);
|
|
|
|
Values[2] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumClasses);
|
|
|
|
Values[3] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumCategories);
|
|
|
|
|
2008-08-23 04:34:54 +08:00
|
|
|
// The runtime expects exactly the list of defined classes followed
|
|
|
|
// by the list of defined categories, in a single array.
|
2008-08-21 12:36:09 +08:00
|
|
|
std::vector<llvm::Constant*> Symbols(NumClasses + NumCategories);
|
2008-08-23 04:34:54 +08:00
|
|
|
for (unsigned i=0; i<NumClasses; i++)
|
|
|
|
Symbols[i] = llvm::ConstantExpr::getBitCast(DefinedClasses[i],
|
|
|
|
ObjCTypes.Int8PtrTy);
|
|
|
|
for (unsigned i=0; i<NumCategories; i++)
|
|
|
|
Symbols[NumClasses + i] =
|
|
|
|
llvm::ConstantExpr::getBitCast(DefinedCategories[i],
|
|
|
|
ObjCTypes.Int8PtrTy);
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
Values[4] =
|
2008-08-23 04:34:54 +08:00
|
|
|
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
|
2008-08-21 12:36:09 +08:00
|
|
|
NumClasses + NumCategories),
|
|
|
|
Symbols);
|
|
|
|
|
|
|
|
llvm::Constant *Init = llvm::ConstantStruct::get(Values);
|
|
|
|
|
2008-08-12 14:48:42 +08:00
|
|
|
llvm::GlobalVariable *GV =
|
2008-08-21 12:36:09 +08:00
|
|
|
new llvm::GlobalVariable(Init->getType(), false,
|
2008-08-12 14:48:42 +08:00
|
|
|
llvm::GlobalValue::InternalLinkage,
|
2008-08-21 12:36:09 +08:00
|
|
|
Init,
|
2008-08-12 14:48:42 +08:00
|
|
|
"\01L_OBJC_SYMBOLS",
|
|
|
|
&CGM.getModule());
|
|
|
|
GV->setSection("__OBJC,__symbols,regular,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(GV);
|
2008-08-21 12:36:09 +08:00
|
|
|
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Value *CGObjCMac::EmitClassRef(llvm::IRBuilder<> &Builder,
|
|
|
|
const ObjCInterfaceDecl *ID) {
|
2008-08-25 14:02:07 +08:00
|
|
|
LazySymbols.insert(ID->getIdentifier());
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
|
|
|
|
|
|
|
|
if (!Entry) {
|
|
|
|
llvm::Constant *Casted =
|
|
|
|
llvm::ConstantExpr::getBitCast(GetClassName(ID->getIdentifier()),
|
|
|
|
ObjCTypes.ClassPtrTy);
|
|
|
|
Entry =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.ClassPtrTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Casted, "\01L_OBJC_CLASS_REFERENCES_",
|
|
|
|
&CGM.getModule());
|
|
|
|
Entry->setSection("__OBJC,__cls_refs,literal_pointers,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(Entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Builder.CreateLoad(Entry, false, "tmp");
|
2008-08-12 14:48:42 +08:00
|
|
|
}
|
|
|
|
|
2008-08-12 11:39:23 +08:00
|
|
|
llvm::Value *CGObjCMac::EmitSelector(llvm::IRBuilder<> &Builder, Selector Sel) {
|
|
|
|
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
|
|
|
|
|
|
|
|
if (!Entry) {
|
|
|
|
llvm::Constant *Casted =
|
|
|
|
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
|
|
|
|
ObjCTypes.SelectorPtrTy);
|
|
|
|
Entry =
|
|
|
|
new llvm::GlobalVariable(ObjCTypes.SelectorPtrTy, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
Casted, "\01L_OBJC_SELECTOR_REFERENCES_",
|
|
|
|
&CGM.getModule());
|
|
|
|
Entry->setSection("__OBJC,__message_refs,literal_pointers,no_dead_strip");
|
|
|
|
UsedGlobals.push_back(Entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Builder.CreateLoad(Entry, false, "tmp");
|
|
|
|
}
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
llvm::Constant *CGObjCMac::GetClassName(IdentifierInfo *Ident) {
|
|
|
|
llvm::GlobalVariable *&Entry = ClassNames[Ident];
|
2008-08-12 14:48:42 +08:00
|
|
|
|
|
|
|
if (!Entry) {
|
2008-08-13 11:21:16 +08:00
|
|
|
llvm::Constant *C = llvm::ConstantArray::get(Ident->getName());
|
2008-08-12 14:48:42 +08:00
|
|
|
Entry =
|
2008-08-13 11:21:16 +08:00
|
|
|
new llvm::GlobalVariable(C->getType(), false,
|
2008-08-12 14:48:42 +08:00
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
C, "\01L_OBJC_CLASS_NAME_",
|
|
|
|
&CGM.getModule());
|
|
|
|
Entry->setSection("__TEXT,__cstring,cstring_literals");
|
|
|
|
UsedGlobals.push_back(Entry);
|
|
|
|
}
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
return getConstantGEP(Entry, 0, 0);
|
2008-08-12 14:48:42 +08:00
|
|
|
}
|
|
|
|
|
2008-08-12 11:39:23 +08:00
|
|
|
llvm::Constant *CGObjCMac::GetMethodVarName(Selector Sel) {
|
|
|
|
llvm::GlobalVariable *&Entry = MethodVarNames[Sel];
|
|
|
|
|
|
|
|
if (!Entry) {
|
|
|
|
llvm::Constant *C = llvm::ConstantArray::get(Sel.getName());
|
|
|
|
Entry =
|
2008-08-13 11:21:16 +08:00
|
|
|
new llvm::GlobalVariable(C->getType(), false,
|
2008-08-12 11:39:23 +08:00
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
C, "\01L_OBJC_METH_VAR_NAME_",
|
|
|
|
&CGM.getModule());
|
|
|
|
Entry->setSection("__TEXT,__cstring,cstring_literals");
|
|
|
|
UsedGlobals.push_back(Entry);
|
|
|
|
}
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
return getConstantGEP(Entry, 0, 0);
|
|
|
|
}
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
// FIXME: Merge into a single cstring creation function.
|
|
|
|
llvm::Constant *CGObjCMac::GetMethodVarName(IdentifierInfo *ID) {
|
|
|
|
return GetMethodVarName(CGM.getContext().Selectors.getNullarySelector(ID));
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Merge into a single cstring creation function.
|
|
|
|
llvm::Constant *CGObjCMac::GetMethodVarName(const std::string &Name) {
|
|
|
|
return GetMethodVarName(&CGM.getContext().Idents.get(Name));
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Constant *CGObjCMac::GetMethodVarType(const std::string &Name) {
|
|
|
|
llvm::GlobalVariable *&Entry = MethodVarTypes[Name];
|
2008-08-13 11:21:16 +08:00
|
|
|
|
|
|
|
if (!Entry) {
|
2008-08-21 12:36:09 +08:00
|
|
|
llvm::Constant *C = llvm::ConstantArray::get(Name);
|
2008-08-13 11:21:16 +08:00
|
|
|
Entry =
|
|
|
|
new llvm::GlobalVariable(C->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
C, "\01L_OBJC_METH_VAR_TYPE_",
|
|
|
|
&CGM.getModule());
|
|
|
|
Entry->setSection("__TEXT,__cstring,cstring_literals");
|
|
|
|
UsedGlobals.push_back(Entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
return getConstantGEP(Entry, 0, 0);
|
2008-08-12 11:39:23 +08:00
|
|
|
}
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
// FIXME: Merge into a single cstring creation function.
|
2008-08-27 05:51:14 +08:00
|
|
|
llvm::Constant *CGObjCMac::GetMethodVarType(const ObjCMethodDecl *D) {
|
2008-08-21 12:36:09 +08:00
|
|
|
std::string TypeStr;
|
2008-08-27 05:51:14 +08:00
|
|
|
CGM.getContext().getObjCEncodingForMethodDecl(const_cast<ObjCMethodDecl*>(D),
|
|
|
|
TypeStr);
|
2008-08-21 12:36:09 +08:00
|
|
|
return GetMethodVarType(TypeStr);
|
|
|
|
}
|
|
|
|
|
2008-08-23 08:19:03 +08:00
|
|
|
// FIXME: Merge into a single cstring creation function.
|
|
|
|
llvm::Constant *CGObjCMac::GetPropertyName(IdentifierInfo *Ident) {
|
|
|
|
llvm::GlobalVariable *&Entry = PropertyNames[Ident];
|
|
|
|
|
|
|
|
if (!Entry) {
|
|
|
|
llvm::Constant *C = llvm::ConstantArray::get(Ident->getName());
|
|
|
|
Entry =
|
|
|
|
new llvm::GlobalVariable(C->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
C, "\01L_OBJC_PROP_NAME_ATTR_",
|
|
|
|
&CGM.getModule());
|
|
|
|
Entry->setSection("__TEXT,__cstring,cstring_literals");
|
|
|
|
UsedGlobals.push_back(Entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
return getConstantGEP(Entry, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Merge into a single cstring creation function.
|
2008-08-28 12:38:10 +08:00
|
|
|
// FIXME: This Decl should be more precise.
|
|
|
|
llvm::Constant *CGObjCMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
|
|
|
|
const Decl *Container) {
|
|
|
|
std::string TypeStr;
|
|
|
|
CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container, TypeStr);
|
2008-08-23 08:19:03 +08:00
|
|
|
return GetPropertyName(&CGM.getContext().Idents.get(TypeStr));
|
|
|
|
}
|
|
|
|
|
2008-08-16 11:19:19 +08:00
|
|
|
void CGObjCMac::GetNameForMethod(const ObjCMethodDecl *D,
|
|
|
|
std::string &NameOut) {
|
|
|
|
// FIXME: Find the mangling GCC uses.
|
|
|
|
std::stringstream s;
|
|
|
|
s << (D->isInstance() ? "-" : "+");
|
|
|
|
s << "[";
|
|
|
|
s << D->getClassInterface()->getName();
|
|
|
|
s << " ";
|
|
|
|
s << D->getSelector().getName();
|
|
|
|
s << "]";
|
|
|
|
NameOut = s.str();
|
|
|
|
}
|
|
|
|
|
2008-08-12 05:35:06 +08:00
|
|
|
void CGObjCMac::FinishModule() {
|
2008-08-12 14:48:42 +08:00
|
|
|
EmitModuleInfo();
|
|
|
|
|
2008-08-12 05:35:06 +08:00
|
|
|
std::vector<llvm::Constant*> Used;
|
2008-08-12 14:48:42 +08:00
|
|
|
|
|
|
|
for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
|
2008-08-12 05:35:06 +08:00
|
|
|
e = UsedGlobals.end(); i != e; ++i) {
|
2008-08-21 12:36:09 +08:00
|
|
|
Used.push_back(llvm::ConstantExpr::getBitCast(*i, ObjCTypes.Int8PtrTy));
|
2008-08-12 05:35:06 +08:00
|
|
|
}
|
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy, Used.size());
|
2008-08-12 05:35:06 +08:00
|
|
|
llvm::GlobalValue *GV =
|
|
|
|
new llvm::GlobalVariable(AT, false,
|
|
|
|
llvm::GlobalValue::AppendingLinkage,
|
|
|
|
llvm::ConstantArray::get(AT, Used),
|
|
|
|
"llvm.used",
|
|
|
|
&CGM.getModule());
|
|
|
|
|
|
|
|
GV->setSection("llvm.metadata");
|
2008-08-25 14:02:07 +08:00
|
|
|
|
|
|
|
// Add assembler directives to add lazy undefined symbol references
|
|
|
|
// for classes which are referenced but not defined. This is
|
|
|
|
// important for correct linker interaction.
|
|
|
|
|
|
|
|
// FIXME: Uh, this isn't particularly portable.
|
|
|
|
std::stringstream s;
|
|
|
|
for (std::set<IdentifierInfo*>::iterator i = LazySymbols.begin(),
|
|
|
|
e = LazySymbols.end(); i != e; ++i) {
|
|
|
|
s << "\t.lazy_reference .objc_class_name_" << (*i)->getName() << "\n";
|
|
|
|
}
|
|
|
|
for (std::set<IdentifierInfo*>::iterator i = DefinedSymbols.begin(),
|
|
|
|
e = DefinedSymbols.end(); i != e; ++i) {
|
2008-08-28 12:38:10 +08:00
|
|
|
s << "\t.objc_class_name_" << (*i)->getName() << "=0\n"
|
2008-08-25 14:02:07 +08:00
|
|
|
<< "\t.globl .objc_class_name_" << (*i)->getName() << "\n";
|
|
|
|
}
|
|
|
|
CGM.getModule().appendModuleInlineAsm(s.str());
|
2008-08-12 05:35:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* *** */
|
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
|
2008-08-24 02:37:06 +08:00
|
|
|
: CGM(cgm)
|
2008-08-12 08:12:39 +08:00
|
|
|
{
|
2008-08-12 14:48:42 +08:00
|
|
|
CodeGen::CodeGenTypes &Types = CGM.getTypes();
|
|
|
|
ASTContext &Ctx = CGM.getContext();
|
2008-08-13 11:21:16 +08:00
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
ShortTy = Types.ConvertType(Ctx.ShortTy);
|
2008-08-13 11:21:16 +08:00
|
|
|
IntTy = Types.ConvertType(Ctx.IntTy);
|
2008-08-12 14:48:42 +08:00
|
|
|
LongTy = Types.ConvertType(Ctx.LongTy);
|
2008-08-21 12:36:09 +08:00
|
|
|
Int8PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
|
|
|
|
2008-08-12 14:48:42 +08:00
|
|
|
ObjectPtrTy = Types.ConvertType(Ctx.getObjCIdType());
|
|
|
|
SelectorPtrTy = Types.ConvertType(Ctx.getObjCSelType());
|
2008-08-13 11:21:16 +08:00
|
|
|
|
|
|
|
// FIXME: It would be nice to unify this with the opaque type, so
|
|
|
|
// that the IR comes out a bit cleaner.
|
|
|
|
const llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
|
|
|
|
ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
|
2008-08-12 14:48:42 +08:00
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
MethodDescriptionTy =
|
|
|
|
llvm::StructType::get(SelectorPtrTy,
|
2008-08-21 12:36:09 +08:00
|
|
|
Int8PtrTy,
|
2008-08-13 11:21:16 +08:00
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_method_description",
|
|
|
|
MethodDescriptionTy);
|
|
|
|
|
|
|
|
MethodDescriptionListTy =
|
|
|
|
llvm::StructType::get(IntTy,
|
|
|
|
llvm::ArrayType::get(MethodDescriptionTy, 0),
|
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_method_description_list",
|
|
|
|
MethodDescriptionListTy);
|
|
|
|
MethodDescriptionListPtrTy =
|
|
|
|
llvm::PointerType::getUnqual(MethodDescriptionListTy);
|
|
|
|
|
2008-08-23 08:19:03 +08:00
|
|
|
PropertyTy = llvm::StructType::get(Int8PtrTy,
|
|
|
|
Int8PtrTy,
|
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_property",
|
|
|
|
PropertyTy);
|
|
|
|
|
|
|
|
PropertyListTy = llvm::StructType::get(IntTy,
|
|
|
|
IntTy,
|
|
|
|
llvm::ArrayType::get(PropertyTy, 0),
|
|
|
|
NULL);
|
2008-08-13 11:21:16 +08:00
|
|
|
CGM.getModule().addTypeName("struct._objc_property_list",
|
|
|
|
PropertyListTy);
|
|
|
|
PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
|
|
|
|
|
|
|
|
// Protocol description structures
|
|
|
|
|
|
|
|
ProtocolExtensionTy =
|
|
|
|
llvm::StructType::get(Types.ConvertType(Ctx.IntTy),
|
|
|
|
llvm::PointerType::getUnqual(MethodDescriptionListTy),
|
|
|
|
llvm::PointerType::getUnqual(MethodDescriptionListTy),
|
|
|
|
PropertyListPtrTy,
|
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_protocol_extension",
|
|
|
|
ProtocolExtensionTy);
|
|
|
|
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
|
|
|
|
|
|
|
|
// Handle recursive construction of Protocl and ProtocolList types
|
|
|
|
|
|
|
|
llvm::PATypeHolder ProtocolTyHolder = llvm::OpaqueType::get();
|
|
|
|
llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get();
|
|
|
|
|
|
|
|
T = llvm::StructType::get(llvm::PointerType::getUnqual(ProtocolListTyHolder),
|
|
|
|
LongTy,
|
|
|
|
llvm::ArrayType::get(ProtocolTyHolder, 0),
|
|
|
|
NULL);
|
|
|
|
cast<llvm::OpaqueType>(ProtocolListTyHolder.get())->refineAbstractTypeTo(T);
|
|
|
|
|
|
|
|
T = llvm::StructType::get(llvm::PointerType::getUnqual(ProtocolExtensionTy),
|
2008-08-21 12:36:09 +08:00
|
|
|
Int8PtrTy,
|
2008-08-13 11:21:16 +08:00
|
|
|
llvm::PointerType::getUnqual(ProtocolListTyHolder),
|
|
|
|
MethodDescriptionListPtrTy,
|
|
|
|
MethodDescriptionListPtrTy,
|
|
|
|
NULL);
|
|
|
|
cast<llvm::OpaqueType>(ProtocolTyHolder.get())->refineAbstractTypeTo(T);
|
|
|
|
|
|
|
|
ProtocolListTy = cast<llvm::StructType>(ProtocolListTyHolder.get());
|
|
|
|
CGM.getModule().addTypeName("struct._objc_protocol_list",
|
|
|
|
ProtocolListTy);
|
|
|
|
ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
|
|
|
|
|
|
|
|
ProtocolTy = cast<llvm::StructType>(ProtocolTyHolder.get());
|
|
|
|
CGM.getModule().addTypeName("struct.__objc_protocol", ProtocolTy);
|
|
|
|
ProtocolPtrTy = llvm::PointerType::getUnqual(ProtocolTy);
|
2008-08-21 12:36:09 +08:00
|
|
|
|
|
|
|
// Class description structures
|
|
|
|
|
|
|
|
IvarTy = llvm::StructType::get(Int8PtrTy,
|
|
|
|
Int8PtrTy,
|
|
|
|
IntTy,
|
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_ivar", IvarTy);
|
|
|
|
|
|
|
|
IvarListTy = llvm::OpaqueType::get();
|
|
|
|
CGM.getModule().addTypeName("struct._objc_ivar_list", IvarListTy);
|
|
|
|
IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
|
|
|
|
|
|
|
|
MethodTy = llvm::StructType::get(SelectorPtrTy,
|
|
|
|
Int8PtrTy,
|
|
|
|
Int8PtrTy,
|
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_method", MethodTy);
|
|
|
|
|
|
|
|
MethodListTy = llvm::OpaqueType::get();
|
|
|
|
CGM.getModule().addTypeName("struct._objc_method_list", MethodListTy);
|
|
|
|
MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
|
|
|
|
|
|
|
|
CacheTy = llvm::OpaqueType::get();
|
|
|
|
CGM.getModule().addTypeName("struct._objc_cache", CacheTy);
|
|
|
|
CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
|
|
|
|
|
|
|
|
ClassExtensionTy =
|
|
|
|
llvm::StructType::get(IntTy,
|
|
|
|
Int8PtrTy,
|
|
|
|
PropertyListPtrTy,
|
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_class_extension", ClassExtensionTy);
|
|
|
|
ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
|
|
|
|
|
|
|
|
llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get();
|
|
|
|
|
|
|
|
T = llvm::StructType::get(llvm::PointerType::getUnqual(ClassTyHolder),
|
|
|
|
llvm::PointerType::getUnqual(ClassTyHolder),
|
|
|
|
Int8PtrTy,
|
|
|
|
LongTy,
|
|
|
|
LongTy,
|
|
|
|
LongTy,
|
|
|
|
IvarListPtrTy,
|
|
|
|
MethodListPtrTy,
|
|
|
|
CachePtrTy,
|
|
|
|
ProtocolListPtrTy,
|
|
|
|
Int8PtrTy,
|
|
|
|
ClassExtensionPtrTy,
|
|
|
|
NULL);
|
|
|
|
cast<llvm::OpaqueType>(ClassTyHolder.get())->refineAbstractTypeTo(T);
|
|
|
|
|
|
|
|
ClassTy = cast<llvm::StructType>(ClassTyHolder.get());
|
|
|
|
CGM.getModule().addTypeName("struct._objc_class", ClassTy);
|
|
|
|
ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
|
|
|
|
|
2008-08-23 04:34:54 +08:00
|
|
|
CategoryTy = llvm::StructType::get(Int8PtrTy,
|
|
|
|
Int8PtrTy,
|
|
|
|
MethodListPtrTy,
|
|
|
|
MethodListPtrTy,
|
|
|
|
ProtocolListPtrTy,
|
|
|
|
IntTy,
|
|
|
|
PropertyListPtrTy,
|
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_category", CategoryTy);
|
|
|
|
|
2008-08-30 11:02:31 +08:00
|
|
|
// I'm not sure I like this. The implicit coordination is a bit
|
|
|
|
// gross. We should solve this in a reasonable fashion because this
|
|
|
|
// is a pretty common task (match some runtime data structure with
|
|
|
|
// an LLVM data structure).
|
|
|
|
|
|
|
|
// FIXME: This is leaked.
|
|
|
|
// FIXME: Merge with rewriter code?
|
|
|
|
RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0,
|
|
|
|
SourceLocation(),
|
2008-09-05 09:34:33 +08:00
|
|
|
&Ctx.Idents.get("_objc_super"));
|
2008-08-30 11:02:31 +08:00
|
|
|
FieldDecl *FieldDecls[2];
|
|
|
|
FieldDecls[0] = FieldDecl::Create(Ctx, SourceLocation(), 0,
|
|
|
|
Ctx.getObjCIdType());
|
|
|
|
FieldDecls[1] = FieldDecl::Create(Ctx, SourceLocation(), 0,
|
|
|
|
Ctx.getObjCClassType());
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
RD->defineBody(Ctx, FieldDecls, 2);
|
2008-08-30 11:02:31 +08:00
|
|
|
|
|
|
|
SuperCTy = Ctx.getTagDeclType(RD);
|
|
|
|
SuperPtrCTy = Ctx.getPointerType(SuperCTy);
|
|
|
|
|
|
|
|
SuperTy = cast<llvm::StructType>(Types.ConvertType(SuperCTy));
|
2008-08-23 17:25:55 +08:00
|
|
|
SuperPtrTy = llvm::PointerType::getUnqual(SuperTy);
|
2008-08-23 12:28:29 +08:00
|
|
|
|
2008-08-21 12:36:09 +08:00
|
|
|
// Global metadata structures
|
|
|
|
|
|
|
|
SymtabTy = llvm::StructType::get(LongTy,
|
|
|
|
SelectorPtrTy,
|
|
|
|
ShortTy,
|
|
|
|
ShortTy,
|
2008-08-23 04:34:54 +08:00
|
|
|
llvm::ArrayType::get(Int8PtrTy, 0),
|
2008-08-21 12:36:09 +08:00
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_symtab", SymtabTy);
|
|
|
|
SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
|
|
|
|
|
|
|
|
ModuleTy =
|
|
|
|
llvm::StructType::get(LongTy,
|
|
|
|
LongTy,
|
|
|
|
Int8PtrTy,
|
|
|
|
SymtabPtrTy,
|
|
|
|
NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_module", ModuleTy);
|
2008-08-23 17:25:55 +08:00
|
|
|
|
2008-09-24 11:38:44 +08:00
|
|
|
// Message send functions.
|
2008-08-23 17:25:55 +08:00
|
|
|
|
|
|
|
std::vector<const llvm::Type*> Params;
|
|
|
|
Params.push_back(ObjectPtrTy);
|
|
|
|
Params.push_back(SelectorPtrTy);
|
2008-10-01 09:06:06 +08:00
|
|
|
MessageSendFn =
|
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
|
|
|
|
Params,
|
|
|
|
true),
|
|
|
|
"objc_msgSend");
|
2008-08-23 17:25:55 +08:00
|
|
|
|
|
|
|
Params.clear();
|
|
|
|
Params.push_back(Int8PtrTy);
|
|
|
|
Params.push_back(ObjectPtrTy);
|
|
|
|
Params.push_back(SelectorPtrTy);
|
|
|
|
MessageSendStretFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
|
|
|
|
Params,
|
|
|
|
true),
|
|
|
|
"objc_msgSend_stret");
|
2008-08-23 17:25:55 +08:00
|
|
|
|
|
|
|
Params.clear();
|
|
|
|
Params.push_back(SuperPtrTy);
|
|
|
|
Params.push_back(SelectorPtrTy);
|
|
|
|
MessageSendSuperFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
|
|
|
|
Params,
|
|
|
|
true),
|
|
|
|
"objc_msgSendSuper");
|
2008-08-23 17:25:55 +08:00
|
|
|
|
|
|
|
Params.clear();
|
|
|
|
Params.push_back(Int8PtrTy);
|
|
|
|
Params.push_back(SuperPtrTy);
|
|
|
|
Params.push_back(SelectorPtrTy);
|
|
|
|
MessageSendSuperStretFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
|
|
|
|
Params,
|
|
|
|
true),
|
|
|
|
"objc_msgSendSuper_stret");
|
2008-08-31 12:05:03 +08:00
|
|
|
|
2008-09-24 11:38:44 +08:00
|
|
|
// Property manipulation functions.
|
|
|
|
|
|
|
|
Params.clear();
|
|
|
|
Params.push_back(ObjectPtrTy);
|
|
|
|
Params.push_back(SelectorPtrTy);
|
|
|
|
Params.push_back(LongTy);
|
|
|
|
Params.push_back(Types.ConvertTypeForMem(Ctx.BoolTy));
|
|
|
|
GetPropertyFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"objc_getProperty");
|
|
|
|
|
2008-09-24 11:38:44 +08:00
|
|
|
Params.clear();
|
|
|
|
Params.push_back(ObjectPtrTy);
|
|
|
|
Params.push_back(SelectorPtrTy);
|
|
|
|
Params.push_back(LongTy);
|
2008-09-24 14:32:09 +08:00
|
|
|
Params.push_back(ObjectPtrTy);
|
2008-09-24 11:38:44 +08:00
|
|
|
Params.push_back(Types.ConvertTypeForMem(Ctx.BoolTy));
|
|
|
|
Params.push_back(Types.ConvertTypeForMem(Ctx.BoolTy));
|
|
|
|
SetPropertyFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"objc_setProperty");
|
2008-09-24 11:38:44 +08:00
|
|
|
|
2008-08-31 12:05:03 +08:00
|
|
|
// Enumeration mutation.
|
2008-09-24 11:38:44 +08:00
|
|
|
|
2008-08-31 12:05:03 +08:00
|
|
|
Params.clear();
|
|
|
|
Params.push_back(ObjectPtrTy);
|
|
|
|
EnumerationMutationFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"objc_enumerationMutation");
|
2008-09-09 18:10:21 +08:00
|
|
|
|
|
|
|
// FIXME: This is the size of the setjmp buffer and should be
|
|
|
|
// target specific. 18 is what's used on 32-bit X86.
|
|
|
|
uint64_t SetJmpBufferSize = 18;
|
|
|
|
|
|
|
|
// Exceptions
|
|
|
|
const llvm::Type *StackPtrTy =
|
2008-09-27 14:32:25 +08:00
|
|
|
llvm::ArrayType::get(llvm::PointerType::getUnqual(llvm::Type::Int8Ty), 4);
|
2008-09-09 18:10:21 +08:00
|
|
|
|
|
|
|
ExceptionDataTy =
|
|
|
|
llvm::StructType::get(llvm::ArrayType::get(llvm::Type::Int32Ty,
|
|
|
|
SetJmpBufferSize),
|
|
|
|
StackPtrTy, NULL);
|
|
|
|
CGM.getModule().addTypeName("struct._objc_exception_data",
|
|
|
|
ExceptionDataTy);
|
|
|
|
|
|
|
|
Params.clear();
|
|
|
|
Params.push_back(ObjectPtrTy);
|
|
|
|
ExceptionThrowFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"objc_exception_throw");
|
2008-09-09 18:10:21 +08:00
|
|
|
|
|
|
|
Params.clear();
|
|
|
|
Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
|
|
|
|
ExceptionTryEnterFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"objc_exception_try_enter");
|
2008-09-09 18:10:21 +08:00
|
|
|
ExceptionTryExitFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"objc_exception_try_exit");
|
2008-09-09 18:10:21 +08:00
|
|
|
ExceptionExtractFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"objc_exception_extract");
|
2008-09-09 18:10:21 +08:00
|
|
|
|
|
|
|
Params.clear();
|
|
|
|
Params.push_back(ClassPtrTy);
|
|
|
|
Params.push_back(ObjectPtrTy);
|
|
|
|
ExceptionMatchFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"objc_exception_match");
|
2008-09-09 18:10:21 +08:00
|
|
|
|
|
|
|
Params.clear();
|
|
|
|
Params.push_back(llvm::PointerType::getUnqual(llvm::Type::Int32Ty));
|
|
|
|
SetJmpFn =
|
2008-10-01 09:06:06 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty,
|
|
|
|
Params,
|
|
|
|
false),
|
|
|
|
"_setjmp");
|
2008-08-12 08:12:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ObjCTypesHelper::~ObjCTypesHelper() {
|
|
|
|
}
|
|
|
|
|
2008-09-10 15:00:50 +08:00
|
|
|
llvm::Constant *ObjCTypesHelper::getMessageSendFn(bool IsSuper, bool IsStret) {
|
2008-09-10 07:48:28 +08:00
|
|
|
if (IsStret) {
|
2008-09-10 15:00:50 +08:00
|
|
|
return IsSuper ? MessageSendSuperStretFn : MessageSendStretFn;
|
2008-08-30 01:28:43 +08:00
|
|
|
} else { // FIXME: floating point?
|
2008-09-10 15:00:50 +08:00
|
|
|
return IsSuper ? MessageSendSuperFn : MessageSendFn;
|
2008-08-23 12:28:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-12 08:12:39 +08:00
|
|
|
/* *** */
|
|
|
|
|
2008-08-13 11:21:16 +08:00
|
|
|
CodeGen::CGObjCRuntime *
|
|
|
|
CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
|
2008-08-11 10:45:11 +08:00
|
|
|
return new CGObjCMac(CGM);
|
|
|
|
}
|