blob: 827055de4d2d0a6add5a4250f031e755423d008a [file] [log] [blame]
//===------- 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 targeting the Apple runtime.
//
//===----------------------------------------------------------------------===//
#include "CGObjCRuntime.h"
#include "CGRecordLayout.h"
#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "CGBlocks.h"
#include "CGCleanup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/InlineAsm.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
#include <cstdio>
using namespace clang;
using namespace CodeGen;
namespace {
typedef std::vector<llvm::Constant*> ConstantVector;
// FIXME: We should find a nicer way to make the labels for metadata, string
// concatenation is lame.
class ObjCCommonTypesHelper {
protected:
llvm::LLVMContext &VMContext;
private:
// The types of these functions don't really matter because we
// should always bitcast before calling them.
/// id objc_msgSend (id, SEL, ...)
///
/// The default messenger, used for sends whose ABI is unchanged from
/// the all-integer/pointer case.
llvm::Constant *getMessageSendFn() const {
// Add the non-lazy-bind attribute, since objc_msgSend is likely to
// be called a lot.
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend",
llvm::Attribute::NonLazyBind);
}
/// void objc_msgSend_stret (id, SEL, ...)
///
/// The messenger used when the return value is an aggregate returned
/// by indirect reference in the first argument, and therefore the
/// self and selector parameters are shifted over by one.
llvm::Constant *getMessageSendStretFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy,
params, true),
"objc_msgSend_stret");
}
/// [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
///
/// The messenger used when the return value is returned on the x87
/// floating-point stack; without a special entrypoint, the nil case
/// would be unbalanced.
llvm::Constant *getMessageSendFpretFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::Type::getDoubleTy(VMContext),
params, true),
"objc_msgSend_fpret");
}
/// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
///
/// The messenger used when the return value is returned in two values on the
/// x87 floating point stack; without a special entrypoint, the nil case
/// would be unbalanced. Only used on 64-bit X86.
llvm::Constant *getMessageSendFp2retFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
llvm::Type *resultType =
llvm::StructType::get(longDoubleType, longDoubleType, NULL);
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
params, true),
"objc_msgSend_fp2ret");
}
/// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
///
/// The messenger used for super calls, which have different dispatch
/// semantics. The class passed is the superclass of the current
/// class.
llvm::Constant *getMessageSendSuperFn() const {
llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper");
}
/// id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
///
/// A slightly different messenger used for super calls. The class
/// passed is the current class.
llvm::Constant *getMessageSendSuperFn2() const {
llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper2");
}
/// void objc_msgSendSuper_stret(void *stretAddr, struct objc_super *super,
/// SEL op, ...)
///
/// The messenger used for super calls which return an aggregate indirectly.
llvm::Constant *getMessageSendSuperStretFn() const {
llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper_stret");
}
/// void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
/// SEL op, ...)
///
/// objc_msgSendSuper_stret with the super2 semantics.
llvm::Constant *getMessageSendSuperStretFn2() const {
llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper2_stret");
}
llvm::Constant *getMessageSendSuperFpretFn() const {
// There is no objc_msgSendSuper_fpret? How can that work?
return getMessageSendSuperFn();
}
llvm::Constant *getMessageSendSuperFpretFn2() const {
// There is no objc_msgSendSuper_fpret? How can that work?
return getMessageSendSuperFn2();
}
protected:
CodeGen::CodeGenModule &CGM;
public:
llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy;
llvm::Type *Int8PtrTy, *Int8PtrPtrTy;
/// ObjectPtrTy - LLVM type for object handles (typeof(id))
llvm::Type *ObjectPtrTy;
/// PtrObjectPtrTy - LLVM type for id *
llvm::Type *PtrObjectPtrTy;
/// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
llvm::Type *SelectorPtrTy;
private:
/// ProtocolPtrTy - LLVM type for external protocol handles
/// (typeof(Protocol))
llvm::Type *ExternalProtocolPtrTy;
public:
llvm::Type *getExternalProtocolPtrTy() {
if (!ExternalProtocolPtrTy) {
// FIXME: It would be nice to unify this with the opaque type, so that the
// IR comes out a bit cleaner.
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
}
return ExternalProtocolPtrTy;
}
// SuperCTy - clang type for struct objc_super.
QualType SuperCTy;
// SuperPtrCTy - clang type for struct objc_super *.
QualType SuperPtrCTy;
/// SuperTy - LLVM type for struct objc_super.
llvm::StructType *SuperTy;
/// SuperPtrTy - LLVM type for struct objc_super *.
llvm::Type *SuperPtrTy;
/// PropertyTy - LLVM type for struct objc_property (struct _prop_t
/// in GCC parlance).
llvm::StructType *PropertyTy;
/// PropertyListTy - LLVM type for struct objc_property_list
/// (_prop_list_t in GCC parlance).
llvm::StructType *PropertyListTy;
/// PropertyListPtrTy - LLVM type for struct objc_property_list*.
llvm::Type *PropertyListPtrTy;
// MethodTy - LLVM type for struct objc_method.
llvm::StructType *MethodTy;
/// CacheTy - LLVM type for struct objc_cache.
llvm::Type *CacheTy;
/// CachePtrTy - LLVM type for struct objc_cache *.
llvm::Type *CachePtrTy;
llvm::Constant *getGetPropertyFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
// id objc_getProperty (id, SEL, ptrdiff_t, bool)
SmallVector<CanQualType,4> Params;
CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
Params.push_back(IdType);
Params.push_back(SelType);
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
FunctionType::ExtInfo()),
false);
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
llvm::Constant *getSetPropertyFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
// void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
SmallVector<CanQualType,6> Params;
CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
Params.push_back(IdType);
Params.push_back(SelType);
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(IdType);
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
llvm::Constant *getCopyStructFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
// void objc_copyStruct (void *, const void *, size_t, bool, bool)
SmallVector<CanQualType,5> Params;
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.LongTy);
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
}
/// This routine declares and returns address of:
/// void objc_copyCppObjectAtomic(
/// void *dest, const void *src,
/// void (*copyHelper) (void *dest, const void *source));
llvm::Constant *getCppAtomicObjectFunction() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
/// void objc_copyCppObjectAtomic(void *dest, const void *src, void *helper);
SmallVector<CanQualType,3> Params;
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
}
llvm::Constant *getEnumerationMutationFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
// void objc_enumerationMutation (id)
SmallVector<CanQualType,1> Params;
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
/// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
llvm::Constant *getGcReadWeakFn() {
// id objc_read_weak (id *)
llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
}
/// GcAssignWeakFn -- LLVM objc_assign_weak function.
llvm::Constant *getGcAssignWeakFn() {
// id objc_assign_weak (id, id *)
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
}
/// GcAssignGlobalFn -- LLVM objc_assign_global function.
llvm::Constant *getGcAssignGlobalFn() {
// id objc_assign_global(id, id *)
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
}
/// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function.
llvm::Constant *getGcAssignThreadLocalFn() {
// id objc_assign_threadlocal(id src, id * dest)
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
}
/// GcAssignIvarFn -- LLVM objc_assign_ivar function.
llvm::Constant *getGcAssignIvarFn() {
// id objc_assign_ivar(id, id *, ptrdiff_t)
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
CGM.PtrDiffTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
}
/// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function.
llvm::Constant *GcMemmoveCollectableFn() {
// void *objc_memmove_collectable(void *dst, const void *src, size_t size)
llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
}
/// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
llvm::Constant *getGcAssignStrongCastFn() {
// id objc_assign_strongCast(id, id *)
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
}
/// ExceptionThrowFn - LLVM objc_exception_throw function.
llvm::Constant *getExceptionThrowFn() {
// void objc_exception_throw(id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
}
/// ExceptionRethrowFn - LLVM objc_exception_rethrow function.
llvm::Constant *getExceptionRethrowFn() {
// void objc_exception_rethrow(void)
llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow");
}
/// SyncEnterFn - LLVM object_sync_enter function.
llvm::Constant *getSyncEnterFn() {
// void objc_sync_enter (id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
}
/// SyncExitFn - LLVM object_sync_exit function.
llvm::Constant *getSyncExitFn() {
// void objc_sync_exit (id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
}
llvm::Constant *getSendFn(bool IsSuper) const {
return IsSuper ? getMessageSendSuperFn() : getMessageSendFn();
}
llvm::Constant *getSendFn2(bool IsSuper) const {
return IsSuper ? getMessageSendSuperFn2() : getMessageSendFn();
}
llvm::Constant *getSendStretFn(bool IsSuper) const {
return IsSuper ? getMessageSendSuperStretFn() : getMessageSendStretFn();
}
llvm::Constant *getSendStretFn2(bool IsSuper) const {
return IsSuper ? getMessageSendSuperStretFn2() : getMessageSendStretFn();
}
llvm::Constant *getSendFpretFn(bool IsSuper) const {
return IsSuper ? getMessageSendSuperFpretFn() : getMessageSendFpretFn();
}
llvm::Constant *getSendFpretFn2(bool IsSuper) const {
return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn();
}
llvm::Constant *getSendFp2retFn(bool IsSuper) const {
return IsSuper ? getMessageSendSuperFn() : getMessageSendFp2retFn();
}
llvm::Constant *getSendFp2RetFn2(bool IsSuper) const {
return IsSuper ? getMessageSendSuperFn2() : getMessageSendFp2retFn();
}
ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCCommonTypesHelper(){}
};
/// ObjCTypesHelper - Helper class that encapsulates lazy
/// construction of varies types used during ObjC generation.
class ObjCTypesHelper : public ObjCCommonTypesHelper {
public:
/// SymtabTy - LLVM type for struct objc_symtab.
llvm::StructType *SymtabTy;
/// SymtabPtrTy - LLVM type for struct objc_symtab *.
llvm::Type *SymtabPtrTy;
/// ModuleTy - LLVM type for struct objc_module.
llvm::StructType *ModuleTy;
/// ProtocolTy - LLVM type for struct objc_protocol.
llvm::StructType *ProtocolTy;
/// ProtocolPtrTy - LLVM type for struct objc_protocol *.
llvm::Type *ProtocolPtrTy;
/// ProtocolExtensionTy - LLVM type for struct
/// objc_protocol_extension.
llvm::StructType *ProtocolExtensionTy;
/// ProtocolExtensionTy - LLVM type for struct
/// objc_protocol_extension *.
llvm::Type *ProtocolExtensionPtrTy;
/// MethodDescriptionTy - LLVM type for struct
/// objc_method_description.
llvm::StructType *MethodDescriptionTy;
/// MethodDescriptionListTy - LLVM type for struct
/// objc_method_description_list.
llvm::StructType *MethodDescriptionListTy;
/// MethodDescriptionListPtrTy - LLVM type for struct
/// objc_method_description_list *.
llvm::Type *MethodDescriptionListPtrTy;
/// ProtocolListTy - LLVM type for struct objc_property_list.
llvm::StructType *ProtocolListTy;
/// ProtocolListPtrTy - LLVM type for struct objc_property_list*.
llvm::Type *ProtocolListPtrTy;
/// CategoryTy - LLVM type for struct objc_category.
llvm::StructType *CategoryTy;
/// ClassTy - LLVM type for struct objc_class.
llvm::StructType *ClassTy;
/// ClassPtrTy - LLVM type for struct objc_class *.
llvm::Type *ClassPtrTy;
/// ClassExtensionTy - LLVM type for struct objc_class_ext.
llvm::StructType *ClassExtensionTy;
/// ClassExtensionPtrTy - LLVM type for struct objc_class_ext *.
llvm::Type *ClassExtensionPtrTy;
// IvarTy - LLVM type for struct objc_ivar.
llvm::StructType *IvarTy;
/// IvarListTy - LLVM type for struct objc_ivar_list.
llvm::Type *IvarListTy;
/// IvarListPtrTy - LLVM type for struct objc_ivar_list *.
llvm::Type *IvarListPtrTy;
/// MethodListTy - LLVM type for struct objc_method_list.
llvm::Type *MethodListTy;
/// MethodListPtrTy - LLVM type for struct objc_method_list *.
llvm::Type *MethodListPtrTy;
/// ExceptionDataTy - LLVM type for struct _objc_exception_data.
llvm::Type *ExceptionDataTy;
/// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
llvm::Constant *getExceptionTryEnterFn() {
llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_enter");
}
/// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
llvm::Constant *getExceptionTryExitFn() {
llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_exit");
}
/// ExceptionExtractFn - LLVM objc_exception_extract function.
llvm::Constant *getExceptionExtractFn() {
llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, false),
"objc_exception_extract");
}
/// ExceptionMatchFn - LLVM objc_exception_match function.
llvm::Constant *getExceptionMatchFn() {
llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.Int32Ty, params, false),
"objc_exception_match");
}
/// SetJmpFn - LLVM _setjmp function.
llvm::Constant *getSetJmpFn() {
// This is specifically the prototype for x86.
llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
params, false),
"_setjmp",
llvm::Attribute::ReturnsTwice);
}
public:
ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCTypesHelper() {}
};
/// ObjCNonFragileABITypesHelper - will have all types needed by objective-c's
/// modern abi
class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper {
public:
// MethodListnfABITy - LLVM for struct _method_list_t
llvm::StructType *MethodListnfABITy;
// MethodListnfABIPtrTy - LLVM for struct _method_list_t*
llvm::Type *MethodListnfABIPtrTy;
// ProtocolnfABITy = LLVM for struct _protocol_t
llvm::StructType *ProtocolnfABITy;
// ProtocolnfABIPtrTy = LLVM for struct _protocol_t*
llvm::Type *ProtocolnfABIPtrTy;
// ProtocolListnfABITy - LLVM for struct _objc_protocol_list
llvm::StructType *ProtocolListnfABITy;
// ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list*
llvm::Type *ProtocolListnfABIPtrTy;
// ClassnfABITy - LLVM for struct _class_t
llvm::StructType *ClassnfABITy;
// ClassnfABIPtrTy - LLVM for struct _class_t*
llvm::Type *ClassnfABIPtrTy;
// IvarnfABITy - LLVM for struct _ivar_t
llvm::StructType *IvarnfABITy;
// IvarListnfABITy - LLVM for struct _ivar_list_t
llvm::StructType *IvarListnfABITy;
// IvarListnfABIPtrTy = LLVM for struct _ivar_list_t*
llvm::Type *IvarListnfABIPtrTy;
// ClassRonfABITy - LLVM for struct _class_ro_t
llvm::StructType *ClassRonfABITy;
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
llvm::Type *ImpnfABITy;
// CategorynfABITy - LLVM for struct _category_t
llvm::StructType *CategorynfABITy;
// New types for nonfragile abi messaging.
// MessageRefTy - LLVM for:
// struct _message_ref_t {
// IMP messenger;
// SEL name;
// };
llvm::StructType *MessageRefTy;
// MessageRefCTy - clang type for struct _message_ref_t
QualType MessageRefCTy;
// MessageRefPtrTy - LLVM for struct _message_ref_t*
llvm::Type *MessageRefPtrTy;
// MessageRefCPtrTy - clang type for struct _message_ref_t*
QualType MessageRefCPtrTy;
// MessengerTy - Type of the messenger (shown as IMP above)
llvm::FunctionType *MessengerTy;
// SuperMessageRefTy - LLVM for:
// struct _super_message_ref_t {
// SUPER_IMP messenger;
// SEL name;
// };
llvm::StructType *SuperMessageRefTy;
// SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
llvm::Type *SuperMessageRefPtrTy;
llvm::Constant *getMessageSendFixupFn() {
// id objc_msgSend_fixup(id, struct message_ref_t*, ...)
llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_fixup");
}
llvm::Constant *getMessageSendFpretFixupFn() {
// id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_fpret_fixup");
}
llvm::Constant *getMessageSendStretFixupFn() {
// id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...)
llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_stret_fixup");
}
llvm::Constant *getMessageSendSuper2FixupFn() {
// id objc_msgSendSuper2_fixup (struct objc_super *,
// struct _super_message_ref_t*, ...)
llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper2_fixup");
}
llvm::Constant *getMessageSendSuper2StretFixupFn() {
// id objc_msgSendSuper2_stret_fixup(struct objc_super *,
// struct _super_message_ref_t*, ...)
llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper2_stret_fixup");
}
llvm::Constant *getObjCEndCatchFn() {
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy, false),
"objc_end_catch");
}
llvm::Constant *getObjCBeginCatchFn() {
llvm::Type *params[] = { Int8PtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy,
params, false),
"objc_begin_catch");
}
llvm::StructType *EHTypeTy;
llvm::Type *EHTypePtrTy;
ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCNonFragileABITypesHelper(){}
};
class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
public:
// FIXME - accessibility
class GC_IVAR {
public:
unsigned ivar_bytepos;
unsigned ivar_size;
GC_IVAR(unsigned bytepos = 0, unsigned size = 0)
: ivar_bytepos(bytepos), ivar_size(size) {}
// Allow sorting based on byte pos.
bool operator<(const GC_IVAR &b) const {
return ivar_bytepos < b.ivar_bytepos;
}
};
class SKIP_SCAN {
public:
unsigned skip;
unsigned scan;
SKIP_SCAN(unsigned _skip = 0, unsigned _scan = 0)
: skip(_skip), scan(_scan) {}
};
protected:
CodeGen::CodeGenModule &CGM;
llvm::LLVMContext &VMContext;
// FIXME! May not be needing this after all.
unsigned ObjCABI;
// gc ivar layout bitmap calculation helper caches.
SmallVector<GC_IVAR, 16> SkipIvars;
SmallVector<GC_IVAR, 16> IvarsInfo;
/// LazySymbols - Symbols to generate a lazy reference for. See
/// DefinedSymbols and FinishModule().
llvm::SetVector<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.
llvm::SetVector<IdentifierInfo*> DefinedSymbols;
/// ClassNames - uniqued class names.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassNames;
/// MethodVarNames - uniqued method variable names.
llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
/// DefinedCategoryNames - list of category names in form Class_Category.
llvm::SetVector<std::string> DefinedCategoryNames;
/// MethodVarTypes - uniqued method type signatures. We have to use
/// a StringMap here because have no other unique reference.
llvm::StringMap<llvm::GlobalVariable*> MethodVarTypes;
/// MethodDefinitions - map of methods which have been defined in
/// this translation unit.
llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
/// PropertyNames - uniqued method variable names.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
/// ClassReferences - uniqued class references.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassReferences;
/// SelectorReferences - uniqued selector references.
llvm::DenseMap<Selector, llvm::GlobalVariable*> SelectorReferences;
/// Protocols - Protocols for which an objc_protocol structure has
/// been emitted. Forward declarations are handled by creating an
/// empty structure whose initializer is filled in when/if defined.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> Protocols;
/// DefinedProtocols - Protocols which have actually been
/// defined. We should not need this, see FIXME in GenerateProtocol.
llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
/// DefinedClasses - List of defined classes.
std::vector<llvm::GlobalValue*> DefinedClasses;
/// DefinedNonLazyClasses - List of defined "non-lazy" classes.
std::vector<llvm::GlobalValue*> DefinedNonLazyClasses;
/// DefinedCategories - List of defined categories.
std::vector<llvm::GlobalValue*> DefinedCategories;
/// DefinedNonLazyCategories - List of defined "non-lazy" categories.
std::vector<llvm::GlobalValue*> DefinedNonLazyCategories;
/// GetNameForMethod - Return a name for the given method.
/// \param[out] NameOut - The return value.
void GetNameForMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD,
SmallVectorImpl<char> &NameOut);
/// GetMethodVarName - Return a unique constant for the given
/// selector's name. The return value has type char *.
llvm::Constant *GetMethodVarName(Selector Sel);
llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
/// GetMethodVarType - Return a unique constant for the given
/// method's type encoding string. The return value has type char *.
// FIXME: This is a horrible name.
llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D,
bool Extended = false);
llvm::Constant *GetMethodVarType(const FieldDecl *D);
/// GetPropertyName - Return a unique constant for the given
/// name. The return value has type char *.
llvm::Constant *GetPropertyName(IdentifierInfo *Ident);
// FIXME: This can be dropped once string functions are unified.
llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD,
const Decl *Container);
/// GetClassName - Return a unique constant for the given selector's
/// name. The return value has type char *.
llvm::Constant *GetClassName(IdentifierInfo *Ident);
llvm::Function *GetMethodDefinition(const ObjCMethodDecl *MD);
/// BuildIvarLayout - Builds ivar layout bitmap for the class
/// implementation for the __strong or __weak case.
///
llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI,
bool ForStrongLayout);
llvm::Constant *BuildIvarLayoutBitmap(std::string &BitMap);
void BuildAggrIvarRecordLayout(const RecordType *RT,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
void BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
const llvm::StructLayout *Layout,
const RecordDecl *RD,
const SmallVectorImpl<const FieldDecl*> &RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
llvm::Constant *GetIvarLayoutName(IdentifierInfo *Ident,
const ObjCCommonTypesHelper &ObjCTypes);
/// EmitPropertyList - Emit the given property list. The return
/// value has type PropertyListPtrTy.
llvm::Constant *EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes);
/// EmitProtocolMethodTypes - Generate the array of extended method type
/// strings. The return value has type Int8PtrPtrTy.
llvm::Constant *EmitProtocolMethodTypes(Twine Name,
const ConstantVector &MethodTypes,
const ObjCCommonTypesHelper &ObjCTypes);
/// PushProtocolProperties - Push protocol's property on the input stack.
void PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
std::vector<llvm::Constant*> &Properties,
const Decl *Container,
const ObjCProtocolDecl *PROTO,
const ObjCCommonTypesHelper &ObjCTypes);
/// GetProtocolRef - Return a reference to the internal protocol
/// description, creating an empty one if it has not been
/// defined. The return value has type ProtocolPtrTy.
llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
/// CreateMetadataVar - Create a global variable with internal
/// linkage for use by the Objective-C runtime.
///
/// This is a convenience wrapper which not only creates the
/// variable, but also sets the section and alignment and adds the
/// global to the "llvm.used" list.
///
/// \param Name - The variable name.
/// \param Init - The variable initializer; this is also used to
/// define the type of the variable.
/// \param Section - The section the variable should go into, or 0.
/// \param Align - The alignment for the variable, or 0.
/// \param AddToUsed - Whether the variable should be added to
/// "llvm.used".
llvm::GlobalVariable *CreateMetadataVar(Twine Name,
llvm::Constant *Init,
const char *Section,
unsigned Align,
bool AddToUsed);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
llvm::Value *Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *OMD,
const ObjCCommonTypesHelper &ObjCTypes);
/// EmitImageInfo - Emit the image info marker used to encode some module
/// level information.
void EmitImageInfo();
public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGM(cgm), VMContext(cgm.getLLVMContext()) { }
virtual llvm::Constant *GenerateConstantString(const StringLiteral *SL);
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD=0);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
/// GetOrEmitProtocol - Get the protocol object for the given
/// declaration, emitting it if necessary. The return value has type
/// ProtocolPtrTy.
virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD)=0;
/// GetOrEmitProtocolRef - Get a forward reference to the protocol
/// object for the given declaration, emitting it if needed. These
/// forward references will be filled in with empty bodies if no
/// definition is seen. The return value has type ProtocolPtrTy.
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CGBlockInfo &blockInfo);
};
class CGObjCMac : public CGObjCCommonMac {
private:
ObjCTypesHelper ObjCTypes;
/// EmitModuleInfo - Another marker encoding module level
/// information.
void EmitModuleInfo();
/// EmitModuleSymols - Emit module symbols, the list of defined
/// classes and categories. The result has type SymtabPtrTy.
llvm::Constant *EmitModuleSymbols();
/// FinishModule - Write out global data structures at the end of
/// processing a translation unit.
void FinishModule();
/// EmitClassExtension - Generate the class extension structure used
/// to store the weak ivar layout and properties. The return value
/// has type ClassExtensionPtrTy.
llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID);
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class.
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II);
llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
/// EmitSuperClassRef - Emits reference to class's main metadata class.
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
/// 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);
/// EmitMetaClass - Emit a forward reference to the class structure
/// for the metaclass of the given interface. The return value has
/// type ClassPtrTy.
llvm::Constant *EmitMetaClassRef(const ObjCInterfaceDecl *ID);
/// EmitMetaClass - Emit a class structure for the metaclass of the
/// given implementation. The return value has type ClassPtrTy.
llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
const ConstantVector &Methods);
llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD);
/// EmitMethodList - Emit the method list for the given
/// implementation. The return value has type MethodListPtrTy.
llvm::Constant *EmitMethodList(Twine Name,
const char *Section,
const ConstantVector &Methods);
/// EmitMethodDescList - Emit a method description list for a list of
/// method declarations.
/// - TypeName: The name for the type containing the methods.
/// - IsProtocol: True iff these methods are for a protocol.
/// - ClassMethds: True iff these are class methods.
/// - Required: When true, only "required" methods are
/// listed. Similarly, when false only "optional" methods are
/// listed. For classes this should always be true.
/// - begin, end: The method list to output.
///
/// The return value has type MethodDescriptionListPtrTy.
llvm::Constant *EmitMethodDescList(Twine Name,
const char *Section,
const ConstantVector &Methods);
/// GetOrEmitProtocol - Get the protocol object for the given
/// declaration, emitting it if necessary. The return value has type
/// ProtocolPtrTy.
virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
/// GetOrEmitProtocolRef - Get a forward reference to the protocol
/// object for the given declaration, emitting it if needed. These
/// forward references will be filled in with empty bodies if no
/// definition is seen. The return value has type ProtocolPtrTy.
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
/// EmitProtocolExtension - Generate the protocol extension
/// structure used to store optional instance and class methods, and
/// protocol properties. The return value has type
/// ProtocolExtensionPtrTy.
llvm::Constant *
EmitProtocolExtension(const ObjCProtocolDecl *PD,
const ConstantVector &OptInstanceMethods,
const ConstantVector &OptClassMethods,
const ConstantVector &MethodTypesExt);
/// EmitProtocolList - Generate the list of referenced
/// protocols. The return value has type ProtocolListPtrTy.
llvm::Constant *EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
bool lval=false);
public:
CGObjCMac(CodeGen::CodeGenModule &cgm);
virtual llvm::Function *ModuleInitFunction();
virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
bool isCategoryImpl,
llvm::Value *Receiver,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
bool lval = false);
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
const ObjCMethodDecl *Method);
virtual llvm::Constant *GetEHType(QualType T);
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {};
virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetPropertyGetFunction();
virtual llvm::Constant *GetPropertySetFunction();
virtual llvm::Constant *GetGetStructFunction();
virtual llvm::Constant *GetSetStructFunction();
virtual llvm::Constant *GetCppAtomicObjectFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt &S);
virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S);
void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S);
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtThrowStmt &S);
virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst);
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest,
bool threadlocal = false);
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest,
llvm::Value *ivarOffset);
virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest);
virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
llvm::Value *dest, llvm::Value *src,
llvm::Value *size);
virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers);
virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
llvm_unreachable("CGObjCMac::GetClassGlobal");
}
};
class CGObjCNonFragileABIMac : public CGObjCCommonMac {
private:
ObjCNonFragileABITypesHelper ObjCTypes;
llvm::GlobalVariable* ObjCEmptyCacheVar;
llvm::GlobalVariable* ObjCEmptyVtableVar;
/// SuperClassReferences - uniqued super class references.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> SuperClassReferences;
/// MetaClassReferences - uniqued meta class references.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> MetaClassReferences;
/// EHTypeReferences - uniqued class ehtype references.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
/// VTableDispatchMethods - List of methods for which we generate
/// vtable-based message dispatch.
llvm::DenseSet<Selector> VTableDispatchMethods;
/// DefinedMetaClasses - List of defined meta-classes.
std::vector<llvm::GlobalValue*> DefinedMetaClasses;
/// isVTableDispatchedSelector - Returns true if SEL is a
/// vtable-based selector.
bool isVTableDispatchedSelector(Selector Sel);
/// FinishNonFragileABIModule - Write out global data structures at the end of
/// processing a translation unit.
void FinishNonFragileABIModule();
/// AddModuleClassList - Add the given list of class pointers to the
/// module with the provided symbol and section names.
void AddModuleClassList(const std::vector<llvm::GlobalValue*> &Container,
const char *SymbolName,
const char *SectionName);
llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags,
unsigned InstanceStart,
unsigned InstanceSize,
const ObjCImplementationDecl *ID);
llvm::GlobalVariable * BuildClassMetaData(std::string &ClassName,
llvm::Constant *IsAGV,
llvm::Constant *SuperClassGV,
llvm::Constant *ClassRoGV,
bool HiddenVisibility);
llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD);
/// EmitMethodList - Emit the method list for the given
/// implementation. The return value has type MethodListnfABITy.
llvm::Constant *EmitMethodList(Twine Name,
const char *Section,
const ConstantVector &Methods);
/// EmitIvarList - Emit the ivar list for the given
/// implementation. If ForClass is true the list of class ivars
/// (i.e. metaclass ivars) is emitted, otherwise the list of
/// interface ivars will be emitted. The return value has type
/// IvarListnfABIPtrTy.
llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID);
llvm::Constant *EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar,
unsigned long int offset);
/// GetOrEmitProtocol - Get the protocol object for the given
/// declaration, emitting it if necessary. The return value has type
/// ProtocolPtrTy.
virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
/// GetOrEmitProtocolRef - Get a forward reference to the protocol
/// object for the given declaration, emitting it if needed. These
/// forward references will be filled in with empty bodies if no
/// definition is seen. The return value has type ProtocolPtrTy.
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
/// EmitProtocolList - Generate the list of referenced
/// protocols. The return value has type ProtocolListPtrTy.
llvm::Constant *EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
llvm::GlobalVariable *GetClassGlobal(const std::string &Name);
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class reference.
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II);
llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
/// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given super class reference.
llvm::Value *EmitSuperClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
/// EmitMetaClassRef - Return a Value * of the address of _class_t
/// meta-data
llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
/// the given ivar.
///
llvm::GlobalVariable * ObjCIvarOffsetVariable(
const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
bool lval=false);
/// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
/// interface. The return value has type EHTypePtrTy.
llvm::Constant *GetInterfaceEHType(const ObjCInterfaceDecl *ID,
bool ForDefinition);
const char *getMetaclassSymbolPrefix() const {
return "OBJC_METACLASS_$_";
}
const char *getClassSymbolPrefix() const {
return "OBJC_CLASS_$_";
}
void GetClassSizeInfo(const ObjCImplementationDecl *OID,
uint32_t &InstanceStart,
uint32_t &InstanceSize);
// Shamelessly stolen from Analysis/CFRefCount.cpp
Selector GetNullarySelector(const char* name) const {
IdentifierInfo* II = &CGM.getContext().Idents.get(name);
return CGM.getContext().Selectors.getSelector(0, &II);
}
Selector GetUnarySelector(const char* name) const {
IdentifierInfo* II = &CGM.getContext().Idents.get(name);
return CGM.getContext().Selectors.getSelector(1, &II);
}
/// ImplementationIsNonLazy - Check whether the given category or
/// class implementation is "non-lazy".
bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const;
public:
CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
// FIXME. All stubs for now!
virtual llvm::Function *ModuleInitFunction();
virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
bool isCategoryImpl,
llvm::Value *Receiver,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
bool lvalue = false)
{ return EmitSelector(Builder, Sel, lvalue); }
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
const ObjCMethodDecl *Method)
{ return EmitSelector(Builder, Method->getSelector()); }
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {};
virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetEHType(QualType T);
virtual llvm::Constant *GetPropertyGetFunction() {
return ObjCTypes.getGetPropertyFn();
}
virtual llvm::Constant *GetPropertySetFunction() {
return ObjCTypes.getSetPropertyFn();
}
virtual llvm::Constant *GetSetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
virtual llvm::Constant *GetGetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
virtual llvm::Constant *GetCppAtomicObjectFunction() {
return ObjCTypes.getCppAtomicObjectFunction();
}
virtual llvm::Constant *EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
}
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt &S);
virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S);
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtThrowStmt &S);
virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst);
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest,
bool threadlocal = false);
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest,
llvm::Value *ivarOffset);
virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest);
virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
llvm::Value *dest, llvm::Value *src,
llvm::Value *size);
virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers);
virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
};
/// A helper class for performing the null-initialization of a return
/// value.
struct NullReturnState {
llvm::BasicBlock *NullBB;
llvm::BasicBlock *callBB;
NullReturnState() : NullBB(0), callBB(0) {}
void init(CodeGenFunction &CGF, llvm::Value *receiver) {
// Make blocks for the null-init and call edges.
NullBB = CGF.createBasicBlock("msgSend.nullinit");
callBB = CGF.createBasicBlock("msgSend.call");
// Check for a null receiver and, if there is one, jump to the
// null-init test.
llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
// Otherwise, start performing the call.
CGF.EmitBlock(callBB);
}
RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
if (!NullBB) return result;
llvm::Value *NullInitPtr = 0;
if (result.isScalar() && !resultType->isVoidType()) {
NullInitPtr = CGF.CreateTempAlloca(result.getScalarVal()->getType());
CGF.Builder.CreateStore(result.getScalarVal(), NullInitPtr);
}
// Finish the call path.
llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB);
// Emit the null-init block and perform the null-initialization there.
CGF.EmitBlock(NullBB);
// Release consumed arguments along the null-receiver path.
if (Method) {
CallArgList::const_iterator I = CallArgs.begin();
for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
e = Method->param_end(); i != e; ++i, ++I) {
const ParmVarDecl *ParamDecl = (*i);
if (ParamDecl->hasAttr<NSConsumedAttr>()) {
RValue RV = I->RV;
assert(RV.isScalar() &&
"NullReturnState::complete - arg not on object");
CGF.EmitARCRelease(RV.getScalarVal(), true);
}
}
}
if (result.isScalar()) {
if (NullInitPtr)
CGF.EmitNullInitialization(NullInitPtr, resultType);
// Jump to the continuation block.
CGF.EmitBlock(contBB);
return NullInitPtr ? RValue::get(CGF.Builder.CreateLoad(NullInitPtr))
: result;
}
if (!resultType->isAnyComplexType()) {
assert(result.isAggregate() && "null init of non-aggregate result?");
CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
// Jump to the continuation block.
CGF.EmitBlock(contBB);
return result;
}
// _Complex type
// FIXME. Now easy to handle any other scalar type whose result is returned
// in memory due to ABI limitations.
CGF.EmitBlock(contBB);
CodeGenFunction::ComplexPairTy CallCV = result.getComplexVal();
llvm::Type *MemberType = CallCV.first->getType();
llvm::Constant *ZeroCV = llvm::Constant::getNullValue(MemberType);
// Create phi instruction for scalar complex value.
llvm::PHINode *PHIReal = CGF.Builder.CreatePHI(MemberType, 2);
PHIReal->addIncoming(ZeroCV, NullBB);
PHIReal->addIncoming(CallCV.first, callBB);
llvm::PHINode *PHIImag = CGF.Builder.CreatePHI(MemberType, 2);
PHIImag->addIncoming(ZeroCV, NullBB);
PHIImag->addIncoming(CallCV.second, callBB);
return RValue::getComplex(PHIReal, PHIImag);
}
};
} // end anonymous namespace
/* *** Helper Functions *** */
/// getConstantGEP() - Help routine to construct simple GEPs.
static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext,
llvm::Constant *C,
unsigned idx0,
unsigned idx1) {
llvm::Value *Idxs[] = {
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0),
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx1)
};
return llvm::ConstantExpr::getGetElementPtr(C, Idxs);
}
/// hasObjCExceptionAttribute - Return true if this class or any super
/// class has the __objc_exception__ attribute.
static bool hasObjCExceptionAttribute(ASTContext &Context,
const ObjCInterfaceDecl *OID) {
if (OID->hasAttr<ObjCExceptionAttr>())
return true;
if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
return hasObjCExceptionAttribute(Context, Super);
return false;
}
/* *** CGObjCMac Public Interface *** */
CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
ObjCTypes(cgm) {
ObjCABI = 1;
EmitImageInfo();
}
/// GetClass - Return a reference to the class for the given interface
/// decl.
llvm::Value *CGObjCMac::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
return EmitClassRef(Builder, ID);
}
/// GetSelector - Return the pointer to the unique'd string for this selector.
llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, Selector Sel,
bool lval) {
return EmitSelector(Builder, Sel, lval);
}
llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
*Method) {
return EmitSelector(Builder, Method->getSelector());
}
llvm::Constant *CGObjCMac::GetEHType(QualType T) {
if (T->isObjCIdType() ||
T->isObjCQualifiedIdType()) {
return CGM.GetAddrOfRTTIDescriptor(
CGM.getContext().getObjCIdRedefinitionType(), /*ForEH=*/true);
}
if (T->isObjCClassType() ||
T->isObjCQualifiedClassType()) {
return CGM.GetAddrOfRTTIDescriptor(
CGM.getContext().getObjCClassRedefinitionType(), /*ForEH=*/true);
}
if (T->isObjCObjectPointerType())
return CGM.GetAddrOfRTTIDescriptor(T, /*ForEH=*/true);
llvm_unreachable("asking for catch type for ObjC type in fragile runtime");
}
/// Generate a constant CFString object.
/*
struct __builtin_CFString {
const int *isa; // point to __CFConstantStringClassReference
int flags;
const char *str;
long length;
};
*/
/// or Generate a constant NSString object.
/*
struct __builtin_NSString {
const int *isa; // point to __NSConstantStringClassReference
const char *str;
unsigned int length;
};
*/
llvm::Constant *CGObjCCommonMac::GenerateConstantString(
const StringLiteral *SL) {
return (CGM.getLangOptions().NoConstantCFStrings == 0 ?
CGM.GetAddrOfConstantCFString(SL) :
CGM.GetAddrOfConstantString(SL));
}
/// Generates a message send where the super is the receiver. This is
/// a message send to self with special delivery semantics indicating
/// which class's method should be called.
CodeGen::RValue
CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
bool isCategoryImpl,
llvm::Value *Receiver,
bool IsClassMessage,
const CodeGen::CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
// Create and init a super structure; this is a (receiver, class)
// pair we will pass to objc_msgSendSuper.
llvm::Value *ObjCSuper =
CGF.CreateTempAlloca(ObjCTypes.SuperTy, "objc_super");
llvm::Value *ReceiverAsObject =
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
CGF.Builder.CreateStore(ReceiverAsObject,
CGF.Builder.CreateStructGEP(ObjCSuper, 0));
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
if (IsClassMessage) {
if (isCategoryImpl) {
// Message sent to 'super' in a class method defined in a category
// implementation requires an odd treatment.
// If we are in a class method, we must retrieve the
// _metaclass_ for the current class, pointed at by
// the class's "isa" pointer. The following assumes that
// isa" is the first ivar in a class (which it must be).
Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
Target = CGF.Builder.CreateStructGEP(Target, 0);
Target = CGF.Builder.CreateLoad(Target);
} else {
llvm::Value *MetaClassPtr = EmitMetaClassRef(Class);
llvm::Value *SuperPtr = CGF.Builder.CreateStructGEP(MetaClassPtr, 1);
llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr);
Target = Super;
}
}
else if (isCategoryImpl)
Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
else {
llvm::Value *ClassPtr = EmitSuperClassRef(Class);
ClassPtr = CGF.Builder.CreateStructGEP(ClassPtr, 1);
Target = CGF.Builder.CreateLoad(ClassPtr);
}
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
llvm::Type *ClassTy =
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
return EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
/// Generate code for a message send expression.
CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
CodeGen::RValue
CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
llvm::Value *Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method,
const ObjCCommonTypesHelper &ObjCTypes) {
CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
FunctionType::ExtInfo());
llvm::FunctionType *FTy =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
if (Method)
assert(CGM.getContext().getCanonicalType(Method->getResultType()) ==
CGM.getContext().getCanonicalType(ResultType) &&
"Result type mismatch!");
NullReturnState nullReturn;
llvm::Constant *Fn = NULL;
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
if (!IsSuper) nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFpretFn2(IsSuper)
: ObjCTypes.getSendFpretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFP2Ret(ResultType)) {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFp2RetFn2(IsSuper)
: ObjCTypes.getSendFp2retFn(IsSuper);
} else {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
bool requiresnullCheck = false;
if (CGM.getLangOptions().ObjCAutoRefCount && Method)
for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
e = Method->param_end(); i != e; ++i) {
const ParmVarDecl *ParamDecl = (*i);
if (ParamDecl->hasAttr<NSConsumedAttr>()) {
if (!nullReturn.NullBB)
nullReturn.init(CGF, Arg0);
requiresnullCheck = true;
break;
}
}
Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
RValue rvalue = CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
return nullReturn.complete(CGF, rvalue, ResultType, CallArgs,
requiresnullCheck ? Method : 0);
}
static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
if (FQT.isObjCGCStrong())
return Qualifiers::Strong;
if (FQT.isObjCGCWeak() || FQT.getObjCLifetime() == Qualifiers::OCL_Weak)
return Qualifiers::Weak;
if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
return Qualifiers::Strong;
if (const PointerType *PT = FQT->getAs<PointerType>())
return GetGCAttrTypeForType(Ctx, PT->getPointeeType());
return Qualifiers::GCNone;
}
llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
llvm::Constant *nullPtr =
llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
if (CGM.getLangOptions().getGC() == LangOptions::NonGC &&
!CGM.getLangOptions().ObjCAutoRefCount)
return nullPtr;
bool hasUnion = false;
SkipIvars.clear();
IvarsInfo.clear();
unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
// __isa is the first field in block descriptor and must assume by runtime's
// convention that it is GC'able.
IvarsInfo.push_back(GC_IVAR(0, 1));
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
// Calculate the basic layout of the block structure.
const llvm::StructLayout *layout =
CGM.getTargetData().getStructLayout(blockInfo.StructureType);
// Ignore the optional 'this' capture: C++ objects are not assumed
// to be GC'ed.
// Walk the captured variables.
for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
ce = blockDecl->capture_end(); ci != ce; ++ci) {
const VarDecl *variable = ci->getVariable();
QualType type = variable->getType();
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
// Ignore constant captures.
if (capture.isConstant()) continue;
uint64_t fieldOffset = layout->getElementOffset(capture.getIndex());
// __block variables are passed by their descriptor address.
if (ci->isByRef()) {
IvarsInfo.push_back(GC_IVAR(fieldOffset, /*size in words*/ 1));
continue;
}
assert(!type->isArrayType() && "array variable should not be caught");
if (const RecordType *record = type->getAs<RecordType>()) {
BuildAggrIvarRecordLayout(record, fieldOffset, true, hasUnion);
continue;
}
Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), type);
unsigned fieldSize = CGM.getContext().getTypeSize(type);
if (GCAttr == Qualifiers::Strong)
IvarsInfo.push_back(GC_IVAR(fieldOffset,
fieldSize / WordSizeInBits));
else if (GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak)
SkipIvars.push_back(GC_IVAR(fieldOffset,
fieldSize / ByteSizeInBits));
}
if (IvarsInfo.empty())
return nullPtr;
// Sort on byte position; captures might not be allocated in order,
// and unions can do funny things.
llvm::array_pod_sort(IvarsInfo.begin(), IvarsInfo.end());
llvm::array_pod_sort(SkipIvars.begin(), SkipIvars.end());
std::string BitMap;
llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
if (CGM.getLangOptions().ObjCGCBitmapPrint) {
printf("\n block variable layout for block: ");
const unsigned char *s = (unsigned char*)BitMap.c_str();
for (unsigned i = 0; i < BitMap.size(); i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
else
printf("0x%x%s", s[i], s[i] != 0 ? ", " : "");
printf("\n");
}
return C;
}
llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD) {
// FIXME: I don't understand why gcc generates this, or where it is
// resolved. Investigate. Its also wasteful to look this up over and over.
LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
ObjCTypes.getExternalProtocolPtrTy());
}
void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
// FIXME: We shouldn't need this, the protocol decl should contain enough
// information to tell us whether this was a declaration or a definition.
DefinedProtocols.insert(PD->getIdentifier());
// If we have generated a forward reference to this protocol, emit
// it now. Otherwise do nothing, the protocol objects are lazily
// emitted.
if (Protocols.count(PD->getIdentifier()))
GetOrEmitProtocol(PD);
}
llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
if (DefinedProtocols.count(PD->getIdentifier()))
return GetOrEmitProtocol(PD);
return GetOrEmitProtocolRef(PD);
}
/*
// APPLE LOCAL radar 4585769 - Objective-C 1.0 extensions
struct _objc_protocol {
struct _objc_protocol_extension *isa;
char *protocol_name;
struct _objc_protocol_list *protocol_list;
struct _objc__method_prototype_list *instance_methods;
struct _objc__method_prototype_list *class_methods
};
See EmitProtocolExtension().
*/
llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
// Early exit if a defining object has already been generated.
if (Entry && Entry->hasInitializer())
return Entry;
// Use the protocol definition, if there is one.
if (const ObjCProtocolDecl *Def = PD->getDefinition())
PD = Def;
// 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"));
// Construct method lists.
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
std::vector<llvm::Constant*> MethodTypesExt, OptMethodTypesExt;
for (ObjCProtocolDecl::instmeth_iterator
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
if (!C)
return GetOrEmitProtocolRef(PD);
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptInstanceMethods.push_back(C);
OptMethodTypesExt.push_back(GetMethodVarType(MD, true));
} else {
InstanceMethods.push_back(C);
MethodTypesExt.push_back(GetMethodVarType(MD, true));
}
}
for (ObjCProtocolDecl::classmeth_iterator
i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
if (!C)
return GetOrEmitProtocolRef(PD);
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptClassMethods.push_back(C);
OptMethodTypesExt.push_back(GetMethodVarType(MD, true));
} else {
ClassMethods.push_back(C);
MethodTypesExt.push_back(GetMethodVarType(MD, true));
}
}
MethodTypesExt.insert(MethodTypesExt.end(),
OptMethodTypesExt.begin(), OptMethodTypesExt.end());
llvm::Constant *Values[] = {
EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods,
MethodTypesExt),
GetClassName(PD->getIdentifier()),
EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getName(),
PD->protocol_begin(),
PD->protocol_end()),
EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_" + PD->getName(),
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
InstanceMethods),
EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" + PD->getName(),
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
ClassMethods)
};
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
Values);
if (Entry) {
// Already created, fix the linkage and update the initializer.
Entry->setLinkage(llvm::GlobalValue::InternalLinkage);
Entry->setInitializer(Init);
} else {
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false,
llvm::GlobalValue::InternalLinkage,
Init,
"\01L_OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
}
CGM.AddUsedGlobal(Entry);
return Entry;
}
llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
if (!Entry) {
// We use the initializer as a marker of whether this is a forward
// reference or not. At module finalization we add the empty
// contents for protocols which were referenced but never defined.
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false,
llvm::GlobalValue::ExternalLinkage,
0,
"\01L_OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
// 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;
const char ** extendedMethodTypes;
};
*/
llvm::Constant *
CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
const ConstantVector &OptInstanceMethods,
const ConstantVector &OptClassMethods,
const ConstantVector &MethodTypesExt) {
uint64_t Size =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
llvm::Constant *Values[] = {
llvm::ConstantInt::get(ObjCTypes.IntTy, Size),
EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"
+ PD->getName(),
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
OptInstanceMethods),
EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" + PD->getName(),
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
OptClassMethods),
EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(), 0, PD,
ObjCTypes),
EmitProtocolMethodTypes("\01L_OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
MethodTypesExt, ObjCTypes)
};
// Return null if no extension bits are used.
if (Values[1]->isNullValue() && Values[2]->isNullValue() &&
Values[3]->isNullValue() && Values[4]->isNullValue())
return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.ProtocolExtensionTy, Values);
// No special section, but goes in llvm.used
return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getName(),
Init,
0, 0, true);
}
/*
struct objc_protocol_list {
struct objc_protocol_list *next;
long count;
Protocol *list[];
};
*/
llvm::Constant *
CGObjCMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
std::vector<llvm::Constant*> ProtocolRefs;
for (; begin != end; ++begin)
ProtocolRefs.push_back(GetProtocolRef(*begin));
// Just return null for empty protocol lists
if (ProtocolRefs.empty())
return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
// This list is null terminated.
ProtocolRefs.push_back(llvm::Constant::getNullValue(ObjCTypes.ProtocolPtrTy));
llvm::Constant *Values[3];
// This field is only used by the runtime.
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::getAnon(Values);
llvm::GlobalVariable *GV =
CreateMetadataVar(Name, Init, "__OBJC,__cat_cls_meth,regular,no_dead_strip",
4, false);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
}
void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
std::vector<llvm::Constant*> &Properties,
const Decl *Container,
const ObjCProtocolDecl *PROTO,
const ObjCCommonTypesHelper &ObjCTypes) {
for (ObjCProtocolDecl::protocol_iterator P = PROTO->protocol_begin(),
E = PROTO->protocol_end(); P != E; ++P)
PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes);
for (ObjCContainerDecl::prop_iterator I = PROTO->prop_begin(),
E = PROTO->prop_end(); I != E; ++I) {
const ObjCPropertyDecl *PD = *I;
if (!PropertySet.insert(PD->getIdentifier()))
continue;
llvm::Constant *Prop[] = {
GetPropertyName(PD->getIdentifier()),
GetPropertyTypeString(PD, Container)
};
Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop));
}
}
/*
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 *CGObjCCommonMac::EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes) {
std::vector<llvm::Constant*> Properties;
llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(),
E = OCD->prop_end(); I != E; ++I) {
const ObjCPropertyDecl *PD = *I;
PropertySet.insert(PD->getIdentifier());
llvm::Constant *Prop[] = {
GetPropertyName(PD->getIdentifier()),
GetPropertyTypeString(PD, Container)
};
Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy,
Prop));
}
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
for (ObjCInterfaceDecl::all_protocol_iterator
P = OID->all_referenced_protocol_begin(),
E = OID->all_referenced_protocol_end(); P != E; ++P)
PushProtocolProperties(PropertySet, Properties, Container, (*P),
ObjCTypes);
}
else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD)) {
for (ObjCCategoryDecl::protocol_iterator P = CD->protocol_begin(),
E = CD->protocol_end(); P != E; ++P)
PushProtocolProperties(PropertySet, Properties, Container, (*P),
ObjCTypes);
}
// Return null for empty list.
if (Properties.empty())
return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
unsigned PropertySize =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.PropertyTy);
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::getAnon(Values);
llvm::GlobalVariable *GV =
CreateMetadataVar(Name, Init,
(ObjCABI == 2) ? "__DATA, __objc_const" :
"__OBJC,__property,regular,no_dead_strip",
(ObjCABI == 2) ? 8 : 4,
true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy);
}
llvm::Constant *CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name,
const ConstantVector &MethodTypes,
const ObjCCommonTypesHelper &ObjCTypes) {
// Return null for empty list.
if (MethodTypes.empty())
return llvm::Constant::getNullValue(ObjCTypes.Int8PtrPtrTy);
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
MethodTypes.size());
llvm::Constant *Init = llvm::ConstantArray::get(AT, MethodTypes);
llvm::GlobalVariable *GV =
CreateMetadataVar(Name, Init,
(ObjCABI == 2) ? "__DATA, __objc_const" : 0,
(ObjCABI == 2) ? 8 : 4,
true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy);
}
/*
struct objc_method_description_list {
int count;
struct objc_method_description list[];
};
*/
llvm::Constant *
CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
llvm::Constant *Desc[] = {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy),
GetMethodVarType(MD)
};
if (!Desc[1])
return 0;
return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy,
Desc);
}
llvm::Constant *CGObjCMac::EmitMethodDescList(Twine Name,
const char *Section,
const ConstantVector &Methods) {
// Return null for empty list.
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
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::getAnon(Values);
llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.MethodDescriptionListPtrTy);
}
/*
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;
};
*/
void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.CategoryTy);
// 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.
const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
SmallString<256> ExtName;
llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_'
<< OCD->getName();
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));
}
llvm::Constant *Values[7];
Values[0] = GetClassName(OCD->getIdentifier());
Values[1] = GetClassName(Interface->getIdentifier());
LazySymbols.insert(Interface->getIdentifier());
Values[2] =
EmitMethodList("\01L_OBJC_CATEGORY_INSTANCE_METHODS_" + ExtName.str(),
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
InstanceMethods);
Values[3] =
EmitMethodList("\01L_OBJC_CATEGORY_CLASS_METHODS_" + ExtName.str(),
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
ClassMethods);
if (Category) {
Values[4] =
EmitProtocolList("\01L_OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(),
Category->protocol_begin(),
Category->protocol_end());
} else {
Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
}
Values[5] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
// If there is no category @interface then there can be no properties.
if (Category) {
Values[6] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(),
OCD, Category, ObjCTypes);
} else {
Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
}
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.CategoryTy,
Values);
llvm::GlobalVariable *GV =
CreateMetadataVar("\01L_OBJC_CATEGORY_" + ExtName.str(), Init,
"__OBJC,__category,regular,no_dead_strip",
4, true);
DefinedCategories.push_back(GV);
DefinedCategoryNames.insert(ExtName.str());
// method definition entries must be clear for next implementation.
MethodDefinitions.clear();
}
// 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>
};
/*
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) {
DefinedSymbols.insert(ID->getIdentifier());
std::string ClassName = ID->getNameAsString();
// FIXME: Gross
ObjCInterfaceDecl *Interface =
const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
llvm::Constant *Protocols =
EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(),
Interface->all_referenced_protocol_begin(),
Interface->all_referenced_protocol_end());
unsigned Flags = eClassFlags_Factory;
if (ID->hasCXXStructors())
Flags |= eClassFlags_HasCXXStructors;
unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
// FIXME: Set CXX-structors flag.
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
Flags |= eClassFlags_Hidden;
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);
}
}
llvm::Constant *Values[12];
Values[ 0] = EmitMetaClass(ID, Protocols, ClassMethods);
if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) {
// Record a reference to the super class.
LazySymbols.insert(Super->getIdentifier());
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);
Values[ 7] =
EmitMethodList("\01L_OBJC_INSTANCE_METHODS_" + ID->getName(),
"__OBJC,__inst_meth,regular,no_dead_strip",
InstanceMethods);
// cache is always NULL.
Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
Values[ 9] = Protocols;
Values[10] = BuildIvarLayout(ID, true);
Values[11] = EmitClassExtension(ID);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
std::string Name("\01L_OBJC_CLASS_");
Name += ClassName;
const char *Section = "__OBJC,__class,regular,no_dead_strip";
// 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);
GV->setSection(Section);
GV->setAlignment(4);
CGM.AddUsedGlobal(GV);
}
else
GV = CreateMetadataVar(Name, Init, Section, 4, true);
DefinedClasses.push_back(GV);
// method definition entries must be clear for next implementation.
MethodDefinitions.clear();
}
llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
const ConstantVector &Methods) {
unsigned Flags = eClassFlags_Meta;
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy);
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
Flags |= eClassFlags_Hidden;
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);
// 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.
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);
Values[ 7] =
EmitMethodList("\01L_OBJC_CLASS_METHODS_" + ID->getNameAsString(),
"__OBJC,__cls_meth,regular,no_dead_strip",
Methods);
// 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);
std::string Name("\01L_OBJC_METACLASS_");
Name += ID->getNameAsCString();
// Check for a forward reference.
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
if (GV) {