#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 {
class ObjCCommonTypesHelper {
protected:
llvm::LLVMContext &VMContext;
private:
llvm::Constant *getMessageSendFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend",
llvm::Attribute::NonLazyBind);
}
llvm::Constant *getMessageSendStretFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy,
params, true),
"objc_msgSend_stret");
}
llvm::Constant *getMessageSendFpretFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.DoubleTy,
params, true),
"objc_msgSend_fpret");
}
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");
}
llvm::Constant *getMessageSendSuperFn() const {
llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper");
}
llvm::Constant *getMessageSendSuperFn2() const {
llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper2");
}
llvm::Constant *getMessageSendSuperStretFn() const {
llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper_stret");
}
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 {
return getMessageSendSuperFn();
}
llvm::Constant *getMessageSendSuperFpretFn2() const {
return getMessageSendSuperFn2();
}
protected:
CodeGen::CodeGenModule &CGM;
public:
llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy;
llvm::Type *Int8PtrTy, *Int8PtrPtrTy;
llvm::Type *ObjectPtrTy;
llvm::Type *PtrObjectPtrTy;
llvm::Type *SelectorPtrTy;
private:
llvm::Type *ExternalProtocolPtrTy;
public:
llvm::Type *getExternalProtocolPtrTy() {
if (!ExternalProtocolPtrTy) {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
}
return ExternalProtocolPtrTy;
}
QualType SuperCTy;
QualType SuperPtrCTy;
llvm::StructType *SuperTy;
llvm::Type *SuperPtrTy;
llvm::StructType *PropertyTy;
llvm::StructType *PropertyListTy;
llvm::Type *PropertyListPtrTy;
llvm::StructType *MethodTy;
llvm::Type *CacheTy;
llvm::Type *CachePtrTy;
llvm::Constant *getGetPropertyFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
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.arrangeFunctionType(IdType, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
llvm::Constant *getSetPropertyFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
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.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
llvm::Constant *getOptimizedSetPropertyFn(bool atomic, bool copy) {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
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(IdType);
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
const char *name;
if (atomic && copy)
name = "objc_setProperty_atomic_copy";
else if (atomic && !copy)
name = "objc_setProperty_atomic";
else if (!atomic && copy)
name = "objc_setProperty_nonatomic_copy";
else
name = "objc_setProperty_nonatomic";
return CGM.CreateRuntimeFunction(FTy, name);
}
llvm::Constant *getCopyStructFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
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.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
}
llvm::Constant *getCppAtomicObjectFunction() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
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.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
}
llvm::Constant *getEnumerationMutationFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
SmallVector<CanQualType,1> Params;
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
llvm::Constant *getGcReadWeakFn() {
llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
}
llvm::Constant *getGcAssignWeakFn() {
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
}
llvm::Constant *getGcAssignGlobalFn() {
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
}
llvm::Constant *getGcAssignThreadLocalFn() {
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
}
llvm::Constant *getGcAssignIvarFn() {
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
CGM.PtrDiffTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
}
llvm::Constant *GcMemmoveCollectableFn() {
llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
}
llvm::Constant *getGcAssignStrongCastFn() {
llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
}
llvm::Constant *getExceptionThrowFn() {
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
}
llvm::Constant *getExceptionRethrowFn() {
llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow");
}
llvm::Constant *getSyncEnterFn() {
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
}
llvm::Constant *getSyncExitFn() {
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(){}
};
class ObjCTypesHelper : public ObjCCommonTypesHelper {
public:
llvm::StructType *SymtabTy;
llvm::Type *SymtabPtrTy;
llvm::StructType *ModuleTy;
llvm::StructType *ProtocolTy;
llvm::Type *ProtocolPtrTy;
llvm::StructType *ProtocolExtensionTy;
llvm::Type *ProtocolExtensionPtrTy;
llvm::StructType *MethodDescriptionTy;
llvm::StructType *MethodDescriptionListTy;
llvm::Type *MethodDescriptionListPtrTy;
llvm::StructType *ProtocolListTy;
llvm::Type *ProtocolListPtrTy;
llvm::StructType *CategoryTy;
llvm::StructType *ClassTy;
llvm::Type *ClassPtrTy;
llvm::StructType *ClassExtensionTy;
llvm::Type *ClassExtensionPtrTy;
llvm::StructType *IvarTy;
llvm::Type *IvarListTy;
llvm::Type *IvarListPtrTy;
llvm::Type *MethodListTy;
llvm::Type *MethodListPtrTy;
llvm::Type *ExceptionDataTy;
llvm::Constant *getExceptionTryEnterFn() {
llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_enter");
}
llvm::Constant *getExceptionTryExitFn() {
llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_exit");
}
llvm::Constant *getExceptionExtractFn() {
llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, false),
"objc_exception_extract");
}
llvm::Constant *getExceptionMatchFn() {
llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.Int32Ty, params, false),
"objc_exception_match");
}
llvm::Constant *getSetJmpFn() {
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() {}
};
class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper {
public:
llvm::StructType *MethodListnfABITy;
llvm::Type *MethodListnfABIPtrTy;
llvm::StructType *ProtocolnfABITy;
llvm::Type *ProtocolnfABIPtrTy;
llvm::StructType *ProtocolListnfABITy;
llvm::Type *ProtocolListnfABIPtrTy;
llvm::StructType *ClassnfABITy;
llvm::Type *ClassnfABIPtrTy;
llvm::StructType *IvarnfABITy;
llvm::StructType *IvarListnfABITy;
llvm::Type *IvarListnfABIPtrTy;
llvm::StructType *ClassRonfABITy;
llvm::Type *ImpnfABITy;
llvm::StructType *CategorynfABITy;
llvm::StructType *MessageRefTy;
QualType MessageRefCTy;
llvm::Type *MessageRefPtrTy;
QualType MessageRefCPtrTy;
llvm::FunctionType *MessengerTy;
llvm::StructType *SuperMessageRefTy;
llvm::Type *SuperMessageRefPtrTy;
llvm::Constant *getMessageSendFixupFn() {
llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_fixup");
}
llvm::Constant *getMessageSendFpretFixupFn() {
llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_fpret_fixup");
}
llvm::Constant *getMessageSendStretFixupFn() {
llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_stret_fixup");
}
llvm::Constant *getMessageSendSuper2FixupFn() {
llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper2_fixup");
}
llvm::Constant *getMessageSendSuper2StretFixupFn() {
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:
class GC_IVAR {
public:
unsigned ivar_bytepos;
unsigned ivar_size;
GC_IVAR(unsigned bytepos = 0, unsigned size = 0)
: ivar_bytepos(bytepos), ivar_size(size) {}
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:
llvm::LLVMContext &VMContext;
unsigned ObjCABI;
SmallVector<GC_IVAR, 16> SkipIvars;
SmallVector<GC_IVAR, 16> IvarsInfo;
llvm::SetVector<IdentifierInfo*> LazySymbols;
llvm::SetVector<IdentifierInfo*> DefinedSymbols;
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassNames;
llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
llvm::SetVector<std::string> DefinedCategoryNames;
llvm::StringMap<llvm::GlobalVariable*> MethodVarTypes;
llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassReferences;
llvm::DenseMap<Selector, llvm::GlobalVariable*> SelectorReferences;
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> Protocols;
llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
llvm::SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
llvm::SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
llvm::SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
llvm::SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
void GetNameForMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD,
SmallVectorImpl<char> &NameOut);
llvm::Constant *GetMethodVarName(Selector Sel);
llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D,
bool Extended = false);
llvm::Constant *GetMethodVarType(const FieldDecl *D);
llvm::Constant *GetPropertyName(IdentifierInfo *Ident);
llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD,
const Decl *Container);
llvm::Constant *GetClassName(IdentifierInfo *Ident);
llvm::Function *GetMethodDefinition(const ObjCMethodDecl *MD);
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,
ArrayRef<const FieldDecl*> RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
llvm::Constant *GetIvarLayoutName(IdentifierInfo *Ident,
const ObjCCommonTypesHelper &ObjCTypes);
llvm::Constant *EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes);
llvm::Constant *EmitProtocolMethodTypes(Twine Name,
ArrayRef<llvm::Constant*> MethodTypes,
const ObjCCommonTypesHelper &ObjCTypes);
void PushProtocolProperties(
llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
llvm::SmallVectorImpl<llvm::Constant*> &Properties,
const Decl *Container,
const ObjCProtocolDecl *PROTO,
const ObjCCommonTypesHelper &ObjCTypes);
llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
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);
void EmitImageInfo();
public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGObjCRuntime(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);
virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD)=0;
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;
void EmitModuleInfo();
llvm::Constant *EmitModuleSymbols();
void FinishModule();
llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID);
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II);
llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID,
bool ForClass);
llvm::Constant *EmitMetaClassRef(const ObjCInterfaceDecl *ID);
llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
ArrayRef<llvm::Constant*> Methods);
llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD);
llvm::Constant *EmitMethodList(Twine Name,
const char *Section,
ArrayRef<llvm::Constant*> Methods);
llvm::Constant *EmitMethodDescList(Twine Name,
const char *Section,
ArrayRef<llvm::Constant*> Methods);
virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
llvm::Constant *
EmitProtocolExtension(const ObjCProtocolDecl *PD,
ArrayRef<llvm::Constant*> OptInstanceMethods,
ArrayRef<llvm::Constant*> OptClassMethods,
ArrayRef<llvm::Constant*> MethodTypesExt);
llvm::Constant *EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
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);
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 *GetOptimizedPropertySetFunction(bool atomic,
bool copy);
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);
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;
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> SuperClassReferences;
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> MetaClassReferences;
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
llvm::DenseSet<Selector> VTableDispatchMethods;
std::vector<llvm::GlobalValue*> DefinedMetaClasses;
bool isVTableDispatchedSelector(Selector Sel);
void FinishNonFragileABIModule();
void AddModuleClassList(ArrayRef<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);
llvm::Constant *EmitMethodList(Twine Name,
const char *Section,
ArrayRef<llvm::Constant*> Methods);
llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID);
llvm::Constant *EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar,
unsigned long int offset);
virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
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);
llvm::GlobalVariable *GetClassGlobal(const std::string &Name);
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II);
llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
llvm::Value *EmitSuperClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
llvm::GlobalVariable * ObjCIvarOffsetVariable(
const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
bool lval=false);
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);
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);
}
bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const;
public:
CGObjCNonFragileABIMac(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 lvalue = false)
{ return EmitSelector(Builder, Sel, lvalue); }
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 *GetOptimizedPropertySetFunction(bool atomic,
bool copy) {
return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
}
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);
};
struct NullReturnState {
llvm::BasicBlock *NullBB;
llvm::BasicBlock *callBB;
NullReturnState() : NullBB(0), callBB(0) {}
void init(CodeGenFunction &CGF, llvm::Value *receiver) {
NullBB = CGF.createBasicBlock("msgSend.nullinit");
callBB = CGF.createBasicBlock("msgSend.call");
llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
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);
}
llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB);
CGF.EmitBlock(NullBB);
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);
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);
CGF.EmitBlock(contBB);
return result;
}
CGF.EmitBlock(contBB);
CodeGenFunction::ComplexPairTy CallCV = result.getComplexVal();
llvm::Type *MemberType = CallCV.first->getType();
llvm::Constant *ZeroCV = llvm::Constant::getNullValue(MemberType);
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);
}
};
}
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);
}
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::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
ObjCTypes(cgm) {
ObjCABI = 1;
EmitImageInfo();
}
llvm::Value *CGObjCMac::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
return EmitClassRef(Builder, ID);
}
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(), true);
}
if (T->isObjCClassType() ||
T->isObjCQualifiedClassType()) {
return CGM.GetAddrOfRTTIDescriptor(
CGM.getContext().getObjCClassRedefinitionType(), true);
}
if (T->isObjCObjectPointerType())
return CGM.GetAddrOfRTTIDescriptor(T, true);
llvm_unreachable("asking for catch type for ObjC type in fragile runtime");
}
llvm::Constant *CGObjCCommonMac::GenerateConstantString(
const StringLiteral *SL) {
return (CGM.getLangOptions().NoConstantCFStrings == 0 ?
CGM.GetAddrOfConstantCFString(SL) :
CGM.GetAddrOfConstantString(SL));
}
enum {
kCFTaggedObjectID_Integer = (1 << 1) + 1
};
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) {
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));
llvm::Value *Target;
if (IsClassMessage) {
if (isCategoryImpl) {
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);
}
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);
}
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);
MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
if (Method)
assert(CGM.getContext().getCanonicalType(Method->getResultType()) ==
CGM.getContext().getCanonicalType(ResultType) &&
"Result type mismatch!");
NullReturnState nullReturn;
llvm::Constant *Fn = NULL;
if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
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, MSI.MessengerType);
RValue rvalue = CGF.EmitCall(MSI.CallInfo, 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.getObjCLifetime() == Qualifiers::OCL_ExplicitNone)
return Qualifiers::GCNone;
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(CGM.Int8PtrTy);
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();
IvarsInfo.push_back(GC_IVAR(0, 1));
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
const llvm::StructLayout *layout =
CGM.getTargetData().getStructLayout(blockInfo.StructureType);
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);
if (capture.isConstant()) continue;
uint64_t fieldOffset = layout->getElementOffset(capture.getIndex());
if (ci->isByRef()) {
IvarsInfo.push_back(GC_IVAR(fieldOffset, 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;
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, e = BitMap.size(); i < e; 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) {
LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
ObjCTypes.getExternalProtocolPtrTy());
}
void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
DefinedProtocols.insert(PD->getIdentifier());
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);
}
llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
if (Entry && Entry->hasInitializer())
return Entry;
if (const ObjCProtocolDecl *Def = PD->getDefinition())
PD = Def;
LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
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) {
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");
Entry->setAlignment(4);
}
CGM.AddUsedGlobal(Entry);
return Entry;
}
llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
if (!Entry) {
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");
Entry->setAlignment(4);
}
return Entry;
}
llvm::Constant *
CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
ArrayRef<llvm::Constant*> OptInstanceMethods,
ArrayRef<llvm::Constant*> OptClassMethods,
ArrayRef<llvm::Constant*> 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)
};
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);
return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getName(),
Init,
0, 0, true);
}
llvm::Constant *
CGObjCMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
llvm::SmallVector<llvm::Constant*, 16> ProtocolRefs;
for (; begin != end; ++begin)
ProtocolRefs.push_back(GetProtocolRef(*begin));
if (ProtocolRefs.empty())
return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
ProtocolRefs.push_back(llvm::Constant::getNullValue(ObjCTypes.ProtocolPtrTy));
llvm::Constant *Values[3];
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,
llvm::SmallVectorImpl<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));
}
}
llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes) {
llvm::SmallVector<llvm::Constant*, 16> 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);
}
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,
ArrayRef<llvm::Constant*> MethodTypes,
const ObjCCommonTypesHelper &ObjCTypes) {
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);
}
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,
ArrayRef<llvm::Constant*> Methods) {
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);
}
void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.CategoryTy);
const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
SmallString<256> ExtName;
llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_'
<< OCD->getName();
llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
for (ObjCCategoryImplDecl::instmeth_iterator
i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
InstanceMethods.push_back(GetMethodConstant(*i));
}
for (ObjCCategoryImplDecl::classmeth_iterator
i = OCD->classmeth_begin(), e = OCD->classmeth_end(); i != e; ++i) {
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 (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());
MethodDefinitions.clear();
}
enum ClassFlags {
eClassFlags_Factory = 0x00001,
eClassFlags_Meta = 0x00002,
eClassFlags_HasCXXStructors = 0x02000,
eClassFlags_Hidden = 0x20000,
eClassFlags_ABI2_Hidden = 0x00010,
eClassFlags_ABI2_HasCXXStructors = 0x00004 };
void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
DefinedSymbols.insert(ID->getIdentifier());
std::string ClassName = ID->getNameAsString();
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();
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
Flags |= eClassFlags_Hidden;
llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
for (ObjCImplementationDecl::instmeth_iterator
i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
InstanceMethods.push_back(GetMethodConstant(*i));
}
for (ObjCImplementationDecl::classmeth_iterator
i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
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()) {
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());
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);
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";
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);
MethodDefinitions.clear();
}
llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
ArrayRef<llvm::Constant*> Methods) {
unsigned Flags = eClassFlags_Meta;
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy);
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
Flags |= eClassFlags_Hidden;
llvm::Constant *Values[12];
const ObjCInterfaceDecl *Root = ID->getClassInterface();
while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
Root = Super;
Values[ 0] =
llvm::ConstantExpr::getBitCast(GetClassName(Root->getIdentifier()),
ObjCTypes.ClassPtrTy);
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());
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);
Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
Values[ 9] = Protocols;
Values[10] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
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();
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(CGM.getModule(), ObjCTypes.ClassTy, false,
llvm::GlobalValue::InternalLinkage,
Init, Name);
}
GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
GV->setAlignment(4);
CGM.AddUsedGlobal(GV);
return GV;
}
llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
std::string Name = "\01L_OBJC_METACLASS_" + ID->getNameAsString();
if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name,
true)) {
assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
"Forward metaclass reference has incorrect type.");
return GV;
} else {
return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
llvm::GlobalValue::ExternalLinkage,
0,
Name);
}
}
llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
std::string Name = "\01L_OBJC_CLASS_" + ID->getNameAsString();
if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name,
true)) {
assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
"Forward class metadata reference has incorrect type.");
return GV;
} else {
return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
llvm::GlobalValue::ExternalLinkage,
0,
Name);
}
}
llvm::Constant *
CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
uint64_t Size =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[1] = BuildIvarLayout(ID, false);
Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
ID, ID->getClassInterface(), ObjCTypes);
if (Values[1]->isNullValue() && Values[2]->isNullValue())
return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values);
return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getName(),
Init, "__OBJC,__class_ext,regular,no_dead_strip",
4, true);
}
llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
bool ForClass) {
std::vector<llvm::Constant*> Ivars;
if (ForClass)
return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
const ObjCInterfaceDecl *OID = ID->getClassInterface();
for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar()) {
if (!IVD->getDeclName())
continue;
llvm::Constant *Ivar[] = {
GetMethodVarName(IVD->getIdentifier()),
GetMethodVarType(IVD),
llvm::ConstantInt::get(ObjCTypes.IntTy,
ComputeIvarBaseOffset(CGM, OID, IVD))
};
Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy, Ivar));
}
if (Ivars.empty())
return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
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::getAnon(Values);
llvm::GlobalVariable *GV;
if (ForClass)
GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getName(),
Init, "__OBJC,__class_vars,regular,no_dead_strip",
4, true);
else
GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_" + ID->getName(),
Init, "__OBJC,__instance_vars,regular,no_dead_strip",
4, true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy);
}
llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) {
llvm::Function *Fn = GetMethodDefinition(MD);
if (!Fn)
return 0;
llvm::Constant *Method[] = {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy),
GetMethodVarType(MD),
llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy)
};
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method);
}
llvm::Constant *CGObjCMac::EmitMethodList(Twine Name,
const char *Section,
ArrayRef<llvm::Constant*> Methods) {
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodListPtrTy);
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::getAnon(Values);
llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListPtrTy);
}
llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
SmallString<256> Name;
GetNameForMethod(OMD, CD, Name);
CodeGenTypes &Types = CGM.getTypes();
llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
llvm::Function *Method =
llvm::Function::Create(MethodTy,
llvm::GlobalValue::InternalLinkage,
Name.str(),
&CGM.getModule());
MethodDefinitions.insert(std::make_pair(OMD, Method));
return Method;
}
llvm::GlobalVariable *
CGObjCCommonMac::CreateMetadataVar(Twine Name,
llvm::Constant *Init,
const char *Section,
unsigned Align,
bool AddToUsed) {
llvm::Type *Ty = Init->getType();
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Ty, false,
llvm::GlobalValue::InternalLinkage, Init, Name);
if (Section)
GV->setSection(Section);
if (Align)
GV->setAlignment(Align);
if (AddToUsed)
CGM.AddUsedGlobal(GV);
return GV;
}
llvm::Function *CGObjCMac::ModuleInitFunction() {
FinishModule();
return NULL;
}
llvm::Constant *CGObjCMac::GetPropertyGetFunction() {
return ObjCTypes.getGetPropertyFn();
}
llvm::Constant *CGObjCMac::GetPropertySetFunction() {
return ObjCTypes.getSetPropertyFn();
}
llvm::Constant *CGObjCMac::GetOptimizedPropertySetFunction(bool atomic,
bool copy) {
return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
}
llvm::Constant *CGObjCMac::GetGetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
llvm::Constant *CGObjCMac::GetSetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
llvm::Constant *CGObjCMac::GetCppAtomicObjectFunction() {
return ObjCTypes.getCppAtomicObjectFunction();
}
llvm::Constant *CGObjCMac::EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
}
void CGObjCMac::EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S) {
return EmitTryOrSynchronizedStmt(CGF, S);
}
void CGObjCMac::EmitSynchronizedStmt(CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S) {
return EmitTryOrSynchronizedStmt(CGF, S);
}
namespace {
struct PerformFragileFinally : EHScopeStack::Cleanup {
const Stmt &S;
llvm::Value *SyncArgSlot;
llvm::Value *CallTryExitVar;
llvm::Value *ExceptionData;
ObjCTypesHelper &ObjCTypes;
PerformFragileFinally(const Stmt *S,
llvm::Value *SyncArgSlot,
llvm::Value *CallTryExitVar,
llvm::Value *ExceptionData,
ObjCTypesHelper *ObjCTypes)
: S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar),
ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::BasicBlock *FinallyCallExit =
CGF.createBasicBlock("finally.call_exit");
llvm::BasicBlock *FinallyNoCallExit =
CGF.createBasicBlock("finally.no_call_exit");
CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CallTryExitVar),
FinallyCallExit, FinallyNoCallExit);
CGF.EmitBlock(FinallyCallExit);
CGF.Builder.CreateCall(ObjCTypes.getExceptionTryExitFn(), ExceptionData)
->setDoesNotThrow();
CGF.EmitBlock(FinallyNoCallExit);
if (isa<ObjCAtTryStmt>(S)) {
if (const ObjCAtFinallyStmt* FinallyStmt =
cast<ObjCAtTryStmt>(S).getFinallyStmt()) {
llvm::Value *CurCleanupDest =
CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot());
CGF.EmitStmt(FinallyStmt->getFinallyBody());
if (CGF.HaveInsertPoint()) {
CGF.Builder.CreateStore(CurCleanupDest,
CGF.getNormalCleanupDestSlot());
} else {
CGF.EnsureInsertPoint();
}
}
} else {
llvm::Value *SyncArg = CGF.Builder.CreateLoad(SyncArgSlot);
CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg)
->setDoesNotThrow();
}
}
};
class FragileHazards {
CodeGenFunction &CGF;
SmallVector<llvm::Value*, 20> Locals;
llvm::DenseSet<llvm::BasicBlock*> BlocksBeforeTry;
llvm::InlineAsm *ReadHazard;
llvm::InlineAsm *WriteHazard;
llvm::FunctionType *GetAsmFnType();
void collectLocals();
void emitReadHazard(CGBuilderTy &Builder);
public:
FragileHazards(CodeGenFunction &CGF);
void emitWriteHazard();
void emitHazardsInNewBlocks();
};
}
FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
collectLocals();
if (Locals.empty()) return;
for (llvm::Function::iterator
I = CGF.CurFn->begin(), E = CGF.CurFn->end(); I != E; ++I)
BlocksBeforeTry.insert(&*I);
llvm::FunctionType *AsmFnTy = GetAsmFnType();
{
std::string Constraint;
for (unsigned I = 0, E = Locals.size(); I != E; ++I) {
if (I) Constraint += ',';
Constraint += "*m";
}
ReadHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false);
}
{
std::string Constraint;
for (unsigned I = 0, E = Locals.size(); I != E; ++I) {
if (I) Constraint += ',';
Constraint += "=*m";
}
WriteHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false);
}
}
void FragileHazards::emitWriteHazard() {
if (Locals.empty()) return;
CGF.Builder.CreateCall(WriteHazard, Locals)->setDoesNotThrow();
}
void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
assert(!Locals.empty());
Builder.CreateCall(ReadHazard, Locals)->setDoesNotThrow();
}
void FragileHazards::emitHazardsInNewBlocks() {
if (Locals.empty()) return;
CGBuilderTy Builder(CGF.getLLVMContext());
for (llvm::Function::iterator
FI = CGF.CurFn->begin(), FE = CGF.CurFn->end(); FI != FE; ++FI) {
llvm::BasicBlock &BB = *FI;
if (BlocksBeforeTry.count(&BB)) continue;
for (llvm::BasicBlock::iterator
BI = BB.begin(), BE = BB.end(); BI != BE; ++BI) {
llvm::Instruction &I = *BI;
if (!isa<llvm::CallInst>(I) && !isa<llvm::InvokeInst>(I)) continue;
if (isa<llvm::IntrinsicInst>(I))
continue;
llvm::CallSite CS(&I);
if (CS.doesNotThrow()) continue;
Builder.SetInsertPoint(&BB, BI);
emitReadHazard(Builder);
}
}
}
static void addIfPresent(llvm::DenseSet<llvm::Value*> &S, llvm::Value *V) {
if (V) S.insert(V);
}
void FragileHazards::collectLocals() {
llvm::DenseSet<llvm::Value*> AllocasToIgnore;
addIfPresent(AllocasToIgnore, CGF.ReturnValue);
addIfPresent(AllocasToIgnore, CGF.NormalCleanupDest);
llvm::BasicBlock &Entry = CGF.CurFn->getEntryBlock();
for (llvm::BasicBlock::iterator
I = Entry.begin(), E = Entry.end(); I != E; ++I)
if (isa<llvm::AllocaInst>(*I) && !AllocasToIgnore.count(&*I))
Locals.push_back(&*I);
}
llvm::FunctionType *FragileHazards::GetAsmFnType() {
SmallVector<llvm::Type *, 16> tys(Locals.size());
for (unsigned i = 0, e = Locals.size(); i != e; ++i)
tys[i] = Locals[i]->getType();
return llvm::FunctionType::get(CGF.VoidTy, tys, false);
}
void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const Stmt &S) {
bool isTry = isa<ObjCAtTryStmt>(S);
CodeGenFunction::JumpDest FinallyEnd =
CGF.getJumpDestInCurrentScope("finally.end");
CodeGenFunction::JumpDest FinallyRethrow =
CGF.getJumpDestInCurrentScope("finally.rethrow");
llvm::Value *SyncArgSlot = 0;
if (!isTry) {
llvm::Value *SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg)
->setDoesNotThrow();
SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(), "sync.arg");
CGF.Builder.CreateStore(SyncArg, SyncArgSlot);
}
llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
"exceptiondata.ptr");
FragileHazards Hazards(CGF);
llvm::Value *CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(),
"_call_try_exit");
llvm::Value *PropagatingExnVar = 0;
CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalCleanup, &S,
SyncArgSlot,
CallTryExitVar,
ExceptionData,
&ObjCTypes);
CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
->setDoesNotThrow();
llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
llvm::Value *GEPIndexes[] = { Zero, Zero, Zero };
llvm::Value *SetJmpBuffer =
CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, "setjmp_buffer");
llvm::CallInst *SetJmpResult =
CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
SetJmpResult->setDoesNotThrow();
SetJmpResult->setCanReturnTwice();
llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
llvm::Value *DidCatch =
CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
CGF.Builder.CreateCondBr(DidCatch, TryHandler, TryBlock);
CGF.EmitBlock(TryBlock);
CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar);
CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
: cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
CGBuilderTy::InsertPoint TryFallthroughIP = CGF.Builder.saveAndClearIP();
CGF.EmitBlock(TryHandler);
Hazards.emitWriteHazard();
if (!isTry || !cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
} else {
llvm::CallInst *Caught =
CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
ExceptionData, "caught");
Caught->setDoesNotThrow();
CGF.ObjCEHValueStack.push_back(Caught);
const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S);
bool HasFinally = (AtTryStmt->getFinallyStmt() != 0);
llvm::BasicBlock *CatchBlock = 0;
llvm::BasicBlock *CatchHandler = 0;
if (HasFinally) {
PropagatingExnVar = CGF.CreateTempAlloca(Caught->getType(),
"propagating_exception");
CGF.Builder.CreateStore(Caught, PropagatingExnVar);
CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
->setDoesNotThrow();
llvm::CallInst *SetJmpResult =
CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer,
"setjmp.result");
SetJmpResult->setDoesNotThrow();
SetJmpResult->setCanReturnTwice();
llvm::Value *Threw =
CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
CatchBlock = CGF.createBasicBlock("catch");
CatchHandler = CGF.createBasicBlock("catch_for_catch");
CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock);
CGF.EmitBlock(CatchBlock);
}
CGF.Builder.CreateStore(CGF.Builder.getInt1(HasFinally), CallTryExitVar);
bool AllMatched = false;
for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) {
const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I);
const VarDecl *CatchParam = CatchStmt->getCatchParamDecl();
const ObjCObjectPointerType *OPT = 0;
if (!CatchParam) {
AllMatched = true;
} else {
OPT = CatchParam->getType()->getAs<ObjCObjectPointerType>();
if (OPT && (OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()))
AllMatched = true;
}
if (AllMatched) {
CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF);
if (CatchParam) {
CGF.EmitAutoVarDecl(*CatchParam);
assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
CGF.Builder.CreateStore(Caught, CGF.GetAddrOfLocalVar(CatchParam));
}
CGF.EmitStmt(CatchStmt->getCatchBody());
CatchVarCleanups.ForceCleanup();
CGF.EmitBranchThroughCleanup(FinallyEnd);
break;
}
assert(OPT && "Unexpected non-object pointer type in @catch");
const ObjCObjectType *ObjTy = OPT->getObjectType();
ObjCInterfaceDecl *IDecl = ObjTy->getInterface();
assert(IDecl && "Catch parameter must have Objective-C type!");
llvm::Value *Class = EmitClassRef(CGF.Builder, IDecl);
llvm::CallInst *Match =
CGF.Builder.CreateCall2(ObjCTypes.getExceptionMatchFn(),
Class, Caught, "match");
Match->setDoesNotThrow();
llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("match");
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch.next");
CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(Match, "matched"),
MatchedBlock, NextCatchBlock);
CGF.EmitBlock(MatchedBlock);
CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF);
CGF.EmitAutoVarDecl(*CatchParam);
assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
llvm::Value *Tmp =
CGF.Builder.CreateBitCast(Caught,
CGF.ConvertType(CatchParam->getType()));
CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(CatchParam));
CGF.EmitStmt(CatchStmt->getCatchBody());
CatchVarCleanups.ForceCleanup();
CGF.EmitBranchThroughCleanup(FinallyEnd);
CGF.EmitBlock(NextCatchBlock);
}
CGF.ObjCEHValueStack.pop_back();
if (Caught->use_empty())
Caught->eraseFromParent();
if (!AllMatched)
CGF.EmitBranchThroughCleanup(FinallyRethrow);
if (HasFinally) {
CGF.EmitBlock(CatchHandler);
assert(PropagatingExnVar);
llvm::CallInst *NewCaught =
CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
ExceptionData, "caught");
NewCaught->setDoesNotThrow();
CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
}
}
Hazards.emitHazardsInNewBlocks();
CGF.Builder.restoreIP(TryFallthroughIP);
if (CGF.HaveInsertPoint())
CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar);
CGF.PopCleanupBlock();
CGF.EmitBlock(FinallyEnd.getBlock(), true);
CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
CGF.EmitBlock(FinallyRethrow.getBlock(), true);
if (CGF.HaveInsertPoint()) {
llvm::Value *PropagatingExn;
if (PropagatingExnVar) {
PropagatingExn = CGF.Builder.CreateLoad(PropagatingExnVar);
} else {
llvm::CallInst *Caught =
CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
ExceptionData);
Caught->setDoesNotThrow();
PropagatingExn = Caught;
}
CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), PropagatingExn)
->setDoesNotThrow();
CGF.Builder.CreateUnreachable();
}
CGF.Builder.restoreIP(SavedIP);
}
void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtThrowStmt &S) {
llvm::Value *ExceptionAsObject;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
ExceptionAsObject =
CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
} else {
assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
"Unexpected rethrow outside @catch block.");
ExceptionAsObject = CGF.ObjCEHValueStack.back();
}
CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
->setDoesNotReturn();
CGF.Builder.CreateUnreachable();
CGF.Builder.ClearInsertionPoint();
}
llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
llvm::Type* DestTy =
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj,
ObjCTypes.PtrObjectPtrTy);
llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
AddrWeakObj, "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
src, dst, "weakassign");
return;
}
void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
if (!threadlocal)
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
src, dst, "globalassign");
else
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
src, dst, "threadlocalassign");
return;
}
void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
llvm::Value *ivarOffset) {
assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
src, dst, ivarOffset);
return;
}
void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
src, dst, "weakassign");
return;
}
void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
llvm::Value *size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
DestPtr, SrcPtr, size);
return;
}
LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
const ObjCInterfaceDecl *ID =
ObjectTy->getAs<ObjCObjectType>()->getInterface();
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
uint64_t Offset = ComputeIvarBaseOffset(CGM, Interface, Ivar);
return llvm::ConstantInt::get(
CGM.getTypes().ConvertType(CGM.getContext().LongTy),
Offset);
}
enum ImageInfoFlags {
eImageInfo_FixAndContinue = (1 << 0),
eImageInfo_GarbageCollected = (1 << 1),
eImageInfo_GCOnly = (1 << 2),
eImageInfo_OptimizedByDyld = (1 << 3),
eImageInfo_CorrectedSynthesize = (1 << 4)
};
void CGObjCCommonMac::EmitImageInfo() {
unsigned version = 0; const char *Section = (ObjCABI == 1) ?
"__OBJC, __image_info,regular" :
"__DATA, __objc_imageinfo, regular, no_dead_strip";
llvm::Module &Mod = CGM.getModule();
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Version", ObjCABI);
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
version);
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
llvm::MDString::get(VMContext,Section));
if (CGM.getLangOptions().getGC() == LangOptions::NonGC) {
Mod.addModuleFlag(llvm::Module::Override,
"Objective-C Garbage Collection", (uint32_t)0);
} else {
Mod.addModuleFlag(llvm::Module::Error,
"Objective-C Garbage Collection",
eImageInfo_GarbageCollected);
if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) {
Mod.addModuleFlag(llvm::Module::Error, "Objective-C GC Only",
eImageInfo_GCOnly);
llvm::Value *Ops[2] = {
llvm::MDString::get(VMContext, "Objective-C Garbage Collection"),
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
eImageInfo_GarbageCollected)
};
Mod.addModuleFlag(llvm::Module::Require, "Objective-C GC Only",
llvm::MDNode::get(VMContext, Ops));
}
}
}
static const int ModuleVersion = 7;
void CGObjCMac::EmitModuleInfo() {
uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ModuleTy);
llvm::Constant *Values[] = {
llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion),
llvm::ConstantInt::get(ObjCTypes.LongTy, Size),
GetClassName(&CGM.getContext().Idents.get("")),
EmitModuleSymbols()
};
CreateMetadataVar("\01L_OBJC_MODULES",
llvm::ConstantStruct::get(ObjCTypes.ModuleTy, Values),
"__OBJC,__module_info,regular,no_dead_strip",
4, true);
}
llvm::Constant *CGObjCMac::EmitModuleSymbols() {
unsigned NumClasses = DefinedClasses.size();
unsigned NumCategories = DefinedCategories.size();
if (!NumClasses && !NumCategories)
return llvm::Constant::getNullValue(ObjCTypes.SymtabPtrTy);
llvm::Constant *Values[5];
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);
SmallVector<llvm::Constant*, 8> Symbols(NumClasses + NumCategories);
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);
Values[4] =
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
Symbols.size()),
Symbols);
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV =
CreateMetadataVar("\01L_OBJC_SYMBOLS", Init,
"__OBJC,__symbols,regular,no_dead_strip",
4, true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II) {
LazySymbols.insert(II);
llvm::GlobalVariable *&Entry = ClassReferences[II];
if (!Entry) {
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetClassName(II),
ObjCTypes.ClassPtrTy);
Entry =
CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
"__OBJC,__cls_refs,literal_pointers,no_dead_strip",
4, true);
}
return Builder.CreateLoad(Entry);
}
llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
return EmitClassRefFromId(Builder, ID->getIdentifier());
}
llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
return EmitClassRefFromId(Builder, II);
}
llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
bool lvalue) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
if (!Entry) {
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
ObjCTypes.SelectorPtrTy);
Entry =
CreateMetadataVar("\01L_OBJC_SELECTOR_REFERENCES_", Casted,
"__OBJC,__message_refs,literal_pointers,no_dead_strip",
4, true);
}
if (lvalue)
return Entry;
return Builder.CreateLoad(Entry);
}
llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
llvm::GlobalVariable *&Entry = ClassNames[Ident];
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
llvm::ConstantDataArray::getString(VMContext,
Ident->getNameStart()),
((ObjCABI == 2) ?
"__TEXT,__objc_classname,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) {
llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*>::iterator
I = MethodDefinitions.find(MD);
if (I != MethodDefinitions.end())
return I->second;
return NULL;
}
llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident,
const ObjCCommonTypesHelper &ObjCTypes) {
return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
}
void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
unsigned int BytePos,
bool ForStrongLayout,
bool &HasUnion) {
const RecordDecl *RD = RT->getDecl();
SmallVector<const FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end());
llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
const llvm::StructLayout *RecLayout =
CGM.getTargetData().getStructLayout(cast<llvm::StructType>(Ty));
BuildAggrIvarLayout(0, RecLayout, RD, Fields, BytePos,
ForStrongLayout, HasUnion);
}
void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
const llvm::StructLayout *Layout,
const RecordDecl *RD,
ArrayRef<const FieldDecl*> RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion) {
bool IsUnion = (RD && RD->isUnion());
uint64_t MaxUnionIvarSize = 0;
uint64_t MaxSkippedUnionIvarSize = 0;
const FieldDecl *MaxField = 0;
const FieldDecl *MaxSkippedField = 0;
const FieldDecl *LastFieldBitfieldOrUnnamed = 0;
uint64_t MaxFieldOffset = 0;
uint64_t MaxSkippedFieldOffset = 0;
uint64_t LastBitfieldOrUnnamedOffset = 0;
uint64_t FirstFieldDelta = 0;
if (RecFields.empty())
return;
unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
if (!RD && CGM.getLangOptions().ObjCAutoRefCount) {
const FieldDecl *FirstField = RecFields[0];
FirstFieldDelta =
ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(FirstField));
}
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
const FieldDecl *Field = RecFields[i];
uint64_t FieldOffset;
if (RD) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
FieldOffset = (RL.getFieldOffset(i) / ByteSizeInBits) - FirstFieldDelta;
} else
FieldOffset =
ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field)) - FirstFieldDelta;
if (!Field->getIdentifier() || Field->isBitField()) {
LastFieldBitfieldOrUnnamed = Field;
LastBitfieldOrUnnamedOffset = FieldOffset;
continue;
}
LastFieldBitfieldOrUnnamed = 0;
QualType FQT = Field->getType();
if (FQT->isRecordType() || FQT->isUnionType()) {
if (FQT->isUnionType())
HasUnion = true;
BuildAggrIvarRecordLayout(FQT->getAs<RecordType>(),
BytePos + FieldOffset,
ForStrongLayout, HasUnion);
continue;
}
if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
const ConstantArrayType *CArray =
dyn_cast_or_null<ConstantArrayType>(Array);
uint64_t ElCount = CArray->getSize().getZExtValue();
assert(CArray && "only array with known element size is supported");
FQT = CArray->getElementType();
while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
const ConstantArrayType *CArray =
dyn_cast_or_null<ConstantArrayType>(Array);
ElCount *= CArray->getSize().getZExtValue();
FQT = CArray->getElementType();
}
assert(!FQT->isUnionType() &&
"layout for array of unions not supported");
if (FQT->isRecordType() && ElCount) {
int OldIndex = IvarsInfo.size() - 1;
int OldSkIndex = SkipIvars.size() -1;
const RecordType *RT = FQT->getAs<RecordType>();
BuildAggrIvarRecordLayout(RT, BytePos + FieldOffset,
ForStrongLayout, HasUnion);
uint64_t ElIx = 1;
for (int FirstIndex = IvarsInfo.size() - 1,
FirstSkIndex = SkipIvars.size() - 1 ;ElIx < ElCount; ElIx++) {
uint64_t Size = CGM.getContext().getTypeSize(RT)/ByteSizeInBits;
for (int i = OldIndex+1; i <= FirstIndex; ++i)
IvarsInfo.push_back(GC_IVAR(IvarsInfo[i].ivar_bytepos + Size*ElIx,
IvarsInfo[i].ivar_size));
for (int i = OldSkIndex+1; i <= FirstSkIndex; ++i)
SkipIvars.push_back(GC_IVAR(SkipIvars[i].ivar_bytepos + Size*ElIx,
SkipIvars[i].ivar_size));
}
continue;
}
}
Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), FQT);
unsigned FieldSize = CGM.getContext().getTypeSize(Field->getType());
if ((ForStrongLayout && GCAttr == Qualifiers::Strong)
|| (!ForStrongLayout && GCAttr == Qualifiers::Weak)) {
if (IsUnion) {
uint64_t UnionIvarSize = FieldSize / WordSizeInBits;
if (UnionIvarSize > MaxUnionIvarSize) {
MaxUnionIvarSize = UnionIvarSize;
MaxField = Field;
MaxFieldOffset = FieldOffset;
}
} else {
IvarsInfo.push_back(GC_IVAR(BytePos + FieldOffset,
FieldSize / WordSizeInBits));
}
} else if ((ForStrongLayout &&
(GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak))
|| (!ForStrongLayout && GCAttr != Qualifiers::Weak)) {
if (IsUnion) {
uint64_t UnionIvarSize = FieldSize;
if (UnionIvarSize > MaxSkippedUnionIvarSize) {
MaxSkippedUnionIvarSize = UnionIvarSize;
MaxSkippedField = Field;
MaxSkippedFieldOffset = FieldOffset;
}
} else {
SkipIvars.push_back(GC_IVAR(BytePos + FieldOffset,
FieldSize / ByteSizeInBits));
}
}
}
if (LastFieldBitfieldOrUnnamed) {
if (LastFieldBitfieldOrUnnamed->isBitField()) {
uint64_t BitFieldSize
= LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
GC_IVAR skivar;
skivar.ivar_bytepos = BytePos + LastBitfieldOrUnnamedOffset;
skivar.ivar_size = (BitFieldSize / ByteSizeInBits)
+ ((BitFieldSize % ByteSizeInBits) != 0);
SkipIvars.push_back(skivar);
} else {
assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed");
unsigned FieldSize
= CGM.getContext().getTypeSize(LastFieldBitfieldOrUnnamed->getType());
SkipIvars.push_back(GC_IVAR(BytePos + LastBitfieldOrUnnamedOffset,
FieldSize / ByteSizeInBits));
}
}
if (MaxField)
IvarsInfo.push_back(GC_IVAR(BytePos + MaxFieldOffset,
MaxUnionIvarSize));
if (MaxSkippedField)
SkipIvars.push_back(GC_IVAR(BytePos + MaxSkippedFieldOffset,
MaxSkippedUnionIvarSize));
}
llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) {
unsigned int WordsToScan, WordsToSkip;
llvm::Type *PtrTy = CGM.Int8PtrTy;
SmallVector<SKIP_SCAN, 32> SkipScanIvars;
unsigned int WordSize =
CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy);
if (IvarsInfo[0].ivar_bytepos == 0) {
WordsToSkip = 0;
WordsToScan = IvarsInfo[0].ivar_size;
} else {
WordsToSkip = IvarsInfo[0].ivar_bytepos/WordSize;
WordsToScan = IvarsInfo[0].ivar_size;
}
for (unsigned int i=1, Last=IvarsInfo.size(); i != Last; i++) {
unsigned int TailPrevGCObjC =
IvarsInfo[i-1].ivar_bytepos + IvarsInfo[i-1].ivar_size * WordSize;
if (IvarsInfo[i].ivar_bytepos == TailPrevGCObjC) {
WordsToScan += IvarsInfo[i].ivar_size;
} else {
if (TailPrevGCObjC > IvarsInfo[i].ivar_bytepos)
continue;
SKIP_SCAN SkScan;
SkScan.skip = WordsToSkip;
SkScan.scan = WordsToScan;
SkipScanIvars.push_back(SkScan);
SkScan.skip = (IvarsInfo[i].ivar_bytepos - TailPrevGCObjC) / WordSize;
SkScan.scan = 0;
SkipScanIvars.push_back(SkScan);
WordsToSkip = 0;
WordsToScan = IvarsInfo[i].ivar_size;
}
}
if (WordsToScan > 0) {
SKIP_SCAN SkScan;
SkScan.skip = WordsToSkip;
SkScan.scan = WordsToScan;
SkipScanIvars.push_back(SkScan);
}
if (!SkipIvars.empty()) {
unsigned int LastIndex = SkipIvars.size()-1;
int LastByteSkipped =
SkipIvars[LastIndex].ivar_bytepos + SkipIvars[LastIndex].ivar_size;
LastIndex = IvarsInfo.size()-1;
int LastByteScanned =
IvarsInfo[LastIndex].ivar_bytepos +
IvarsInfo[LastIndex].ivar_size * WordSize;
if (LastByteSkipped > LastByteScanned) {
unsigned int TotalWords = (LastByteSkipped + (WordSize -1)) / WordSize;
SKIP_SCAN SkScan;
SkScan.skip = TotalWords - (LastByteScanned/WordSize);
SkScan.scan = 0;
SkipScanIvars.push_back(SkScan);
}
}
int SkipScan = SkipScanIvars.size()-1;
for (int i = 0; i <= SkipScan; i++) {
if ((i < SkipScan) && SkipScanIvars[i].skip && SkipScanIvars[i].scan == 0
&& SkipScanIvars[i+1].skip == 0 && SkipScanIvars[i+1].scan) {
SkipScanIvars[i].scan = SkipScanIvars[i+1].scan;
for (int j = i+1; j < SkipScan; j++)
SkipScanIvars[j] = SkipScanIvars[j+1];
--SkipScan;
}
}
for (int i = 0; i <= SkipScan; i++) {
unsigned char byte;
unsigned int skip_small = SkipScanIvars[i].skip % 0xf;
unsigned int scan_small = SkipScanIvars[i].scan % 0xf;
unsigned int skip_big = SkipScanIvars[i].skip / 0xf;
unsigned int scan_big = SkipScanIvars[i].scan / 0xf;
for (unsigned int ix = 0; ix < skip_big; ix++)
BitMap += (unsigned char)(0xf0);
if (skip_small) {
byte = skip_small << 4;
if (scan_big > 0) {
byte |= 0xf;
--scan_big;
} else if (scan_small) {
byte |= scan_small;
scan_small = 0;
}
BitMap += byte;
}
for (unsigned int ix = 0; ix < scan_big; ix++)
BitMap += (unsigned char)(0x0f);
if (scan_small) {
byte = scan_small;
BitMap += byte;
}
}
unsigned char zero = 0;
BitMap += zero;
llvm::GlobalVariable * Entry =
CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
llvm::ConstantDataArray::getString(VMContext, BitMap,false),
((ObjCABI == 2) ?
"__TEXT,__objc_classname,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
const ObjCImplementationDecl *OMD,
bool ForStrongLayout) {
bool hasUnion = false;
llvm::Type *PtrTy = CGM.Int8PtrTy;
if (CGM.getLangOptions().getGC() == LangOptions::NonGC &&
!CGM.getLangOptions().ObjCAutoRefCount)
return llvm::Constant::getNullValue(PtrTy);
const ObjCInterfaceDecl *OI = OMD->getClassInterface();
SmallVector<const FieldDecl*, 32> RecFields;
if (CGM.getLangOptions().ObjCAutoRefCount) {
for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar())
RecFields.push_back(cast<FieldDecl>(IVD));
}
else {
SmallVector<const ObjCIvarDecl*, 32> Ivars;
CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
RecFields.append(Ivars.begin(), Ivars.end());
}
if (RecFields.empty())
return llvm::Constant::getNullValue(PtrTy);
SkipIvars.clear();
IvarsInfo.clear();
BuildAggrIvarLayout(OMD, 0, 0, RecFields, 0, ForStrongLayout, hasUnion);
if (IvarsInfo.empty())
return llvm::Constant::getNullValue(PtrTy);
if (hasUnion && !IvarsInfo.empty())
std::sort(IvarsInfo.begin(), IvarsInfo.end());
if (hasUnion && !SkipIvars.empty())
std::sort(SkipIvars.begin(), SkipIvars.end());
std::string BitMap;
llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
if (CGM.getLangOptions().ObjCGCBitmapPrint) {
printf("\n%s ivar layout for class '%s': ",
ForStrongLayout ? "strong" : "weak",
OMD->getClassInterface()->getName().data());
const unsigned char *s = (unsigned char*)BitMap.c_str();
for (unsigned i = 0, e = BitMap.size(); i < e; 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::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
llvm::GlobalVariable *&Entry = MethodVarNames[Sel];
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_",
llvm::ConstantDataArray::getString(VMContext, Sel.getAsString()),
((ObjCABI == 2) ?
"__TEXT,__objc_methname,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Constant *CGObjCCommonMac::GetMethodVarName(IdentifierInfo *ID) {
return GetMethodVarName(CGM.getContext().Selectors.getNullarySelector(ID));
}
llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
std::string TypeStr;
CGM.getContext().getObjCEncodingForType(Field->getType(), TypeStr, Field);
llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
llvm::ConstantDataArray::getString(VMContext, TypeStr),
((ObjCABI == 2) ?
"__TEXT,__objc_methtype,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D,
bool Extended) {
std::string TypeStr;
if (CGM.getContext().getObjCEncodingForMethodDecl(D, TypeStr, Extended))
return 0;
llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
llvm::ConstantDataArray::getString(VMContext, TypeStr),
((ObjCABI == 2) ?
"__TEXT,__objc_methtype,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
llvm::GlobalVariable *&Entry = PropertyNames[Ident];
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_",
llvm::ConstantDataArray::getString(VMContext,
Ident->getNameStart()),
"__TEXT,__cstring,cstring_literals",
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Constant *
CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
const Decl *Container) {
std::string TypeStr;
CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container, TypeStr);
return GetPropertyName(&CGM.getContext().Idents.get(TypeStr));
}
void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
const ObjCContainerDecl *CD,
SmallVectorImpl<char> &Name) {
llvm::raw_svector_ostream OS(Name);
assert (CD && "Missing container decl in GetNameForMethod");
OS << '\01' << (D->isInstanceMethod() ? '-' : '+')
<< '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
OS << '(' << *CID << ')';
OS << ' ' << D->getSelector().getAsString() << ']';
}
void CGObjCMac::FinishModule() {
EmitModuleInfo();
for (llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*>::iterator
I = Protocols.begin(), e = Protocols.end(); I != e; ++I) {
if (I->second->hasInitializer())
continue;
llvm::Constant *Values[5];
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
Values[1] = GetClassName(I->first);
Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
Values[3] = Values[4] =
llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
I->second->setLinkage(llvm::GlobalValue::InternalLinkage);
I->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
Values));
CGM.AddUsedGlobal(I->second);
}
if (!LazySymbols.empty() || !DefinedSymbols.empty()) {
SmallString<256> Asm;
Asm += CGM.getModule().getModuleInlineAsm();
if (!Asm.empty() && Asm.back() != '\n')
Asm += '\n';
llvm::raw_svector_ostream OS(Asm);
for (llvm::SetVector<IdentifierInfo*>::iterator I = DefinedSymbols.begin(),
e = DefinedSymbols.end(); I != e; ++I)
OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n"
<< "\t.globl .objc_class_name_" << (*I)->getName() << "\n";
for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(),
e = LazySymbols.end(); I != e; ++I) {
OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n";
}
for (size_t i = 0, e = DefinedCategoryNames.size(); i < e; ++i) {
OS << "\t.objc_category_name_" << DefinedCategoryNames[i] << "=0\n"
<< "\t.globl .objc_category_name_" << DefinedCategoryNames[i] << "\n";
}
CGM.getModule().setModuleInlineAsm(OS.str());
}
}
CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
: CGObjCCommonMac(cgm),
ObjCTypes(cgm) {
ObjCEmptyCacheVar = ObjCEmptyVtableVar = NULL;
ObjCABI = 2;
}
ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
: VMContext(cgm.getLLVMContext()), CGM(cgm), ExternalProtocolPtrTy(0)
{
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
ShortTy = Types.ConvertType(Ctx.ShortTy);
IntTy = Types.ConvertType(Ctx.IntTy);
LongTy = Types.ConvertType(Ctx.LongTy);
LongLongTy = Types.ConvertType(Ctx.LongLongTy);
Int8PtrTy = CGM.Int8PtrTy;
Int8PtrPtrTy = CGM.Int8PtrPtrTy;
ObjectPtrTy = Types.ConvertType(Ctx.getObjCIdType());
PtrObjectPtrTy = llvm::PointerType::getUnqual(ObjectPtrTy);
SelectorPtrTy = Types.ConvertType(Ctx.getObjCSelType());
RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
Ctx.getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_objc_super"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
Ctx.getObjCIdType(), 0, 0, false, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
Ctx.getObjCClassType(), 0, 0, false, false));
RD->completeDefinition();
SuperCTy = Ctx.getTagDeclType(RD);
SuperPtrCTy = Ctx.getPointerType(SuperCTy);
SuperTy = cast<llvm::StructType>(Types.ConvertType(SuperCTy));
SuperPtrTy = llvm::PointerType::getUnqual(SuperTy);
PropertyTy = llvm::StructType::create("struct._prop_t",
Int8PtrTy, Int8PtrTy, NULL);
PropertyListTy =
llvm::StructType::create("struct._prop_list_t", IntTy, IntTy,
llvm::ArrayType::get(PropertyTy, 0), NULL);
PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
MethodTy = llvm::StructType::create("struct._objc_method",
SelectorPtrTy, Int8PtrTy, Int8PtrTy,
NULL);
CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
}
ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
: ObjCCommonTypesHelper(cgm) {
MethodDescriptionTy =
llvm::StructType::create("struct._objc_method_description",
SelectorPtrTy, Int8PtrTy, NULL);
MethodDescriptionListTy =
llvm::StructType::create("struct._objc_method_description_list",
IntTy,
llvm::ArrayType::get(MethodDescriptionTy, 0),NULL);
MethodDescriptionListPtrTy =
llvm::PointerType::getUnqual(MethodDescriptionListTy);
ProtocolExtensionTy =
llvm::StructType::create("struct._objc_protocol_extension",
IntTy, MethodDescriptionListPtrTy,
MethodDescriptionListPtrTy, PropertyListPtrTy,
Int8PtrPtrTy, NULL);
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
ProtocolTy =
llvm::StructType::create(VMContext, "struct._objc_protocol");
ProtocolListTy =
llvm::StructType::create(VMContext, "struct._objc_protocol_list");
ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy),
LongTy,
llvm::ArrayType::get(ProtocolTy, 0),
NULL);
ProtocolTy->setBody(ProtocolExtensionPtrTy, Int8PtrTy,
llvm::PointerType::getUnqual(ProtocolListTy),
MethodDescriptionListPtrTy,
MethodDescriptionListPtrTy,
NULL);
ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
ProtocolPtrTy = llvm::PointerType::getUnqual(ProtocolTy);
IvarTy = llvm::StructType::create("struct._objc_ivar",
Int8PtrTy, Int8PtrTy, IntTy, NULL);
IvarListTy =
llvm::StructType::create(VMContext, "struct._objc_ivar_list");
IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
MethodListTy =
llvm::StructType::create(VMContext, "struct._objc_method_list");
MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
ClassExtensionTy =
llvm::StructType::create("struct._objc_class_extension",
IntTy, Int8PtrTy, PropertyListPtrTy, NULL);
ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
ClassTy = llvm::StructType::create(VMContext, "struct._objc_class");
ClassTy->setBody(llvm::PointerType::getUnqual(ClassTy),
llvm::PointerType::getUnqual(ClassTy),
Int8PtrTy,
LongTy,
LongTy,
LongTy,
IvarListPtrTy,
MethodListPtrTy,
CachePtrTy,
ProtocolListPtrTy,
Int8PtrTy,
ClassExtensionPtrTy,
NULL);
ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
CategoryTy =
llvm::StructType::create("struct._objc_category",
Int8PtrTy, Int8PtrTy, MethodListPtrTy,
MethodListPtrTy, ProtocolListPtrTy,
IntTy, PropertyListPtrTy, NULL);
SymtabTy =
llvm::StructType::create("struct._objc_symtab",
LongTy, SelectorPtrTy, ShortTy, ShortTy,
llvm::ArrayType::get(Int8PtrTy, 0), NULL);
SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
ModuleTy =
llvm::StructType::create("struct._objc_module",
LongTy, LongTy, Int8PtrTy, SymtabPtrTy, NULL);
uint64_t SetJmpBufferSize = 18;
llvm::Type *StackPtrTy = llvm::ArrayType::get(CGM.Int8PtrTy, 4);
ExceptionDataTy =
llvm::StructType::create("struct._objc_exception_data",
llvm::ArrayType::get(CGM.Int32Ty,SetJmpBufferSize),
StackPtrTy, NULL);
}
ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm)
: ObjCCommonTypesHelper(cgm) {
MethodListnfABITy =
llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
llvm::ArrayType::get(MethodTy, 0), NULL);
MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
ProtocolListnfABITy =
llvm::StructType::create(VMContext, "struct._objc_protocol_list");
ProtocolnfABITy =
llvm::StructType::create("struct._protocol_t", ObjectPtrTy, Int8PtrTy,
llvm::PointerType::getUnqual(ProtocolListnfABITy),
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy,
NULL);
ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
ProtocolListnfABITy->setBody(LongTy,
llvm::ArrayType::get(ProtocolnfABIPtrTy, 0),
NULL);
ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
IvarnfABITy =
llvm::StructType::create("struct._ivar_t",
llvm::PointerType::getUnqual(LongTy),
Int8PtrTy, Int8PtrTy, IntTy, IntTy, NULL);
IvarListnfABITy =
llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
llvm::ArrayType::get(IvarnfABITy, 0), NULL);
IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
ClassRonfABITy = llvm::StructType::create("struct._class_ro_t",
IntTy, IntTy, IntTy, Int8PtrTy,
Int8PtrTy, MethodListnfABIPtrTy,
ProtocolListnfABIPtrTy,
IvarListnfABIPtrTy,
Int8PtrTy, PropertyListPtrTy, NULL);
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
ImpnfABITy = llvm::FunctionType::get(ObjectPtrTy, params, false)
->getPointerTo();
ClassnfABITy = llvm::StructType::create(VMContext, "struct._class_t");
ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy),
llvm::PointerType::getUnqual(ClassnfABITy),
CachePtrTy,
llvm::PointerType::getUnqual(ImpnfABITy),
llvm::PointerType::getUnqual(ClassRonfABITy),
NULL);
ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
CategorynfABITy = llvm::StructType::create("struct._category_t",
Int8PtrTy, ClassnfABIPtrTy,
MethodListnfABIPtrTy,
MethodListnfABIPtrTy,
ProtocolListnfABIPtrTy,
PropertyListPtrTy,
NULL);
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
Ctx.getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
Ctx.VoidPtrTy, 0, 0, false, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
Ctx.getObjCSelType(), 0, 0, false, false));
RD->completeDefinition();
MessageRefCTy = Ctx.getTagDeclType(RD);
MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy);
MessageRefTy = cast<llvm::StructType>(Types.ConvertType(MessageRefCTy));
MessageRefPtrTy = llvm::PointerType::getUnqual(MessageRefTy);
SuperMessageRefTy =
llvm::StructType::create("struct._super_message_ref_t",
ImpnfABITy, SelectorPtrTy, NULL);
SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
EHTypeTy =
llvm::StructType::create("struct._objc_typeinfo",
llvm::PointerType::getUnqual(Int8PtrTy),
Int8PtrTy, ClassnfABIPtrTy, NULL);
EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
}
llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
FinishNonFragileABIModule();
return NULL;
}
void CGObjCNonFragileABIMac::
AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container,
const char *SymbolName,
const char *SectionName) {
unsigned NumClasses = Container.size();
if (!NumClasses)
return;
SmallVector<llvm::Constant*, 8> Symbols(NumClasses);
for (unsigned i=0; i<NumClasses; i++)
Symbols[i] = llvm::ConstantExpr::getBitCast(Container[i],
ObjCTypes.Int8PtrTy);
llvm::Constant *Init =
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
Symbols.size()),
Symbols);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
Init,
SymbolName);
GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection(SectionName);
CGM.AddUsedGlobal(GV);
}
void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
AddModuleClassList(DefinedClasses,
"\01L_OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
for (unsigned i = 0, e = DefinedClasses.size(); i < e; i++) {
llvm::GlobalValue *IMPLGV = DefinedClasses[i];
if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
continue;
IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
}
for (unsigned i = 0, e = DefinedMetaClasses.size(); i < e; i++) {
llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i];
if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
continue;
IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
}
AddModuleClassList(DefinedNonLazyClasses,
"\01L_OBJC_LABEL_NONLAZY_CLASS_$",
"__DATA, __objc_nlclslist, regular, no_dead_strip");
AddModuleClassList(DefinedCategories,
"\01L_OBJC_LABEL_CATEGORY_$",
"__DATA, __objc_catlist, regular, no_dead_strip");
AddModuleClassList(DefinedNonLazyCategories,
"\01L_OBJC_LABEL_NONLAZY_CATEGORY_$",
"__DATA, __objc_nlcatlist, regular, no_dead_strip");
EmitImageInfo();
}
bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
case CodeGenOptions::Legacy:
return false;
case CodeGenOptions::NonLegacy:
return true;
case CodeGenOptions::Mixed:
break;
}
if (VTableDispatchMethods.empty()) {
VTableDispatchMethods.insert(GetNullarySelector("alloc"));
VTableDispatchMethods.insert(GetNullarySelector("class"));
VTableDispatchMethods.insert(GetNullarySelector("self"));
VTableDispatchMethods.insert(GetNullarySelector("isFlipped"));
VTableDispatchMethods.insert(GetNullarySelector("length"));
VTableDispatchMethods.insert(GetNullarySelector("count"));
if (CGM.getLangOptions().getGC() != LangOptions::GCOnly) {
VTableDispatchMethods.insert(GetNullarySelector("retain"));
VTableDispatchMethods.insert(GetNullarySelector("release"));
VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
}
VTableDispatchMethods.insert(GetUnarySelector("allocWithZone"));
VTableDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
VTableDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
VTableDispatchMethods.insert(GetUnarySelector("objectForKey"));
VTableDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
VTableDispatchMethods.insert(GetUnarySelector("isEqualToString"));
VTableDispatchMethods.insert(GetUnarySelector("isEqual"));
if (CGM.getLangOptions().getGC() != LangOptions::NonGC) {
VTableDispatchMethods.insert(GetNullarySelector("hash"));
VTableDispatchMethods.insert(GetUnarySelector("addObject"));
IdentifierInfo *KeyIdents[] = {
&CGM.getContext().Idents.get("countByEnumeratingWithState"),
&CGM.getContext().Idents.get("objects"),
&CGM.getContext().Idents.get("count")
};
VTableDispatchMethods.insert(
CGM.getContext().Selectors.getSelector(3, KeyIdents));
}
}
return VTableDispatchMethods.count(Sel);
}
enum MetaDataDlags {
CLS = 0x0,
CLS_META = 0x1,
CLS_ROOT = 0x2,
OBJC2_CLS_HIDDEN = 0x10,
CLS_EXCEPTION = 0x20,
CLS_HAS_IVAR_RELEASER = 0x40,
CLS_COMPILED_BY_ARC = 0x80 };
llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
unsigned flags,
unsigned InstanceStart,
unsigned InstanceSize,
const ObjCImplementationDecl *ID) {
std::string ClassName = ID->getNameAsString();
llvm::Constant *Values[10];
if (CGM.getLangOptions().ObjCAutoRefCount)
flags |= CLS_COMPILED_BY_ARC;
Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
Values[ 3] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
: BuildIvarLayout(ID, true);
Values[ 4] = GetClassName(ID->getIdentifier());
std::vector<llvm::Constant*> Methods;
std::string MethodListName("\01l_OBJC_$_");
if (flags & CLS_META) {
MethodListName += "CLASS_METHODS_" + ID->getNameAsString();
for (ObjCImplementationDecl::classmeth_iterator
i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
Methods.push_back(GetMethodConstant(*i));
}
} else {
MethodListName += "INSTANCE_METHODS_" + ID->getNameAsString();
for (ObjCImplementationDecl::instmeth_iterator
i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
Methods.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))
Methods.push_back(C);
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl())
if (llvm::Constant *C = GetMethodConstant(MD))
Methods.push_back(C);
}
}
}
Values[ 5] = EmitMethodList(MethodListName,
"__DATA, __objc_const", Methods);
const ObjCInterfaceDecl *OID = ID->getClassInterface();
assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_"
+ OID->getName(),
OID->all_referenced_protocol_begin(),
OID->all_referenced_protocol_end());
if (flags & CLS_META)
Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
else
Values[ 7] = EmitIvarList(ID);
Values[ 8] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
: BuildIvarLayout(ID, false);
if (flags & CLS_META)
Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
else
Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
ID, ID->getClassInterface(), ObjCTypes);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy,
Values);
llvm::GlobalVariable *CLASS_RO_GV =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false,
llvm::GlobalValue::InternalLinkage,
Init,
(flags & CLS_META) ?
std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
CLASS_RO_GV->setAlignment(
CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
return CLASS_RO_GV;
}
llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
std::string &ClassName,
llvm::Constant *IsAGV,
llvm::Constant *SuperClassGV,
llvm::Constant *ClassRoGV,
bool HiddenVisibility) {
llvm::Constant *Values[] = {
IsAGV,
SuperClassGV,
ObjCEmptyCacheVar, ObjCEmptyVtableVar, ClassRoGV };
if (!Values[1])
Values[1] = llvm::Constant::getNullValue(ObjCTypes.ClassnfABIPtrTy);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy,
Values);
llvm::GlobalVariable *GV = GetClassGlobal(ClassName);
GV->setInitializer(Init);
GV->setSection("__DATA, __objc_data");
GV->setAlignment(
CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy));
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
return GV;
}
bool
CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
return OD->getClassMethod(GetNullarySelector("load")) != 0;
}
void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
uint32_t &InstanceStart,
uint32_t &InstanceSize) {
const ASTRecordLayout &RL =
CGM.getContext().getASTObjCImplementationLayout(OID);
InstanceSize = RL.getDataSize().getQuantity();
if (!RL.getFieldCount())
InstanceStart = InstanceSize;
else
InstanceStart = RL.getFieldOffset(0) / CGM.getContext().getCharWidth();
}
void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
std::string ClassName = ID->getNameAsString();
if (!ObjCEmptyCacheVar) {
ObjCEmptyCacheVar = new llvm::GlobalVariable(
CGM.getModule(),
ObjCTypes.CacheTy,
false,
llvm::GlobalValue::ExternalLinkage,
0,
"_objc_empty_cache");
ObjCEmptyVtableVar = new llvm::GlobalVariable(
CGM.getModule(),
ObjCTypes.ImpnfABITy,
false,
llvm::GlobalValue::ExternalLinkage,
0,
"_objc_empty_vtable");
}
assert(ID->getClassInterface() &&
"CGObjCNonFragileABIMac::GenerateClass - class is 0");
uint32_t InstanceStart =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassnfABITy);
uint32_t InstanceSize = InstanceStart;
uint32_t flags = CLS_META;
std::string ObjCMetaClassName(getMetaclassSymbolPrefix());
std::string ObjCClassName(getClassSymbolPrefix());
llvm::GlobalVariable *SuperClassGV, *IsAGV;
bool classIsHidden =
ID->getClassInterface()->getVisibility() == HiddenVisibility;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
if (ID->hasCXXStructors())
flags |= eClassFlags_ABI2_HasCXXStructors;
if (!ID->getClassInterface()->getSuperClass()) {
flags |= CLS_ROOT;
SuperClassGV = GetClassGlobal(ObjCClassName + ClassName);
IsAGV = GetClassGlobal(ObjCMetaClassName + ClassName);
} else {
const ObjCInterfaceDecl *Root = ID->getClassInterface();
while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
Root = Super;
IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString());
if (Root->isWeakImported())
IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
std::string SuperClassName =
ObjCMetaClassName +
ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(SuperClassName);
if (ID->getClassInterface()->getSuperClass()->isWeakImported())
SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags,
InstanceStart,
InstanceSize,ID);
std::string TClassName = ObjCMetaClassName + ClassName;
llvm::GlobalVariable *MetaTClass =
BuildClassMetaData(TClassName, IsAGV, SuperClassGV, CLASS_RO_GV,
classIsHidden);
DefinedMetaClasses.push_back(MetaTClass);
flags = CLS;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
if (ID->hasCXXStructors())
flags |= eClassFlags_ABI2_HasCXXStructors;
if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
flags |= CLS_EXCEPTION;
if (!ID->getClassInterface()->getSuperClass()) {
flags |= CLS_ROOT;
SuperClassGV = 0;
} else {
std::string RootClassName =
ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName);
if (ID->getClassInterface()->getSuperClass()->isWeakImported())
SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
GetClassSizeInfo(ID, InstanceStart, InstanceSize);
CLASS_RO_GV = BuildClassRoTInitializer(flags,
InstanceStart,
InstanceSize,
ID);
TClassName = ObjCClassName + ClassName;
llvm::GlobalVariable *ClassMD =
BuildClassMetaData(TClassName, MetaTClass, SuperClassGV, CLASS_RO_GV,
classIsHidden);
DefinedClasses.push_back(ClassMD);
if (ImplementationIsNonLazy(ID))
DefinedNonLazyClasses.push_back(ClassMD);
if (flags & CLS_EXCEPTION)
GetInterfaceEHType(ID->getClassInterface(), true);
MethodDefinitions.clear();
}
llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD) {
llvm::Constant *Init =
llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD),
ObjCTypes.getExternalProtocolPtrTy());
std::string ProtocolName("\01l_OBJC_PROTOCOL_REFERENCE_$_");
ProtocolName += PD->getName();
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
return Builder.CreateLoad(PTGV);
PTGV = new llvm::GlobalVariable(
CGM.getModule(),
Init->getType(), false,
llvm::GlobalValue::WeakAnyLinkage,
Init,
ProtocolName);
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
return Builder.CreateLoad(PTGV);
}
void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
const char *Prefix = "\01l_OBJC_$_CATEGORY_";
std::string ExtCatName(Prefix + Interface->getNameAsString()+
"_$_" + OCD->getNameAsString());
std::string ExtClassName(getClassSymbolPrefix() +
Interface->getNameAsString());
llvm::Constant *Values[6];
Values[0] = GetClassName(OCD->getIdentifier());
llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName);
if (Interface->isWeakImported())
ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
Values[1] = ClassGV;
std::vector<llvm::Constant*> Methods;
std::string MethodListName(Prefix);
MethodListName += "INSTANCE_METHODS_" + Interface->getNameAsString() +
"_$_" + OCD->getNameAsString();
for (ObjCCategoryImplDecl::instmeth_iterator
i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
Methods.push_back(GetMethodConstant(*i));
}
Values[2] = EmitMethodList(MethodListName,
"__DATA, __objc_const",
Methods);
MethodListName = Prefix;
MethodListName += "CLASS_METHODS_" + Interface->getNameAsString() + "_$_" +
OCD->getNameAsString();
Methods.clear();
for (ObjCCategoryImplDecl::classmeth_iterator
i = OCD->classmeth_begin(), e = OCD->classmeth_end(); i != e; ++i) {
Methods.push_back(GetMethodConstant(*i));
}
Values[3] = EmitMethodList(MethodListName,
"__DATA, __objc_const",
Methods);
const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
if (Category) {
SmallString<256> ExtName;
llvm::raw_svector_ostream(ExtName) << Interface->getName() << "_$_"
<< OCD->getName();
Values[4] = EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_"
+ Interface->getName() + "_$_"
+ Category->getName(),
Category->protocol_begin(),
Category->protocol_end());
Values[5] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(),
OCD, Category, ObjCTypes);
} else {
Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
Values[5] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
}
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.CategorynfABITy,
Values);
llvm::GlobalVariable *GCATV
= new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.CategorynfABITy,
false,
llvm::GlobalValue::InternalLinkage,
Init,
ExtCatName);
GCATV->setAlignment(
CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GCATV);
DefinedCategories.push_back(GCATV);
if (ImplementationIsNonLazy(OCD))
DefinedNonLazyCategories.push_back(GCATV);
MethodDefinitions.clear();
}
llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant(
const ObjCMethodDecl *MD) {
llvm::Function *Fn = GetMethodDefinition(MD);
if (!Fn)
return 0;
llvm::Constant *Method[] = {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy),
GetMethodVarType(MD),
llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy)
};
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method);
}
llvm::Constant *
CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
const char *Section,
ArrayRef<llvm::Constant*> Methods) {
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy);
llvm::Constant *Values[3];
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.MethodTy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
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::getAnon(Values);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage, Init, Name);
GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
}
llvm::GlobalVariable *
CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar) {
const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
std::string Name = "OBJC_IVAR_$_" + Container->getNameAsString() +
'.' + Ivar->getNameAsString();
llvm::GlobalVariable *IvarOffsetGV =
CGM.getModule().getGlobalVariable(Name);
if (!IvarOffsetGV)
IvarOffsetGV =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.LongTy,
false,
llvm::GlobalValue::ExternalLinkage,
0,
Name);
return IvarOffsetGV;
}
llvm::Constant *
CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar,
unsigned long int Offset) {
llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
Offset));
IvarOffsetGV->setAlignment(
CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy));
if (Ivar->getAccessControl() == ObjCIvarDecl::Private ||
Ivar->getAccessControl() == ObjCIvarDecl::Package ||
ID->getVisibility() == HiddenVisibility)
IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
else
IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
IvarOffsetGV->setSection("__DATA, __objc_ivar");
return IvarOffsetGV;
}
llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
const ObjCImplementationDecl *ID) {
std::vector<llvm::Constant*> Ivars;
const ObjCInterfaceDecl *OID = ID->getClassInterface();
assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface");
for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar()) {
if (!IVD->getDeclName())
continue;
llvm::Constant *Ivar[5];
Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD,
ComputeIvarBaseOffset(CGM, ID, IVD));
Ivar[1] = GetMethodVarName(IVD->getIdentifier());
Ivar[2] = GetMethodVarType(IVD);
llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(IVD->getType());
unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy);
unsigned Align = CGM.getContext().getPreferredTypeAlign(
IVD->getType().getTypePtr()) >> 3;
Align = llvm::Log2_32(Align);
Ivar[3] = llvm::ConstantInt::get(ObjCTypes.IntTy, Align);
Ivar[4] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarnfABITy, Ivar));
}
if (Ivars.empty())
return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
llvm::Constant *Values[3];
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.IvarnfABITy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy,
Ivars.size());
Values[2] = llvm::ConstantArray::get(AT, Ivars);
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
const char *Prefix = "\01l_OBJC_$_INSTANCE_VARIABLES_";
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
Init,
Prefix + OID->getName());
GV->setAlignment(
CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListnfABIPtrTy);
}
llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
const ObjCProtocolDecl *PD) {
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
if (!Entry) {
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false,
llvm::GlobalValue::ExternalLinkage,
0,
"\01l_OBJC_PROTOCOL_$_" + PD->getName());
Entry->setSection("__DATA,__datacoal_nt,coalesced");
}
return Entry;
}
llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
const ObjCProtocolDecl *PD) {
llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
if (Entry && Entry->hasInitializer())
return Entry;
if (const ObjCProtocolDecl *Def = PD->getDefinition())
PD = Def;
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[11];
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy);
Values[1] = GetClassName(PD->getIdentifier());
Values[2] = EmitProtocolList("\01l_OBJC_$_PROTOCOL_REFS_" + PD->getName(),
PD->protocol_begin(),
PD->protocol_end());
Values[3] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_"
+ PD->getName(),
"__DATA, __objc_const",
InstanceMethods);
Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_"
+ PD->getName(),
"__DATA, __objc_const",
ClassMethods);
Values[5] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_"
+ PD->getName(),
"__DATA, __objc_const",
OptInstanceMethods);
Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_"
+ PD->getName(),
"__DATA, __objc_const",
OptClassMethods);
Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getName(),
0, PD, ObjCTypes);
uint32_t Size =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy);
Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_"
+ PD->getName(),
MethodTypesExt, ObjCTypes);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy,
Values);
if (Entry) {
Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
Entry->setInitializer(Init);
} else {
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy,
false, llvm::GlobalValue::WeakAnyLinkage, Init,
"\01l_OBJC_PROTOCOL_$_" + PD->getName());
Entry->setAlignment(
CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
}
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(Entry);
llvm::GlobalVariable *PTGV =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABIPtrTy,
false, llvm::GlobalValue::WeakAnyLinkage, Entry,
"\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName());
PTGV->setAlignment(
CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
return Entry;
}
llvm::Constant *
CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
llvm::SmallVector<llvm::Constant*, 16> ProtocolRefs;
if (begin == end)
return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
SmallString<256> TmpName;
Name.toVector(TmpName);
llvm::GlobalVariable *GV =
CGM.getModule().getGlobalVariable(TmpName.str(), true);
if (GV)
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy);
for (; begin != end; ++begin)
ProtocolRefs.push_back(GetProtocolRef(*begin));
ProtocolRefs.push_back(llvm::Constant::getNullValue(
ObjCTypes.ProtocolnfABIPtrTy));
llvm::Constant *Values[2];
Values[0] =
llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1);
Values[1] =
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolnfABIPtrTy,
ProtocolRefs.size()),
ProtocolRefs);
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
Init, Name);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
CGM.getTargetData().getABITypeAlignment(Init->getType()));
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.ProtocolListnfABIPtrTy);
}
llvm::Constant *
CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
llvm::Constant *Desc[3];
Desc[0] =
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy);
Desc[1] = GetMethodVarType(MD);
if (!Desc[1])
return 0;
Desc[2] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Desc);
}
LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface();
llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
if (llvm::LoadInst *LI = dyn_cast<llvm::LoadInst>(Offset))
LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
llvm::MDNode::get(VMContext,
ArrayRef<llvm::Value*>()));
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
Offset);
}
llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),"ivar");
}
static void appendSelectorForMessageRefTable(std::string &buffer,
Selector selector) {
if (selector.isUnarySelector()) {
buffer += selector.getNameForSlot(0);
return;
}
for (unsigned i = 0, e = selector.getNumArgs(); i != e; ++i) {
buffer += selector.getNameForSlot(i);
buffer += '_';
}
}
RValue
CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
ReturnValueSlot returnSlot,
QualType resultType,
Selector selector,
llvm::Value *arg0,
QualType arg0Type,
bool isSuper,
const CallArgList &formalArgs,
const ObjCMethodDecl *method) {
CallArgList args;
if (!isSuper)
arg0 = CGF.Builder.CreateBitCast(arg0, ObjCTypes.ObjectPtrTy);
args.add(RValue::get(arg0), arg0Type);
args.add(RValue::get(0), ObjCTypes.MessageRefCPtrTy);
args.insert(args.end(), formalArgs.begin(), formalArgs.end());
MessageSendInfo MSI = getMessageSendInfo(method, resultType, args);
NullReturnState nullReturn;
llvm::Constant *fn = 0;
std::string messageRefName("\01l_");
if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
if (isSuper) {
fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
messageRefName += "objc_msgSendSuper2_stret_fixup";
} else {
nullReturn.init(CGF, arg0);
fn = ObjCTypes.getMessageSendStretFixupFn();
messageRefName += "objc_msgSend_stret_fixup";
}
} else if (!isSuper && CGM.ReturnTypeUsesFPRet(resultType)) {
fn = ObjCTypes.getMessageSendFpretFixupFn();
messageRefName += "objc_msgSend_fpret_fixup";
} else {
if (isSuper) {
fn = ObjCTypes.getMessageSendSuper2FixupFn();
messageRefName += "objc_msgSendSuper2_fixup";
} else {
fn = ObjCTypes.getMessageSendFixupFn();
messageRefName += "objc_msgSend_fixup";
}
}
assert(fn && "CGObjCNonFragileABIMac::EmitMessageSend");
messageRefName += '_';
appendSelectorForMessageRefTable(messageRefName, selector);
llvm::GlobalVariable *messageRef
= CGM.getModule().getGlobalVariable(messageRefName);
if (!messageRef) {
llvm::Constant *values[] = { fn, GetMethodVarName(selector) };
llvm::Constant *init = llvm::ConstantStruct::getAnon(values);
messageRef = new llvm::GlobalVariable(CGM.getModule(),
init->getType(),
false,
llvm::GlobalValue::WeakAnyLinkage,
init,
messageRefName);
messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
messageRef->setAlignment(16);
messageRef->setSection("__DATA, __objc_msgrefs, coalesced");
}
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;
}
}
llvm::Value *mref =
CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy);
args[1].RV = RValue::get(mref);
llvm::Value *callee = CGF.Builder.CreateStructGEP(mref, 0);
callee = CGF.Builder.CreateLoad(callee, "msgSend_fn");
callee = CGF.Builder.CreateBitCast(callee, MSI.MessengerType);
RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
return nullReturn.complete(CGF, result, resultType, formalArgs,
requiresnullCheck ? method : 0);
}
CodeGen::RValue
CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return isVTableDispatchedSelector(Sel)
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
llvm::GlobalVariable *
CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
if (!GV) {
GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
false, llvm::GlobalValue::ExternalLinkage,
0, Name);
}
return GV;
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II) {
llvm::GlobalVariable *&Entry = ClassReferences[II];
if (!Entry) {
std::string ClassName(getClassSymbolPrefix() + II->getName().str());
llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
false, llvm::GlobalValue::InternalLinkage,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
}
return Builder.CreateLoad(Entry);
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
return EmitClassRefFromId(Builder, ID->getIdentifier());
}
llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
CGBuilderTy &Builder) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
return EmitClassRefFromId(Builder, II);
}
llvm::Value *
CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
if (!Entry) {
std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
false, llvm::GlobalValue::InternalLinkage,
ClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
}
return Builder.CreateLoad(Entry);
}
llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
if (Entry)
return Builder.CreateLoad(Entry);
std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false,
llvm::GlobalValue::InternalLinkage,
MetaClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
return Builder.CreateLoad(Entry);
}
llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
if (ID->isWeakImported()) {
std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
return EmitClassRef(Builder, ID);
}
CodeGen::RValue
CGObjCNonFragileABIMac::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) {
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));
llvm::Value *Target;
if (IsClassMessage) {
if (isCategoryImpl) {
Target = EmitClassRef(CGF.Builder, Class);
Target = CGF.Builder.CreateStructGEP(Target, 0);
Target = CGF.Builder.CreateLoad(Target);
} else
Target = EmitMetaClassRef(CGF.Builder, Class);
} else
Target = EmitSuperClassRef(CGF.Builder, Class);
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 (isVTableDispatchedSelector(Sel))
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
Selector Sel, bool lval) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
if (!Entry) {
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
ObjCTypes.SelectorPtrTy);
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
llvm::GlobalValue::InternalLinkage,
Casted, "\01L_OBJC_SELECTOR_REFERENCES_");
Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
CGM.AddUsedGlobal(Entry);
}
if (lval)
return Entry;
llvm::LoadInst* LI = Builder.CreateLoad(Entry);
LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
llvm::MDNode::get(VMContext,
ArrayRef<llvm::Value*>()));
return LI;
}
void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src,
llvm::Value *dst,
llvm::Value *ivarOffset) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
src, dst, ivarOffset);
return;
}
void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
src, dst, "weakassign");
return;
}
void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
CodeGen::CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
llvm::Value *Size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
DestPtr, SrcPtr, Size);
return;
}
llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
llvm::Type* DestTy =
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
AddrWeakObj, "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
src, dst, "weakassign");
return;
}
void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
if (!threadlocal)
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
src, dst, "globalassign");
else
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
src, dst, "threadlocalassign");
return;
}
void
CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S) {
EmitAtSynchronizedStmt(CGF, S,
cast<llvm::Function>(ObjCTypes.getSyncEnterFn()),
cast<llvm::Function>(ObjCTypes.getSyncExitFn()));
}
llvm::Constant *
CGObjCNonFragileABIMac::GetEHType(QualType T) {
if (T->isObjCIdType() ||
T->isObjCQualifiedIdType()) {
llvm::Constant *IDEHType =
CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
if (!IDEHType)
IDEHType =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
false,
llvm::GlobalValue::ExternalLinkage,
0, "OBJC_EHTYPE_id");
return IDEHType;
}
const ObjCObjectPointerType *PT =
T->getAs<ObjCObjectPointerType>();
assert(PT && "Invalid @catch type.");
const ObjCInterfaceType *IT = PT->getInterfaceType();
assert(IT && "Invalid @catch type.");
return GetInterfaceEHType(IT->getDecl(), false);
}
void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt &S) {
EmitTryCatchStmt(CGF, S,
cast<llvm::Function>(ObjCTypes.getObjCBeginCatchFn()),
cast<llvm::Function>(ObjCTypes.getObjCEndCatchFn()),
cast<llvm::Function>(ObjCTypes.getExceptionRethrowFn()));
}
void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtThrowStmt &S) {
if (const Expr *ThrowExpr = S.getThrowExpr()) {
llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
.setDoesNotReturn();
} else {
CGF.EmitCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
.setDoesNotReturn();
}
CGF.Builder.CreateUnreachable();
CGF.Builder.ClearInsertionPoint();
}
llvm::Constant *
CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
bool ForDefinition) {
llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()];
if (!ForDefinition) {
if (Entry)
return Entry;
if (hasObjCExceptionAttribute(CGM.getContext(), ID))
return Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
llvm::GlobalValue::ExternalLinkage,
0,
("OBJC_EHTYPE_$_" +
ID->getIdentifier()->getName()));
}
assert((!Entry || !Entry->hasInitializer()) && "Duplicate EHType definition");
std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
std::string VTableName = "objc_ehtype_vtable";
llvm::GlobalVariable *VTableGV =
CGM.getModule().getGlobalVariable(VTableName);
if (!VTableGV)
VTableGV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.Int8PtrTy,
false,
llvm::GlobalValue::ExternalLinkage,
0, VTableName);
llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
llvm::Constant *Values[] = {
llvm::ConstantExpr::getGetElementPtr(VTableGV, VTableIdx),
GetClassName(ID->getIdentifier()),
GetClassGlobal(ClassName)
};
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values);
if (Entry) {
Entry->setInitializer(Init);
} else {
Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
llvm::GlobalValue::WeakAnyLinkage,
Init,
("OBJC_EHTYPE_$_" +
ID->getIdentifier()->getName()));
}
if (CGM.getLangOptions().getVisibilityMode() == HiddenVisibility)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
Entry->setAlignment(CGM.getTargetData().getABITypeAlignment(
ObjCTypes.EHTypeTy));
if (ForDefinition) {
Entry->setSection("__DATA,__objc_const");
Entry->setLinkage(llvm::GlobalValue::ExternalLinkage);
} else {
Entry->setSection("__DATA,__datacoal_nt,coalesced");
}
return Entry;
}
CodeGen::CGObjCRuntime *
CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
if (CGM.getLangOptions().ObjCNonFragileABI)
return new CGObjCNonFragileABIMac(CGM);
return new CGObjCMac(CGM);
}