17330f729Sjoerg //===------- CGObjCMac.cpp - Interface to Apple Objective-C Runtime -------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This provides Objective-C code generation targeting the Apple runtime.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "CGBlocks.h"
147330f729Sjoerg #include "CGCleanup.h"
157330f729Sjoerg #include "CGObjCRuntime.h"
167330f729Sjoerg #include "CGRecordLayout.h"
177330f729Sjoerg #include "CodeGenFunction.h"
187330f729Sjoerg #include "CodeGenModule.h"
197330f729Sjoerg #include "clang/AST/ASTContext.h"
20*e038c9c4Sjoerg #include "clang/AST/Attr.h"
217330f729Sjoerg #include "clang/AST/Decl.h"
227330f729Sjoerg #include "clang/AST/DeclObjC.h"
23*e038c9c4Sjoerg #include "clang/AST/Mangle.h"
247330f729Sjoerg #include "clang/AST/RecordLayout.h"
257330f729Sjoerg #include "clang/AST/StmtObjC.h"
267330f729Sjoerg #include "clang/Basic/CodeGenOptions.h"
277330f729Sjoerg #include "clang/Basic/LangOptions.h"
287330f729Sjoerg #include "clang/CodeGen/CGFunctionInfo.h"
29*e038c9c4Sjoerg #include "clang/CodeGen/ConstantInitBuilder.h"
307330f729Sjoerg #include "llvm/ADT/CachedHashString.h"
317330f729Sjoerg #include "llvm/ADT/DenseSet.h"
327330f729Sjoerg #include "llvm/ADT/SetVector.h"
337330f729Sjoerg #include "llvm/ADT/SmallPtrSet.h"
347330f729Sjoerg #include "llvm/ADT/SmallString.h"
35*e038c9c4Sjoerg #include "llvm/ADT/UniqueVector.h"
367330f729Sjoerg #include "llvm/IR/DataLayout.h"
377330f729Sjoerg #include "llvm/IR/InlineAsm.h"
387330f729Sjoerg #include "llvm/IR/IntrinsicInst.h"
397330f729Sjoerg #include "llvm/IR/LLVMContext.h"
407330f729Sjoerg #include "llvm/IR/Module.h"
417330f729Sjoerg #include "llvm/Support/ScopedPrinter.h"
427330f729Sjoerg #include "llvm/Support/raw_ostream.h"
437330f729Sjoerg #include <cstdio>
447330f729Sjoerg
457330f729Sjoerg using namespace clang;
467330f729Sjoerg using namespace CodeGen;
477330f729Sjoerg
487330f729Sjoerg namespace {
497330f729Sjoerg
507330f729Sjoerg // FIXME: We should find a nicer way to make the labels for metadata, string
517330f729Sjoerg // concatenation is lame.
527330f729Sjoerg
537330f729Sjoerg class ObjCCommonTypesHelper {
547330f729Sjoerg protected:
557330f729Sjoerg llvm::LLVMContext &VMContext;
567330f729Sjoerg
577330f729Sjoerg private:
587330f729Sjoerg // The types of these functions don't really matter because we
597330f729Sjoerg // should always bitcast before calling them.
607330f729Sjoerg
617330f729Sjoerg /// id objc_msgSend (id, SEL, ...)
627330f729Sjoerg ///
637330f729Sjoerg /// The default messenger, used for sends whose ABI is unchanged from
647330f729Sjoerg /// the all-integer/pointer case.
getMessageSendFn() const657330f729Sjoerg llvm::FunctionCallee getMessageSendFn() const {
667330f729Sjoerg // Add the non-lazy-bind attribute, since objc_msgSend is likely to
677330f729Sjoerg // be called a lot.
687330f729Sjoerg llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
697330f729Sjoerg return CGM.CreateRuntimeFunction(
707330f729Sjoerg llvm::FunctionType::get(ObjectPtrTy, params, true), "objc_msgSend",
717330f729Sjoerg llvm::AttributeList::get(CGM.getLLVMContext(),
727330f729Sjoerg llvm::AttributeList::FunctionIndex,
737330f729Sjoerg llvm::Attribute::NonLazyBind));
747330f729Sjoerg }
757330f729Sjoerg
767330f729Sjoerg /// void objc_msgSend_stret (id, SEL, ...)
777330f729Sjoerg ///
787330f729Sjoerg /// The messenger used when the return value is an aggregate returned
797330f729Sjoerg /// by indirect reference in the first argument, and therefore the
807330f729Sjoerg /// self and selector parameters are shifted over by one.
getMessageSendStretFn() const817330f729Sjoerg llvm::FunctionCallee getMessageSendStretFn() const {
827330f729Sjoerg llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
837330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy,
847330f729Sjoerg params, true),
857330f729Sjoerg "objc_msgSend_stret");
867330f729Sjoerg }
877330f729Sjoerg
887330f729Sjoerg /// [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
897330f729Sjoerg ///
907330f729Sjoerg /// The messenger used when the return value is returned on the x87
917330f729Sjoerg /// floating-point stack; without a special entrypoint, the nil case
927330f729Sjoerg /// would be unbalanced.
getMessageSendFpretFn() const937330f729Sjoerg llvm::FunctionCallee getMessageSendFpretFn() const {
947330f729Sjoerg llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
957330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.DoubleTy,
967330f729Sjoerg params, true),
977330f729Sjoerg "objc_msgSend_fpret");
987330f729Sjoerg }
997330f729Sjoerg
1007330f729Sjoerg /// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
1017330f729Sjoerg ///
1027330f729Sjoerg /// The messenger used when the return value is returned in two values on the
1037330f729Sjoerg /// x87 floating point stack; without a special entrypoint, the nil case
1047330f729Sjoerg /// would be unbalanced. Only used on 64-bit X86.
getMessageSendFp2retFn() const1057330f729Sjoerg llvm::FunctionCallee getMessageSendFp2retFn() const {
1067330f729Sjoerg llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
1077330f729Sjoerg llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
1087330f729Sjoerg llvm::Type *resultType =
1097330f729Sjoerg llvm::StructType::get(longDoubleType, longDoubleType);
1107330f729Sjoerg
1117330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
1127330f729Sjoerg params, true),
1137330f729Sjoerg "objc_msgSend_fp2ret");
1147330f729Sjoerg }
1157330f729Sjoerg
1167330f729Sjoerg /// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
1177330f729Sjoerg ///
1187330f729Sjoerg /// The messenger used for super calls, which have different dispatch
1197330f729Sjoerg /// semantics. The class passed is the superclass of the current
1207330f729Sjoerg /// class.
getMessageSendSuperFn() const1217330f729Sjoerg llvm::FunctionCallee getMessageSendSuperFn() const {
1227330f729Sjoerg llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
1237330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
1247330f729Sjoerg params, true),
1257330f729Sjoerg "objc_msgSendSuper");
1267330f729Sjoerg }
1277330f729Sjoerg
1287330f729Sjoerg /// id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
1297330f729Sjoerg ///
1307330f729Sjoerg /// A slightly different messenger used for super calls. The class
1317330f729Sjoerg /// passed is the current class.
getMessageSendSuperFn2() const1327330f729Sjoerg llvm::FunctionCallee getMessageSendSuperFn2() const {
1337330f729Sjoerg llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
1347330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
1357330f729Sjoerg params, true),
1367330f729Sjoerg "objc_msgSendSuper2");
1377330f729Sjoerg }
1387330f729Sjoerg
1397330f729Sjoerg /// void objc_msgSendSuper_stret(void *stretAddr, struct objc_super *super,
1407330f729Sjoerg /// SEL op, ...)
1417330f729Sjoerg ///
1427330f729Sjoerg /// The messenger used for super calls which return an aggregate indirectly.
getMessageSendSuperStretFn() const1437330f729Sjoerg llvm::FunctionCallee getMessageSendSuperStretFn() const {
1447330f729Sjoerg llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
1457330f729Sjoerg return CGM.CreateRuntimeFunction(
1467330f729Sjoerg llvm::FunctionType::get(CGM.VoidTy, params, true),
1477330f729Sjoerg "objc_msgSendSuper_stret");
1487330f729Sjoerg }
1497330f729Sjoerg
1507330f729Sjoerg /// void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
1517330f729Sjoerg /// SEL op, ...)
1527330f729Sjoerg ///
1537330f729Sjoerg /// objc_msgSendSuper_stret with the super2 semantics.
getMessageSendSuperStretFn2() const1547330f729Sjoerg llvm::FunctionCallee getMessageSendSuperStretFn2() const {
1557330f729Sjoerg llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
1567330f729Sjoerg return CGM.CreateRuntimeFunction(
1577330f729Sjoerg llvm::FunctionType::get(CGM.VoidTy, params, true),
1587330f729Sjoerg "objc_msgSendSuper2_stret");
1597330f729Sjoerg }
1607330f729Sjoerg
getMessageSendSuperFpretFn() const1617330f729Sjoerg llvm::FunctionCallee getMessageSendSuperFpretFn() const {
1627330f729Sjoerg // There is no objc_msgSendSuper_fpret? How can that work?
1637330f729Sjoerg return getMessageSendSuperFn();
1647330f729Sjoerg }
1657330f729Sjoerg
getMessageSendSuperFpretFn2() const1667330f729Sjoerg llvm::FunctionCallee getMessageSendSuperFpretFn2() const {
1677330f729Sjoerg // There is no objc_msgSendSuper_fpret? How can that work?
1687330f729Sjoerg return getMessageSendSuperFn2();
1697330f729Sjoerg }
1707330f729Sjoerg
1717330f729Sjoerg protected:
1727330f729Sjoerg CodeGen::CodeGenModule &CGM;
1737330f729Sjoerg
1747330f729Sjoerg public:
1757330f729Sjoerg llvm::IntegerType *ShortTy, *IntTy, *LongTy;
1767330f729Sjoerg llvm::PointerType *Int8PtrTy, *Int8PtrPtrTy;
1777330f729Sjoerg llvm::Type *IvarOffsetVarTy;
1787330f729Sjoerg
1797330f729Sjoerg /// ObjectPtrTy - LLVM type for object handles (typeof(id))
1807330f729Sjoerg llvm::PointerType *ObjectPtrTy;
1817330f729Sjoerg
1827330f729Sjoerg /// PtrObjectPtrTy - LLVM type for id *
1837330f729Sjoerg llvm::PointerType *PtrObjectPtrTy;
1847330f729Sjoerg
1857330f729Sjoerg /// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
1867330f729Sjoerg llvm::PointerType *SelectorPtrTy;
1877330f729Sjoerg
1887330f729Sjoerg private:
1897330f729Sjoerg /// ProtocolPtrTy - LLVM type for external protocol handles
1907330f729Sjoerg /// (typeof(Protocol))
1917330f729Sjoerg llvm::Type *ExternalProtocolPtrTy;
1927330f729Sjoerg
1937330f729Sjoerg public:
getExternalProtocolPtrTy()1947330f729Sjoerg llvm::Type *getExternalProtocolPtrTy() {
1957330f729Sjoerg if (!ExternalProtocolPtrTy) {
1967330f729Sjoerg // FIXME: It would be nice to unify this with the opaque type, so that the
1977330f729Sjoerg // IR comes out a bit cleaner.
1987330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
1997330f729Sjoerg ASTContext &Ctx = CGM.getContext();
2007330f729Sjoerg llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
2017330f729Sjoerg ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
2027330f729Sjoerg }
2037330f729Sjoerg
2047330f729Sjoerg return ExternalProtocolPtrTy;
2057330f729Sjoerg }
2067330f729Sjoerg
2077330f729Sjoerg // SuperCTy - clang type for struct objc_super.
2087330f729Sjoerg QualType SuperCTy;
2097330f729Sjoerg // SuperPtrCTy - clang type for struct objc_super *.
2107330f729Sjoerg QualType SuperPtrCTy;
2117330f729Sjoerg
2127330f729Sjoerg /// SuperTy - LLVM type for struct objc_super.
2137330f729Sjoerg llvm::StructType *SuperTy;
2147330f729Sjoerg /// SuperPtrTy - LLVM type for struct objc_super *.
2157330f729Sjoerg llvm::PointerType *SuperPtrTy;
2167330f729Sjoerg
2177330f729Sjoerg /// PropertyTy - LLVM type for struct objc_property (struct _prop_t
2187330f729Sjoerg /// in GCC parlance).
2197330f729Sjoerg llvm::StructType *PropertyTy;
2207330f729Sjoerg
2217330f729Sjoerg /// PropertyListTy - LLVM type for struct objc_property_list
2227330f729Sjoerg /// (_prop_list_t in GCC parlance).
2237330f729Sjoerg llvm::StructType *PropertyListTy;
2247330f729Sjoerg /// PropertyListPtrTy - LLVM type for struct objc_property_list*.
2257330f729Sjoerg llvm::PointerType *PropertyListPtrTy;
2267330f729Sjoerg
2277330f729Sjoerg // MethodTy - LLVM type for struct objc_method.
2287330f729Sjoerg llvm::StructType *MethodTy;
2297330f729Sjoerg
2307330f729Sjoerg /// CacheTy - LLVM type for struct objc_cache.
2317330f729Sjoerg llvm::Type *CacheTy;
2327330f729Sjoerg /// CachePtrTy - LLVM type for struct objc_cache *.
2337330f729Sjoerg llvm::PointerType *CachePtrTy;
2347330f729Sjoerg
getGetPropertyFn()2357330f729Sjoerg llvm::FunctionCallee getGetPropertyFn() {
2367330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
2377330f729Sjoerg ASTContext &Ctx = CGM.getContext();
2387330f729Sjoerg // id objc_getProperty (id, SEL, ptrdiff_t, bool)
2397330f729Sjoerg CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
2407330f729Sjoerg CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
2417330f729Sjoerg CanQualType Params[] = {
2427330f729Sjoerg IdType, SelType,
2437330f729Sjoerg Ctx.getPointerDiffType()->getCanonicalTypeUnqualified(), Ctx.BoolTy};
2447330f729Sjoerg llvm::FunctionType *FTy =
2457330f729Sjoerg Types.GetFunctionType(
2467330f729Sjoerg Types.arrangeBuiltinFunctionDeclaration(IdType, Params));
2477330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
2487330f729Sjoerg }
2497330f729Sjoerg
getSetPropertyFn()2507330f729Sjoerg llvm::FunctionCallee getSetPropertyFn() {
2517330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
2527330f729Sjoerg ASTContext &Ctx = CGM.getContext();
2537330f729Sjoerg // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
2547330f729Sjoerg CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
2557330f729Sjoerg CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
2567330f729Sjoerg CanQualType Params[] = {
2577330f729Sjoerg IdType,
2587330f729Sjoerg SelType,
2597330f729Sjoerg Ctx.getPointerDiffType()->getCanonicalTypeUnqualified(),
2607330f729Sjoerg IdType,
2617330f729Sjoerg Ctx.BoolTy,
2627330f729Sjoerg Ctx.BoolTy};
2637330f729Sjoerg llvm::FunctionType *FTy =
2647330f729Sjoerg Types.GetFunctionType(
2657330f729Sjoerg Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
2667330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
2677330f729Sjoerg }
2687330f729Sjoerg
getOptimizedSetPropertyFn(bool atomic,bool copy)2697330f729Sjoerg llvm::FunctionCallee getOptimizedSetPropertyFn(bool atomic, bool copy) {
2707330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
2717330f729Sjoerg ASTContext &Ctx = CGM.getContext();
2727330f729Sjoerg // void objc_setProperty_atomic(id self, SEL _cmd,
2737330f729Sjoerg // id newValue, ptrdiff_t offset);
2747330f729Sjoerg // void objc_setProperty_nonatomic(id self, SEL _cmd,
2757330f729Sjoerg // id newValue, ptrdiff_t offset);
2767330f729Sjoerg // void objc_setProperty_atomic_copy(id self, SEL _cmd,
2777330f729Sjoerg // id newValue, ptrdiff_t offset);
2787330f729Sjoerg // void objc_setProperty_nonatomic_copy(id self, SEL _cmd,
2797330f729Sjoerg // id newValue, ptrdiff_t offset);
2807330f729Sjoerg
2817330f729Sjoerg SmallVector<CanQualType,4> Params;
2827330f729Sjoerg CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
2837330f729Sjoerg CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
2847330f729Sjoerg Params.push_back(IdType);
2857330f729Sjoerg Params.push_back(SelType);
2867330f729Sjoerg Params.push_back(IdType);
2877330f729Sjoerg Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
2887330f729Sjoerg llvm::FunctionType *FTy =
2897330f729Sjoerg Types.GetFunctionType(
2907330f729Sjoerg Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
2917330f729Sjoerg const char *name;
2927330f729Sjoerg if (atomic && copy)
2937330f729Sjoerg name = "objc_setProperty_atomic_copy";
2947330f729Sjoerg else if (atomic && !copy)
2957330f729Sjoerg name = "objc_setProperty_atomic";
2967330f729Sjoerg else if (!atomic && copy)
2977330f729Sjoerg name = "objc_setProperty_nonatomic_copy";
2987330f729Sjoerg else
2997330f729Sjoerg name = "objc_setProperty_nonatomic";
3007330f729Sjoerg
3017330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, name);
3027330f729Sjoerg }
3037330f729Sjoerg
getCopyStructFn()3047330f729Sjoerg llvm::FunctionCallee getCopyStructFn() {
3057330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
3067330f729Sjoerg ASTContext &Ctx = CGM.getContext();
3077330f729Sjoerg // void objc_copyStruct (void *, const void *, size_t, bool, bool)
3087330f729Sjoerg SmallVector<CanQualType,5> Params;
3097330f729Sjoerg Params.push_back(Ctx.VoidPtrTy);
3107330f729Sjoerg Params.push_back(Ctx.VoidPtrTy);
3117330f729Sjoerg Params.push_back(Ctx.getSizeType());
3127330f729Sjoerg Params.push_back(Ctx.BoolTy);
3137330f729Sjoerg Params.push_back(Ctx.BoolTy);
3147330f729Sjoerg llvm::FunctionType *FTy =
3157330f729Sjoerg Types.GetFunctionType(
3167330f729Sjoerg Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
3177330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
3187330f729Sjoerg }
3197330f729Sjoerg
3207330f729Sjoerg /// This routine declares and returns address of:
3217330f729Sjoerg /// void objc_copyCppObjectAtomic(
3227330f729Sjoerg /// void *dest, const void *src,
3237330f729Sjoerg /// void (*copyHelper) (void *dest, const void *source));
getCppAtomicObjectFunction()3247330f729Sjoerg llvm::FunctionCallee getCppAtomicObjectFunction() {
3257330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
3267330f729Sjoerg ASTContext &Ctx = CGM.getContext();
3277330f729Sjoerg /// void objc_copyCppObjectAtomic(void *dest, const void *src, void *helper);
3287330f729Sjoerg SmallVector<CanQualType,3> Params;
3297330f729Sjoerg Params.push_back(Ctx.VoidPtrTy);
3307330f729Sjoerg Params.push_back(Ctx.VoidPtrTy);
3317330f729Sjoerg Params.push_back(Ctx.VoidPtrTy);
3327330f729Sjoerg llvm::FunctionType *FTy =
3337330f729Sjoerg Types.GetFunctionType(
3347330f729Sjoerg Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
3357330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
3367330f729Sjoerg }
3377330f729Sjoerg
getEnumerationMutationFn()3387330f729Sjoerg llvm::FunctionCallee getEnumerationMutationFn() {
3397330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
3407330f729Sjoerg ASTContext &Ctx = CGM.getContext();
3417330f729Sjoerg // void objc_enumerationMutation (id)
3427330f729Sjoerg SmallVector<CanQualType,1> Params;
3437330f729Sjoerg Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
3447330f729Sjoerg llvm::FunctionType *FTy =
3457330f729Sjoerg Types.GetFunctionType(
3467330f729Sjoerg Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
3477330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
3487330f729Sjoerg }
3497330f729Sjoerg
getLookUpClassFn()3507330f729Sjoerg llvm::FunctionCallee getLookUpClassFn() {
3517330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
3527330f729Sjoerg ASTContext &Ctx = CGM.getContext();
3537330f729Sjoerg // Class objc_lookUpClass (const char *)
3547330f729Sjoerg SmallVector<CanQualType,1> Params;
3557330f729Sjoerg Params.push_back(
3567330f729Sjoerg Ctx.getCanonicalType(Ctx.getPointerType(Ctx.CharTy.withConst())));
3577330f729Sjoerg llvm::FunctionType *FTy =
3587330f729Sjoerg Types.GetFunctionType(Types.arrangeBuiltinFunctionDeclaration(
3597330f729Sjoerg Ctx.getCanonicalType(Ctx.getObjCClassType()),
3607330f729Sjoerg Params));
3617330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_lookUpClass");
3627330f729Sjoerg }
3637330f729Sjoerg
3647330f729Sjoerg /// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
getGcReadWeakFn()3657330f729Sjoerg llvm::FunctionCallee getGcReadWeakFn() {
3667330f729Sjoerg // id objc_read_weak (id *)
3677330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
3687330f729Sjoerg llvm::FunctionType *FTy =
3697330f729Sjoerg llvm::FunctionType::get(ObjectPtrTy, args, false);
3707330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
3717330f729Sjoerg }
3727330f729Sjoerg
3737330f729Sjoerg /// GcAssignWeakFn -- LLVM objc_assign_weak function.
getGcAssignWeakFn()3747330f729Sjoerg llvm::FunctionCallee getGcAssignWeakFn() {
3757330f729Sjoerg // id objc_assign_weak (id, id *)
3767330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
3777330f729Sjoerg llvm::FunctionType *FTy =
3787330f729Sjoerg llvm::FunctionType::get(ObjectPtrTy, args, false);
3797330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
3807330f729Sjoerg }
3817330f729Sjoerg
3827330f729Sjoerg /// GcAssignGlobalFn -- LLVM objc_assign_global function.
getGcAssignGlobalFn()3837330f729Sjoerg llvm::FunctionCallee getGcAssignGlobalFn() {
3847330f729Sjoerg // id objc_assign_global(id, id *)
3857330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
3867330f729Sjoerg llvm::FunctionType *FTy =
3877330f729Sjoerg llvm::FunctionType::get(ObjectPtrTy, args, false);
3887330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
3897330f729Sjoerg }
3907330f729Sjoerg
3917330f729Sjoerg /// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function.
getGcAssignThreadLocalFn()3927330f729Sjoerg llvm::FunctionCallee getGcAssignThreadLocalFn() {
3937330f729Sjoerg // id objc_assign_threadlocal(id src, id * dest)
3947330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
3957330f729Sjoerg llvm::FunctionType *FTy =
3967330f729Sjoerg llvm::FunctionType::get(ObjectPtrTy, args, false);
3977330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
3987330f729Sjoerg }
3997330f729Sjoerg
4007330f729Sjoerg /// GcAssignIvarFn -- LLVM objc_assign_ivar function.
getGcAssignIvarFn()4017330f729Sjoerg llvm::FunctionCallee getGcAssignIvarFn() {
4027330f729Sjoerg // id objc_assign_ivar(id, id *, ptrdiff_t)
4037330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
4047330f729Sjoerg CGM.PtrDiffTy };
4057330f729Sjoerg llvm::FunctionType *FTy =
4067330f729Sjoerg llvm::FunctionType::get(ObjectPtrTy, args, false);
4077330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
4087330f729Sjoerg }
4097330f729Sjoerg
4107330f729Sjoerg /// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function.
GcMemmoveCollectableFn()4117330f729Sjoerg llvm::FunctionCallee GcMemmoveCollectableFn() {
4127330f729Sjoerg // void *objc_memmove_collectable(void *dst, const void *src, size_t size)
4137330f729Sjoerg llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
4147330f729Sjoerg llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false);
4157330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
4167330f729Sjoerg }
4177330f729Sjoerg
4187330f729Sjoerg /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
getGcAssignStrongCastFn()4197330f729Sjoerg llvm::FunctionCallee getGcAssignStrongCastFn() {
4207330f729Sjoerg // id objc_assign_strongCast(id, id *)
4217330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
4227330f729Sjoerg llvm::FunctionType *FTy =
4237330f729Sjoerg llvm::FunctionType::get(ObjectPtrTy, args, false);
4247330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
4257330f729Sjoerg }
4267330f729Sjoerg
4277330f729Sjoerg /// ExceptionThrowFn - LLVM objc_exception_throw function.
getExceptionThrowFn()4287330f729Sjoerg llvm::FunctionCallee getExceptionThrowFn() {
4297330f729Sjoerg // void objc_exception_throw(id)
4307330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy };
4317330f729Sjoerg llvm::FunctionType *FTy =
4327330f729Sjoerg llvm::FunctionType::get(CGM.VoidTy, args, false);
4337330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
4347330f729Sjoerg }
4357330f729Sjoerg
4367330f729Sjoerg /// ExceptionRethrowFn - LLVM objc_exception_rethrow function.
getExceptionRethrowFn()4377330f729Sjoerg llvm::FunctionCallee getExceptionRethrowFn() {
4387330f729Sjoerg // void objc_exception_rethrow(void)
4397330f729Sjoerg llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
4407330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow");
4417330f729Sjoerg }
4427330f729Sjoerg
4437330f729Sjoerg /// SyncEnterFn - LLVM object_sync_enter function.
getSyncEnterFn()4447330f729Sjoerg llvm::FunctionCallee getSyncEnterFn() {
4457330f729Sjoerg // int objc_sync_enter (id)
4467330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy };
4477330f729Sjoerg llvm::FunctionType *FTy =
4487330f729Sjoerg llvm::FunctionType::get(CGM.IntTy, args, false);
4497330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
4507330f729Sjoerg }
4517330f729Sjoerg
4527330f729Sjoerg /// SyncExitFn - LLVM object_sync_exit function.
getSyncExitFn()4537330f729Sjoerg llvm::FunctionCallee getSyncExitFn() {
4547330f729Sjoerg // int objc_sync_exit (id)
4557330f729Sjoerg llvm::Type *args[] = { ObjectPtrTy };
4567330f729Sjoerg llvm::FunctionType *FTy =
4577330f729Sjoerg llvm::FunctionType::get(CGM.IntTy, args, false);
4587330f729Sjoerg return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
4597330f729Sjoerg }
4607330f729Sjoerg
getSendFn(bool IsSuper) const4617330f729Sjoerg llvm::FunctionCallee getSendFn(bool IsSuper) const {
4627330f729Sjoerg return IsSuper ? getMessageSendSuperFn() : getMessageSendFn();
4637330f729Sjoerg }
4647330f729Sjoerg
getSendFn2(bool IsSuper) const4657330f729Sjoerg llvm::FunctionCallee getSendFn2(bool IsSuper) const {
4667330f729Sjoerg return IsSuper ? getMessageSendSuperFn2() : getMessageSendFn();
4677330f729Sjoerg }
4687330f729Sjoerg
getSendStretFn(bool IsSuper) const4697330f729Sjoerg llvm::FunctionCallee getSendStretFn(bool IsSuper) const {
4707330f729Sjoerg return IsSuper ? getMessageSendSuperStretFn() : getMessageSendStretFn();
4717330f729Sjoerg }
4727330f729Sjoerg
getSendStretFn2(bool IsSuper) const4737330f729Sjoerg llvm::FunctionCallee getSendStretFn2(bool IsSuper) const {
4747330f729Sjoerg return IsSuper ? getMessageSendSuperStretFn2() : getMessageSendStretFn();
4757330f729Sjoerg }
4767330f729Sjoerg
getSendFpretFn(bool IsSuper) const4777330f729Sjoerg llvm::FunctionCallee getSendFpretFn(bool IsSuper) const {
4787330f729Sjoerg return IsSuper ? getMessageSendSuperFpretFn() : getMessageSendFpretFn();
4797330f729Sjoerg }
4807330f729Sjoerg
getSendFpretFn2(bool IsSuper) const4817330f729Sjoerg llvm::FunctionCallee getSendFpretFn2(bool IsSuper) const {
4827330f729Sjoerg return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn();
4837330f729Sjoerg }
4847330f729Sjoerg
getSendFp2retFn(bool IsSuper) const4857330f729Sjoerg llvm::FunctionCallee getSendFp2retFn(bool IsSuper) const {
4867330f729Sjoerg return IsSuper ? getMessageSendSuperFn() : getMessageSendFp2retFn();
4877330f729Sjoerg }
4887330f729Sjoerg
getSendFp2RetFn2(bool IsSuper) const4897330f729Sjoerg llvm::FunctionCallee getSendFp2RetFn2(bool IsSuper) const {
4907330f729Sjoerg return IsSuper ? getMessageSendSuperFn2() : getMessageSendFp2retFn();
4917330f729Sjoerg }
4927330f729Sjoerg
4937330f729Sjoerg ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
4947330f729Sjoerg };
4957330f729Sjoerg
4967330f729Sjoerg /// ObjCTypesHelper - Helper class that encapsulates lazy
4977330f729Sjoerg /// construction of varies types used during ObjC generation.
4987330f729Sjoerg class ObjCTypesHelper : public ObjCCommonTypesHelper {
4997330f729Sjoerg public:
5007330f729Sjoerg /// SymtabTy - LLVM type for struct objc_symtab.
5017330f729Sjoerg llvm::StructType *SymtabTy;
5027330f729Sjoerg /// SymtabPtrTy - LLVM type for struct objc_symtab *.
5037330f729Sjoerg llvm::PointerType *SymtabPtrTy;
5047330f729Sjoerg /// ModuleTy - LLVM type for struct objc_module.
5057330f729Sjoerg llvm::StructType *ModuleTy;
5067330f729Sjoerg
5077330f729Sjoerg /// ProtocolTy - LLVM type for struct objc_protocol.
5087330f729Sjoerg llvm::StructType *ProtocolTy;
5097330f729Sjoerg /// ProtocolPtrTy - LLVM type for struct objc_protocol *.
5107330f729Sjoerg llvm::PointerType *ProtocolPtrTy;
5117330f729Sjoerg /// ProtocolExtensionTy - LLVM type for struct
5127330f729Sjoerg /// objc_protocol_extension.
5137330f729Sjoerg llvm::StructType *ProtocolExtensionTy;
5147330f729Sjoerg /// ProtocolExtensionTy - LLVM type for struct
5157330f729Sjoerg /// objc_protocol_extension *.
5167330f729Sjoerg llvm::PointerType *ProtocolExtensionPtrTy;
5177330f729Sjoerg /// MethodDescriptionTy - LLVM type for struct
5187330f729Sjoerg /// objc_method_description.
5197330f729Sjoerg llvm::StructType *MethodDescriptionTy;
5207330f729Sjoerg /// MethodDescriptionListTy - LLVM type for struct
5217330f729Sjoerg /// objc_method_description_list.
5227330f729Sjoerg llvm::StructType *MethodDescriptionListTy;
5237330f729Sjoerg /// MethodDescriptionListPtrTy - LLVM type for struct
5247330f729Sjoerg /// objc_method_description_list *.
5257330f729Sjoerg llvm::PointerType *MethodDescriptionListPtrTy;
5267330f729Sjoerg /// ProtocolListTy - LLVM type for struct objc_property_list.
5277330f729Sjoerg llvm::StructType *ProtocolListTy;
5287330f729Sjoerg /// ProtocolListPtrTy - LLVM type for struct objc_property_list*.
5297330f729Sjoerg llvm::PointerType *ProtocolListPtrTy;
5307330f729Sjoerg /// CategoryTy - LLVM type for struct objc_category.
5317330f729Sjoerg llvm::StructType *CategoryTy;
5327330f729Sjoerg /// ClassTy - LLVM type for struct objc_class.
5337330f729Sjoerg llvm::StructType *ClassTy;
5347330f729Sjoerg /// ClassPtrTy - LLVM type for struct objc_class *.
5357330f729Sjoerg llvm::PointerType *ClassPtrTy;
5367330f729Sjoerg /// ClassExtensionTy - LLVM type for struct objc_class_ext.
5377330f729Sjoerg llvm::StructType *ClassExtensionTy;
5387330f729Sjoerg /// ClassExtensionPtrTy - LLVM type for struct objc_class_ext *.
5397330f729Sjoerg llvm::PointerType *ClassExtensionPtrTy;
5407330f729Sjoerg // IvarTy - LLVM type for struct objc_ivar.
5417330f729Sjoerg llvm::StructType *IvarTy;
5427330f729Sjoerg /// IvarListTy - LLVM type for struct objc_ivar_list.
5437330f729Sjoerg llvm::StructType *IvarListTy;
5447330f729Sjoerg /// IvarListPtrTy - LLVM type for struct objc_ivar_list *.
5457330f729Sjoerg llvm::PointerType *IvarListPtrTy;
5467330f729Sjoerg /// MethodListTy - LLVM type for struct objc_method_list.
5477330f729Sjoerg llvm::StructType *MethodListTy;
5487330f729Sjoerg /// MethodListPtrTy - LLVM type for struct objc_method_list *.
5497330f729Sjoerg llvm::PointerType *MethodListPtrTy;
5507330f729Sjoerg
5517330f729Sjoerg /// ExceptionDataTy - LLVM type for struct _objc_exception_data.
5527330f729Sjoerg llvm::StructType *ExceptionDataTy;
5537330f729Sjoerg
5547330f729Sjoerg /// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
getExceptionTryEnterFn()5557330f729Sjoerg llvm::FunctionCallee getExceptionTryEnterFn() {
5567330f729Sjoerg llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
5577330f729Sjoerg return CGM.CreateRuntimeFunction(
5587330f729Sjoerg llvm::FunctionType::get(CGM.VoidTy, params, false),
5597330f729Sjoerg "objc_exception_try_enter");
5607330f729Sjoerg }
5617330f729Sjoerg
5627330f729Sjoerg /// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
getExceptionTryExitFn()5637330f729Sjoerg llvm::FunctionCallee getExceptionTryExitFn() {
5647330f729Sjoerg llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
5657330f729Sjoerg return CGM.CreateRuntimeFunction(
5667330f729Sjoerg llvm::FunctionType::get(CGM.VoidTy, params, false),
5677330f729Sjoerg "objc_exception_try_exit");
5687330f729Sjoerg }
5697330f729Sjoerg
5707330f729Sjoerg /// ExceptionExtractFn - LLVM objc_exception_extract function.
getExceptionExtractFn()5717330f729Sjoerg llvm::FunctionCallee getExceptionExtractFn() {
5727330f729Sjoerg llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
5737330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
5747330f729Sjoerg params, false),
5757330f729Sjoerg "objc_exception_extract");
5767330f729Sjoerg }
5777330f729Sjoerg
5787330f729Sjoerg /// ExceptionMatchFn - LLVM objc_exception_match function.
getExceptionMatchFn()5797330f729Sjoerg llvm::FunctionCallee getExceptionMatchFn() {
5807330f729Sjoerg llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
5817330f729Sjoerg return CGM.CreateRuntimeFunction(
5827330f729Sjoerg llvm::FunctionType::get(CGM.Int32Ty, params, false),
5837330f729Sjoerg "objc_exception_match");
5847330f729Sjoerg }
5857330f729Sjoerg
5867330f729Sjoerg /// SetJmpFn - LLVM _setjmp function.
getSetJmpFn()5877330f729Sjoerg llvm::FunctionCallee getSetJmpFn() {
5887330f729Sjoerg // This is specifically the prototype for x86.
5897330f729Sjoerg llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
5907330f729Sjoerg return CGM.CreateRuntimeFunction(
5917330f729Sjoerg llvm::FunctionType::get(CGM.Int32Ty, params, false), "_setjmp",
5927330f729Sjoerg llvm::AttributeList::get(CGM.getLLVMContext(),
5937330f729Sjoerg llvm::AttributeList::FunctionIndex,
5947330f729Sjoerg llvm::Attribute::NonLazyBind));
5957330f729Sjoerg }
5967330f729Sjoerg
5977330f729Sjoerg public:
5987330f729Sjoerg ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
5997330f729Sjoerg };
6007330f729Sjoerg
6017330f729Sjoerg /// ObjCNonFragileABITypesHelper - will have all types needed by objective-c's
6027330f729Sjoerg /// modern abi
6037330f729Sjoerg class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper {
6047330f729Sjoerg public:
6057330f729Sjoerg // MethodListnfABITy - LLVM for struct _method_list_t
6067330f729Sjoerg llvm::StructType *MethodListnfABITy;
6077330f729Sjoerg
6087330f729Sjoerg // MethodListnfABIPtrTy - LLVM for struct _method_list_t*
6097330f729Sjoerg llvm::PointerType *MethodListnfABIPtrTy;
6107330f729Sjoerg
6117330f729Sjoerg // ProtocolnfABITy = LLVM for struct _protocol_t
6127330f729Sjoerg llvm::StructType *ProtocolnfABITy;
6137330f729Sjoerg
6147330f729Sjoerg // ProtocolnfABIPtrTy = LLVM for struct _protocol_t*
6157330f729Sjoerg llvm::PointerType *ProtocolnfABIPtrTy;
6167330f729Sjoerg
6177330f729Sjoerg // ProtocolListnfABITy - LLVM for struct _objc_protocol_list
6187330f729Sjoerg llvm::StructType *ProtocolListnfABITy;
6197330f729Sjoerg
6207330f729Sjoerg // ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list*
6217330f729Sjoerg llvm::PointerType *ProtocolListnfABIPtrTy;
6227330f729Sjoerg
6237330f729Sjoerg // ClassnfABITy - LLVM for struct _class_t
6247330f729Sjoerg llvm::StructType *ClassnfABITy;
6257330f729Sjoerg
6267330f729Sjoerg // ClassnfABIPtrTy - LLVM for struct _class_t*
6277330f729Sjoerg llvm::PointerType *ClassnfABIPtrTy;
6287330f729Sjoerg
6297330f729Sjoerg // IvarnfABITy - LLVM for struct _ivar_t
6307330f729Sjoerg llvm::StructType *IvarnfABITy;
6317330f729Sjoerg
6327330f729Sjoerg // IvarListnfABITy - LLVM for struct _ivar_list_t
6337330f729Sjoerg llvm::StructType *IvarListnfABITy;
6347330f729Sjoerg
6357330f729Sjoerg // IvarListnfABIPtrTy = LLVM for struct _ivar_list_t*
6367330f729Sjoerg llvm::PointerType *IvarListnfABIPtrTy;
6377330f729Sjoerg
6387330f729Sjoerg // ClassRonfABITy - LLVM for struct _class_ro_t
6397330f729Sjoerg llvm::StructType *ClassRonfABITy;
6407330f729Sjoerg
6417330f729Sjoerg // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
6427330f729Sjoerg llvm::PointerType *ImpnfABITy;
6437330f729Sjoerg
6447330f729Sjoerg // CategorynfABITy - LLVM for struct _category_t
6457330f729Sjoerg llvm::StructType *CategorynfABITy;
6467330f729Sjoerg
6477330f729Sjoerg // New types for nonfragile abi messaging.
6487330f729Sjoerg
6497330f729Sjoerg // MessageRefTy - LLVM for:
6507330f729Sjoerg // struct _message_ref_t {
6517330f729Sjoerg // IMP messenger;
6527330f729Sjoerg // SEL name;
6537330f729Sjoerg // };
6547330f729Sjoerg llvm::StructType *MessageRefTy;
6557330f729Sjoerg // MessageRefCTy - clang type for struct _message_ref_t
6567330f729Sjoerg QualType MessageRefCTy;
6577330f729Sjoerg
6587330f729Sjoerg // MessageRefPtrTy - LLVM for struct _message_ref_t*
6597330f729Sjoerg llvm::Type *MessageRefPtrTy;
6607330f729Sjoerg // MessageRefCPtrTy - clang type for struct _message_ref_t*
6617330f729Sjoerg QualType MessageRefCPtrTy;
6627330f729Sjoerg
6637330f729Sjoerg // SuperMessageRefTy - LLVM for:
6647330f729Sjoerg // struct _super_message_ref_t {
6657330f729Sjoerg // SUPER_IMP messenger;
6667330f729Sjoerg // SEL name;
6677330f729Sjoerg // };
6687330f729Sjoerg llvm::StructType *SuperMessageRefTy;
6697330f729Sjoerg
6707330f729Sjoerg // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
6717330f729Sjoerg llvm::PointerType *SuperMessageRefPtrTy;
6727330f729Sjoerg
getMessageSendFixupFn()6737330f729Sjoerg llvm::FunctionCallee getMessageSendFixupFn() {
6747330f729Sjoerg // id objc_msgSend_fixup(id, struct message_ref_t*, ...)
6757330f729Sjoerg llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
6767330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
6777330f729Sjoerg params, true),
6787330f729Sjoerg "objc_msgSend_fixup");
6797330f729Sjoerg }
6807330f729Sjoerg
getMessageSendFpretFixupFn()6817330f729Sjoerg llvm::FunctionCallee getMessageSendFpretFixupFn() {
6827330f729Sjoerg // id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
6837330f729Sjoerg llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
6847330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
6857330f729Sjoerg params, true),
6867330f729Sjoerg "objc_msgSend_fpret_fixup");
6877330f729Sjoerg }
6887330f729Sjoerg
getMessageSendStretFixupFn()6897330f729Sjoerg llvm::FunctionCallee getMessageSendStretFixupFn() {
6907330f729Sjoerg // id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...)
6917330f729Sjoerg llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
6927330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
6937330f729Sjoerg params, true),
6947330f729Sjoerg "objc_msgSend_stret_fixup");
6957330f729Sjoerg }
6967330f729Sjoerg
getMessageSendSuper2FixupFn()6977330f729Sjoerg llvm::FunctionCallee getMessageSendSuper2FixupFn() {
6987330f729Sjoerg // id objc_msgSendSuper2_fixup (struct objc_super *,
6997330f729Sjoerg // struct _super_message_ref_t*, ...)
7007330f729Sjoerg llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
7017330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
7027330f729Sjoerg params, true),
7037330f729Sjoerg "objc_msgSendSuper2_fixup");
7047330f729Sjoerg }
7057330f729Sjoerg
getMessageSendSuper2StretFixupFn()7067330f729Sjoerg llvm::FunctionCallee getMessageSendSuper2StretFixupFn() {
7077330f729Sjoerg // id objc_msgSendSuper2_stret_fixup(struct objc_super *,
7087330f729Sjoerg // struct _super_message_ref_t*, ...)
7097330f729Sjoerg llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
7107330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
7117330f729Sjoerg params, true),
7127330f729Sjoerg "objc_msgSendSuper2_stret_fixup");
7137330f729Sjoerg }
7147330f729Sjoerg
getObjCEndCatchFn()7157330f729Sjoerg llvm::FunctionCallee getObjCEndCatchFn() {
7167330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy, false),
7177330f729Sjoerg "objc_end_catch");
7187330f729Sjoerg }
7197330f729Sjoerg
getObjCBeginCatchFn()7207330f729Sjoerg llvm::FunctionCallee getObjCBeginCatchFn() {
7217330f729Sjoerg llvm::Type *params[] = { Int8PtrTy };
7227330f729Sjoerg return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy,
7237330f729Sjoerg params, false),
7247330f729Sjoerg "objc_begin_catch");
7257330f729Sjoerg }
7267330f729Sjoerg
7277330f729Sjoerg /// Class objc_loadClassref (void *)
7287330f729Sjoerg ///
7297330f729Sjoerg /// Loads from a classref. For Objective-C stub classes, this invokes the
7307330f729Sjoerg /// initialization callback stored inside the stub. For all other classes
7317330f729Sjoerg /// this simply dereferences the pointer.
getLoadClassrefFn() const7327330f729Sjoerg llvm::FunctionCallee getLoadClassrefFn() const {
7337330f729Sjoerg // Add the non-lazy-bind attribute, since objc_loadClassref is likely to
7347330f729Sjoerg // be called a lot.
7357330f729Sjoerg //
7367330f729Sjoerg // Also it is safe to make it readnone, since we never load or store the
7377330f729Sjoerg // classref except by calling this function.
7387330f729Sjoerg llvm::Type *params[] = { Int8PtrPtrTy };
7397330f729Sjoerg llvm::FunctionCallee F = CGM.CreateRuntimeFunction(
7407330f729Sjoerg llvm::FunctionType::get(ClassnfABIPtrTy, params, false),
7417330f729Sjoerg "objc_loadClassref",
7427330f729Sjoerg llvm::AttributeList::get(CGM.getLLVMContext(),
7437330f729Sjoerg llvm::AttributeList::FunctionIndex,
7447330f729Sjoerg {llvm::Attribute::NonLazyBind,
7457330f729Sjoerg llvm::Attribute::ReadNone,
7467330f729Sjoerg llvm::Attribute::NoUnwind}));
7477330f729Sjoerg if (!CGM.getTriple().isOSBinFormatCOFF())
7487330f729Sjoerg cast<llvm::Function>(F.getCallee())->setLinkage(
7497330f729Sjoerg llvm::Function::ExternalWeakLinkage);
7507330f729Sjoerg
7517330f729Sjoerg return F;
7527330f729Sjoerg }
7537330f729Sjoerg
7547330f729Sjoerg llvm::StructType *EHTypeTy;
7557330f729Sjoerg llvm::Type *EHTypePtrTy;
7567330f729Sjoerg
7577330f729Sjoerg ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
7587330f729Sjoerg };
7597330f729Sjoerg
7607330f729Sjoerg enum class ObjCLabelType {
7617330f729Sjoerg ClassName,
7627330f729Sjoerg MethodVarName,
7637330f729Sjoerg MethodVarType,
7647330f729Sjoerg PropertyName,
7657330f729Sjoerg };
7667330f729Sjoerg
7677330f729Sjoerg class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
7687330f729Sjoerg public:
7697330f729Sjoerg class SKIP_SCAN {
7707330f729Sjoerg public:
7717330f729Sjoerg unsigned skip;
7727330f729Sjoerg unsigned scan;
SKIP_SCAN(unsigned _skip=0,unsigned _scan=0)7737330f729Sjoerg SKIP_SCAN(unsigned _skip = 0, unsigned _scan = 0)
7747330f729Sjoerg : skip(_skip), scan(_scan) {}
7757330f729Sjoerg };
7767330f729Sjoerg
7777330f729Sjoerg /// opcode for captured block variables layout 'instructions'.
7787330f729Sjoerg /// In the following descriptions, 'I' is the value of the immediate field.
7797330f729Sjoerg /// (field following the opcode).
7807330f729Sjoerg ///
7817330f729Sjoerg enum BLOCK_LAYOUT_OPCODE {
7827330f729Sjoerg /// An operator which affects how the following layout should be
7837330f729Sjoerg /// interpreted.
7847330f729Sjoerg /// I == 0: Halt interpretation and treat everything else as
7857330f729Sjoerg /// a non-pointer. Note that this instruction is equal
7867330f729Sjoerg /// to '\0'.
7877330f729Sjoerg /// I != 0: Currently unused.
7887330f729Sjoerg BLOCK_LAYOUT_OPERATOR = 0,
7897330f729Sjoerg
7907330f729Sjoerg /// The next I+1 bytes do not contain a value of object pointer type.
7917330f729Sjoerg /// Note that this can leave the stream unaligned, meaning that
7927330f729Sjoerg /// subsequent word-size instructions do not begin at a multiple of
7937330f729Sjoerg /// the pointer size.
7947330f729Sjoerg BLOCK_LAYOUT_NON_OBJECT_BYTES = 1,
7957330f729Sjoerg
7967330f729Sjoerg /// The next I+1 words do not contain a value of object pointer type.
7977330f729Sjoerg /// This is simply an optimized version of BLOCK_LAYOUT_BYTES for
7987330f729Sjoerg /// when the required skip quantity is a multiple of the pointer size.
7997330f729Sjoerg BLOCK_LAYOUT_NON_OBJECT_WORDS = 2,
8007330f729Sjoerg
8017330f729Sjoerg /// The next I+1 words are __strong pointers to Objective-C
8027330f729Sjoerg /// objects or blocks.
8037330f729Sjoerg BLOCK_LAYOUT_STRONG = 3,
8047330f729Sjoerg
8057330f729Sjoerg /// The next I+1 words are pointers to __block variables.
8067330f729Sjoerg BLOCK_LAYOUT_BYREF = 4,
8077330f729Sjoerg
8087330f729Sjoerg /// The next I+1 words are __weak pointers to Objective-C
8097330f729Sjoerg /// objects or blocks.
8107330f729Sjoerg BLOCK_LAYOUT_WEAK = 5,
8117330f729Sjoerg
8127330f729Sjoerg /// The next I+1 words are __unsafe_unretained pointers to
8137330f729Sjoerg /// Objective-C objects or blocks.
8147330f729Sjoerg BLOCK_LAYOUT_UNRETAINED = 6
8157330f729Sjoerg
8167330f729Sjoerg /// The next I+1 words are block or object pointers with some
8177330f729Sjoerg /// as-yet-unspecified ownership semantics. If we add more
8187330f729Sjoerg /// flavors of ownership semantics, values will be taken from
8197330f729Sjoerg /// this range.
8207330f729Sjoerg ///
8217330f729Sjoerg /// This is included so that older tools can at least continue
8227330f729Sjoerg /// processing the layout past such things.
8237330f729Sjoerg //BLOCK_LAYOUT_OWNERSHIP_UNKNOWN = 7..10,
8247330f729Sjoerg
8257330f729Sjoerg /// All other opcodes are reserved. Halt interpretation and
8267330f729Sjoerg /// treat everything else as opaque.
8277330f729Sjoerg };
8287330f729Sjoerg
8297330f729Sjoerg class RUN_SKIP {
8307330f729Sjoerg public:
8317330f729Sjoerg enum BLOCK_LAYOUT_OPCODE opcode;
8327330f729Sjoerg CharUnits block_var_bytepos;
8337330f729Sjoerg CharUnits block_var_size;
RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode=BLOCK_LAYOUT_OPERATOR,CharUnits BytePos=CharUnits::Zero (),CharUnits Size=CharUnits::Zero ())8347330f729Sjoerg RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode = BLOCK_LAYOUT_OPERATOR,
8357330f729Sjoerg CharUnits BytePos = CharUnits::Zero(),
8367330f729Sjoerg CharUnits Size = CharUnits::Zero())
8377330f729Sjoerg : opcode(Opcode), block_var_bytepos(BytePos), block_var_size(Size) {}
8387330f729Sjoerg
8397330f729Sjoerg // Allow sorting based on byte pos.
operator <(const RUN_SKIP & b) const8407330f729Sjoerg bool operator<(const RUN_SKIP &b) const {
8417330f729Sjoerg return block_var_bytepos < b.block_var_bytepos;
8427330f729Sjoerg }
8437330f729Sjoerg };
8447330f729Sjoerg
8457330f729Sjoerg protected:
8467330f729Sjoerg llvm::LLVMContext &VMContext;
8477330f729Sjoerg // FIXME! May not be needing this after all.
8487330f729Sjoerg unsigned ObjCABI;
8497330f729Sjoerg
8507330f729Sjoerg // arc/mrr layout of captured block literal variables.
8517330f729Sjoerg SmallVector<RUN_SKIP, 16> RunSkipBlockVars;
8527330f729Sjoerg
8537330f729Sjoerg /// LazySymbols - Symbols to generate a lazy reference for. See
8547330f729Sjoerg /// DefinedSymbols and FinishModule().
8557330f729Sjoerg llvm::SetVector<IdentifierInfo*> LazySymbols;
8567330f729Sjoerg
8577330f729Sjoerg /// DefinedSymbols - External symbols which are defined by this
8587330f729Sjoerg /// module. The symbols in this list and LazySymbols are used to add
8597330f729Sjoerg /// special linker symbols which ensure that Objective-C modules are
8607330f729Sjoerg /// linked properly.
8617330f729Sjoerg llvm::SetVector<IdentifierInfo*> DefinedSymbols;
8627330f729Sjoerg
8637330f729Sjoerg /// ClassNames - uniqued class names.
8647330f729Sjoerg llvm::StringMap<llvm::GlobalVariable*> ClassNames;
8657330f729Sjoerg
8667330f729Sjoerg /// MethodVarNames - uniqued method variable names.
8677330f729Sjoerg llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
8687330f729Sjoerg
8697330f729Sjoerg /// DefinedCategoryNames - list of category names in form Class_Category.
8707330f729Sjoerg llvm::SmallSetVector<llvm::CachedHashString, 16> DefinedCategoryNames;
8717330f729Sjoerg
8727330f729Sjoerg /// MethodVarTypes - uniqued method type signatures. We have to use
8737330f729Sjoerg /// a StringMap here because have no other unique reference.
8747330f729Sjoerg llvm::StringMap<llvm::GlobalVariable*> MethodVarTypes;
8757330f729Sjoerg
8767330f729Sjoerg /// MethodDefinitions - map of methods which have been defined in
8777330f729Sjoerg /// this translation unit.
8787330f729Sjoerg llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
8797330f729Sjoerg
880*e038c9c4Sjoerg /// DirectMethodDefinitions - map of direct methods which have been defined in
881*e038c9c4Sjoerg /// this translation unit.
882*e038c9c4Sjoerg llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> DirectMethodDefinitions;
883*e038c9c4Sjoerg
8847330f729Sjoerg /// PropertyNames - uniqued method variable names.
8857330f729Sjoerg llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
8867330f729Sjoerg
8877330f729Sjoerg /// ClassReferences - uniqued class references.
8887330f729Sjoerg llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassReferences;
8897330f729Sjoerg
8907330f729Sjoerg /// SelectorReferences - uniqued selector references.
8917330f729Sjoerg llvm::DenseMap<Selector, llvm::GlobalVariable*> SelectorReferences;
8927330f729Sjoerg
8937330f729Sjoerg /// Protocols - Protocols for which an objc_protocol structure has
8947330f729Sjoerg /// been emitted. Forward declarations are handled by creating an
8957330f729Sjoerg /// empty structure whose initializer is filled in when/if defined.
8967330f729Sjoerg llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> Protocols;
8977330f729Sjoerg
8987330f729Sjoerg /// DefinedProtocols - Protocols which have actually been
8997330f729Sjoerg /// defined. We should not need this, see FIXME in GenerateProtocol.
9007330f729Sjoerg llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
9017330f729Sjoerg
9027330f729Sjoerg /// DefinedClasses - List of defined classes.
9037330f729Sjoerg SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
9047330f729Sjoerg
9057330f729Sjoerg /// ImplementedClasses - List of @implemented classes.
9067330f729Sjoerg SmallVector<const ObjCInterfaceDecl*, 16> ImplementedClasses;
9077330f729Sjoerg
9087330f729Sjoerg /// DefinedNonLazyClasses - List of defined "non-lazy" classes.
9097330f729Sjoerg SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
9107330f729Sjoerg
9117330f729Sjoerg /// DefinedCategories - List of defined categories.
9127330f729Sjoerg SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
9137330f729Sjoerg
9147330f729Sjoerg /// DefinedStubCategories - List of defined categories on class stubs.
9157330f729Sjoerg SmallVector<llvm::GlobalValue*, 16> DefinedStubCategories;
9167330f729Sjoerg
9177330f729Sjoerg /// DefinedNonLazyCategories - List of defined "non-lazy" categories.
9187330f729Sjoerg SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
9197330f729Sjoerg
9207330f729Sjoerg /// Cached reference to the class for constant strings. This value has type
9217330f729Sjoerg /// int * but is actually an Obj-C class pointer.
9227330f729Sjoerg llvm::WeakTrackingVH ConstantStringClassRef;
9237330f729Sjoerg
9247330f729Sjoerg /// The LLVM type corresponding to NSConstantString.
9257330f729Sjoerg llvm::StructType *NSConstantStringType = nullptr;
9267330f729Sjoerg
9277330f729Sjoerg llvm::StringMap<llvm::GlobalVariable *> NSConstantStringMap;
9287330f729Sjoerg
9297330f729Sjoerg /// GetMethodVarName - Return a unique constant for the given
9307330f729Sjoerg /// selector's name. The return value has type char *.
9317330f729Sjoerg llvm::Constant *GetMethodVarName(Selector Sel);
9327330f729Sjoerg llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
9337330f729Sjoerg
9347330f729Sjoerg /// GetMethodVarType - Return a unique constant for the given
9357330f729Sjoerg /// method's type encoding string. The return value has type char *.
9367330f729Sjoerg
9377330f729Sjoerg // FIXME: This is a horrible name.
9387330f729Sjoerg llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D,
9397330f729Sjoerg bool Extended = false);
9407330f729Sjoerg llvm::Constant *GetMethodVarType(const FieldDecl *D);
9417330f729Sjoerg
9427330f729Sjoerg /// GetPropertyName - Return a unique constant for the given
9437330f729Sjoerg /// name. The return value has type char *.
9447330f729Sjoerg llvm::Constant *GetPropertyName(IdentifierInfo *Ident);
9457330f729Sjoerg
9467330f729Sjoerg // FIXME: This can be dropped once string functions are unified.
9477330f729Sjoerg llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD,
9487330f729Sjoerg const Decl *Container);
9497330f729Sjoerg
9507330f729Sjoerg /// GetClassName - Return a unique constant for the given selector's
9517330f729Sjoerg /// runtime name (which may change via use of objc_runtime_name attribute on
9527330f729Sjoerg /// class or protocol definition. The return value has type char *.
9537330f729Sjoerg llvm::Constant *GetClassName(StringRef RuntimeName);
9547330f729Sjoerg
9557330f729Sjoerg llvm::Function *GetMethodDefinition(const ObjCMethodDecl *MD);
9567330f729Sjoerg
9577330f729Sjoerg /// BuildIvarLayout - Builds ivar layout bitmap for the class
9587330f729Sjoerg /// implementation for the __strong or __weak case.
9597330f729Sjoerg ///
9607330f729Sjoerg /// \param hasMRCWeakIvars - Whether we are compiling in MRC and there
9617330f729Sjoerg /// are any weak ivars defined directly in the class. Meaningless unless
9627330f729Sjoerg /// building a weak layout. Does not guarantee that the layout will
9637330f729Sjoerg /// actually have any entries, because the ivar might be under-aligned.
9647330f729Sjoerg llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI,
9657330f729Sjoerg CharUnits beginOffset,
9667330f729Sjoerg CharUnits endOffset,
9677330f729Sjoerg bool forStrongLayout,
9687330f729Sjoerg bool hasMRCWeakIvars);
9697330f729Sjoerg
BuildStrongIvarLayout(const ObjCImplementationDecl * OI,CharUnits beginOffset,CharUnits endOffset)9707330f729Sjoerg llvm::Constant *BuildStrongIvarLayout(const ObjCImplementationDecl *OI,
9717330f729Sjoerg CharUnits beginOffset,
9727330f729Sjoerg CharUnits endOffset) {
9737330f729Sjoerg return BuildIvarLayout(OI, beginOffset, endOffset, true, false);
9747330f729Sjoerg }
9757330f729Sjoerg
BuildWeakIvarLayout(const ObjCImplementationDecl * OI,CharUnits beginOffset,CharUnits endOffset,bool hasMRCWeakIvars)9767330f729Sjoerg llvm::Constant *BuildWeakIvarLayout(const ObjCImplementationDecl *OI,
9777330f729Sjoerg CharUnits beginOffset,
9787330f729Sjoerg CharUnits endOffset,
9797330f729Sjoerg bool hasMRCWeakIvars) {
9807330f729Sjoerg return BuildIvarLayout(OI, beginOffset, endOffset, false, hasMRCWeakIvars);
9817330f729Sjoerg }
9827330f729Sjoerg
9837330f729Sjoerg Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT, bool ByrefLayout);
9847330f729Sjoerg
9857330f729Sjoerg void UpdateRunSkipBlockVars(bool IsByref,
9867330f729Sjoerg Qualifiers::ObjCLifetime LifeTime,
9877330f729Sjoerg CharUnits FieldOffset,
9887330f729Sjoerg CharUnits FieldSize);
9897330f729Sjoerg
9907330f729Sjoerg void BuildRCBlockVarRecordLayout(const RecordType *RT,
9917330f729Sjoerg CharUnits BytePos, bool &HasUnion,
9927330f729Sjoerg bool ByrefLayout=false);
9937330f729Sjoerg
9947330f729Sjoerg void BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
9957330f729Sjoerg const RecordDecl *RD,
9967330f729Sjoerg ArrayRef<const FieldDecl*> RecFields,
9977330f729Sjoerg CharUnits BytePos, bool &HasUnion,
9987330f729Sjoerg bool ByrefLayout);
9997330f729Sjoerg
10007330f729Sjoerg uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
10017330f729Sjoerg
10027330f729Sjoerg llvm::Constant *getBitmapBlockLayout(bool ComputeByrefLayout);
10037330f729Sjoerg
10047330f729Sjoerg /// GetIvarLayoutName - Returns a unique constant for the given
10057330f729Sjoerg /// ivar layout bitmap.
10067330f729Sjoerg llvm::Constant *GetIvarLayoutName(IdentifierInfo *Ident,
10077330f729Sjoerg const ObjCCommonTypesHelper &ObjCTypes);
10087330f729Sjoerg
10097330f729Sjoerg /// EmitPropertyList - Emit the given property list. The return
10107330f729Sjoerg /// value has type PropertyListPtrTy.
10117330f729Sjoerg llvm::Constant *EmitPropertyList(Twine Name,
10127330f729Sjoerg const Decl *Container,
10137330f729Sjoerg const ObjCContainerDecl *OCD,
10147330f729Sjoerg const ObjCCommonTypesHelper &ObjCTypes,
10157330f729Sjoerg bool IsClassProperty);
10167330f729Sjoerg
10177330f729Sjoerg /// EmitProtocolMethodTypes - Generate the array of extended method type
10187330f729Sjoerg /// strings. The return value has type Int8PtrPtrTy.
10197330f729Sjoerg llvm::Constant *EmitProtocolMethodTypes(Twine Name,
10207330f729Sjoerg ArrayRef<llvm::Constant*> MethodTypes,
10217330f729Sjoerg const ObjCCommonTypesHelper &ObjCTypes);
10227330f729Sjoerg
10237330f729Sjoerg /// GetProtocolRef - Return a reference to the internal protocol
10247330f729Sjoerg /// description, creating an empty one if it has not been
10257330f729Sjoerg /// defined. The return value has type ProtocolPtrTy.
10267330f729Sjoerg llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
10277330f729Sjoerg
10287330f729Sjoerg /// Return a reference to the given Class using runtime calls rather than
10297330f729Sjoerg /// by a symbol reference.
10307330f729Sjoerg llvm::Value *EmitClassRefViaRuntime(CodeGenFunction &CGF,
10317330f729Sjoerg const ObjCInterfaceDecl *ID,
10327330f729Sjoerg ObjCCommonTypesHelper &ObjCTypes);
10337330f729Sjoerg
10347330f729Sjoerg std::string GetSectionName(StringRef Section, StringRef MachOAttributes);
10357330f729Sjoerg
10367330f729Sjoerg public:
10377330f729Sjoerg /// CreateMetadataVar - Create a global variable with internal
10387330f729Sjoerg /// linkage for use by the Objective-C runtime.
10397330f729Sjoerg ///
10407330f729Sjoerg /// This is a convenience wrapper which not only creates the
10417330f729Sjoerg /// variable, but also sets the section and alignment and adds the
10427330f729Sjoerg /// global to the "llvm.used" list.
10437330f729Sjoerg ///
10447330f729Sjoerg /// \param Name - The variable name.
10457330f729Sjoerg /// \param Init - The variable initializer; this is also used to
10467330f729Sjoerg /// define the type of the variable.
10477330f729Sjoerg /// \param Section - The section the variable should go into, or empty.
10487330f729Sjoerg /// \param Align - The alignment for the variable, or 0.
10497330f729Sjoerg /// \param AddToUsed - Whether the variable should be added to
10507330f729Sjoerg /// "llvm.used".
10517330f729Sjoerg llvm::GlobalVariable *CreateMetadataVar(Twine Name,
10527330f729Sjoerg ConstantStructBuilder &Init,
10537330f729Sjoerg StringRef Section, CharUnits Align,
10547330f729Sjoerg bool AddToUsed);
10557330f729Sjoerg llvm::GlobalVariable *CreateMetadataVar(Twine Name,
10567330f729Sjoerg llvm::Constant *Init,
10577330f729Sjoerg StringRef Section, CharUnits Align,
10587330f729Sjoerg bool AddToUsed);
10597330f729Sjoerg
10607330f729Sjoerg llvm::GlobalVariable *CreateCStringLiteral(StringRef Name,
10617330f729Sjoerg ObjCLabelType LabelType,
10627330f729Sjoerg bool ForceNonFragileABI = false,
10637330f729Sjoerg bool NullTerminate = true);
10647330f729Sjoerg
10657330f729Sjoerg protected:
10667330f729Sjoerg CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
10677330f729Sjoerg ReturnValueSlot Return,
10687330f729Sjoerg QualType ResultType,
1069*e038c9c4Sjoerg Selector Sel,
10707330f729Sjoerg llvm::Value *Arg0,
10717330f729Sjoerg QualType Arg0Ty,
10727330f729Sjoerg bool IsSuper,
10737330f729Sjoerg const CallArgList &CallArgs,
10747330f729Sjoerg const ObjCMethodDecl *OMD,
10757330f729Sjoerg const ObjCInterfaceDecl *ClassReceiver,
10767330f729Sjoerg const ObjCCommonTypesHelper &ObjCTypes);
10777330f729Sjoerg
10787330f729Sjoerg /// EmitImageInfo - Emit the image info marker used to encode some module
10797330f729Sjoerg /// level information.
10807330f729Sjoerg void EmitImageInfo();
10817330f729Sjoerg
10827330f729Sjoerg public:
CGObjCCommonMac(CodeGen::CodeGenModule & cgm)1083*e038c9c4Sjoerg CGObjCCommonMac(CodeGen::CodeGenModule &cgm)
1084*e038c9c4Sjoerg : CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) {}
10857330f729Sjoerg
isNonFragileABI() const10867330f729Sjoerg bool isNonFragileABI() const {
10877330f729Sjoerg return ObjCABI == 2;
10887330f729Sjoerg }
10897330f729Sjoerg
10907330f729Sjoerg ConstantAddress GenerateConstantString(const StringLiteral *SL) override;
10917330f729Sjoerg ConstantAddress GenerateConstantNSString(const StringLiteral *SL);
10927330f729Sjoerg
10937330f729Sjoerg llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
10947330f729Sjoerg const ObjCContainerDecl *CD=nullptr) override;
10957330f729Sjoerg
1096*e038c9c4Sjoerg llvm::Function *GenerateDirectMethod(const ObjCMethodDecl *OMD,
1097*e038c9c4Sjoerg const ObjCContainerDecl *CD);
10987330f729Sjoerg
1099*e038c9c4Sjoerg void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
1100*e038c9c4Sjoerg const ObjCMethodDecl *OMD,
1101*e038c9c4Sjoerg const ObjCContainerDecl *CD) override;
1102*e038c9c4Sjoerg
1103*e038c9c4Sjoerg void GenerateProtocol(const ObjCProtocolDecl *PD) override;
11047330f729Sjoerg
11057330f729Sjoerg /// GetOrEmitProtocolRef - Get a forward reference to the protocol
11067330f729Sjoerg /// object for the given declaration, emitting it if needed. These
11077330f729Sjoerg /// forward references will be filled in with empty bodies if no
11087330f729Sjoerg /// definition is seen. The return value has type ProtocolPtrTy.
11097330f729Sjoerg virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
11107330f729Sjoerg
11117330f729Sjoerg virtual llvm::Constant *getNSConstantStringClassRef() = 0;
11127330f729Sjoerg
11137330f729Sjoerg llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
11147330f729Sjoerg const CGBlockInfo &blockInfo) override;
11157330f729Sjoerg llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
11167330f729Sjoerg const CGBlockInfo &blockInfo) override;
11177330f729Sjoerg std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM,
11187330f729Sjoerg const CGBlockInfo &blockInfo) override;
11197330f729Sjoerg
11207330f729Sjoerg llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
11217330f729Sjoerg QualType T) override;
11227330f729Sjoerg
11237330f729Sjoerg private:
11247330f729Sjoerg void fillRunSkipBlockVars(CodeGenModule &CGM, const CGBlockInfo &blockInfo);
11257330f729Sjoerg };
11267330f729Sjoerg
11277330f729Sjoerg namespace {
11287330f729Sjoerg
11297330f729Sjoerg enum class MethodListType {
11307330f729Sjoerg CategoryInstanceMethods,
11317330f729Sjoerg CategoryClassMethods,
11327330f729Sjoerg InstanceMethods,
11337330f729Sjoerg ClassMethods,
11347330f729Sjoerg ProtocolInstanceMethods,
11357330f729Sjoerg ProtocolClassMethods,
11367330f729Sjoerg OptionalProtocolInstanceMethods,
11377330f729Sjoerg OptionalProtocolClassMethods,
11387330f729Sjoerg };
11397330f729Sjoerg
11407330f729Sjoerg /// A convenience class for splitting the methods of a protocol into
11417330f729Sjoerg /// the four interesting groups.
11427330f729Sjoerg class ProtocolMethodLists {
11437330f729Sjoerg public:
11447330f729Sjoerg enum Kind {
11457330f729Sjoerg RequiredInstanceMethods,
11467330f729Sjoerg RequiredClassMethods,
11477330f729Sjoerg OptionalInstanceMethods,
11487330f729Sjoerg OptionalClassMethods
11497330f729Sjoerg };
11507330f729Sjoerg enum {
11517330f729Sjoerg NumProtocolMethodLists = 4
11527330f729Sjoerg };
11537330f729Sjoerg
getMethodListKind(Kind kind)11547330f729Sjoerg static MethodListType getMethodListKind(Kind kind) {
11557330f729Sjoerg switch (kind) {
11567330f729Sjoerg case RequiredInstanceMethods:
11577330f729Sjoerg return MethodListType::ProtocolInstanceMethods;
11587330f729Sjoerg case RequiredClassMethods:
11597330f729Sjoerg return MethodListType::ProtocolClassMethods;
11607330f729Sjoerg case OptionalInstanceMethods:
11617330f729Sjoerg return MethodListType::OptionalProtocolInstanceMethods;
11627330f729Sjoerg case OptionalClassMethods:
11637330f729Sjoerg return MethodListType::OptionalProtocolClassMethods;
11647330f729Sjoerg }
11657330f729Sjoerg llvm_unreachable("bad kind");
11667330f729Sjoerg }
11677330f729Sjoerg
11687330f729Sjoerg SmallVector<const ObjCMethodDecl *, 4> Methods[NumProtocolMethodLists];
11697330f729Sjoerg
get(const ObjCProtocolDecl * PD)11707330f729Sjoerg static ProtocolMethodLists get(const ObjCProtocolDecl *PD) {
11717330f729Sjoerg ProtocolMethodLists result;
11727330f729Sjoerg
11737330f729Sjoerg for (auto MD : PD->methods()) {
11747330f729Sjoerg size_t index = (2 * size_t(MD->isOptional()))
11757330f729Sjoerg + (size_t(MD->isClassMethod()));
11767330f729Sjoerg result.Methods[index].push_back(MD);
11777330f729Sjoerg }
11787330f729Sjoerg
11797330f729Sjoerg return result;
11807330f729Sjoerg }
11817330f729Sjoerg
11827330f729Sjoerg template <class Self>
emitExtendedTypesArray(Self * self) const11837330f729Sjoerg SmallVector<llvm::Constant*, 8> emitExtendedTypesArray(Self *self) const {
11847330f729Sjoerg // In both ABIs, the method types list is parallel with the
11857330f729Sjoerg // concatenation of the methods arrays in the following order:
11867330f729Sjoerg // instance methods
11877330f729Sjoerg // class methods
11887330f729Sjoerg // optional instance methods
11897330f729Sjoerg // optional class methods
11907330f729Sjoerg SmallVector<llvm::Constant*, 8> result;
11917330f729Sjoerg
11927330f729Sjoerg // Methods is already in the correct order for both ABIs.
11937330f729Sjoerg for (auto &list : Methods) {
11947330f729Sjoerg for (auto MD : list) {
11957330f729Sjoerg result.push_back(self->GetMethodVarType(MD, true));
11967330f729Sjoerg }
11977330f729Sjoerg }
11987330f729Sjoerg
11997330f729Sjoerg return result;
12007330f729Sjoerg }
12017330f729Sjoerg
12027330f729Sjoerg template <class Self>
emitMethodList(Self * self,const ObjCProtocolDecl * PD,Kind kind) const12037330f729Sjoerg llvm::Constant *emitMethodList(Self *self, const ObjCProtocolDecl *PD,
12047330f729Sjoerg Kind kind) const {
12057330f729Sjoerg return self->emitMethodList(PD->getObjCRuntimeNameAsString(),
12067330f729Sjoerg getMethodListKind(kind), Methods[kind]);
12077330f729Sjoerg }
12087330f729Sjoerg };
12097330f729Sjoerg
12107330f729Sjoerg } // end anonymous namespace
12117330f729Sjoerg
12127330f729Sjoerg class CGObjCMac : public CGObjCCommonMac {
12137330f729Sjoerg private:
12147330f729Sjoerg friend ProtocolMethodLists;
12157330f729Sjoerg
12167330f729Sjoerg ObjCTypesHelper ObjCTypes;
12177330f729Sjoerg
12187330f729Sjoerg /// EmitModuleInfo - Another marker encoding module level
12197330f729Sjoerg /// information.
12207330f729Sjoerg void EmitModuleInfo();
12217330f729Sjoerg
12227330f729Sjoerg /// EmitModuleSymols - Emit module symbols, the list of defined
12237330f729Sjoerg /// classes and categories. The result has type SymtabPtrTy.
12247330f729Sjoerg llvm::Constant *EmitModuleSymbols();
12257330f729Sjoerg
12267330f729Sjoerg /// FinishModule - Write out global data structures at the end of
12277330f729Sjoerg /// processing a translation unit.
12287330f729Sjoerg void FinishModule();
12297330f729Sjoerg
12307330f729Sjoerg /// EmitClassExtension - Generate the class extension structure used
12317330f729Sjoerg /// to store the weak ivar layout and properties. The return value
12327330f729Sjoerg /// has type ClassExtensionPtrTy.
12337330f729Sjoerg llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID,
12347330f729Sjoerg CharUnits instanceSize,
12357330f729Sjoerg bool hasMRCWeakIvars,
12367330f729Sjoerg bool isMetaclass);
12377330f729Sjoerg
12387330f729Sjoerg /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
12397330f729Sjoerg /// for the given class.
12407330f729Sjoerg llvm::Value *EmitClassRef(CodeGenFunction &CGF,
12417330f729Sjoerg const ObjCInterfaceDecl *ID);
12427330f729Sjoerg
12437330f729Sjoerg llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
12447330f729Sjoerg IdentifierInfo *II);
12457330f729Sjoerg
12467330f729Sjoerg llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
12477330f729Sjoerg
12487330f729Sjoerg /// EmitSuperClassRef - Emits reference to class's main metadata class.
12497330f729Sjoerg llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
12507330f729Sjoerg
12517330f729Sjoerg /// EmitIvarList - Emit the ivar list for the given
12527330f729Sjoerg /// implementation. If ForClass is true the list of class ivars
12537330f729Sjoerg /// (i.e. metaclass ivars) is emitted, otherwise the list of
12547330f729Sjoerg /// interface ivars will be emitted. The return value has type
12557330f729Sjoerg /// IvarListPtrTy.
12567330f729Sjoerg llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID,
12577330f729Sjoerg bool ForClass);
12587330f729Sjoerg
12597330f729Sjoerg /// EmitMetaClass - Emit a forward reference to the class structure
12607330f729Sjoerg /// for the metaclass of the given interface. The return value has
12617330f729Sjoerg /// type ClassPtrTy.
12627330f729Sjoerg llvm::Constant *EmitMetaClassRef(const ObjCInterfaceDecl *ID);
12637330f729Sjoerg
12647330f729Sjoerg /// EmitMetaClass - Emit a class structure for the metaclass of the
12657330f729Sjoerg /// given implementation. The return value has type ClassPtrTy.
12667330f729Sjoerg llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
12677330f729Sjoerg llvm::Constant *Protocols,
12687330f729Sjoerg ArrayRef<const ObjCMethodDecl *> Methods);
12697330f729Sjoerg
12707330f729Sjoerg void emitMethodConstant(ConstantArrayBuilder &builder,
12717330f729Sjoerg const ObjCMethodDecl *MD);
12727330f729Sjoerg
12737330f729Sjoerg void emitMethodDescriptionConstant(ConstantArrayBuilder &builder,
12747330f729Sjoerg const ObjCMethodDecl *MD);
12757330f729Sjoerg
12767330f729Sjoerg /// EmitMethodList - Emit the method list for the given
12777330f729Sjoerg /// implementation. The return value has type MethodListPtrTy.
12787330f729Sjoerg llvm::Constant *emitMethodList(Twine Name, MethodListType MLT,
12797330f729Sjoerg ArrayRef<const ObjCMethodDecl *> Methods);
12807330f729Sjoerg
12817330f729Sjoerg /// GetOrEmitProtocol - Get the protocol object for the given
12827330f729Sjoerg /// declaration, emitting it if necessary. The return value has type
12837330f729Sjoerg /// ProtocolPtrTy.
12847330f729Sjoerg llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override;
12857330f729Sjoerg
12867330f729Sjoerg /// GetOrEmitProtocolRef - Get a forward reference to the protocol
12877330f729Sjoerg /// object for the given declaration, emitting it if needed. These
12887330f729Sjoerg /// forward references will be filled in with empty bodies if no
12897330f729Sjoerg /// definition is seen. The return value has type ProtocolPtrTy.
12907330f729Sjoerg llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) override;
12917330f729Sjoerg
12927330f729Sjoerg /// EmitProtocolExtension - Generate the protocol extension
12937330f729Sjoerg /// structure used to store optional instance and class methods, and
12947330f729Sjoerg /// protocol properties. The return value has type
12957330f729Sjoerg /// ProtocolExtensionPtrTy.
12967330f729Sjoerg llvm::Constant *
12977330f729Sjoerg EmitProtocolExtension(const ObjCProtocolDecl *PD,
12987330f729Sjoerg const ProtocolMethodLists &methodLists);
12997330f729Sjoerg
13007330f729Sjoerg /// EmitProtocolList - Generate the list of referenced
13017330f729Sjoerg /// protocols. The return value has type ProtocolListPtrTy.
13027330f729Sjoerg llvm::Constant *EmitProtocolList(Twine Name,
13037330f729Sjoerg ObjCProtocolDecl::protocol_iterator begin,
13047330f729Sjoerg ObjCProtocolDecl::protocol_iterator end);
13057330f729Sjoerg
13067330f729Sjoerg /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
13077330f729Sjoerg /// for the given selector.
13087330f729Sjoerg llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
1309*e038c9c4Sjoerg Address EmitSelectorAddr(Selector Sel);
13107330f729Sjoerg
13117330f729Sjoerg public:
13127330f729Sjoerg CGObjCMac(CodeGen::CodeGenModule &cgm);
13137330f729Sjoerg
13147330f729Sjoerg llvm::Constant *getNSConstantStringClassRef() override;
13157330f729Sjoerg
13167330f729Sjoerg llvm::Function *ModuleInitFunction() override;
13177330f729Sjoerg
13187330f729Sjoerg CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
13197330f729Sjoerg ReturnValueSlot Return,
13207330f729Sjoerg QualType ResultType,
13217330f729Sjoerg Selector Sel, llvm::Value *Receiver,
13227330f729Sjoerg const CallArgList &CallArgs,
13237330f729Sjoerg const ObjCInterfaceDecl *Class,
13247330f729Sjoerg const ObjCMethodDecl *Method) override;
13257330f729Sjoerg
13267330f729Sjoerg CodeGen::RValue
13277330f729Sjoerg GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
13287330f729Sjoerg ReturnValueSlot Return, QualType ResultType,
13297330f729Sjoerg Selector Sel, const ObjCInterfaceDecl *Class,
13307330f729Sjoerg bool isCategoryImpl, llvm::Value *Receiver,
13317330f729Sjoerg bool IsClassMessage, const CallArgList &CallArgs,
13327330f729Sjoerg const ObjCMethodDecl *Method) override;
13337330f729Sjoerg
13347330f729Sjoerg llvm::Value *GetClass(CodeGenFunction &CGF,
13357330f729Sjoerg const ObjCInterfaceDecl *ID) override;
13367330f729Sjoerg
13377330f729Sjoerg llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override;
13387330f729Sjoerg Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override;
13397330f729Sjoerg
13407330f729Sjoerg /// The NeXT/Apple runtimes do not support typed selectors; just emit an
13417330f729Sjoerg /// untyped one.
13427330f729Sjoerg llvm::Value *GetSelector(CodeGenFunction &CGF,
13437330f729Sjoerg const ObjCMethodDecl *Method) override;
13447330f729Sjoerg
13457330f729Sjoerg llvm::Constant *GetEHType(QualType T) override;
13467330f729Sjoerg
13477330f729Sjoerg void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
13487330f729Sjoerg
13497330f729Sjoerg void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
13507330f729Sjoerg
RegisterAlias(const ObjCCompatibleAliasDecl * OAD)13517330f729Sjoerg void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override {}
13527330f729Sjoerg
13537330f729Sjoerg llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
13547330f729Sjoerg const ObjCProtocolDecl *PD) override;
13557330f729Sjoerg
13567330f729Sjoerg llvm::FunctionCallee GetPropertyGetFunction() override;
13577330f729Sjoerg llvm::FunctionCallee GetPropertySetFunction() override;
13587330f729Sjoerg llvm::FunctionCallee GetOptimizedPropertySetFunction(bool atomic,
13597330f729Sjoerg bool copy) override;
13607330f729Sjoerg llvm::FunctionCallee GetGetStructFunction() override;
13617330f729Sjoerg llvm::FunctionCallee GetSetStructFunction() override;
13627330f729Sjoerg llvm::FunctionCallee GetCppAtomicObjectGetFunction() override;
13637330f729Sjoerg llvm::FunctionCallee GetCppAtomicObjectSetFunction() override;
13647330f729Sjoerg llvm::FunctionCallee EnumerationMutationFunction() override;
13657330f729Sjoerg
13667330f729Sjoerg void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
13677330f729Sjoerg const ObjCAtTryStmt &S) override;
13687330f729Sjoerg void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
13697330f729Sjoerg const ObjCAtSynchronizedStmt &S) override;
13707330f729Sjoerg void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S);
13717330f729Sjoerg void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
13727330f729Sjoerg bool ClearInsertionPoint=true) override;
13737330f729Sjoerg llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
13747330f729Sjoerg Address AddrWeakObj) override;
13757330f729Sjoerg void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
13767330f729Sjoerg llvm::Value *src, Address dst) override;
13777330f729Sjoerg void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
13787330f729Sjoerg llvm::Value *src, Address dest,
13797330f729Sjoerg bool threadlocal = false) override;
13807330f729Sjoerg void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
13817330f729Sjoerg llvm::Value *src, Address dest,
13827330f729Sjoerg llvm::Value *ivarOffset) override;
13837330f729Sjoerg void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
13847330f729Sjoerg llvm::Value *src, Address dest) override;
13857330f729Sjoerg void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
13867330f729Sjoerg Address dest, Address src,
13877330f729Sjoerg llvm::Value *size) override;
13887330f729Sjoerg
13897330f729Sjoerg LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
13907330f729Sjoerg llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
13917330f729Sjoerg unsigned CVRQualifiers) override;
13927330f729Sjoerg llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
13937330f729Sjoerg const ObjCInterfaceDecl *Interface,
13947330f729Sjoerg const ObjCIvarDecl *Ivar) override;
13957330f729Sjoerg };
13967330f729Sjoerg
13977330f729Sjoerg class CGObjCNonFragileABIMac : public CGObjCCommonMac {
13987330f729Sjoerg private:
13997330f729Sjoerg friend ProtocolMethodLists;
14007330f729Sjoerg ObjCNonFragileABITypesHelper ObjCTypes;
14017330f729Sjoerg llvm::GlobalVariable* ObjCEmptyCacheVar;
14027330f729Sjoerg llvm::Constant* ObjCEmptyVtableVar;
14037330f729Sjoerg
14047330f729Sjoerg /// SuperClassReferences - uniqued super class references.
14057330f729Sjoerg llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> SuperClassReferences;
14067330f729Sjoerg
14077330f729Sjoerg /// MetaClassReferences - uniqued meta class references.
14087330f729Sjoerg llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> MetaClassReferences;
14097330f729Sjoerg
14107330f729Sjoerg /// EHTypeReferences - uniqued class ehtype references.
14117330f729Sjoerg llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
14127330f729Sjoerg
14137330f729Sjoerg /// VTableDispatchMethods - List of methods for which we generate
14147330f729Sjoerg /// vtable-based message dispatch.
14157330f729Sjoerg llvm::DenseSet<Selector> VTableDispatchMethods;
14167330f729Sjoerg
14177330f729Sjoerg /// DefinedMetaClasses - List of defined meta-classes.
14187330f729Sjoerg std::vector<llvm::GlobalValue*> DefinedMetaClasses;
14197330f729Sjoerg
14207330f729Sjoerg /// isVTableDispatchedSelector - Returns true if SEL is a
14217330f729Sjoerg /// vtable-based selector.
14227330f729Sjoerg bool isVTableDispatchedSelector(Selector Sel);
14237330f729Sjoerg
14247330f729Sjoerg /// FinishNonFragileABIModule - Write out global data structures at the end of
14257330f729Sjoerg /// processing a translation unit.
14267330f729Sjoerg void FinishNonFragileABIModule();
14277330f729Sjoerg
14287330f729Sjoerg /// AddModuleClassList - Add the given list of class pointers to the
14297330f729Sjoerg /// module with the provided symbol and section names.
14307330f729Sjoerg void AddModuleClassList(ArrayRef<llvm::GlobalValue *> Container,
14317330f729Sjoerg StringRef SymbolName, StringRef SectionName);
14327330f729Sjoerg
14337330f729Sjoerg llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags,
14347330f729Sjoerg unsigned InstanceStart,
14357330f729Sjoerg unsigned InstanceSize,
14367330f729Sjoerg const ObjCImplementationDecl *ID);
14377330f729Sjoerg llvm::GlobalVariable *BuildClassObject(const ObjCInterfaceDecl *CI,
14387330f729Sjoerg bool isMetaclass,
14397330f729Sjoerg llvm::Constant *IsAGV,
14407330f729Sjoerg llvm::Constant *SuperClassGV,
14417330f729Sjoerg llvm::Constant *ClassRoGV,
14427330f729Sjoerg bool HiddenVisibility);
14437330f729Sjoerg
14447330f729Sjoerg void emitMethodConstant(ConstantArrayBuilder &builder,
14457330f729Sjoerg const ObjCMethodDecl *MD,
14467330f729Sjoerg bool forProtocol);
14477330f729Sjoerg
14487330f729Sjoerg /// Emit the method list for the given implementation. The return value
14497330f729Sjoerg /// has type MethodListnfABITy.
14507330f729Sjoerg llvm::Constant *emitMethodList(Twine Name, MethodListType MLT,
14517330f729Sjoerg ArrayRef<const ObjCMethodDecl *> Methods);
14527330f729Sjoerg
14537330f729Sjoerg /// EmitIvarList - Emit the ivar list for the given
14547330f729Sjoerg /// implementation. If ForClass is true the list of class ivars
14557330f729Sjoerg /// (i.e. metaclass ivars) is emitted, otherwise the list of
14567330f729Sjoerg /// interface ivars will be emitted. The return value has type
14577330f729Sjoerg /// IvarListnfABIPtrTy.
14587330f729Sjoerg llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID);
14597330f729Sjoerg
14607330f729Sjoerg llvm::Constant *EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
14617330f729Sjoerg const ObjCIvarDecl *Ivar,
14627330f729Sjoerg unsigned long int offset);
14637330f729Sjoerg
14647330f729Sjoerg /// GetOrEmitProtocol - Get the protocol object for the given
14657330f729Sjoerg /// declaration, emitting it if necessary. The return value has type
14667330f729Sjoerg /// ProtocolPtrTy.
14677330f729Sjoerg llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override;
14687330f729Sjoerg
14697330f729Sjoerg /// GetOrEmitProtocolRef - Get a forward reference to the protocol
14707330f729Sjoerg /// object for the given declaration, emitting it if needed. These
14717330f729Sjoerg /// forward references will be filled in with empty bodies if no
14727330f729Sjoerg /// definition is seen. The return value has type ProtocolPtrTy.
14737330f729Sjoerg llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) override;
14747330f729Sjoerg
14757330f729Sjoerg /// EmitProtocolList - Generate the list of referenced
14767330f729Sjoerg /// protocols. The return value has type ProtocolListPtrTy.
14777330f729Sjoerg llvm::Constant *EmitProtocolList(Twine Name,
14787330f729Sjoerg ObjCProtocolDecl::protocol_iterator begin,
14797330f729Sjoerg ObjCProtocolDecl::protocol_iterator end);
14807330f729Sjoerg
14817330f729Sjoerg CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF,
14827330f729Sjoerg ReturnValueSlot Return,
14837330f729Sjoerg QualType ResultType,
14847330f729Sjoerg Selector Sel,
14857330f729Sjoerg llvm::Value *Receiver,
14867330f729Sjoerg QualType Arg0Ty,
14877330f729Sjoerg bool IsSuper,
14887330f729Sjoerg const CallArgList &CallArgs,
14897330f729Sjoerg const ObjCMethodDecl *Method);
14907330f729Sjoerg
14917330f729Sjoerg /// GetClassGlobal - Return the global variable for the Objective-C
14927330f729Sjoerg /// class of the given name.
14937330f729Sjoerg llvm::Constant *GetClassGlobal(StringRef Name,
14947330f729Sjoerg ForDefinition_t IsForDefinition,
14957330f729Sjoerg bool Weak = false, bool DLLImport = false);
14967330f729Sjoerg llvm::Constant *GetClassGlobal(const ObjCInterfaceDecl *ID,
14977330f729Sjoerg bool isMetaclass,
14987330f729Sjoerg ForDefinition_t isForDefinition);
14997330f729Sjoerg
15007330f729Sjoerg llvm::Constant *GetClassGlobalForClassRef(const ObjCInterfaceDecl *ID);
15017330f729Sjoerg
15027330f729Sjoerg llvm::Value *EmitLoadOfClassRef(CodeGenFunction &CGF,
15037330f729Sjoerg const ObjCInterfaceDecl *ID,
15047330f729Sjoerg llvm::GlobalVariable *Entry);
15057330f729Sjoerg
15067330f729Sjoerg /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
15077330f729Sjoerg /// for the given class reference.
15087330f729Sjoerg llvm::Value *EmitClassRef(CodeGenFunction &CGF,
15097330f729Sjoerg const ObjCInterfaceDecl *ID);
15107330f729Sjoerg
15117330f729Sjoerg llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
15127330f729Sjoerg IdentifierInfo *II,
15137330f729Sjoerg const ObjCInterfaceDecl *ID);
15147330f729Sjoerg
15157330f729Sjoerg llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
15167330f729Sjoerg
15177330f729Sjoerg /// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
15187330f729Sjoerg /// for the given super class reference.
15197330f729Sjoerg llvm::Value *EmitSuperClassRef(CodeGenFunction &CGF,
15207330f729Sjoerg const ObjCInterfaceDecl *ID);
15217330f729Sjoerg
15227330f729Sjoerg /// EmitMetaClassRef - Return a Value * of the address of _class_t
15237330f729Sjoerg /// meta-data
15247330f729Sjoerg llvm::Value *EmitMetaClassRef(CodeGenFunction &CGF,
15257330f729Sjoerg const ObjCInterfaceDecl *ID, bool Weak);
15267330f729Sjoerg
15277330f729Sjoerg /// ObjCIvarOffsetVariable - Returns the ivar offset variable for
15287330f729Sjoerg /// the given ivar.
15297330f729Sjoerg ///
15307330f729Sjoerg llvm::GlobalVariable * ObjCIvarOffsetVariable(
15317330f729Sjoerg const ObjCInterfaceDecl *ID,
15327330f729Sjoerg const ObjCIvarDecl *Ivar);
15337330f729Sjoerg
15347330f729Sjoerg /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
15357330f729Sjoerg /// for the given selector.
15367330f729Sjoerg llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
1537*e038c9c4Sjoerg Address EmitSelectorAddr(Selector Sel);
15387330f729Sjoerg
15397330f729Sjoerg /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
15407330f729Sjoerg /// interface. The return value has type EHTypePtrTy.
15417330f729Sjoerg llvm::Constant *GetInterfaceEHType(const ObjCInterfaceDecl *ID,
15427330f729Sjoerg ForDefinition_t IsForDefinition);
15437330f729Sjoerg
getMetaclassSymbolPrefix() const15447330f729Sjoerg StringRef getMetaclassSymbolPrefix() const { return "OBJC_METACLASS_$_"; }
15457330f729Sjoerg
getClassSymbolPrefix() const15467330f729Sjoerg StringRef getClassSymbolPrefix() const { return "OBJC_CLASS_$_"; }
15477330f729Sjoerg
15487330f729Sjoerg void GetClassSizeInfo(const ObjCImplementationDecl *OID,
15497330f729Sjoerg uint32_t &InstanceStart,
15507330f729Sjoerg uint32_t &InstanceSize);
15517330f729Sjoerg
15527330f729Sjoerg // Shamelessly stolen from Analysis/CFRefCount.cpp
GetNullarySelector(const char * name) const15537330f729Sjoerg Selector GetNullarySelector(const char* name) const {
15547330f729Sjoerg IdentifierInfo* II = &CGM.getContext().Idents.get(name);
15557330f729Sjoerg return CGM.getContext().Selectors.getSelector(0, &II);
15567330f729Sjoerg }
15577330f729Sjoerg
GetUnarySelector(const char * name) const15587330f729Sjoerg Selector GetUnarySelector(const char* name) const {
15597330f729Sjoerg IdentifierInfo* II = &CGM.getContext().Idents.get(name);
15607330f729Sjoerg return CGM.getContext().Selectors.getSelector(1, &II);
15617330f729Sjoerg }
15627330f729Sjoerg
15637330f729Sjoerg /// ImplementationIsNonLazy - Check whether the given category or
15647330f729Sjoerg /// class implementation is "non-lazy".
15657330f729Sjoerg bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const;
15667330f729Sjoerg
IsIvarOffsetKnownIdempotent(const CodeGen::CodeGenFunction & CGF,const ObjCIvarDecl * IV)15677330f729Sjoerg bool IsIvarOffsetKnownIdempotent(const CodeGen::CodeGenFunction &CGF,
15687330f729Sjoerg const ObjCIvarDecl *IV) {
15697330f729Sjoerg // Annotate the load as an invariant load iff inside an instance method
15707330f729Sjoerg // and ivar belongs to instance method's class and one of its super class.
15717330f729Sjoerg // This check is needed because the ivar offset is a lazily
15727330f729Sjoerg // initialised value that may depend on objc_msgSend to perform a fixup on
15737330f729Sjoerg // the first message dispatch.
15747330f729Sjoerg //
15757330f729Sjoerg // An additional opportunity to mark the load as invariant arises when the
15767330f729Sjoerg // base of the ivar access is a parameter to an Objective C method.
15777330f729Sjoerg // However, because the parameters are not available in the current
15787330f729Sjoerg // interface, we cannot perform this check.
1579*e038c9c4Sjoerg //
1580*e038c9c4Sjoerg // Note that for direct methods, because objc_msgSend is skipped,
1581*e038c9c4Sjoerg // and that the method may be inlined, this optimization actually
1582*e038c9c4Sjoerg // can't be performed.
15837330f729Sjoerg if (const ObjCMethodDecl *MD =
15847330f729Sjoerg dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
1585*e038c9c4Sjoerg if (MD->isInstanceMethod() && !MD->isDirectMethod())
15867330f729Sjoerg if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
15877330f729Sjoerg return IV->getContainingInterface()->isSuperClassOf(ID);
15887330f729Sjoerg return false;
15897330f729Sjoerg }
15907330f729Sjoerg
isClassLayoutKnownStatically(const ObjCInterfaceDecl * ID)15917330f729Sjoerg bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
15927330f729Sjoerg // NSObject is a fixed size. If we can see the @implementation of a class
15937330f729Sjoerg // which inherits from NSObject then we know that all it's offsets also must
15947330f729Sjoerg // be fixed. FIXME: Can we do this if see a chain of super classes with
15957330f729Sjoerg // implementations leading to NSObject?
15967330f729Sjoerg return ID->getImplementation() && ID->getSuperClass() &&
15977330f729Sjoerg ID->getSuperClass()->getName() == "NSObject";
15987330f729Sjoerg }
15997330f729Sjoerg
16007330f729Sjoerg public:
16017330f729Sjoerg CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
16027330f729Sjoerg
16037330f729Sjoerg llvm::Constant *getNSConstantStringClassRef() override;
16047330f729Sjoerg
16057330f729Sjoerg llvm::Function *ModuleInitFunction() override;
16067330f729Sjoerg
16077330f729Sjoerg CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
16087330f729Sjoerg ReturnValueSlot Return,
16097330f729Sjoerg QualType ResultType, Selector Sel,
16107330f729Sjoerg llvm::Value *Receiver,
16117330f729Sjoerg const CallArgList &CallArgs,
16127330f729Sjoerg const ObjCInterfaceDecl *Class,
16137330f729Sjoerg const ObjCMethodDecl *Method) override;
16147330f729Sjoerg
16157330f729Sjoerg CodeGen::RValue
16167330f729Sjoerg GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
16177330f729Sjoerg ReturnValueSlot Return, QualType ResultType,
16187330f729Sjoerg Selector Sel, const ObjCInterfaceDecl *Class,
16197330f729Sjoerg bool isCategoryImpl, llvm::Value *Receiver,
16207330f729Sjoerg bool IsClassMessage, const CallArgList &CallArgs,
16217330f729Sjoerg const ObjCMethodDecl *Method) override;
16227330f729Sjoerg
16237330f729Sjoerg llvm::Value *GetClass(CodeGenFunction &CGF,
16247330f729Sjoerg const ObjCInterfaceDecl *ID) override;
16257330f729Sjoerg
GetSelector(CodeGenFunction & CGF,Selector Sel)16267330f729Sjoerg llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override
16277330f729Sjoerg { return EmitSelector(CGF, Sel); }
GetAddrOfSelector(CodeGenFunction & CGF,Selector Sel)16287330f729Sjoerg Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override
1629*e038c9c4Sjoerg { return EmitSelectorAddr(Sel); }
16307330f729Sjoerg
16317330f729Sjoerg /// The NeXT/Apple runtimes do not support typed selectors; just emit an
16327330f729Sjoerg /// untyped one.
GetSelector(CodeGenFunction & CGF,const ObjCMethodDecl * Method)16337330f729Sjoerg llvm::Value *GetSelector(CodeGenFunction &CGF,
16347330f729Sjoerg const ObjCMethodDecl *Method) override
16357330f729Sjoerg { return EmitSelector(CGF, Method->getSelector()); }
16367330f729Sjoerg
16377330f729Sjoerg void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
16387330f729Sjoerg
16397330f729Sjoerg void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
16407330f729Sjoerg
RegisterAlias(const ObjCCompatibleAliasDecl * OAD)16417330f729Sjoerg void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override {}
16427330f729Sjoerg
16437330f729Sjoerg llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
16447330f729Sjoerg const ObjCProtocolDecl *PD) override;
16457330f729Sjoerg
16467330f729Sjoerg llvm::Constant *GetEHType(QualType T) override;
16477330f729Sjoerg
GetPropertyGetFunction()16487330f729Sjoerg llvm::FunctionCallee GetPropertyGetFunction() override {
16497330f729Sjoerg return ObjCTypes.getGetPropertyFn();
16507330f729Sjoerg }
GetPropertySetFunction()16517330f729Sjoerg llvm::FunctionCallee GetPropertySetFunction() override {
16527330f729Sjoerg return ObjCTypes.getSetPropertyFn();
16537330f729Sjoerg }
16547330f729Sjoerg
GetOptimizedPropertySetFunction(bool atomic,bool copy)16557330f729Sjoerg llvm::FunctionCallee GetOptimizedPropertySetFunction(bool atomic,
16567330f729Sjoerg bool copy) override {
16577330f729Sjoerg return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
16587330f729Sjoerg }
16597330f729Sjoerg
GetSetStructFunction()16607330f729Sjoerg llvm::FunctionCallee GetSetStructFunction() override {
16617330f729Sjoerg return ObjCTypes.getCopyStructFn();
16627330f729Sjoerg }
16637330f729Sjoerg
GetGetStructFunction()16647330f729Sjoerg llvm::FunctionCallee GetGetStructFunction() override {
16657330f729Sjoerg return ObjCTypes.getCopyStructFn();
16667330f729Sjoerg }
16677330f729Sjoerg
GetCppAtomicObjectSetFunction()16687330f729Sjoerg llvm::FunctionCallee GetCppAtomicObjectSetFunction() override {
16697330f729Sjoerg return ObjCTypes.getCppAtomicObjectFunction();
16707330f729Sjoerg }
16717330f729Sjoerg
GetCppAtomicObjectGetFunction()16727330f729Sjoerg llvm::FunctionCallee GetCppAtomicObjectGetFunction() override {
16737330f729Sjoerg return ObjCTypes.getCppAtomicObjectFunction();
16747330f729Sjoerg }
16757330f729Sjoerg
EnumerationMutationFunction()16767330f729Sjoerg llvm::FunctionCallee EnumerationMutationFunction() override {
16777330f729Sjoerg return ObjCTypes.getEnumerationMutationFn();
16787330f729Sjoerg }
16797330f729Sjoerg
16807330f729Sjoerg void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
16817330f729Sjoerg const ObjCAtTryStmt &S) override;
16827330f729Sjoerg void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
16837330f729Sjoerg const ObjCAtSynchronizedStmt &S) override;
16847330f729Sjoerg void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
16857330f729Sjoerg bool ClearInsertionPoint=true) override;
16867330f729Sjoerg llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
16877330f729Sjoerg Address AddrWeakObj) override;
16887330f729Sjoerg void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
16897330f729Sjoerg llvm::Value *src, Address edst) override;
16907330f729Sjoerg void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
16917330f729Sjoerg llvm::Value *src, Address dest,
16927330f729Sjoerg bool threadlocal = false) override;
16937330f729Sjoerg void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
16947330f729Sjoerg llvm::Value *src, Address dest,
16957330f729Sjoerg llvm::Value *ivarOffset) override;
16967330f729Sjoerg void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
16977330f729Sjoerg llvm::Value *src, Address dest) override;
16987330f729Sjoerg void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
16997330f729Sjoerg Address dest, Address src,
17007330f729Sjoerg llvm::Value *size) override;
17017330f729Sjoerg LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
17027330f729Sjoerg llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
17037330f729Sjoerg unsigned CVRQualifiers) override;
17047330f729Sjoerg llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
17057330f729Sjoerg const ObjCInterfaceDecl *Interface,
17067330f729Sjoerg const ObjCIvarDecl *Ivar) override;
17077330f729Sjoerg };
17087330f729Sjoerg
17097330f729Sjoerg /// A helper class for performing the null-initialization of a return
17107330f729Sjoerg /// value.
17117330f729Sjoerg struct NullReturnState {
17127330f729Sjoerg llvm::BasicBlock *NullBB;
NullReturnState__anon0cc8f9a20111::NullReturnState17137330f729Sjoerg NullReturnState() : NullBB(nullptr) {}
17147330f729Sjoerg
17157330f729Sjoerg /// Perform a null-check of the given receiver.
init__anon0cc8f9a20111::NullReturnState17167330f729Sjoerg void init(CodeGenFunction &CGF, llvm::Value *receiver) {
17177330f729Sjoerg // Make blocks for the null-receiver and call edges.
17187330f729Sjoerg NullBB = CGF.createBasicBlock("msgSend.null-receiver");
17197330f729Sjoerg llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call");
17207330f729Sjoerg
17217330f729Sjoerg // Check for a null receiver and, if there is one, jump to the
17227330f729Sjoerg // null-receiver block. There's no point in trying to avoid it:
17237330f729Sjoerg // we're always going to put *something* there, because otherwise
17247330f729Sjoerg // we shouldn't have done this null-check in the first place.
17257330f729Sjoerg llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
17267330f729Sjoerg CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
17277330f729Sjoerg
17287330f729Sjoerg // Otherwise, start performing the call.
17297330f729Sjoerg CGF.EmitBlock(callBB);
17307330f729Sjoerg }
17317330f729Sjoerg
17327330f729Sjoerg /// Complete the null-return operation. It is valid to call this
17337330f729Sjoerg /// regardless of whether 'init' has been called.
complete__anon0cc8f9a20111::NullReturnState17347330f729Sjoerg RValue complete(CodeGenFunction &CGF,
17357330f729Sjoerg ReturnValueSlot returnSlot,
17367330f729Sjoerg RValue result,
17377330f729Sjoerg QualType resultType,
17387330f729Sjoerg const CallArgList &CallArgs,
17397330f729Sjoerg const ObjCMethodDecl *Method) {
17407330f729Sjoerg // If we never had to do a null-check, just use the raw result.
17417330f729Sjoerg if (!NullBB) return result;
17427330f729Sjoerg
17437330f729Sjoerg // The continuation block. This will be left null if we don't have an
17447330f729Sjoerg // IP, which can happen if the method we're calling is marked noreturn.
17457330f729Sjoerg llvm::BasicBlock *contBB = nullptr;
17467330f729Sjoerg
17477330f729Sjoerg // Finish the call path.
17487330f729Sjoerg llvm::BasicBlock *callBB = CGF.Builder.GetInsertBlock();
17497330f729Sjoerg if (callBB) {
17507330f729Sjoerg contBB = CGF.createBasicBlock("msgSend.cont");
17517330f729Sjoerg CGF.Builder.CreateBr(contBB);
17527330f729Sjoerg }
17537330f729Sjoerg
17547330f729Sjoerg // Okay, start emitting the null-receiver block.
17557330f729Sjoerg CGF.EmitBlock(NullBB);
17567330f729Sjoerg
17577330f729Sjoerg // Release any consumed arguments we've got.
17587330f729Sjoerg if (Method) {
17597330f729Sjoerg CallArgList::const_iterator I = CallArgs.begin();
17607330f729Sjoerg for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
17617330f729Sjoerg e = Method->param_end(); i != e; ++i, ++I) {
17627330f729Sjoerg const ParmVarDecl *ParamDecl = (*i);
17637330f729Sjoerg if (ParamDecl->hasAttr<NSConsumedAttr>()) {
17647330f729Sjoerg RValue RV = I->getRValue(CGF);
17657330f729Sjoerg assert(RV.isScalar() &&
17667330f729Sjoerg "NullReturnState::complete - arg not on object");
17677330f729Sjoerg CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime);
1768*e038c9c4Sjoerg } else {
1769*e038c9c4Sjoerg QualType QT = ParamDecl->getType();
1770*e038c9c4Sjoerg auto *RT = QT->getAs<RecordType>();
1771*e038c9c4Sjoerg if (RT && RT->getDecl()->isParamDestroyedInCallee()) {
1772*e038c9c4Sjoerg RValue RV = I->getRValue(CGF);
1773*e038c9c4Sjoerg QualType::DestructionKind DtorKind = QT.isDestructedType();
1774*e038c9c4Sjoerg switch (DtorKind) {
1775*e038c9c4Sjoerg case QualType::DK_cxx_destructor:
1776*e038c9c4Sjoerg CGF.destroyCXXObject(CGF, RV.getAggregateAddress(), QT);
1777*e038c9c4Sjoerg break;
1778*e038c9c4Sjoerg case QualType::DK_nontrivial_c_struct:
1779*e038c9c4Sjoerg CGF.destroyNonTrivialCStruct(CGF, RV.getAggregateAddress(), QT);
1780*e038c9c4Sjoerg break;
1781*e038c9c4Sjoerg default:
1782*e038c9c4Sjoerg llvm_unreachable("unexpected dtor kind");
1783*e038c9c4Sjoerg break;
1784*e038c9c4Sjoerg }
1785*e038c9c4Sjoerg }
17867330f729Sjoerg }
17877330f729Sjoerg }
17887330f729Sjoerg }
17897330f729Sjoerg
17907330f729Sjoerg // The phi code below assumes that we haven't needed any control flow yet.
17917330f729Sjoerg assert(CGF.Builder.GetInsertBlock() == NullBB);
17927330f729Sjoerg
17937330f729Sjoerg // If we've got a void return, just jump to the continuation block.
17947330f729Sjoerg if (result.isScalar() && resultType->isVoidType()) {
17957330f729Sjoerg // No jumps required if the message-send was noreturn.
17967330f729Sjoerg if (contBB) CGF.EmitBlock(contBB);
17977330f729Sjoerg return result;
17987330f729Sjoerg }
17997330f729Sjoerg
18007330f729Sjoerg // If we've got a scalar return, build a phi.
18017330f729Sjoerg if (result.isScalar()) {
18027330f729Sjoerg // Derive the null-initialization value.
1803*e038c9c4Sjoerg llvm::Value *null =
1804*e038c9c4Sjoerg CGF.EmitFromMemory(CGF.CGM.EmitNullConstant(resultType), resultType);
18057330f729Sjoerg
18067330f729Sjoerg // If no join is necessary, just flow out.
18077330f729Sjoerg if (!contBB) return RValue::get(null);
18087330f729Sjoerg
18097330f729Sjoerg // Otherwise, build a phi.
18107330f729Sjoerg CGF.EmitBlock(contBB);
18117330f729Sjoerg llvm::PHINode *phi = CGF.Builder.CreatePHI(null->getType(), 2);
18127330f729Sjoerg phi->addIncoming(result.getScalarVal(), callBB);
18137330f729Sjoerg phi->addIncoming(null, NullBB);
18147330f729Sjoerg return RValue::get(phi);
18157330f729Sjoerg }
18167330f729Sjoerg
18177330f729Sjoerg // If we've got an aggregate return, null the buffer out.
18187330f729Sjoerg // FIXME: maybe we should be doing things differently for all the
18197330f729Sjoerg // cases where the ABI has us returning (1) non-agg values in
18207330f729Sjoerg // memory or (2) agg values in registers.
18217330f729Sjoerg if (result.isAggregate()) {
18227330f729Sjoerg assert(result.isAggregate() && "null init of non-aggregate result?");
18237330f729Sjoerg if (!returnSlot.isUnused())
18247330f729Sjoerg CGF.EmitNullInitialization(result.getAggregateAddress(), resultType);
18257330f729Sjoerg if (contBB) CGF.EmitBlock(contBB);
18267330f729Sjoerg return result;
18277330f729Sjoerg }
18287330f729Sjoerg
18297330f729Sjoerg // Complex types.
18307330f729Sjoerg CGF.EmitBlock(contBB);
18317330f729Sjoerg CodeGenFunction::ComplexPairTy callResult = result.getComplexVal();
18327330f729Sjoerg
18337330f729Sjoerg // Find the scalar type and its zero value.
18347330f729Sjoerg llvm::Type *scalarTy = callResult.first->getType();
18357330f729Sjoerg llvm::Constant *scalarZero = llvm::Constant::getNullValue(scalarTy);
18367330f729Sjoerg
18377330f729Sjoerg // Build phis for both coordinates.
18387330f729Sjoerg llvm::PHINode *real = CGF.Builder.CreatePHI(scalarTy, 2);
18397330f729Sjoerg real->addIncoming(callResult.first, callBB);
18407330f729Sjoerg real->addIncoming(scalarZero, NullBB);
18417330f729Sjoerg llvm::PHINode *imag = CGF.Builder.CreatePHI(scalarTy, 2);
18427330f729Sjoerg imag->addIncoming(callResult.second, callBB);
18437330f729Sjoerg imag->addIncoming(scalarZero, NullBB);
18447330f729Sjoerg return RValue::getComplex(real, imag);
18457330f729Sjoerg }
18467330f729Sjoerg };
18477330f729Sjoerg
18487330f729Sjoerg } // end anonymous namespace
18497330f729Sjoerg
18507330f729Sjoerg /* *** Helper Functions *** */
18517330f729Sjoerg
18527330f729Sjoerg /// getConstantGEP() - Help routine to construct simple GEPs.
getConstantGEP(llvm::LLVMContext & VMContext,llvm::GlobalVariable * C,unsigned idx0,unsigned idx1)18537330f729Sjoerg static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext,
18547330f729Sjoerg llvm::GlobalVariable *C, unsigned idx0,
18557330f729Sjoerg unsigned idx1) {
18567330f729Sjoerg llvm::Value *Idxs[] = {
18577330f729Sjoerg llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0),
18587330f729Sjoerg llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx1)
18597330f729Sjoerg };
18607330f729Sjoerg return llvm::ConstantExpr::getGetElementPtr(C->getValueType(), C, Idxs);
18617330f729Sjoerg }
18627330f729Sjoerg
18637330f729Sjoerg /// hasObjCExceptionAttribute - Return true if this class or any super
18647330f729Sjoerg /// class has the __objc_exception__ attribute.
hasObjCExceptionAttribute(ASTContext & Context,const ObjCInterfaceDecl * OID)18657330f729Sjoerg static bool hasObjCExceptionAttribute(ASTContext &Context,
18667330f729Sjoerg const ObjCInterfaceDecl *OID) {
18677330f729Sjoerg if (OID->hasAttr<ObjCExceptionAttr>())
18687330f729Sjoerg return true;
18697330f729Sjoerg if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
18707330f729Sjoerg return hasObjCExceptionAttribute(Context, Super);
18717330f729Sjoerg return false;
18727330f729Sjoerg }
18737330f729Sjoerg
18747330f729Sjoerg static llvm::GlobalValue::LinkageTypes
getLinkageTypeForObjCMetadata(CodeGenModule & CGM,StringRef Section)18757330f729Sjoerg getLinkageTypeForObjCMetadata(CodeGenModule &CGM, StringRef Section) {
18767330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO() &&
18777330f729Sjoerg (Section.empty() || Section.startswith("__DATA")))
18787330f729Sjoerg return llvm::GlobalValue::InternalLinkage;
18797330f729Sjoerg return llvm::GlobalValue::PrivateLinkage;
18807330f729Sjoerg }
18817330f729Sjoerg
18827330f729Sjoerg /// A helper function to create an internal or private global variable.
18837330f729Sjoerg static llvm::GlobalVariable *
finishAndCreateGlobal(ConstantInitBuilder::StructBuilder & Builder,const llvm::Twine & Name,CodeGenModule & CGM)18847330f729Sjoerg finishAndCreateGlobal(ConstantInitBuilder::StructBuilder &Builder,
18857330f729Sjoerg const llvm::Twine &Name, CodeGenModule &CGM) {
18867330f729Sjoerg std::string SectionName;
18877330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO())
18887330f729Sjoerg SectionName = "__DATA, __objc_const";
18897330f729Sjoerg auto *GV = Builder.finishAndCreateGlobal(
18907330f729Sjoerg Name, CGM.getPointerAlign(), /*constant*/ false,
18917330f729Sjoerg getLinkageTypeForObjCMetadata(CGM, SectionName));
18927330f729Sjoerg GV->setSection(SectionName);
18937330f729Sjoerg return GV;
18947330f729Sjoerg }
18957330f729Sjoerg
18967330f729Sjoerg /* *** CGObjCMac Public Interface *** */
18977330f729Sjoerg
CGObjCMac(CodeGen::CodeGenModule & cgm)18987330f729Sjoerg CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
18997330f729Sjoerg ObjCTypes(cgm) {
19007330f729Sjoerg ObjCABI = 1;
19017330f729Sjoerg EmitImageInfo();
19027330f729Sjoerg }
19037330f729Sjoerg
19047330f729Sjoerg /// GetClass - Return a reference to the class for the given interface
19057330f729Sjoerg /// decl.
GetClass(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)19067330f729Sjoerg llvm::Value *CGObjCMac::GetClass(CodeGenFunction &CGF,
19077330f729Sjoerg const ObjCInterfaceDecl *ID) {
19087330f729Sjoerg return EmitClassRef(CGF, ID);
19097330f729Sjoerg }
19107330f729Sjoerg
19117330f729Sjoerg /// GetSelector - Return the pointer to the unique'd string for this selector.
GetSelector(CodeGenFunction & CGF,Selector Sel)19127330f729Sjoerg llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel) {
19137330f729Sjoerg return EmitSelector(CGF, Sel);
19147330f729Sjoerg }
GetAddrOfSelector(CodeGenFunction & CGF,Selector Sel)19157330f729Sjoerg Address CGObjCMac::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) {
1916*e038c9c4Sjoerg return EmitSelectorAddr(Sel);
19177330f729Sjoerg }
GetSelector(CodeGenFunction & CGF,const ObjCMethodDecl * Method)19187330f729Sjoerg llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
19197330f729Sjoerg *Method) {
19207330f729Sjoerg return EmitSelector(CGF, Method->getSelector());
19217330f729Sjoerg }
19227330f729Sjoerg
GetEHType(QualType T)19237330f729Sjoerg llvm::Constant *CGObjCMac::GetEHType(QualType T) {
19247330f729Sjoerg if (T->isObjCIdType() ||
19257330f729Sjoerg T->isObjCQualifiedIdType()) {
19267330f729Sjoerg return CGM.GetAddrOfRTTIDescriptor(
19277330f729Sjoerg CGM.getContext().getObjCIdRedefinitionType(), /*ForEH=*/true);
19287330f729Sjoerg }
19297330f729Sjoerg if (T->isObjCClassType() ||
19307330f729Sjoerg T->isObjCQualifiedClassType()) {
19317330f729Sjoerg return CGM.GetAddrOfRTTIDescriptor(
19327330f729Sjoerg CGM.getContext().getObjCClassRedefinitionType(), /*ForEH=*/true);
19337330f729Sjoerg }
19347330f729Sjoerg if (T->isObjCObjectPointerType())
19357330f729Sjoerg return CGM.GetAddrOfRTTIDescriptor(T, /*ForEH=*/true);
19367330f729Sjoerg
19377330f729Sjoerg llvm_unreachable("asking for catch type for ObjC type in fragile runtime");
19387330f729Sjoerg }
19397330f729Sjoerg
19407330f729Sjoerg /// Generate a constant CFString object.
19417330f729Sjoerg /*
19427330f729Sjoerg struct __builtin_CFString {
19437330f729Sjoerg const int *isa; // point to __CFConstantStringClassReference
19447330f729Sjoerg int flags;
19457330f729Sjoerg const char *str;
19467330f729Sjoerg long length;
19477330f729Sjoerg };
19487330f729Sjoerg */
19497330f729Sjoerg
19507330f729Sjoerg /// or Generate a constant NSString object.
19517330f729Sjoerg /*
19527330f729Sjoerg struct __builtin_NSString {
19537330f729Sjoerg const int *isa; // point to __NSConstantStringClassReference
19547330f729Sjoerg const char *str;
19557330f729Sjoerg unsigned int length;
19567330f729Sjoerg };
19577330f729Sjoerg */
19587330f729Sjoerg
19597330f729Sjoerg ConstantAddress
GenerateConstantString(const StringLiteral * SL)19607330f729Sjoerg CGObjCCommonMac::GenerateConstantString(const StringLiteral *SL) {
19617330f729Sjoerg return (!CGM.getLangOpts().NoConstantCFStrings
19627330f729Sjoerg ? CGM.GetAddrOfConstantCFString(SL)
19637330f729Sjoerg : GenerateConstantNSString(SL));
19647330f729Sjoerg }
19657330f729Sjoerg
19667330f729Sjoerg static llvm::StringMapEntry<llvm::GlobalVariable *> &
GetConstantStringEntry(llvm::StringMap<llvm::GlobalVariable * > & Map,const StringLiteral * Literal,unsigned & StringLength)19677330f729Sjoerg GetConstantStringEntry(llvm::StringMap<llvm::GlobalVariable *> &Map,
19687330f729Sjoerg const StringLiteral *Literal, unsigned &StringLength) {
19697330f729Sjoerg StringRef String = Literal->getString();
19707330f729Sjoerg StringLength = String.size();
19717330f729Sjoerg return *Map.insert(std::make_pair(String, nullptr)).first;
19727330f729Sjoerg }
19737330f729Sjoerg
getNSConstantStringClassRef()19747330f729Sjoerg llvm::Constant *CGObjCMac::getNSConstantStringClassRef() {
19757330f729Sjoerg if (llvm::Value *V = ConstantStringClassRef)
19767330f729Sjoerg return cast<llvm::Constant>(V);
19777330f729Sjoerg
19787330f729Sjoerg auto &StringClass = CGM.getLangOpts().ObjCConstantStringClass;
19797330f729Sjoerg std::string str =
19807330f729Sjoerg StringClass.empty() ? "_NSConstantStringClassReference"
19817330f729Sjoerg : "_" + StringClass + "ClassReference";
19827330f729Sjoerg
19837330f729Sjoerg llvm::Type *PTy = llvm::ArrayType::get(CGM.IntTy, 0);
19847330f729Sjoerg auto GV = CGM.CreateRuntimeVariable(PTy, str);
19857330f729Sjoerg auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo());
19867330f729Sjoerg ConstantStringClassRef = V;
19877330f729Sjoerg return V;
19887330f729Sjoerg }
19897330f729Sjoerg
getNSConstantStringClassRef()19907330f729Sjoerg llvm::Constant *CGObjCNonFragileABIMac::getNSConstantStringClassRef() {
19917330f729Sjoerg if (llvm::Value *V = ConstantStringClassRef)
19927330f729Sjoerg return cast<llvm::Constant>(V);
19937330f729Sjoerg
19947330f729Sjoerg auto &StringClass = CGM.getLangOpts().ObjCConstantStringClass;
19957330f729Sjoerg std::string str =
19967330f729Sjoerg StringClass.empty() ? "OBJC_CLASS_$_NSConstantString"
19977330f729Sjoerg : "OBJC_CLASS_$_" + StringClass;
19987330f729Sjoerg llvm::Constant *GV = GetClassGlobal(str, NotForDefinition);
19997330f729Sjoerg
20007330f729Sjoerg // Make sure the result is of the correct type.
20017330f729Sjoerg auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo());
20027330f729Sjoerg
20037330f729Sjoerg ConstantStringClassRef = V;
20047330f729Sjoerg return V;
20057330f729Sjoerg }
20067330f729Sjoerg
20077330f729Sjoerg ConstantAddress
GenerateConstantNSString(const StringLiteral * Literal)20087330f729Sjoerg CGObjCCommonMac::GenerateConstantNSString(const StringLiteral *Literal) {
20097330f729Sjoerg unsigned StringLength = 0;
20107330f729Sjoerg llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
20117330f729Sjoerg GetConstantStringEntry(NSConstantStringMap, Literal, StringLength);
20127330f729Sjoerg
20137330f729Sjoerg if (auto *C = Entry.second)
20147330f729Sjoerg return ConstantAddress(C, CharUnits::fromQuantity(C->getAlignment()));
20157330f729Sjoerg
20167330f729Sjoerg // If we don't already have it, get _NSConstantStringClassReference.
20177330f729Sjoerg llvm::Constant *Class = getNSConstantStringClassRef();
20187330f729Sjoerg
20197330f729Sjoerg // If we don't already have it, construct the type for a constant NSString.
20207330f729Sjoerg if (!NSConstantStringType) {
20217330f729Sjoerg NSConstantStringType =
20227330f729Sjoerg llvm::StructType::create({
20237330f729Sjoerg CGM.Int32Ty->getPointerTo(),
20247330f729Sjoerg CGM.Int8PtrTy,
20257330f729Sjoerg CGM.IntTy
20267330f729Sjoerg }, "struct.__builtin_NSString");
20277330f729Sjoerg }
20287330f729Sjoerg
20297330f729Sjoerg ConstantInitBuilder Builder(CGM);
20307330f729Sjoerg auto Fields = Builder.beginStruct(NSConstantStringType);
20317330f729Sjoerg
20327330f729Sjoerg // Class pointer.
20337330f729Sjoerg Fields.add(Class);
20347330f729Sjoerg
20357330f729Sjoerg // String pointer.
20367330f729Sjoerg llvm::Constant *C =
20377330f729Sjoerg llvm::ConstantDataArray::getString(VMContext, Entry.first());
20387330f729Sjoerg
20397330f729Sjoerg llvm::GlobalValue::LinkageTypes Linkage = llvm::GlobalValue::PrivateLinkage;
20407330f729Sjoerg bool isConstant = !CGM.getLangOpts().WritableStrings;
20417330f729Sjoerg
20427330f729Sjoerg auto *GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), isConstant,
20437330f729Sjoerg Linkage, C, ".str");
20447330f729Sjoerg GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
20457330f729Sjoerg // Don't enforce the target's minimum global alignment, since the only use
20467330f729Sjoerg // of the string is via this class initializer.
2047*e038c9c4Sjoerg GV->setAlignment(llvm::Align(1));
20487330f729Sjoerg Fields.addBitCast(GV, CGM.Int8PtrTy);
20497330f729Sjoerg
20507330f729Sjoerg // String length.
20517330f729Sjoerg Fields.addInt(CGM.IntTy, StringLength);
20527330f729Sjoerg
20537330f729Sjoerg // The struct.
20547330f729Sjoerg CharUnits Alignment = CGM.getPointerAlign();
20557330f729Sjoerg GV = Fields.finishAndCreateGlobal("_unnamed_nsstring_", Alignment,
20567330f729Sjoerg /*constant*/ true,
20577330f729Sjoerg llvm::GlobalVariable::PrivateLinkage);
20587330f729Sjoerg const char *NSStringSection = "__OBJC,__cstring_object,regular,no_dead_strip";
20597330f729Sjoerg const char *NSStringNonFragileABISection =
20607330f729Sjoerg "__DATA,__objc_stringobj,regular,no_dead_strip";
20617330f729Sjoerg // FIXME. Fix section.
20627330f729Sjoerg GV->setSection(CGM.getLangOpts().ObjCRuntime.isNonFragile()
20637330f729Sjoerg ? NSStringNonFragileABISection
20647330f729Sjoerg : NSStringSection);
20657330f729Sjoerg Entry.second = GV;
20667330f729Sjoerg
20677330f729Sjoerg return ConstantAddress(GV, Alignment);
20687330f729Sjoerg }
20697330f729Sjoerg
20707330f729Sjoerg enum {
20717330f729Sjoerg kCFTaggedObjectID_Integer = (1 << 1) + 1
20727330f729Sjoerg };
20737330f729Sjoerg
20747330f729Sjoerg /// Generates a message send where the super is the receiver. This is
20757330f729Sjoerg /// a message send to self with special delivery semantics indicating
20767330f729Sjoerg /// which class's method should be called.
20777330f729Sjoerg CodeGen::RValue
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)20787330f729Sjoerg CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
20797330f729Sjoerg ReturnValueSlot Return,
20807330f729Sjoerg QualType ResultType,
20817330f729Sjoerg Selector Sel,
20827330f729Sjoerg const ObjCInterfaceDecl *Class,
20837330f729Sjoerg bool isCategoryImpl,
20847330f729Sjoerg llvm::Value *Receiver,
20857330f729Sjoerg bool IsClassMessage,
20867330f729Sjoerg const CodeGen::CallArgList &CallArgs,
20877330f729Sjoerg const ObjCMethodDecl *Method) {
20887330f729Sjoerg // Create and init a super structure; this is a (receiver, class)
20897330f729Sjoerg // pair we will pass to objc_msgSendSuper.
20907330f729Sjoerg Address ObjCSuper =
20917330f729Sjoerg CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(),
20927330f729Sjoerg "objc_super");
20937330f729Sjoerg llvm::Value *ReceiverAsObject =
20947330f729Sjoerg CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
20957330f729Sjoerg CGF.Builder.CreateStore(ReceiverAsObject,
20967330f729Sjoerg CGF.Builder.CreateStructGEP(ObjCSuper, 0));
20977330f729Sjoerg
20987330f729Sjoerg // If this is a class message the metaclass is passed as the target.
2099*e038c9c4Sjoerg llvm::Type *ClassTyPtr = llvm::PointerType::getUnqual(ObjCTypes.ClassTy);
21007330f729Sjoerg llvm::Value *Target;
21017330f729Sjoerg if (IsClassMessage) {
21027330f729Sjoerg if (isCategoryImpl) {
21037330f729Sjoerg // Message sent to 'super' in a class method defined in a category
21047330f729Sjoerg // implementation requires an odd treatment.
21057330f729Sjoerg // If we are in a class method, we must retrieve the
21067330f729Sjoerg // _metaclass_ for the current class, pointed at by
21077330f729Sjoerg // the class's "isa" pointer. The following assumes that
21087330f729Sjoerg // isa" is the first ivar in a class (which it must be).
21097330f729Sjoerg Target = EmitClassRef(CGF, Class->getSuperClass());
21107330f729Sjoerg Target = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, Target, 0);
2111*e038c9c4Sjoerg Target = CGF.Builder.CreateAlignedLoad(ClassTyPtr, Target,
2112*e038c9c4Sjoerg CGF.getPointerAlign());
21137330f729Sjoerg } else {
21147330f729Sjoerg llvm::Constant *MetaClassPtr = EmitMetaClassRef(Class);
21157330f729Sjoerg llvm::Value *SuperPtr =
21167330f729Sjoerg CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, MetaClassPtr, 1);
2117*e038c9c4Sjoerg llvm::Value *Super = CGF.Builder.CreateAlignedLoad(ClassTyPtr, SuperPtr,
2118*e038c9c4Sjoerg CGF.getPointerAlign());
21197330f729Sjoerg Target = Super;
21207330f729Sjoerg }
21217330f729Sjoerg } else if (isCategoryImpl)
21227330f729Sjoerg Target = EmitClassRef(CGF, Class->getSuperClass());
21237330f729Sjoerg else {
21247330f729Sjoerg llvm::Value *ClassPtr = EmitSuperClassRef(Class);
21257330f729Sjoerg ClassPtr = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, ClassPtr, 1);
2126*e038c9c4Sjoerg Target = CGF.Builder.CreateAlignedLoad(ClassTyPtr, ClassPtr,
2127*e038c9c4Sjoerg CGF.getPointerAlign());
21287330f729Sjoerg }
21297330f729Sjoerg // FIXME: We shouldn't need to do this cast, rectify the ASTContext and
21307330f729Sjoerg // ObjCTypes types.
21317330f729Sjoerg llvm::Type *ClassTy =
21327330f729Sjoerg CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
21337330f729Sjoerg Target = CGF.Builder.CreateBitCast(Target, ClassTy);
21347330f729Sjoerg CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1));
2135*e038c9c4Sjoerg return EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper.getPointer(),
2136*e038c9c4Sjoerg ObjCTypes.SuperPtrCTy, true, CallArgs, Method, Class,
2137*e038c9c4Sjoerg ObjCTypes);
21387330f729Sjoerg }
21397330f729Sjoerg
21407330f729Sjoerg /// Generate code for a message send expression.
GenerateMessageSend(CodeGen::CodeGenFunction & CGF,ReturnValueSlot Return,QualType ResultType,Selector Sel,llvm::Value * Receiver,const CallArgList & CallArgs,const ObjCInterfaceDecl * Class,const ObjCMethodDecl * Method)21417330f729Sjoerg CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
21427330f729Sjoerg ReturnValueSlot Return,
21437330f729Sjoerg QualType ResultType,
21447330f729Sjoerg Selector Sel,
21457330f729Sjoerg llvm::Value *Receiver,
21467330f729Sjoerg const CallArgList &CallArgs,
21477330f729Sjoerg const ObjCInterfaceDecl *Class,
21487330f729Sjoerg const ObjCMethodDecl *Method) {
2149*e038c9c4Sjoerg return EmitMessageSend(CGF, Return, ResultType, Sel, Receiver,
2150*e038c9c4Sjoerg CGF.getContext().getObjCIdType(), false, CallArgs,
2151*e038c9c4Sjoerg Method, Class, ObjCTypes);
21527330f729Sjoerg }
21537330f729Sjoerg
isWeakLinkedClass(const ObjCInterfaceDecl * ID)21547330f729Sjoerg static bool isWeakLinkedClass(const ObjCInterfaceDecl *ID) {
21557330f729Sjoerg do {
21567330f729Sjoerg if (ID->isWeakImported())
21577330f729Sjoerg return true;
21587330f729Sjoerg } while ((ID = ID->getSuperClass()));
21597330f729Sjoerg
21607330f729Sjoerg return false;
21617330f729Sjoerg }
21627330f729Sjoerg
21637330f729Sjoerg CodeGen::RValue
EmitMessageSend(CodeGen::CodeGenFunction & CGF,ReturnValueSlot Return,QualType ResultType,Selector Sel,llvm::Value * Arg0,QualType Arg0Ty,bool IsSuper,const CallArgList & CallArgs,const ObjCMethodDecl * Method,const ObjCInterfaceDecl * ClassReceiver,const ObjCCommonTypesHelper & ObjCTypes)21647330f729Sjoerg CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
21657330f729Sjoerg ReturnValueSlot Return,
21667330f729Sjoerg QualType ResultType,
2167*e038c9c4Sjoerg Selector Sel,
21687330f729Sjoerg llvm::Value *Arg0,
21697330f729Sjoerg QualType Arg0Ty,
21707330f729Sjoerg bool IsSuper,
21717330f729Sjoerg const CallArgList &CallArgs,
21727330f729Sjoerg const ObjCMethodDecl *Method,
21737330f729Sjoerg const ObjCInterfaceDecl *ClassReceiver,
21747330f729Sjoerg const ObjCCommonTypesHelper &ObjCTypes) {
2175*e038c9c4Sjoerg CodeGenTypes &Types = CGM.getTypes();
2176*e038c9c4Sjoerg auto selTy = CGF.getContext().getObjCSelType();
2177*e038c9c4Sjoerg llvm::Value *SelValue;
2178*e038c9c4Sjoerg
2179*e038c9c4Sjoerg if (Method && Method->isDirectMethod()) {
2180*e038c9c4Sjoerg // Direct methods will synthesize the proper `_cmd` internally,
2181*e038c9c4Sjoerg // so just don't bother with setting the `_cmd` argument.
2182*e038c9c4Sjoerg assert(!IsSuper);
2183*e038c9c4Sjoerg SelValue = llvm::UndefValue::get(Types.ConvertType(selTy));
2184*e038c9c4Sjoerg } else {
2185*e038c9c4Sjoerg SelValue = GetSelector(CGF, Sel);
2186*e038c9c4Sjoerg }
2187*e038c9c4Sjoerg
21887330f729Sjoerg CallArgList ActualArgs;
21897330f729Sjoerg if (!IsSuper)
21907330f729Sjoerg Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
21917330f729Sjoerg ActualArgs.add(RValue::get(Arg0), Arg0Ty);
2192*e038c9c4Sjoerg ActualArgs.add(RValue::get(SelValue), selTy);
21937330f729Sjoerg ActualArgs.addFrom(CallArgs);
21947330f729Sjoerg
21957330f729Sjoerg // If we're calling a method, use the formal signature.
21967330f729Sjoerg MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
21977330f729Sjoerg
21987330f729Sjoerg if (Method)
21997330f729Sjoerg assert(CGM.getContext().getCanonicalType(Method->getReturnType()) ==
22007330f729Sjoerg CGM.getContext().getCanonicalType(ResultType) &&
22017330f729Sjoerg "Result type mismatch!");
22027330f729Sjoerg
22037330f729Sjoerg bool ReceiverCanBeNull = true;
22047330f729Sjoerg
22057330f729Sjoerg // Super dispatch assumes that self is non-null; even the messenger
22067330f729Sjoerg // doesn't have a null check internally.
22077330f729Sjoerg if (IsSuper) {
22087330f729Sjoerg ReceiverCanBeNull = false;
22097330f729Sjoerg
22107330f729Sjoerg // If this is a direct dispatch of a class method, check whether the class,
22117330f729Sjoerg // or anything in its hierarchy, was weak-linked.
22127330f729Sjoerg } else if (ClassReceiver && Method && Method->isClassMethod()) {
22137330f729Sjoerg ReceiverCanBeNull = isWeakLinkedClass(ClassReceiver);
22147330f729Sjoerg
22157330f729Sjoerg // If we're emitting a method, and self is const (meaning just ARC, for now),
22167330f729Sjoerg // and the receiver is a load of self, then self is a valid object.
22177330f729Sjoerg } else if (auto CurMethod =
22187330f729Sjoerg dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl)) {
22197330f729Sjoerg auto Self = CurMethod->getSelfDecl();
22207330f729Sjoerg if (Self->getType().isConstQualified()) {
22217330f729Sjoerg if (auto LI = dyn_cast<llvm::LoadInst>(Arg0->stripPointerCasts())) {
22227330f729Sjoerg llvm::Value *SelfAddr = CGF.GetAddrOfLocalVar(Self).getPointer();
22237330f729Sjoerg if (SelfAddr == LI->getPointerOperand()) {
22247330f729Sjoerg ReceiverCanBeNull = false;
22257330f729Sjoerg }
22267330f729Sjoerg }
22277330f729Sjoerg }
22287330f729Sjoerg }
22297330f729Sjoerg
22307330f729Sjoerg bool RequiresNullCheck = false;
22317330f729Sjoerg
22327330f729Sjoerg llvm::FunctionCallee Fn = nullptr;
2233*e038c9c4Sjoerg if (Method && Method->isDirectMethod()) {
2234*e038c9c4Sjoerg Fn = GenerateDirectMethod(Method, Method->getClassInterface());
2235*e038c9c4Sjoerg } else if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
22367330f729Sjoerg if (ReceiverCanBeNull) RequiresNullCheck = true;
22377330f729Sjoerg Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
22387330f729Sjoerg : ObjCTypes.getSendStretFn(IsSuper);
22397330f729Sjoerg } else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
22407330f729Sjoerg Fn = (ObjCABI == 2) ? ObjCTypes.getSendFpretFn2(IsSuper)
22417330f729Sjoerg : ObjCTypes.getSendFpretFn(IsSuper);
22427330f729Sjoerg } else if (CGM.ReturnTypeUsesFP2Ret(ResultType)) {
22437330f729Sjoerg Fn = (ObjCABI == 2) ? ObjCTypes.getSendFp2RetFn2(IsSuper)
22447330f729Sjoerg : ObjCTypes.getSendFp2retFn(IsSuper);
22457330f729Sjoerg } else {
22467330f729Sjoerg // arm64 uses objc_msgSend for stret methods and yet null receiver check
22477330f729Sjoerg // must be made for it.
22487330f729Sjoerg if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
22497330f729Sjoerg RequiresNullCheck = true;
22507330f729Sjoerg Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
22517330f729Sjoerg : ObjCTypes.getSendFn(IsSuper);
22527330f729Sjoerg }
22537330f729Sjoerg
22547330f729Sjoerg // Cast function to proper signature
22557330f729Sjoerg llvm::Constant *BitcastFn = cast<llvm::Constant>(
22567330f729Sjoerg CGF.Builder.CreateBitCast(Fn.getCallee(), MSI.MessengerType));
22577330f729Sjoerg
22587330f729Sjoerg // We don't need to emit a null check to zero out an indirect result if the
22597330f729Sjoerg // result is ignored.
22607330f729Sjoerg if (Return.isUnused())
22617330f729Sjoerg RequiresNullCheck = false;
22627330f729Sjoerg
22637330f729Sjoerg // Emit a null-check if there's a consumed argument other than the receiver.
22647330f729Sjoerg if (!RequiresNullCheck && CGM.getLangOpts().ObjCAutoRefCount && Method) {
22657330f729Sjoerg for (const auto *ParamDecl : Method->parameters()) {
2266*e038c9c4Sjoerg if (ParamDecl->isDestroyedInCallee()) {
22677330f729Sjoerg RequiresNullCheck = true;
22687330f729Sjoerg break;
22697330f729Sjoerg }
22707330f729Sjoerg }
22717330f729Sjoerg }
22727330f729Sjoerg
22737330f729Sjoerg NullReturnState nullReturn;
22747330f729Sjoerg if (RequiresNullCheck) {
22757330f729Sjoerg nullReturn.init(CGF, Arg0);
22767330f729Sjoerg }
22777330f729Sjoerg
22787330f729Sjoerg llvm::CallBase *CallSite;
22797330f729Sjoerg CGCallee Callee = CGCallee::forDirect(BitcastFn);
22807330f729Sjoerg RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs,
22817330f729Sjoerg &CallSite);
22827330f729Sjoerg
22837330f729Sjoerg // Mark the call as noreturn if the method is marked noreturn and the
22847330f729Sjoerg // receiver cannot be null.
22857330f729Sjoerg if (Method && Method->hasAttr<NoReturnAttr>() && !ReceiverCanBeNull) {
22867330f729Sjoerg CallSite->setDoesNotReturn();
22877330f729Sjoerg }
22887330f729Sjoerg
22897330f729Sjoerg return nullReturn.complete(CGF, Return, rvalue, ResultType, CallArgs,
22907330f729Sjoerg RequiresNullCheck ? Method : nullptr);
22917330f729Sjoerg }
22927330f729Sjoerg
GetGCAttrTypeForType(ASTContext & Ctx,QualType FQT,bool pointee=false)22937330f729Sjoerg static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT,
22947330f729Sjoerg bool pointee = false) {
22957330f729Sjoerg // Note that GC qualification applies recursively to C pointer types
22967330f729Sjoerg // that aren't otherwise decorated. This is weird, but it's probably
22977330f729Sjoerg // an intentional workaround to the unreliable placement of GC qualifiers.
22987330f729Sjoerg if (FQT.isObjCGCStrong())
22997330f729Sjoerg return Qualifiers::Strong;
23007330f729Sjoerg
23017330f729Sjoerg if (FQT.isObjCGCWeak())
23027330f729Sjoerg return Qualifiers::Weak;
23037330f729Sjoerg
23047330f729Sjoerg if (auto ownership = FQT.getObjCLifetime()) {
23057330f729Sjoerg // Ownership does not apply recursively to C pointer types.
23067330f729Sjoerg if (pointee) return Qualifiers::GCNone;
23077330f729Sjoerg switch (ownership) {
23087330f729Sjoerg case Qualifiers::OCL_Weak: return Qualifiers::Weak;
23097330f729Sjoerg case Qualifiers::OCL_Strong: return Qualifiers::Strong;
23107330f729Sjoerg case Qualifiers::OCL_ExplicitNone: return Qualifiers::GCNone;
23117330f729Sjoerg case Qualifiers::OCL_Autoreleasing: llvm_unreachable("autoreleasing ivar?");
23127330f729Sjoerg case Qualifiers::OCL_None: llvm_unreachable("known nonzero");
23137330f729Sjoerg }
23147330f729Sjoerg llvm_unreachable("bad objc ownership");
23157330f729Sjoerg }
23167330f729Sjoerg
23177330f729Sjoerg // Treat unqualified retainable pointers as strong.
23187330f729Sjoerg if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
23197330f729Sjoerg return Qualifiers::Strong;
23207330f729Sjoerg
23217330f729Sjoerg // Walk into C pointer types, but only in GC.
23227330f729Sjoerg if (Ctx.getLangOpts().getGC() != LangOptions::NonGC) {
23237330f729Sjoerg if (const PointerType *PT = FQT->getAs<PointerType>())
23247330f729Sjoerg return GetGCAttrTypeForType(Ctx, PT->getPointeeType(), /*pointee*/ true);
23257330f729Sjoerg }
23267330f729Sjoerg
23277330f729Sjoerg return Qualifiers::GCNone;
23287330f729Sjoerg }
23297330f729Sjoerg
23307330f729Sjoerg namespace {
23317330f729Sjoerg struct IvarInfo {
23327330f729Sjoerg CharUnits Offset;
23337330f729Sjoerg uint64_t SizeInWords;
IvarInfo__anon0cc8f9a20511::IvarInfo23347330f729Sjoerg IvarInfo(CharUnits offset, uint64_t sizeInWords)
23357330f729Sjoerg : Offset(offset), SizeInWords(sizeInWords) {}
23367330f729Sjoerg
23377330f729Sjoerg // Allow sorting based on byte pos.
operator <__anon0cc8f9a20511::IvarInfo23387330f729Sjoerg bool operator<(const IvarInfo &other) const {
23397330f729Sjoerg return Offset < other.Offset;
23407330f729Sjoerg }
23417330f729Sjoerg };
23427330f729Sjoerg
23437330f729Sjoerg /// A helper class for building GC layout strings.
23447330f729Sjoerg class IvarLayoutBuilder {
23457330f729Sjoerg CodeGenModule &CGM;
23467330f729Sjoerg
23477330f729Sjoerg /// The start of the layout. Offsets will be relative to this value,
23487330f729Sjoerg /// and entries less than this value will be silently discarded.
23497330f729Sjoerg CharUnits InstanceBegin;
23507330f729Sjoerg
23517330f729Sjoerg /// The end of the layout. Offsets will never exceed this value.
23527330f729Sjoerg CharUnits InstanceEnd;
23537330f729Sjoerg
23547330f729Sjoerg /// Whether we're generating the strong layout or the weak layout.
23557330f729Sjoerg bool ForStrongLayout;
23567330f729Sjoerg
23577330f729Sjoerg /// Whether the offsets in IvarsInfo might be out-of-order.
23587330f729Sjoerg bool IsDisordered = false;
23597330f729Sjoerg
23607330f729Sjoerg llvm::SmallVector<IvarInfo, 8> IvarsInfo;
23617330f729Sjoerg
23627330f729Sjoerg public:
IvarLayoutBuilder(CodeGenModule & CGM,CharUnits instanceBegin,CharUnits instanceEnd,bool forStrongLayout)23637330f729Sjoerg IvarLayoutBuilder(CodeGenModule &CGM, CharUnits instanceBegin,
23647330f729Sjoerg CharUnits instanceEnd, bool forStrongLayout)
23657330f729Sjoerg : CGM(CGM), InstanceBegin(instanceBegin), InstanceEnd(instanceEnd),
23667330f729Sjoerg ForStrongLayout(forStrongLayout) {
23677330f729Sjoerg }
23687330f729Sjoerg
23697330f729Sjoerg void visitRecord(const RecordType *RT, CharUnits offset);
23707330f729Sjoerg
23717330f729Sjoerg template <class Iterator, class GetOffsetFn>
23727330f729Sjoerg void visitAggregate(Iterator begin, Iterator end,
23737330f729Sjoerg CharUnits aggrOffset,
23747330f729Sjoerg const GetOffsetFn &getOffset);
23757330f729Sjoerg
23767330f729Sjoerg void visitField(const FieldDecl *field, CharUnits offset);
23777330f729Sjoerg
23787330f729Sjoerg /// Add the layout of a block implementation.
23797330f729Sjoerg void visitBlock(const CGBlockInfo &blockInfo);
23807330f729Sjoerg
23817330f729Sjoerg /// Is there any information for an interesting bitmap?
hasBitmapData() const23827330f729Sjoerg bool hasBitmapData() const { return !IvarsInfo.empty(); }
23837330f729Sjoerg
23847330f729Sjoerg llvm::Constant *buildBitmap(CGObjCCommonMac &CGObjC,
23857330f729Sjoerg llvm::SmallVectorImpl<unsigned char> &buffer);
23867330f729Sjoerg
dump(ArrayRef<unsigned char> buffer)23877330f729Sjoerg static void dump(ArrayRef<unsigned char> buffer) {
23887330f729Sjoerg const unsigned char *s = buffer.data();
23897330f729Sjoerg for (unsigned i = 0, e = buffer.size(); i < e; i++)
23907330f729Sjoerg if (!(s[i] & 0xf0))
23917330f729Sjoerg printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
23927330f729Sjoerg else
23937330f729Sjoerg printf("0x%x%s", s[i], s[i] != 0 ? ", " : "");
23947330f729Sjoerg printf("\n");
23957330f729Sjoerg }
23967330f729Sjoerg };
23977330f729Sjoerg } // end anonymous namespace
23987330f729Sjoerg
BuildGCBlockLayout(CodeGenModule & CGM,const CGBlockInfo & blockInfo)23997330f729Sjoerg llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
24007330f729Sjoerg const CGBlockInfo &blockInfo) {
24017330f729Sjoerg
24027330f729Sjoerg llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
24037330f729Sjoerg if (CGM.getLangOpts().getGC() == LangOptions::NonGC)
24047330f729Sjoerg return nullPtr;
24057330f729Sjoerg
24067330f729Sjoerg IvarLayoutBuilder builder(CGM, CharUnits::Zero(), blockInfo.BlockSize,
24077330f729Sjoerg /*for strong layout*/ true);
24087330f729Sjoerg
24097330f729Sjoerg builder.visitBlock(blockInfo);
24107330f729Sjoerg
24117330f729Sjoerg if (!builder.hasBitmapData())
24127330f729Sjoerg return nullPtr;
24137330f729Sjoerg
24147330f729Sjoerg llvm::SmallVector<unsigned char, 32> buffer;
24157330f729Sjoerg llvm::Constant *C = builder.buildBitmap(*this, buffer);
24167330f729Sjoerg if (CGM.getLangOpts().ObjCGCBitmapPrint && !buffer.empty()) {
24177330f729Sjoerg printf("\n block variable layout for block: ");
24187330f729Sjoerg builder.dump(buffer);
24197330f729Sjoerg }
24207330f729Sjoerg
24217330f729Sjoerg return C;
24227330f729Sjoerg }
24237330f729Sjoerg
visitBlock(const CGBlockInfo & blockInfo)24247330f729Sjoerg void IvarLayoutBuilder::visitBlock(const CGBlockInfo &blockInfo) {
24257330f729Sjoerg // __isa is the first field in block descriptor and must assume by runtime's
24267330f729Sjoerg // convention that it is GC'able.
24277330f729Sjoerg IvarsInfo.push_back(IvarInfo(CharUnits::Zero(), 1));
24287330f729Sjoerg
24297330f729Sjoerg const BlockDecl *blockDecl = blockInfo.getBlockDecl();
24307330f729Sjoerg
24317330f729Sjoerg // Ignore the optional 'this' capture: C++ objects are not assumed
24327330f729Sjoerg // to be GC'ed.
24337330f729Sjoerg
24347330f729Sjoerg CharUnits lastFieldOffset;
24357330f729Sjoerg
24367330f729Sjoerg // Walk the captured variables.
24377330f729Sjoerg for (const auto &CI : blockDecl->captures()) {
24387330f729Sjoerg const VarDecl *variable = CI.getVariable();
24397330f729Sjoerg QualType type = variable->getType();
24407330f729Sjoerg
24417330f729Sjoerg const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
24427330f729Sjoerg
24437330f729Sjoerg // Ignore constant captures.
24447330f729Sjoerg if (capture.isConstant()) continue;
24457330f729Sjoerg
24467330f729Sjoerg CharUnits fieldOffset = capture.getOffset();
24477330f729Sjoerg
24487330f729Sjoerg // Block fields are not necessarily ordered; if we detect that we're
24497330f729Sjoerg // adding them out-of-order, make sure we sort later.
24507330f729Sjoerg if (fieldOffset < lastFieldOffset)
24517330f729Sjoerg IsDisordered = true;
24527330f729Sjoerg lastFieldOffset = fieldOffset;
24537330f729Sjoerg
24547330f729Sjoerg // __block variables are passed by their descriptor address.
24557330f729Sjoerg if (CI.isByRef()) {
24567330f729Sjoerg IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
24577330f729Sjoerg continue;
24587330f729Sjoerg }
24597330f729Sjoerg
24607330f729Sjoerg assert(!type->isArrayType() && "array variable should not be caught");
24617330f729Sjoerg if (const RecordType *record = type->getAs<RecordType>()) {
24627330f729Sjoerg visitRecord(record, fieldOffset);
24637330f729Sjoerg continue;
24647330f729Sjoerg }
24657330f729Sjoerg
24667330f729Sjoerg Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), type);
24677330f729Sjoerg
24687330f729Sjoerg if (GCAttr == Qualifiers::Strong) {
24697330f729Sjoerg assert(CGM.getContext().getTypeSize(type)
24707330f729Sjoerg == CGM.getTarget().getPointerWidth(0));
24717330f729Sjoerg IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
24727330f729Sjoerg }
24737330f729Sjoerg }
24747330f729Sjoerg }
24757330f729Sjoerg
24767330f729Sjoerg /// getBlockCaptureLifetime - This routine returns life time of the captured
24777330f729Sjoerg /// block variable for the purpose of block layout meta-data generation. FQT is
24787330f729Sjoerg /// the type of the variable captured in the block.
getBlockCaptureLifetime(QualType FQT,bool ByrefLayout)24797330f729Sjoerg Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT,
24807330f729Sjoerg bool ByrefLayout) {
24817330f729Sjoerg // If it has an ownership qualifier, we're done.
24827330f729Sjoerg if (auto lifetime = FQT.getObjCLifetime())
24837330f729Sjoerg return lifetime;
24847330f729Sjoerg
24857330f729Sjoerg // If it doesn't, and this is ARC, it has no ownership.
24867330f729Sjoerg if (CGM.getLangOpts().ObjCAutoRefCount)
24877330f729Sjoerg return Qualifiers::OCL_None;
24887330f729Sjoerg
24897330f729Sjoerg // In MRC, retainable pointers are owned by non-__block variables.
24907330f729Sjoerg if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
24917330f729Sjoerg return ByrefLayout ? Qualifiers::OCL_ExplicitNone : Qualifiers::OCL_Strong;
24927330f729Sjoerg
24937330f729Sjoerg return Qualifiers::OCL_None;
24947330f729Sjoerg }
24957330f729Sjoerg
UpdateRunSkipBlockVars(bool IsByref,Qualifiers::ObjCLifetime LifeTime,CharUnits FieldOffset,CharUnits FieldSize)24967330f729Sjoerg void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref,
24977330f729Sjoerg Qualifiers::ObjCLifetime LifeTime,
24987330f729Sjoerg CharUnits FieldOffset,
24997330f729Sjoerg CharUnits FieldSize) {
25007330f729Sjoerg // __block variables are passed by their descriptor address.
25017330f729Sjoerg if (IsByref)
25027330f729Sjoerg RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, FieldOffset,
25037330f729Sjoerg FieldSize));
25047330f729Sjoerg else if (LifeTime == Qualifiers::OCL_Strong)
25057330f729Sjoerg RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, FieldOffset,
25067330f729Sjoerg FieldSize));
25077330f729Sjoerg else if (LifeTime == Qualifiers::OCL_Weak)
25087330f729Sjoerg RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, FieldOffset,
25097330f729Sjoerg FieldSize));
25107330f729Sjoerg else if (LifeTime == Qualifiers::OCL_ExplicitNone)
25117330f729Sjoerg RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, FieldOffset,
25127330f729Sjoerg FieldSize));
25137330f729Sjoerg else
25147330f729Sjoerg RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES,
25157330f729Sjoerg FieldOffset,
25167330f729Sjoerg FieldSize));
25177330f729Sjoerg }
25187330f729Sjoerg
BuildRCRecordLayout(const llvm::StructLayout * RecLayout,const RecordDecl * RD,ArrayRef<const FieldDecl * > RecFields,CharUnits BytePos,bool & HasUnion,bool ByrefLayout)25197330f729Sjoerg void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
25207330f729Sjoerg const RecordDecl *RD,
25217330f729Sjoerg ArrayRef<const FieldDecl*> RecFields,
25227330f729Sjoerg CharUnits BytePos, bool &HasUnion,
25237330f729Sjoerg bool ByrefLayout) {
25247330f729Sjoerg bool IsUnion = (RD && RD->isUnion());
25257330f729Sjoerg CharUnits MaxUnionSize = CharUnits::Zero();
25267330f729Sjoerg const FieldDecl *MaxField = nullptr;
25277330f729Sjoerg const FieldDecl *LastFieldBitfieldOrUnnamed = nullptr;
25287330f729Sjoerg CharUnits MaxFieldOffset = CharUnits::Zero();
25297330f729Sjoerg CharUnits LastBitfieldOrUnnamedOffset = CharUnits::Zero();
25307330f729Sjoerg
25317330f729Sjoerg if (RecFields.empty())
25327330f729Sjoerg return;
25337330f729Sjoerg unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
25347330f729Sjoerg
25357330f729Sjoerg for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
25367330f729Sjoerg const FieldDecl *Field = RecFields[i];
25377330f729Sjoerg // Note that 'i' here is actually the field index inside RD of Field,
25387330f729Sjoerg // although this dependency is hidden.
25397330f729Sjoerg const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
25407330f729Sjoerg CharUnits FieldOffset =
25417330f729Sjoerg CGM.getContext().toCharUnitsFromBits(RL.getFieldOffset(i));
25427330f729Sjoerg
25437330f729Sjoerg // Skip over unnamed or bitfields
25447330f729Sjoerg if (!Field->getIdentifier() || Field->isBitField()) {
25457330f729Sjoerg LastFieldBitfieldOrUnnamed = Field;
25467330f729Sjoerg LastBitfieldOrUnnamedOffset = FieldOffset;
25477330f729Sjoerg continue;
25487330f729Sjoerg }
25497330f729Sjoerg
25507330f729Sjoerg LastFieldBitfieldOrUnnamed = nullptr;
25517330f729Sjoerg QualType FQT = Field->getType();
25527330f729Sjoerg if (FQT->isRecordType() || FQT->isUnionType()) {
25537330f729Sjoerg if (FQT->isUnionType())
25547330f729Sjoerg HasUnion = true;
25557330f729Sjoerg
25567330f729Sjoerg BuildRCBlockVarRecordLayout(FQT->getAs<RecordType>(),
25577330f729Sjoerg BytePos + FieldOffset, HasUnion);
25587330f729Sjoerg continue;
25597330f729Sjoerg }
25607330f729Sjoerg
25617330f729Sjoerg if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
25627330f729Sjoerg auto *CArray = cast<ConstantArrayType>(Array);
25637330f729Sjoerg uint64_t ElCount = CArray->getSize().getZExtValue();
25647330f729Sjoerg assert(CArray && "only array with known element size is supported");
25657330f729Sjoerg FQT = CArray->getElementType();
25667330f729Sjoerg while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
25677330f729Sjoerg auto *CArray = cast<ConstantArrayType>(Array);
25687330f729Sjoerg ElCount *= CArray->getSize().getZExtValue();
25697330f729Sjoerg FQT = CArray->getElementType();
25707330f729Sjoerg }
25717330f729Sjoerg if (FQT->isRecordType() && ElCount) {
25727330f729Sjoerg int OldIndex = RunSkipBlockVars.size() - 1;
2573*e038c9c4Sjoerg auto *RT = FQT->castAs<RecordType>();
2574*e038c9c4Sjoerg BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset, HasUnion);
25757330f729Sjoerg
25767330f729Sjoerg // Replicate layout information for each array element. Note that
25777330f729Sjoerg // one element is already done.
25787330f729Sjoerg uint64_t ElIx = 1;
25797330f729Sjoerg for (int FirstIndex = RunSkipBlockVars.size() - 1 ;ElIx < ElCount; ElIx++) {
25807330f729Sjoerg CharUnits Size = CGM.getContext().getTypeSizeInChars(RT);
25817330f729Sjoerg for (int i = OldIndex+1; i <= FirstIndex; ++i)
25827330f729Sjoerg RunSkipBlockVars.push_back(
25837330f729Sjoerg RUN_SKIP(RunSkipBlockVars[i].opcode,
25847330f729Sjoerg RunSkipBlockVars[i].block_var_bytepos + Size*ElIx,
25857330f729Sjoerg RunSkipBlockVars[i].block_var_size));
25867330f729Sjoerg }
25877330f729Sjoerg continue;
25887330f729Sjoerg }
25897330f729Sjoerg }
25907330f729Sjoerg CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(Field->getType());
25917330f729Sjoerg if (IsUnion) {
25927330f729Sjoerg CharUnits UnionIvarSize = FieldSize;
25937330f729Sjoerg if (UnionIvarSize > MaxUnionSize) {
25947330f729Sjoerg MaxUnionSize = UnionIvarSize;
25957330f729Sjoerg MaxField = Field;
25967330f729Sjoerg MaxFieldOffset = FieldOffset;
25977330f729Sjoerg }
25987330f729Sjoerg } else {
25997330f729Sjoerg UpdateRunSkipBlockVars(false,
26007330f729Sjoerg getBlockCaptureLifetime(FQT, ByrefLayout),
26017330f729Sjoerg BytePos + FieldOffset,
26027330f729Sjoerg FieldSize);
26037330f729Sjoerg }
26047330f729Sjoerg }
26057330f729Sjoerg
26067330f729Sjoerg if (LastFieldBitfieldOrUnnamed) {
26077330f729Sjoerg if (LastFieldBitfieldOrUnnamed->isBitField()) {
26087330f729Sjoerg // Last field was a bitfield. Must update the info.
26097330f729Sjoerg uint64_t BitFieldSize
26107330f729Sjoerg = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
26117330f729Sjoerg unsigned UnsSize = (BitFieldSize / ByteSizeInBits) +
26127330f729Sjoerg ((BitFieldSize % ByteSizeInBits) != 0);
26137330f729Sjoerg CharUnits Size = CharUnits::fromQuantity(UnsSize);
26147330f729Sjoerg Size += LastBitfieldOrUnnamedOffset;
26157330f729Sjoerg UpdateRunSkipBlockVars(false,
26167330f729Sjoerg getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
26177330f729Sjoerg ByrefLayout),
26187330f729Sjoerg BytePos + LastBitfieldOrUnnamedOffset,
26197330f729Sjoerg Size);
26207330f729Sjoerg } else {
26217330f729Sjoerg assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed");
26227330f729Sjoerg // Last field was unnamed. Must update skip info.
26237330f729Sjoerg CharUnits FieldSize
26247330f729Sjoerg = CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
26257330f729Sjoerg UpdateRunSkipBlockVars(false,
26267330f729Sjoerg getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
26277330f729Sjoerg ByrefLayout),
26287330f729Sjoerg BytePos + LastBitfieldOrUnnamedOffset,
26297330f729Sjoerg FieldSize);
26307330f729Sjoerg }
26317330f729Sjoerg }
26327330f729Sjoerg
26337330f729Sjoerg if (MaxField)
26347330f729Sjoerg UpdateRunSkipBlockVars(false,
26357330f729Sjoerg getBlockCaptureLifetime(MaxField->getType(), ByrefLayout),
26367330f729Sjoerg BytePos + MaxFieldOffset,
26377330f729Sjoerg MaxUnionSize);
26387330f729Sjoerg }
26397330f729Sjoerg
BuildRCBlockVarRecordLayout(const RecordType * RT,CharUnits BytePos,bool & HasUnion,bool ByrefLayout)26407330f729Sjoerg void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
26417330f729Sjoerg CharUnits BytePos,
26427330f729Sjoerg bool &HasUnion,
26437330f729Sjoerg bool ByrefLayout) {
26447330f729Sjoerg const RecordDecl *RD = RT->getDecl();
26457330f729Sjoerg SmallVector<const FieldDecl*, 16> Fields(RD->fields());
26467330f729Sjoerg llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
26477330f729Sjoerg const llvm::StructLayout *RecLayout =
26487330f729Sjoerg CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
26497330f729Sjoerg
26507330f729Sjoerg BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion, ByrefLayout);
26517330f729Sjoerg }
26527330f729Sjoerg
26537330f729Sjoerg /// InlineLayoutInstruction - This routine produce an inline instruction for the
26547330f729Sjoerg /// block variable layout if it can. If not, it returns 0. Rules are as follow:
26557330f729Sjoerg /// If ((uintptr_t) layout) < (1 << 12), the layout is inline. In the 64bit world,
26567330f729Sjoerg /// an inline layout of value 0x0000000000000xyz is interpreted as follows:
26577330f729Sjoerg /// x captured object pointers of BLOCK_LAYOUT_STRONG. Followed by
26587330f729Sjoerg /// y captured object of BLOCK_LAYOUT_BYREF. Followed by
26597330f729Sjoerg /// z captured object of BLOCK_LAYOUT_WEAK. If any of the above is missing, zero
26607330f729Sjoerg /// replaces it. For example, 0x00000x00 means x BLOCK_LAYOUT_STRONG and no
26617330f729Sjoerg /// BLOCK_LAYOUT_BYREF and no BLOCK_LAYOUT_WEAK objects are captured.
InlineLayoutInstruction(SmallVectorImpl<unsigned char> & Layout)26627330f729Sjoerg uint64_t CGObjCCommonMac::InlineLayoutInstruction(
26637330f729Sjoerg SmallVectorImpl<unsigned char> &Layout) {
26647330f729Sjoerg uint64_t Result = 0;
26657330f729Sjoerg if (Layout.size() <= 3) {
26667330f729Sjoerg unsigned size = Layout.size();
26677330f729Sjoerg unsigned strong_word_count = 0, byref_word_count=0, weak_word_count=0;
26687330f729Sjoerg unsigned char inst;
26697330f729Sjoerg enum BLOCK_LAYOUT_OPCODE opcode ;
26707330f729Sjoerg switch (size) {
26717330f729Sjoerg case 3:
26727330f729Sjoerg inst = Layout[0];
26737330f729Sjoerg opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
26747330f729Sjoerg if (opcode == BLOCK_LAYOUT_STRONG)
26757330f729Sjoerg strong_word_count = (inst & 0xF)+1;
26767330f729Sjoerg else
26777330f729Sjoerg return 0;
26787330f729Sjoerg inst = Layout[1];
26797330f729Sjoerg opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
26807330f729Sjoerg if (opcode == BLOCK_LAYOUT_BYREF)
26817330f729Sjoerg byref_word_count = (inst & 0xF)+1;
26827330f729Sjoerg else
26837330f729Sjoerg return 0;
26847330f729Sjoerg inst = Layout[2];
26857330f729Sjoerg opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
26867330f729Sjoerg if (opcode == BLOCK_LAYOUT_WEAK)
26877330f729Sjoerg weak_word_count = (inst & 0xF)+1;
26887330f729Sjoerg else
26897330f729Sjoerg return 0;
26907330f729Sjoerg break;
26917330f729Sjoerg
26927330f729Sjoerg case 2:
26937330f729Sjoerg inst = Layout[0];
26947330f729Sjoerg opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
26957330f729Sjoerg if (opcode == BLOCK_LAYOUT_STRONG) {
26967330f729Sjoerg strong_word_count = (inst & 0xF)+1;
26977330f729Sjoerg inst = Layout[1];
26987330f729Sjoerg opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
26997330f729Sjoerg if (opcode == BLOCK_LAYOUT_BYREF)
27007330f729Sjoerg byref_word_count = (inst & 0xF)+1;
27017330f729Sjoerg else if (opcode == BLOCK_LAYOUT_WEAK)
27027330f729Sjoerg weak_word_count = (inst & 0xF)+1;
27037330f729Sjoerg else
27047330f729Sjoerg return 0;
27057330f729Sjoerg }
27067330f729Sjoerg else if (opcode == BLOCK_LAYOUT_BYREF) {
27077330f729Sjoerg byref_word_count = (inst & 0xF)+1;
27087330f729Sjoerg inst = Layout[1];
27097330f729Sjoerg opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
27107330f729Sjoerg if (opcode == BLOCK_LAYOUT_WEAK)
27117330f729Sjoerg weak_word_count = (inst & 0xF)+1;
27127330f729Sjoerg else
27137330f729Sjoerg return 0;
27147330f729Sjoerg }
27157330f729Sjoerg else
27167330f729Sjoerg return 0;
27177330f729Sjoerg break;
27187330f729Sjoerg
27197330f729Sjoerg case 1:
27207330f729Sjoerg inst = Layout[0];
27217330f729Sjoerg opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
27227330f729Sjoerg if (opcode == BLOCK_LAYOUT_STRONG)
27237330f729Sjoerg strong_word_count = (inst & 0xF)+1;
27247330f729Sjoerg else if (opcode == BLOCK_LAYOUT_BYREF)
27257330f729Sjoerg byref_word_count = (inst & 0xF)+1;
27267330f729Sjoerg else if (opcode == BLOCK_LAYOUT_WEAK)
27277330f729Sjoerg weak_word_count = (inst & 0xF)+1;
27287330f729Sjoerg else
27297330f729Sjoerg return 0;
27307330f729Sjoerg break;
27317330f729Sjoerg
27327330f729Sjoerg default:
27337330f729Sjoerg return 0;
27347330f729Sjoerg }
27357330f729Sjoerg
27367330f729Sjoerg // Cannot inline when any of the word counts is 15. Because this is one less
27377330f729Sjoerg // than the actual work count (so 15 means 16 actual word counts),
27387330f729Sjoerg // and we can only display 0 thru 15 word counts.
27397330f729Sjoerg if (strong_word_count == 16 || byref_word_count == 16 || weak_word_count == 16)
27407330f729Sjoerg return 0;
27417330f729Sjoerg
27427330f729Sjoerg unsigned count =
27437330f729Sjoerg (strong_word_count != 0) + (byref_word_count != 0) + (weak_word_count != 0);
27447330f729Sjoerg
27457330f729Sjoerg if (size == count) {
27467330f729Sjoerg if (strong_word_count)
27477330f729Sjoerg Result = strong_word_count;
27487330f729Sjoerg Result <<= 4;
27497330f729Sjoerg if (byref_word_count)
27507330f729Sjoerg Result += byref_word_count;
27517330f729Sjoerg Result <<= 4;
27527330f729Sjoerg if (weak_word_count)
27537330f729Sjoerg Result += weak_word_count;
27547330f729Sjoerg }
27557330f729Sjoerg }
27567330f729Sjoerg return Result;
27577330f729Sjoerg }
27587330f729Sjoerg
getBitmapBlockLayout(bool ComputeByrefLayout)27597330f729Sjoerg llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
27607330f729Sjoerg llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
27617330f729Sjoerg if (RunSkipBlockVars.empty())
27627330f729Sjoerg return nullPtr;
27637330f729Sjoerg unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
27647330f729Sjoerg unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
27657330f729Sjoerg unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
27667330f729Sjoerg
27677330f729Sjoerg // Sort on byte position; captures might not be allocated in order,
27687330f729Sjoerg // and unions can do funny things.
27697330f729Sjoerg llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end());
27707330f729Sjoerg SmallVector<unsigned char, 16> Layout;
27717330f729Sjoerg
27727330f729Sjoerg unsigned size = RunSkipBlockVars.size();
27737330f729Sjoerg for (unsigned i = 0; i < size; i++) {
27747330f729Sjoerg enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode;
27757330f729Sjoerg CharUnits start_byte_pos = RunSkipBlockVars[i].block_var_bytepos;
27767330f729Sjoerg CharUnits end_byte_pos = start_byte_pos;
27777330f729Sjoerg unsigned j = i+1;
27787330f729Sjoerg while (j < size) {
27797330f729Sjoerg if (opcode == RunSkipBlockVars[j].opcode) {
27807330f729Sjoerg end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos;
27817330f729Sjoerg i++;
27827330f729Sjoerg }
27837330f729Sjoerg else
27847330f729Sjoerg break;
27857330f729Sjoerg }
27867330f729Sjoerg CharUnits size_in_bytes =
27877330f729Sjoerg end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size;
27887330f729Sjoerg if (j < size) {
27897330f729Sjoerg CharUnits gap =
27907330f729Sjoerg RunSkipBlockVars[j].block_var_bytepos -
27917330f729Sjoerg RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size;
27927330f729Sjoerg size_in_bytes += gap;
27937330f729Sjoerg }
27947330f729Sjoerg CharUnits residue_in_bytes = CharUnits::Zero();
27957330f729Sjoerg if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) {
27967330f729Sjoerg residue_in_bytes = size_in_bytes % WordSizeInBytes;
27977330f729Sjoerg size_in_bytes -= residue_in_bytes;
27987330f729Sjoerg opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS;
27997330f729Sjoerg }
28007330f729Sjoerg
28017330f729Sjoerg unsigned size_in_words = size_in_bytes.getQuantity() / WordSizeInBytes;
28027330f729Sjoerg while (size_in_words >= 16) {
28037330f729Sjoerg // Note that value in imm. is one less that the actual
28047330f729Sjoerg // value. So, 0xf means 16 words follow!
28057330f729Sjoerg unsigned char inst = (opcode << 4) | 0xf;
28067330f729Sjoerg Layout.push_back(inst);
28077330f729Sjoerg size_in_words -= 16;
28087330f729Sjoerg }
28097330f729Sjoerg if (size_in_words > 0) {
28107330f729Sjoerg // Note that value in imm. is one less that the actual
28117330f729Sjoerg // value. So, we subtract 1 away!
28127330f729Sjoerg unsigned char inst = (opcode << 4) | (size_in_words-1);
28137330f729Sjoerg Layout.push_back(inst);
28147330f729Sjoerg }
28157330f729Sjoerg if (residue_in_bytes > CharUnits::Zero()) {
28167330f729Sjoerg unsigned char inst =
28177330f729Sjoerg (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
28187330f729Sjoerg Layout.push_back(inst);
28197330f729Sjoerg }
28207330f729Sjoerg }
28217330f729Sjoerg
28227330f729Sjoerg while (!Layout.empty()) {
28237330f729Sjoerg unsigned char inst = Layout.back();
28247330f729Sjoerg enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
28257330f729Sjoerg if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS)
28267330f729Sjoerg Layout.pop_back();
28277330f729Sjoerg else
28287330f729Sjoerg break;
28297330f729Sjoerg }
28307330f729Sjoerg
28317330f729Sjoerg uint64_t Result = InlineLayoutInstruction(Layout);
28327330f729Sjoerg if (Result != 0) {
28337330f729Sjoerg // Block variable layout instruction has been inlined.
28347330f729Sjoerg if (CGM.getLangOpts().ObjCGCBitmapPrint) {
28357330f729Sjoerg if (ComputeByrefLayout)
28367330f729Sjoerg printf("\n Inline BYREF variable layout: ");
28377330f729Sjoerg else
28387330f729Sjoerg printf("\n Inline block variable layout: ");
28397330f729Sjoerg printf("0x0%" PRIx64 "", Result);
28407330f729Sjoerg if (auto numStrong = (Result & 0xF00) >> 8)
28417330f729Sjoerg printf(", BL_STRONG:%d", (int) numStrong);
28427330f729Sjoerg if (auto numByref = (Result & 0x0F0) >> 4)
28437330f729Sjoerg printf(", BL_BYREF:%d", (int) numByref);
28447330f729Sjoerg if (auto numWeak = (Result & 0x00F) >> 0)
28457330f729Sjoerg printf(", BL_WEAK:%d", (int) numWeak);
28467330f729Sjoerg printf(", BL_OPERATOR:0\n");
28477330f729Sjoerg }
28487330f729Sjoerg return llvm::ConstantInt::get(CGM.IntPtrTy, Result);
28497330f729Sjoerg }
28507330f729Sjoerg
28517330f729Sjoerg unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
28527330f729Sjoerg Layout.push_back(inst);
28537330f729Sjoerg std::string BitMap;
28547330f729Sjoerg for (unsigned i = 0, e = Layout.size(); i != e; i++)
28557330f729Sjoerg BitMap += Layout[i];
28567330f729Sjoerg
28577330f729Sjoerg if (CGM.getLangOpts().ObjCGCBitmapPrint) {
28587330f729Sjoerg if (ComputeByrefLayout)
28597330f729Sjoerg printf("\n Byref variable layout: ");
28607330f729Sjoerg else
28617330f729Sjoerg printf("\n Block variable layout: ");
28627330f729Sjoerg for (unsigned i = 0, e = BitMap.size(); i != e; i++) {
28637330f729Sjoerg unsigned char inst = BitMap[i];
28647330f729Sjoerg enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
28657330f729Sjoerg unsigned delta = 1;
28667330f729Sjoerg switch (opcode) {
28677330f729Sjoerg case BLOCK_LAYOUT_OPERATOR:
28687330f729Sjoerg printf("BL_OPERATOR:");
28697330f729Sjoerg delta = 0;
28707330f729Sjoerg break;
28717330f729Sjoerg case BLOCK_LAYOUT_NON_OBJECT_BYTES:
28727330f729Sjoerg printf("BL_NON_OBJECT_BYTES:");
28737330f729Sjoerg break;
28747330f729Sjoerg case BLOCK_LAYOUT_NON_OBJECT_WORDS:
28757330f729Sjoerg printf("BL_NON_OBJECT_WORD:");
28767330f729Sjoerg break;
28777330f729Sjoerg case BLOCK_LAYOUT_STRONG:
28787330f729Sjoerg printf("BL_STRONG:");
28797330f729Sjoerg break;
28807330f729Sjoerg case BLOCK_LAYOUT_BYREF:
28817330f729Sjoerg printf("BL_BYREF:");
28827330f729Sjoerg break;
28837330f729Sjoerg case BLOCK_LAYOUT_WEAK:
28847330f729Sjoerg printf("BL_WEAK:");
28857330f729Sjoerg break;
28867330f729Sjoerg case BLOCK_LAYOUT_UNRETAINED:
28877330f729Sjoerg printf("BL_UNRETAINED:");
28887330f729Sjoerg break;
28897330f729Sjoerg }
28907330f729Sjoerg // Actual value of word count is one more that what is in the imm.
28917330f729Sjoerg // field of the instruction
28927330f729Sjoerg printf("%d", (inst & 0xf) + delta);
28937330f729Sjoerg if (i < e-1)
28947330f729Sjoerg printf(", ");
28957330f729Sjoerg else
28967330f729Sjoerg printf("\n");
28977330f729Sjoerg }
28987330f729Sjoerg }
28997330f729Sjoerg
29007330f729Sjoerg auto *Entry = CreateCStringLiteral(BitMap, ObjCLabelType::ClassName,
29017330f729Sjoerg /*ForceNonFragileABI=*/true,
29027330f729Sjoerg /*NullTerminate=*/false);
29037330f729Sjoerg return getConstantGEP(VMContext, Entry, 0, 0);
29047330f729Sjoerg }
29057330f729Sjoerg
getBlockLayoutInfoString(const SmallVectorImpl<CGObjCCommonMac::RUN_SKIP> & RunSkipBlockVars,bool HasCopyDisposeHelpers)29067330f729Sjoerg static std::string getBlockLayoutInfoString(
29077330f729Sjoerg const SmallVectorImpl<CGObjCCommonMac::RUN_SKIP> &RunSkipBlockVars,
29087330f729Sjoerg bool HasCopyDisposeHelpers) {
29097330f729Sjoerg std::string Str;
29107330f729Sjoerg for (const CGObjCCommonMac::RUN_SKIP &R : RunSkipBlockVars) {
29117330f729Sjoerg if (R.opcode == CGObjCCommonMac::BLOCK_LAYOUT_UNRETAINED) {
29127330f729Sjoerg // Copy/dispose helpers don't have any information about
29137330f729Sjoerg // __unsafe_unretained captures, so unconditionally concatenate a string.
29147330f729Sjoerg Str += "u";
29157330f729Sjoerg } else if (HasCopyDisposeHelpers) {
29167330f729Sjoerg // Information about __strong, __weak, or byref captures has already been
29177330f729Sjoerg // encoded into the names of the copy/dispose helpers. We have to add a
29187330f729Sjoerg // string here only when the copy/dispose helpers aren't generated (which
29197330f729Sjoerg // happens when the block is non-escaping).
29207330f729Sjoerg continue;
29217330f729Sjoerg } else {
29227330f729Sjoerg switch (R.opcode) {
29237330f729Sjoerg case CGObjCCommonMac::BLOCK_LAYOUT_STRONG:
29247330f729Sjoerg Str += "s";
29257330f729Sjoerg break;
29267330f729Sjoerg case CGObjCCommonMac::BLOCK_LAYOUT_BYREF:
29277330f729Sjoerg Str += "r";
29287330f729Sjoerg break;
29297330f729Sjoerg case CGObjCCommonMac::BLOCK_LAYOUT_WEAK:
29307330f729Sjoerg Str += "w";
29317330f729Sjoerg break;
29327330f729Sjoerg default:
29337330f729Sjoerg continue;
29347330f729Sjoerg }
29357330f729Sjoerg }
29367330f729Sjoerg Str += llvm::to_string(R.block_var_bytepos.getQuantity());
29377330f729Sjoerg Str += "l" + llvm::to_string(R.block_var_size.getQuantity());
29387330f729Sjoerg }
29397330f729Sjoerg return Str;
29407330f729Sjoerg }
29417330f729Sjoerg
fillRunSkipBlockVars(CodeGenModule & CGM,const CGBlockInfo & blockInfo)29427330f729Sjoerg void CGObjCCommonMac::fillRunSkipBlockVars(CodeGenModule &CGM,
29437330f729Sjoerg const CGBlockInfo &blockInfo) {
29447330f729Sjoerg assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
29457330f729Sjoerg
29467330f729Sjoerg RunSkipBlockVars.clear();
29477330f729Sjoerg bool hasUnion = false;
29487330f729Sjoerg
29497330f729Sjoerg unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
29507330f729Sjoerg unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
29517330f729Sjoerg unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
29527330f729Sjoerg
29537330f729Sjoerg const BlockDecl *blockDecl = blockInfo.getBlockDecl();
29547330f729Sjoerg
29557330f729Sjoerg // Calculate the basic layout of the block structure.
29567330f729Sjoerg const llvm::StructLayout *layout =
29577330f729Sjoerg CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
29587330f729Sjoerg
29597330f729Sjoerg // Ignore the optional 'this' capture: C++ objects are not assumed
29607330f729Sjoerg // to be GC'ed.
29617330f729Sjoerg if (blockInfo.BlockHeaderForcedGapSize != CharUnits::Zero())
29627330f729Sjoerg UpdateRunSkipBlockVars(false, Qualifiers::OCL_None,
29637330f729Sjoerg blockInfo.BlockHeaderForcedGapOffset,
29647330f729Sjoerg blockInfo.BlockHeaderForcedGapSize);
29657330f729Sjoerg // Walk the captured variables.
29667330f729Sjoerg for (const auto &CI : blockDecl->captures()) {
29677330f729Sjoerg const VarDecl *variable = CI.getVariable();
29687330f729Sjoerg QualType type = variable->getType();
29697330f729Sjoerg
29707330f729Sjoerg const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
29717330f729Sjoerg
29727330f729Sjoerg // Ignore constant captures.
29737330f729Sjoerg if (capture.isConstant()) continue;
29747330f729Sjoerg
29757330f729Sjoerg CharUnits fieldOffset =
29767330f729Sjoerg CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
29777330f729Sjoerg
29787330f729Sjoerg assert(!type->isArrayType() && "array variable should not be caught");
29797330f729Sjoerg if (!CI.isByRef())
29807330f729Sjoerg if (const RecordType *record = type->getAs<RecordType>()) {
29817330f729Sjoerg BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
29827330f729Sjoerg continue;
29837330f729Sjoerg }
29847330f729Sjoerg CharUnits fieldSize;
29857330f729Sjoerg if (CI.isByRef())
29867330f729Sjoerg fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
29877330f729Sjoerg else
29887330f729Sjoerg fieldSize = CGM.getContext().getTypeSizeInChars(type);
29897330f729Sjoerg UpdateRunSkipBlockVars(CI.isByRef(), getBlockCaptureLifetime(type, false),
29907330f729Sjoerg fieldOffset, fieldSize);
29917330f729Sjoerg }
29927330f729Sjoerg }
29937330f729Sjoerg
29947330f729Sjoerg llvm::Constant *
BuildRCBlockLayout(CodeGenModule & CGM,const CGBlockInfo & blockInfo)29957330f729Sjoerg CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
29967330f729Sjoerg const CGBlockInfo &blockInfo) {
29977330f729Sjoerg fillRunSkipBlockVars(CGM, blockInfo);
29987330f729Sjoerg return getBitmapBlockLayout(false);
29997330f729Sjoerg }
30007330f729Sjoerg
getRCBlockLayoutStr(CodeGenModule & CGM,const CGBlockInfo & blockInfo)30017330f729Sjoerg std::string CGObjCCommonMac::getRCBlockLayoutStr(CodeGenModule &CGM,
30027330f729Sjoerg const CGBlockInfo &blockInfo) {
30037330f729Sjoerg fillRunSkipBlockVars(CGM, blockInfo);
30047330f729Sjoerg return getBlockLayoutInfoString(RunSkipBlockVars,
30057330f729Sjoerg blockInfo.needsCopyDisposeHelpers());
30067330f729Sjoerg }
30077330f729Sjoerg
BuildByrefLayout(CodeGen::CodeGenModule & CGM,QualType T)30087330f729Sjoerg llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
30097330f729Sjoerg QualType T) {
30107330f729Sjoerg assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
30117330f729Sjoerg assert(!T->isArrayType() && "__block array variable should not be caught");
30127330f729Sjoerg CharUnits fieldOffset;
30137330f729Sjoerg RunSkipBlockVars.clear();
30147330f729Sjoerg bool hasUnion = false;
30157330f729Sjoerg if (const RecordType *record = T->getAs<RecordType>()) {
30167330f729Sjoerg BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */);
30177330f729Sjoerg llvm::Constant *Result = getBitmapBlockLayout(true);
30187330f729Sjoerg if (isa<llvm::ConstantInt>(Result))
30197330f729Sjoerg Result = llvm::ConstantExpr::getIntToPtr(Result, CGM.Int8PtrTy);
30207330f729Sjoerg return Result;
30217330f729Sjoerg }
30227330f729Sjoerg llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
30237330f729Sjoerg return nullPtr;
30247330f729Sjoerg }
30257330f729Sjoerg
GenerateProtocolRef(CodeGenFunction & CGF,const ObjCProtocolDecl * PD)30267330f729Sjoerg llvm::Value *CGObjCMac::GenerateProtocolRef(CodeGenFunction &CGF,
30277330f729Sjoerg const ObjCProtocolDecl *PD) {
30287330f729Sjoerg // FIXME: I don't understand why gcc generates this, or where it is
30297330f729Sjoerg // resolved. Investigate. Its also wasteful to look this up over and over.
30307330f729Sjoerg LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
30317330f729Sjoerg
30327330f729Sjoerg return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
30337330f729Sjoerg ObjCTypes.getExternalProtocolPtrTy());
30347330f729Sjoerg }
30357330f729Sjoerg
GenerateProtocol(const ObjCProtocolDecl * PD)30367330f729Sjoerg void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
30377330f729Sjoerg // FIXME: We shouldn't need this, the protocol decl should contain enough
30387330f729Sjoerg // information to tell us whether this was a declaration or a definition.
30397330f729Sjoerg DefinedProtocols.insert(PD->getIdentifier());
30407330f729Sjoerg
30417330f729Sjoerg // If we have generated a forward reference to this protocol, emit
30427330f729Sjoerg // it now. Otherwise do nothing, the protocol objects are lazily
30437330f729Sjoerg // emitted.
30447330f729Sjoerg if (Protocols.count(PD->getIdentifier()))
30457330f729Sjoerg GetOrEmitProtocol(PD);
30467330f729Sjoerg }
30477330f729Sjoerg
GetProtocolRef(const ObjCProtocolDecl * PD)30487330f729Sjoerg llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
30497330f729Sjoerg if (DefinedProtocols.count(PD->getIdentifier()))
30507330f729Sjoerg return GetOrEmitProtocol(PD);
30517330f729Sjoerg
30527330f729Sjoerg return GetOrEmitProtocolRef(PD);
30537330f729Sjoerg }
30547330f729Sjoerg
EmitClassRefViaRuntime(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID,ObjCCommonTypesHelper & ObjCTypes)30557330f729Sjoerg llvm::Value *CGObjCCommonMac::EmitClassRefViaRuntime(
30567330f729Sjoerg CodeGenFunction &CGF,
30577330f729Sjoerg const ObjCInterfaceDecl *ID,
30587330f729Sjoerg ObjCCommonTypesHelper &ObjCTypes) {
30597330f729Sjoerg llvm::FunctionCallee lookUpClassFn = ObjCTypes.getLookUpClassFn();
30607330f729Sjoerg
3061*e038c9c4Sjoerg llvm::Value *className = CGF.CGM
3062*e038c9c4Sjoerg .GetAddrOfConstantCString(std::string(
3063*e038c9c4Sjoerg ID->getObjCRuntimeNameAsString()))
30647330f729Sjoerg .getPointer();
30657330f729Sjoerg ASTContext &ctx = CGF.CGM.getContext();
30667330f729Sjoerg className =
30677330f729Sjoerg CGF.Builder.CreateBitCast(className,
30687330f729Sjoerg CGF.ConvertType(
30697330f729Sjoerg ctx.getPointerType(ctx.CharTy.withConst())));
30707330f729Sjoerg llvm::CallInst *call = CGF.Builder.CreateCall(lookUpClassFn, className);
30717330f729Sjoerg call->setDoesNotThrow();
30727330f729Sjoerg return call;
30737330f729Sjoerg }
30747330f729Sjoerg
30757330f729Sjoerg /*
30767330f729Sjoerg // Objective-C 1.0 extensions
30777330f729Sjoerg struct _objc_protocol {
30787330f729Sjoerg struct _objc_protocol_extension *isa;
30797330f729Sjoerg char *protocol_name;
30807330f729Sjoerg struct _objc_protocol_list *protocol_list;
30817330f729Sjoerg struct _objc__method_prototype_list *instance_methods;
30827330f729Sjoerg struct _objc__method_prototype_list *class_methods
30837330f729Sjoerg };
30847330f729Sjoerg
30857330f729Sjoerg See EmitProtocolExtension().
30867330f729Sjoerg */
GetOrEmitProtocol(const ObjCProtocolDecl * PD)30877330f729Sjoerg llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
30887330f729Sjoerg llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()];
30897330f729Sjoerg
30907330f729Sjoerg // Early exit if a defining object has already been generated.
30917330f729Sjoerg if (Entry && Entry->hasInitializer())
30927330f729Sjoerg return Entry;
30937330f729Sjoerg
30947330f729Sjoerg // Use the protocol definition, if there is one.
30957330f729Sjoerg if (const ObjCProtocolDecl *Def = PD->getDefinition())
30967330f729Sjoerg PD = Def;
30977330f729Sjoerg
30987330f729Sjoerg // FIXME: I don't understand why gcc generates this, or where it is
30997330f729Sjoerg // resolved. Investigate. Its also wasteful to look this up over and over.
31007330f729Sjoerg LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
31017330f729Sjoerg
31027330f729Sjoerg // Construct method lists.
31037330f729Sjoerg auto methodLists = ProtocolMethodLists::get(PD);
31047330f729Sjoerg
31057330f729Sjoerg ConstantInitBuilder builder(CGM);
31067330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ProtocolTy);
31077330f729Sjoerg values.add(EmitProtocolExtension(PD, methodLists));
31087330f729Sjoerg values.add(GetClassName(PD->getObjCRuntimeNameAsString()));
31097330f729Sjoerg values.add(EmitProtocolList("OBJC_PROTOCOL_REFS_" + PD->getName(),
31107330f729Sjoerg PD->protocol_begin(), PD->protocol_end()));
31117330f729Sjoerg values.add(methodLists.emitMethodList(this, PD,
31127330f729Sjoerg ProtocolMethodLists::RequiredInstanceMethods));
31137330f729Sjoerg values.add(methodLists.emitMethodList(this, PD,
31147330f729Sjoerg ProtocolMethodLists::RequiredClassMethods));
31157330f729Sjoerg
31167330f729Sjoerg if (Entry) {
31177330f729Sjoerg // Already created, update the initializer.
31187330f729Sjoerg assert(Entry->hasPrivateLinkage());
31197330f729Sjoerg values.finishAndSetAsInitializer(Entry);
31207330f729Sjoerg } else {
31217330f729Sjoerg Entry = values.finishAndCreateGlobal("OBJC_PROTOCOL_" + PD->getName(),
31227330f729Sjoerg CGM.getPointerAlign(),
31237330f729Sjoerg /*constant*/ false,
31247330f729Sjoerg llvm::GlobalValue::PrivateLinkage);
31257330f729Sjoerg Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
31267330f729Sjoerg
31277330f729Sjoerg Protocols[PD->getIdentifier()] = Entry;
31287330f729Sjoerg }
31297330f729Sjoerg CGM.addCompilerUsedGlobal(Entry);
31307330f729Sjoerg
31317330f729Sjoerg return Entry;
31327330f729Sjoerg }
31337330f729Sjoerg
GetOrEmitProtocolRef(const ObjCProtocolDecl * PD)31347330f729Sjoerg llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
31357330f729Sjoerg llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
31367330f729Sjoerg
31377330f729Sjoerg if (!Entry) {
31387330f729Sjoerg // We use the initializer as a marker of whether this is a forward
31397330f729Sjoerg // reference or not. At module finalization we add the empty
31407330f729Sjoerg // contents for protocols which were referenced but never defined.
31417330f729Sjoerg Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy,
31427330f729Sjoerg false, llvm::GlobalValue::PrivateLinkage,
31437330f729Sjoerg nullptr, "OBJC_PROTOCOL_" + PD->getName());
31447330f729Sjoerg Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
31457330f729Sjoerg // FIXME: Is this necessary? Why only for protocol?
31467330f729Sjoerg Entry->setAlignment(llvm::Align(4));
31477330f729Sjoerg }
31487330f729Sjoerg
31497330f729Sjoerg return Entry;
31507330f729Sjoerg }
31517330f729Sjoerg
31527330f729Sjoerg /*
31537330f729Sjoerg struct _objc_protocol_extension {
31547330f729Sjoerg uint32_t size;
31557330f729Sjoerg struct objc_method_description_list *optional_instance_methods;
31567330f729Sjoerg struct objc_method_description_list *optional_class_methods;
31577330f729Sjoerg struct objc_property_list *instance_properties;
31587330f729Sjoerg const char ** extendedMethodTypes;
31597330f729Sjoerg struct objc_property_list *class_properties;
31607330f729Sjoerg };
31617330f729Sjoerg */
31627330f729Sjoerg llvm::Constant *
EmitProtocolExtension(const ObjCProtocolDecl * PD,const ProtocolMethodLists & methodLists)31637330f729Sjoerg CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
31647330f729Sjoerg const ProtocolMethodLists &methodLists) {
31657330f729Sjoerg auto optInstanceMethods =
31667330f729Sjoerg methodLists.emitMethodList(this, PD,
31677330f729Sjoerg ProtocolMethodLists::OptionalInstanceMethods);
31687330f729Sjoerg auto optClassMethods =
31697330f729Sjoerg methodLists.emitMethodList(this, PD,
31707330f729Sjoerg ProtocolMethodLists::OptionalClassMethods);
31717330f729Sjoerg
31727330f729Sjoerg auto extendedMethodTypes =
31737330f729Sjoerg EmitProtocolMethodTypes("OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
31747330f729Sjoerg methodLists.emitExtendedTypesArray(this),
31757330f729Sjoerg ObjCTypes);
31767330f729Sjoerg
31777330f729Sjoerg auto instanceProperties =
31787330f729Sjoerg EmitPropertyList("OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr, PD,
31797330f729Sjoerg ObjCTypes, false);
31807330f729Sjoerg auto classProperties =
31817330f729Sjoerg EmitPropertyList("OBJC_$_CLASS_PROP_PROTO_LIST_" + PD->getName(), nullptr,
31827330f729Sjoerg PD, ObjCTypes, true);
31837330f729Sjoerg
31847330f729Sjoerg // Return null if no extension bits are used.
31857330f729Sjoerg if (optInstanceMethods->isNullValue() &&
31867330f729Sjoerg optClassMethods->isNullValue() &&
31877330f729Sjoerg extendedMethodTypes->isNullValue() &&
31887330f729Sjoerg instanceProperties->isNullValue() &&
31897330f729Sjoerg classProperties->isNullValue()) {
31907330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
31917330f729Sjoerg }
31927330f729Sjoerg
31937330f729Sjoerg uint64_t size =
31947330f729Sjoerg CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
31957330f729Sjoerg
31967330f729Sjoerg ConstantInitBuilder builder(CGM);
31977330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ProtocolExtensionTy);
31987330f729Sjoerg values.addInt(ObjCTypes.IntTy, size);
31997330f729Sjoerg values.add(optInstanceMethods);
32007330f729Sjoerg values.add(optClassMethods);
32017330f729Sjoerg values.add(instanceProperties);
32027330f729Sjoerg values.add(extendedMethodTypes);
32037330f729Sjoerg values.add(classProperties);
32047330f729Sjoerg
32057330f729Sjoerg // No special section, but goes in llvm.used
32067330f729Sjoerg return CreateMetadataVar("_OBJC_PROTOCOLEXT_" + PD->getName(), values,
32077330f729Sjoerg StringRef(), CGM.getPointerAlign(), true);
32087330f729Sjoerg }
32097330f729Sjoerg
32107330f729Sjoerg /*
32117330f729Sjoerg struct objc_protocol_list {
32127330f729Sjoerg struct objc_protocol_list *next;
32137330f729Sjoerg long count;
32147330f729Sjoerg Protocol *list[];
32157330f729Sjoerg };
32167330f729Sjoerg */
32177330f729Sjoerg llvm::Constant *
EmitProtocolList(Twine name,ObjCProtocolDecl::protocol_iterator begin,ObjCProtocolDecl::protocol_iterator end)32187330f729Sjoerg CGObjCMac::EmitProtocolList(Twine name,
32197330f729Sjoerg ObjCProtocolDecl::protocol_iterator begin,
32207330f729Sjoerg ObjCProtocolDecl::protocol_iterator end) {
32217330f729Sjoerg // Just return null for empty protocol lists
3222*e038c9c4Sjoerg auto PDs = GetRuntimeProtocolList(begin, end);
3223*e038c9c4Sjoerg if (PDs.empty())
32247330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
32257330f729Sjoerg
32267330f729Sjoerg ConstantInitBuilder builder(CGM);
32277330f729Sjoerg auto values = builder.beginStruct();
32287330f729Sjoerg
32297330f729Sjoerg // This field is only used by the runtime.
32307330f729Sjoerg values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
32317330f729Sjoerg
32327330f729Sjoerg // Reserve a slot for the count.
32337330f729Sjoerg auto countSlot = values.addPlaceholder();
32347330f729Sjoerg
32357330f729Sjoerg auto refsArray = values.beginArray(ObjCTypes.ProtocolPtrTy);
3236*e038c9c4Sjoerg for (const auto *Proto : PDs)
3237*e038c9c4Sjoerg refsArray.add(GetProtocolRef(Proto));
3238*e038c9c4Sjoerg
32397330f729Sjoerg auto count = refsArray.size();
32407330f729Sjoerg
32417330f729Sjoerg // This list is null terminated.
32427330f729Sjoerg refsArray.addNullPointer(ObjCTypes.ProtocolPtrTy);
32437330f729Sjoerg
32447330f729Sjoerg refsArray.finishAndAddTo(values);
32457330f729Sjoerg values.fillPlaceholderWithInt(countSlot, ObjCTypes.LongTy, count);
32467330f729Sjoerg
32477330f729Sjoerg StringRef section;
32487330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO())
32497330f729Sjoerg section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
32507330f729Sjoerg
32517330f729Sjoerg llvm::GlobalVariable *GV =
32527330f729Sjoerg CreateMetadataVar(name, values, section, CGM.getPointerAlign(), false);
32537330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
32547330f729Sjoerg }
32557330f729Sjoerg
32567330f729Sjoerg static void
PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo *,16> & PropertySet,SmallVectorImpl<const ObjCPropertyDecl * > & Properties,const ObjCProtocolDecl * Proto,bool IsClassProperty)32577330f729Sjoerg PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
32587330f729Sjoerg SmallVectorImpl<const ObjCPropertyDecl *> &Properties,
32597330f729Sjoerg const ObjCProtocolDecl *Proto,
32607330f729Sjoerg bool IsClassProperty) {
32617330f729Sjoerg for (const auto *PD : Proto->properties()) {
32627330f729Sjoerg if (IsClassProperty != PD->isClassProperty())
32637330f729Sjoerg continue;
32647330f729Sjoerg if (!PropertySet.insert(PD->getIdentifier()).second)
32657330f729Sjoerg continue;
32667330f729Sjoerg Properties.push_back(PD);
32677330f729Sjoerg }
3268*e038c9c4Sjoerg
3269*e038c9c4Sjoerg for (const auto *P : Proto->protocols())
3270*e038c9c4Sjoerg PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
32717330f729Sjoerg }
32727330f729Sjoerg
32737330f729Sjoerg /*
32747330f729Sjoerg struct _objc_property {
32757330f729Sjoerg const char * const name;
32767330f729Sjoerg const char * const attributes;
32777330f729Sjoerg };
32787330f729Sjoerg
32797330f729Sjoerg struct _objc_property_list {
32807330f729Sjoerg uint32_t entsize; // sizeof (struct _objc_property)
32817330f729Sjoerg uint32_t prop_count;
32827330f729Sjoerg struct _objc_property[prop_count];
32837330f729Sjoerg };
32847330f729Sjoerg */
EmitPropertyList(Twine Name,const Decl * Container,const ObjCContainerDecl * OCD,const ObjCCommonTypesHelper & ObjCTypes,bool IsClassProperty)32857330f729Sjoerg llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
32867330f729Sjoerg const Decl *Container,
32877330f729Sjoerg const ObjCContainerDecl *OCD,
32887330f729Sjoerg const ObjCCommonTypesHelper &ObjCTypes,
32897330f729Sjoerg bool IsClassProperty) {
32907330f729Sjoerg if (IsClassProperty) {
32917330f729Sjoerg // Make this entry NULL for OS X with deployment target < 10.11, for iOS
32927330f729Sjoerg // with deployment target < 9.0.
32937330f729Sjoerg const llvm::Triple &Triple = CGM.getTarget().getTriple();
32947330f729Sjoerg if ((Triple.isMacOSX() && Triple.isMacOSXVersionLT(10, 11)) ||
32957330f729Sjoerg (Triple.isiOS() && Triple.isOSVersionLT(9)))
32967330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
32977330f729Sjoerg }
32987330f729Sjoerg
32997330f729Sjoerg SmallVector<const ObjCPropertyDecl *, 16> Properties;
33007330f729Sjoerg llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
33017330f729Sjoerg
33027330f729Sjoerg if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
33037330f729Sjoerg for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
33047330f729Sjoerg for (auto *PD : ClassExt->properties()) {
33057330f729Sjoerg if (IsClassProperty != PD->isClassProperty())
33067330f729Sjoerg continue;
3307*e038c9c4Sjoerg if (PD->isDirectProperty())
3308*e038c9c4Sjoerg continue;
33097330f729Sjoerg PropertySet.insert(PD->getIdentifier());
33107330f729Sjoerg Properties.push_back(PD);
33117330f729Sjoerg }
33127330f729Sjoerg
33137330f729Sjoerg for (const auto *PD : OCD->properties()) {
33147330f729Sjoerg if (IsClassProperty != PD->isClassProperty())
33157330f729Sjoerg continue;
33167330f729Sjoerg // Don't emit duplicate metadata for properties that were already in a
33177330f729Sjoerg // class extension.
33187330f729Sjoerg if (!PropertySet.insert(PD->getIdentifier()).second)
33197330f729Sjoerg continue;
3320*e038c9c4Sjoerg if (PD->isDirectProperty())
3321*e038c9c4Sjoerg continue;
33227330f729Sjoerg Properties.push_back(PD);
33237330f729Sjoerg }
33247330f729Sjoerg
33257330f729Sjoerg if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
33267330f729Sjoerg for (const auto *P : OID->all_referenced_protocols())
33277330f729Sjoerg PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
33287330f729Sjoerg }
33297330f729Sjoerg else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD)) {
33307330f729Sjoerg for (const auto *P : CD->protocols())
33317330f729Sjoerg PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
33327330f729Sjoerg }
33337330f729Sjoerg
33347330f729Sjoerg // Return null for empty list.
33357330f729Sjoerg if (Properties.empty())
33367330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
33377330f729Sjoerg
33387330f729Sjoerg unsigned propertySize =
33397330f729Sjoerg CGM.getDataLayout().getTypeAllocSize(ObjCTypes.PropertyTy);
33407330f729Sjoerg
33417330f729Sjoerg ConstantInitBuilder builder(CGM);
33427330f729Sjoerg auto values = builder.beginStruct();
33437330f729Sjoerg values.addInt(ObjCTypes.IntTy, propertySize);
33447330f729Sjoerg values.addInt(ObjCTypes.IntTy, Properties.size());
33457330f729Sjoerg auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy);
33467330f729Sjoerg for (auto PD : Properties) {
33477330f729Sjoerg auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy);
33487330f729Sjoerg property.add(GetPropertyName(PD->getIdentifier()));
33497330f729Sjoerg property.add(GetPropertyTypeString(PD, Container));
33507330f729Sjoerg property.finishAndAddTo(propertiesArray);
33517330f729Sjoerg }
33527330f729Sjoerg propertiesArray.finishAndAddTo(values);
33537330f729Sjoerg
33547330f729Sjoerg StringRef Section;
33557330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO())
33567330f729Sjoerg Section = (ObjCABI == 2) ? "__DATA, __objc_const"
33577330f729Sjoerg : "__OBJC,__property,regular,no_dead_strip";
33587330f729Sjoerg
33597330f729Sjoerg llvm::GlobalVariable *GV =
33607330f729Sjoerg CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true);
33617330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy);
33627330f729Sjoerg }
33637330f729Sjoerg
33647330f729Sjoerg llvm::Constant *
EmitProtocolMethodTypes(Twine Name,ArrayRef<llvm::Constant * > MethodTypes,const ObjCCommonTypesHelper & ObjCTypes)33657330f729Sjoerg CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name,
33667330f729Sjoerg ArrayRef<llvm::Constant*> MethodTypes,
33677330f729Sjoerg const ObjCCommonTypesHelper &ObjCTypes) {
33687330f729Sjoerg // Return null for empty list.
33697330f729Sjoerg if (MethodTypes.empty())
33707330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.Int8PtrPtrTy);
33717330f729Sjoerg
33727330f729Sjoerg llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
33737330f729Sjoerg MethodTypes.size());
33747330f729Sjoerg llvm::Constant *Init = llvm::ConstantArray::get(AT, MethodTypes);
33757330f729Sjoerg
33767330f729Sjoerg StringRef Section;
33777330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO() && ObjCABI == 2)
33787330f729Sjoerg Section = "__DATA, __objc_const";
33797330f729Sjoerg
33807330f729Sjoerg llvm::GlobalVariable *GV =
33817330f729Sjoerg CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true);
33827330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy);
33837330f729Sjoerg }
33847330f729Sjoerg
33857330f729Sjoerg /*
33867330f729Sjoerg struct _objc_category {
33877330f729Sjoerg char *category_name;
33887330f729Sjoerg char *class_name;
33897330f729Sjoerg struct _objc_method_list *instance_methods;
33907330f729Sjoerg struct _objc_method_list *class_methods;
33917330f729Sjoerg struct _objc_protocol_list *protocols;
33927330f729Sjoerg uint32_t size; // <rdar://4585769>
33937330f729Sjoerg struct _objc_property_list *instance_properties;
33947330f729Sjoerg struct _objc_property_list *class_properties;
33957330f729Sjoerg };
33967330f729Sjoerg */
GenerateCategory(const ObjCCategoryImplDecl * OCD)33977330f729Sjoerg void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
33987330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategoryTy);
33997330f729Sjoerg
34007330f729Sjoerg // FIXME: This is poor design, the OCD should have a pointer to the category
34017330f729Sjoerg // decl. Additionally, note that Category can be null for the @implementation
34027330f729Sjoerg // w/o an @interface case. Sema should just create one for us as it does for
34037330f729Sjoerg // @implementation so everyone else can live life under a clear blue sky.
34047330f729Sjoerg const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
34057330f729Sjoerg const ObjCCategoryDecl *Category =
34067330f729Sjoerg Interface->FindCategoryDeclaration(OCD->getIdentifier());
34077330f729Sjoerg
34087330f729Sjoerg SmallString<256> ExtName;
34097330f729Sjoerg llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_'
34107330f729Sjoerg << OCD->getName();
34117330f729Sjoerg
34127330f729Sjoerg ConstantInitBuilder Builder(CGM);
34137330f729Sjoerg auto Values = Builder.beginStruct(ObjCTypes.CategoryTy);
34147330f729Sjoerg
34157330f729Sjoerg enum {
34167330f729Sjoerg InstanceMethods,
34177330f729Sjoerg ClassMethods,
34187330f729Sjoerg NumMethodLists
34197330f729Sjoerg };
34207330f729Sjoerg SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
34217330f729Sjoerg for (const auto *MD : OCD->methods()) {
3422*e038c9c4Sjoerg if (!MD->isDirectMethod())
34237330f729Sjoerg Methods[unsigned(MD->isClassMethod())].push_back(MD);
34247330f729Sjoerg }
34257330f729Sjoerg
34267330f729Sjoerg Values.add(GetClassName(OCD->getName()));
34277330f729Sjoerg Values.add(GetClassName(Interface->getObjCRuntimeNameAsString()));
34287330f729Sjoerg LazySymbols.insert(Interface->getIdentifier());
34297330f729Sjoerg
34307330f729Sjoerg Values.add(emitMethodList(ExtName, MethodListType::CategoryInstanceMethods,
34317330f729Sjoerg Methods[InstanceMethods]));
34327330f729Sjoerg Values.add(emitMethodList(ExtName, MethodListType::CategoryClassMethods,
34337330f729Sjoerg Methods[ClassMethods]));
34347330f729Sjoerg if (Category) {
34357330f729Sjoerg Values.add(
34367330f729Sjoerg EmitProtocolList("OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(),
34377330f729Sjoerg Category->protocol_begin(), Category->protocol_end()));
34387330f729Sjoerg } else {
34397330f729Sjoerg Values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
34407330f729Sjoerg }
34417330f729Sjoerg Values.addInt(ObjCTypes.IntTy, Size);
34427330f729Sjoerg
34437330f729Sjoerg // If there is no category @interface then there can be no properties.
34447330f729Sjoerg if (Category) {
34457330f729Sjoerg Values.add(EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(),
34467330f729Sjoerg OCD, Category, ObjCTypes, false));
34477330f729Sjoerg Values.add(EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(),
34487330f729Sjoerg OCD, Category, ObjCTypes, true));
34497330f729Sjoerg } else {
34507330f729Sjoerg Values.addNullPointer(ObjCTypes.PropertyListPtrTy);
34517330f729Sjoerg Values.addNullPointer(ObjCTypes.PropertyListPtrTy);
34527330f729Sjoerg }
34537330f729Sjoerg
34547330f729Sjoerg llvm::GlobalVariable *GV =
34557330f729Sjoerg CreateMetadataVar("OBJC_CATEGORY_" + ExtName.str(), Values,
34567330f729Sjoerg "__OBJC,__category,regular,no_dead_strip",
34577330f729Sjoerg CGM.getPointerAlign(), true);
34587330f729Sjoerg DefinedCategories.push_back(GV);
34597330f729Sjoerg DefinedCategoryNames.insert(llvm::CachedHashString(ExtName));
34607330f729Sjoerg // method definition entries must be clear for next implementation.
34617330f729Sjoerg MethodDefinitions.clear();
34627330f729Sjoerg }
34637330f729Sjoerg
34647330f729Sjoerg enum FragileClassFlags {
34657330f729Sjoerg /// Apparently: is not a meta-class.
34667330f729Sjoerg FragileABI_Class_Factory = 0x00001,
34677330f729Sjoerg
34687330f729Sjoerg /// Is a meta-class.
34697330f729Sjoerg FragileABI_Class_Meta = 0x00002,
34707330f729Sjoerg
34717330f729Sjoerg /// Has a non-trivial constructor or destructor.
34727330f729Sjoerg FragileABI_Class_HasCXXStructors = 0x02000,
34737330f729Sjoerg
34747330f729Sjoerg /// Has hidden visibility.
34757330f729Sjoerg FragileABI_Class_Hidden = 0x20000,
34767330f729Sjoerg
34777330f729Sjoerg /// Class implementation was compiled under ARC.
34787330f729Sjoerg FragileABI_Class_CompiledByARC = 0x04000000,
34797330f729Sjoerg
34807330f729Sjoerg /// Class implementation was compiled under MRC and has MRC weak ivars.
34817330f729Sjoerg /// Exclusive with CompiledByARC.
34827330f729Sjoerg FragileABI_Class_HasMRCWeakIvars = 0x08000000,
34837330f729Sjoerg };
34847330f729Sjoerg
34857330f729Sjoerg enum NonFragileClassFlags {
34867330f729Sjoerg /// Is a meta-class.
34877330f729Sjoerg NonFragileABI_Class_Meta = 0x00001,
34887330f729Sjoerg
34897330f729Sjoerg /// Is a root class.
34907330f729Sjoerg NonFragileABI_Class_Root = 0x00002,
34917330f729Sjoerg
34927330f729Sjoerg /// Has a non-trivial constructor or destructor.
34937330f729Sjoerg NonFragileABI_Class_HasCXXStructors = 0x00004,
34947330f729Sjoerg
34957330f729Sjoerg /// Has hidden visibility.
34967330f729Sjoerg NonFragileABI_Class_Hidden = 0x00010,
34977330f729Sjoerg
34987330f729Sjoerg /// Has the exception attribute.
34997330f729Sjoerg NonFragileABI_Class_Exception = 0x00020,
35007330f729Sjoerg
35017330f729Sjoerg /// (Obsolete) ARC-specific: this class has a .release_ivars method
35027330f729Sjoerg NonFragileABI_Class_HasIvarReleaser = 0x00040,
35037330f729Sjoerg
35047330f729Sjoerg /// Class implementation was compiled under ARC.
35057330f729Sjoerg NonFragileABI_Class_CompiledByARC = 0x00080,
35067330f729Sjoerg
35077330f729Sjoerg /// Class has non-trivial destructors, but zero-initialization is okay.
35087330f729Sjoerg NonFragileABI_Class_HasCXXDestructorOnly = 0x00100,
35097330f729Sjoerg
35107330f729Sjoerg /// Class implementation was compiled under MRC and has MRC weak ivars.
35117330f729Sjoerg /// Exclusive with CompiledByARC.
35127330f729Sjoerg NonFragileABI_Class_HasMRCWeakIvars = 0x00200,
35137330f729Sjoerg };
35147330f729Sjoerg
hasWeakMember(QualType type)35157330f729Sjoerg static bool hasWeakMember(QualType type) {
35167330f729Sjoerg if (type.getObjCLifetime() == Qualifiers::OCL_Weak) {
35177330f729Sjoerg return true;
35187330f729Sjoerg }
35197330f729Sjoerg
35207330f729Sjoerg if (auto recType = type->getAs<RecordType>()) {
35217330f729Sjoerg for (auto field : recType->getDecl()->fields()) {
35227330f729Sjoerg if (hasWeakMember(field->getType()))
35237330f729Sjoerg return true;
35247330f729Sjoerg }
35257330f729Sjoerg }
35267330f729Sjoerg
35277330f729Sjoerg return false;
35287330f729Sjoerg }
35297330f729Sjoerg
35307330f729Sjoerg /// For compatibility, we only want to set the "HasMRCWeakIvars" flag
35317330f729Sjoerg /// (and actually fill in a layout string) if we really do have any
35327330f729Sjoerg /// __weak ivars.
hasMRCWeakIvars(CodeGenModule & CGM,const ObjCImplementationDecl * ID)35337330f729Sjoerg static bool hasMRCWeakIvars(CodeGenModule &CGM,
35347330f729Sjoerg const ObjCImplementationDecl *ID) {
35357330f729Sjoerg if (!CGM.getLangOpts().ObjCWeak) return false;
35367330f729Sjoerg assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
35377330f729Sjoerg
35387330f729Sjoerg for (const ObjCIvarDecl *ivar =
35397330f729Sjoerg ID->getClassInterface()->all_declared_ivar_begin();
35407330f729Sjoerg ivar; ivar = ivar->getNextIvar()) {
35417330f729Sjoerg if (hasWeakMember(ivar->getType()))
35427330f729Sjoerg return true;
35437330f729Sjoerg }
35447330f729Sjoerg
35457330f729Sjoerg return false;
35467330f729Sjoerg }
35477330f729Sjoerg
35487330f729Sjoerg /*
35497330f729Sjoerg struct _objc_class {
35507330f729Sjoerg Class isa;
35517330f729Sjoerg Class super_class;
35527330f729Sjoerg const char *name;
35537330f729Sjoerg long version;
35547330f729Sjoerg long info;
35557330f729Sjoerg long instance_size;
35567330f729Sjoerg struct _objc_ivar_list *ivars;
35577330f729Sjoerg struct _objc_method_list *methods;
35587330f729Sjoerg struct _objc_cache *cache;
35597330f729Sjoerg struct _objc_protocol_list *protocols;
35607330f729Sjoerg // Objective-C 1.0 extensions (<rdr://4585769>)
35617330f729Sjoerg const char *ivar_layout;
35627330f729Sjoerg struct _objc_class_ext *ext;
35637330f729Sjoerg };
35647330f729Sjoerg
35657330f729Sjoerg See EmitClassExtension();
35667330f729Sjoerg */
GenerateClass(const ObjCImplementationDecl * ID)35677330f729Sjoerg void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
35687330f729Sjoerg IdentifierInfo *RuntimeName =
35697330f729Sjoerg &CGM.getContext().Idents.get(ID->getObjCRuntimeNameAsString());
35707330f729Sjoerg DefinedSymbols.insert(RuntimeName);
35717330f729Sjoerg
35727330f729Sjoerg std::string ClassName = ID->getNameAsString();
35737330f729Sjoerg // FIXME: Gross
35747330f729Sjoerg ObjCInterfaceDecl *Interface =
35757330f729Sjoerg const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
35767330f729Sjoerg llvm::Constant *Protocols =
35777330f729Sjoerg EmitProtocolList("OBJC_CLASS_PROTOCOLS_" + ID->getName(),
35787330f729Sjoerg Interface->all_referenced_protocol_begin(),
35797330f729Sjoerg Interface->all_referenced_protocol_end());
35807330f729Sjoerg unsigned Flags = FragileABI_Class_Factory;
35817330f729Sjoerg if (ID->hasNonZeroConstructors() || ID->hasDestructors())
35827330f729Sjoerg Flags |= FragileABI_Class_HasCXXStructors;
35837330f729Sjoerg
35847330f729Sjoerg bool hasMRCWeak = false;
35857330f729Sjoerg
35867330f729Sjoerg if (CGM.getLangOpts().ObjCAutoRefCount)
35877330f729Sjoerg Flags |= FragileABI_Class_CompiledByARC;
35887330f729Sjoerg else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID)))
35897330f729Sjoerg Flags |= FragileABI_Class_HasMRCWeakIvars;
35907330f729Sjoerg
35917330f729Sjoerg CharUnits Size =
35927330f729Sjoerg CGM.getContext().getASTObjCImplementationLayout(ID).getSize();
35937330f729Sjoerg
35947330f729Sjoerg // FIXME: Set CXX-structors flag.
35957330f729Sjoerg if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
35967330f729Sjoerg Flags |= FragileABI_Class_Hidden;
35977330f729Sjoerg
35987330f729Sjoerg enum {
35997330f729Sjoerg InstanceMethods,
36007330f729Sjoerg ClassMethods,
36017330f729Sjoerg NumMethodLists
36027330f729Sjoerg };
36037330f729Sjoerg SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
36047330f729Sjoerg for (const auto *MD : ID->methods()) {
3605*e038c9c4Sjoerg if (!MD->isDirectMethod())
36067330f729Sjoerg Methods[unsigned(MD->isClassMethod())].push_back(MD);
36077330f729Sjoerg }
36087330f729Sjoerg
36097330f729Sjoerg for (const auto *PID : ID->property_impls()) {
36107330f729Sjoerg if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
3611*e038c9c4Sjoerg if (PID->getPropertyDecl()->isDirectProperty())
3612*e038c9c4Sjoerg continue;
3613*e038c9c4Sjoerg if (ObjCMethodDecl *MD = PID->getGetterMethodDecl())
36147330f729Sjoerg if (GetMethodDefinition(MD))
36157330f729Sjoerg Methods[InstanceMethods].push_back(MD);
3616*e038c9c4Sjoerg if (ObjCMethodDecl *MD = PID->getSetterMethodDecl())
36177330f729Sjoerg if (GetMethodDefinition(MD))
36187330f729Sjoerg Methods[InstanceMethods].push_back(MD);
36197330f729Sjoerg }
36207330f729Sjoerg }
36217330f729Sjoerg
36227330f729Sjoerg ConstantInitBuilder builder(CGM);
36237330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ClassTy);
36247330f729Sjoerg values.add(EmitMetaClass(ID, Protocols, Methods[ClassMethods]));
36257330f729Sjoerg if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) {
36267330f729Sjoerg // Record a reference to the super class.
36277330f729Sjoerg LazySymbols.insert(Super->getIdentifier());
36287330f729Sjoerg
36297330f729Sjoerg values.addBitCast(GetClassName(Super->getObjCRuntimeNameAsString()),
36307330f729Sjoerg ObjCTypes.ClassPtrTy);
36317330f729Sjoerg } else {
36327330f729Sjoerg values.addNullPointer(ObjCTypes.ClassPtrTy);
36337330f729Sjoerg }
36347330f729Sjoerg values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
36357330f729Sjoerg // Version is always 0.
36367330f729Sjoerg values.addInt(ObjCTypes.LongTy, 0);
36377330f729Sjoerg values.addInt(ObjCTypes.LongTy, Flags);
36387330f729Sjoerg values.addInt(ObjCTypes.LongTy, Size.getQuantity());
36397330f729Sjoerg values.add(EmitIvarList(ID, false));
36407330f729Sjoerg values.add(emitMethodList(ID->getName(), MethodListType::InstanceMethods,
36417330f729Sjoerg Methods[InstanceMethods]));
36427330f729Sjoerg // cache is always NULL.
36437330f729Sjoerg values.addNullPointer(ObjCTypes.CachePtrTy);
36447330f729Sjoerg values.add(Protocols);
36457330f729Sjoerg values.add(BuildStrongIvarLayout(ID, CharUnits::Zero(), Size));
36467330f729Sjoerg values.add(EmitClassExtension(ID, Size, hasMRCWeak,
36477330f729Sjoerg /*isMetaclass*/ false));
36487330f729Sjoerg
36497330f729Sjoerg std::string Name("OBJC_CLASS_");
36507330f729Sjoerg Name += ClassName;
36517330f729Sjoerg const char *Section = "__OBJC,__class,regular,no_dead_strip";
36527330f729Sjoerg // Check for a forward reference.
36537330f729Sjoerg llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
36547330f729Sjoerg if (GV) {
3655*e038c9c4Sjoerg assert(GV->getValueType() == ObjCTypes.ClassTy &&
36567330f729Sjoerg "Forward metaclass reference has incorrect type.");
36577330f729Sjoerg values.finishAndSetAsInitializer(GV);
36587330f729Sjoerg GV->setSection(Section);
36597330f729Sjoerg GV->setAlignment(CGM.getPointerAlign().getAsAlign());
36607330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
36617330f729Sjoerg } else
36627330f729Sjoerg GV = CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true);
36637330f729Sjoerg DefinedClasses.push_back(GV);
36647330f729Sjoerg ImplementedClasses.push_back(Interface);
36657330f729Sjoerg // method definition entries must be clear for next implementation.
36667330f729Sjoerg MethodDefinitions.clear();
36677330f729Sjoerg }
36687330f729Sjoerg
EmitMetaClass(const ObjCImplementationDecl * ID,llvm::Constant * Protocols,ArrayRef<const ObjCMethodDecl * > Methods)36697330f729Sjoerg llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
36707330f729Sjoerg llvm::Constant *Protocols,
36717330f729Sjoerg ArrayRef<const ObjCMethodDecl*> Methods) {
36727330f729Sjoerg unsigned Flags = FragileABI_Class_Meta;
36737330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassTy);
36747330f729Sjoerg
36757330f729Sjoerg if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
36767330f729Sjoerg Flags |= FragileABI_Class_Hidden;
36777330f729Sjoerg
36787330f729Sjoerg ConstantInitBuilder builder(CGM);
36797330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ClassTy);
36807330f729Sjoerg // The isa for the metaclass is the root of the hierarchy.
36817330f729Sjoerg const ObjCInterfaceDecl *Root = ID->getClassInterface();
36827330f729Sjoerg while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
36837330f729Sjoerg Root = Super;
36847330f729Sjoerg values.addBitCast(GetClassName(Root->getObjCRuntimeNameAsString()),
36857330f729Sjoerg ObjCTypes.ClassPtrTy);
36867330f729Sjoerg // The super class for the metaclass is emitted as the name of the
36877330f729Sjoerg // super class. The runtime fixes this up to point to the
36887330f729Sjoerg // *metaclass* for the super class.
36897330f729Sjoerg if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) {
36907330f729Sjoerg values.addBitCast(GetClassName(Super->getObjCRuntimeNameAsString()),
36917330f729Sjoerg ObjCTypes.ClassPtrTy);
36927330f729Sjoerg } else {
36937330f729Sjoerg values.addNullPointer(ObjCTypes.ClassPtrTy);
36947330f729Sjoerg }
36957330f729Sjoerg values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
36967330f729Sjoerg // Version is always 0.
36977330f729Sjoerg values.addInt(ObjCTypes.LongTy, 0);
36987330f729Sjoerg values.addInt(ObjCTypes.LongTy, Flags);
36997330f729Sjoerg values.addInt(ObjCTypes.LongTy, Size);
37007330f729Sjoerg values.add(EmitIvarList(ID, true));
37017330f729Sjoerg values.add(emitMethodList(ID->getName(), MethodListType::ClassMethods,
37027330f729Sjoerg Methods));
37037330f729Sjoerg // cache is always NULL.
37047330f729Sjoerg values.addNullPointer(ObjCTypes.CachePtrTy);
37057330f729Sjoerg values.add(Protocols);
37067330f729Sjoerg // ivar_layout for metaclass is always NULL.
37077330f729Sjoerg values.addNullPointer(ObjCTypes.Int8PtrTy);
37087330f729Sjoerg // The class extension is used to store class properties for metaclasses.
37097330f729Sjoerg values.add(EmitClassExtension(ID, CharUnits::Zero(), false/*hasMRCWeak*/,
37107330f729Sjoerg /*isMetaclass*/true));
37117330f729Sjoerg
37127330f729Sjoerg std::string Name("OBJC_METACLASS_");
37137330f729Sjoerg Name += ID->getName();
37147330f729Sjoerg
37157330f729Sjoerg // Check for a forward reference.
37167330f729Sjoerg llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
37177330f729Sjoerg if (GV) {
3718*e038c9c4Sjoerg assert(GV->getValueType() == ObjCTypes.ClassTy &&
37197330f729Sjoerg "Forward metaclass reference has incorrect type.");
37207330f729Sjoerg values.finishAndSetAsInitializer(GV);
37217330f729Sjoerg } else {
37227330f729Sjoerg GV = values.finishAndCreateGlobal(Name, CGM.getPointerAlign(),
37237330f729Sjoerg /*constant*/ false,
37247330f729Sjoerg llvm::GlobalValue::PrivateLinkage);
37257330f729Sjoerg }
37267330f729Sjoerg GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
37277330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
37287330f729Sjoerg
37297330f729Sjoerg return GV;
37307330f729Sjoerg }
37317330f729Sjoerg
EmitMetaClassRef(const ObjCInterfaceDecl * ID)37327330f729Sjoerg llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
37337330f729Sjoerg std::string Name = "OBJC_METACLASS_" + ID->getNameAsString();
37347330f729Sjoerg
37357330f729Sjoerg // FIXME: Should we look these up somewhere other than the module. Its a bit
37367330f729Sjoerg // silly since we only generate these while processing an implementation, so
37377330f729Sjoerg // exactly one pointer would work if know when we entered/exitted an
37387330f729Sjoerg // implementation block.
37397330f729Sjoerg
37407330f729Sjoerg // Check for an existing forward reference.
37417330f729Sjoerg // Previously, metaclass with internal linkage may have been defined.
37427330f729Sjoerg // pass 'true' as 2nd argument so it is returned.
37437330f729Sjoerg llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
37447330f729Sjoerg if (!GV)
37457330f729Sjoerg GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
37467330f729Sjoerg llvm::GlobalValue::PrivateLinkage, nullptr,
37477330f729Sjoerg Name);
37487330f729Sjoerg
3749*e038c9c4Sjoerg assert(GV->getValueType() == ObjCTypes.ClassTy &&
37507330f729Sjoerg "Forward metaclass reference has incorrect type.");
37517330f729Sjoerg return GV;
37527330f729Sjoerg }
37537330f729Sjoerg
EmitSuperClassRef(const ObjCInterfaceDecl * ID)37547330f729Sjoerg llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
37557330f729Sjoerg std::string Name = "OBJC_CLASS_" + ID->getNameAsString();
37567330f729Sjoerg llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
37577330f729Sjoerg
37587330f729Sjoerg if (!GV)
37597330f729Sjoerg GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
37607330f729Sjoerg llvm::GlobalValue::PrivateLinkage, nullptr,
37617330f729Sjoerg Name);
37627330f729Sjoerg
3763*e038c9c4Sjoerg assert(GV->getValueType() == ObjCTypes.ClassTy &&
37647330f729Sjoerg "Forward class metadata reference has incorrect type.");
37657330f729Sjoerg return GV;
37667330f729Sjoerg }
37677330f729Sjoerg
37687330f729Sjoerg /*
37697330f729Sjoerg Emit a "class extension", which in this specific context means extra
37707330f729Sjoerg data that doesn't fit in the normal fragile-ABI class structure, and
37717330f729Sjoerg has nothing to do with the language concept of a class extension.
37727330f729Sjoerg
37737330f729Sjoerg struct objc_class_ext {
37747330f729Sjoerg uint32_t size;
37757330f729Sjoerg const char *weak_ivar_layout;
37767330f729Sjoerg struct _objc_property_list *properties;
37777330f729Sjoerg };
37787330f729Sjoerg */
37797330f729Sjoerg llvm::Constant *
EmitClassExtension(const ObjCImplementationDecl * ID,CharUnits InstanceSize,bool hasMRCWeakIvars,bool isMetaclass)37807330f729Sjoerg CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID,
37817330f729Sjoerg CharUnits InstanceSize, bool hasMRCWeakIvars,
37827330f729Sjoerg bool isMetaclass) {
37837330f729Sjoerg // Weak ivar layout.
37847330f729Sjoerg llvm::Constant *layout;
37857330f729Sjoerg if (isMetaclass) {
37867330f729Sjoerg layout = llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
37877330f729Sjoerg } else {
37887330f729Sjoerg layout = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize,
37897330f729Sjoerg hasMRCWeakIvars);
37907330f729Sjoerg }
37917330f729Sjoerg
37927330f729Sjoerg // Properties.
37937330f729Sjoerg llvm::Constant *propertyList =
37947330f729Sjoerg EmitPropertyList((isMetaclass ? Twine("_OBJC_$_CLASS_PROP_LIST_")
37957330f729Sjoerg : Twine("_OBJC_$_PROP_LIST_"))
37967330f729Sjoerg + ID->getName(),
37977330f729Sjoerg ID, ID->getClassInterface(), ObjCTypes, isMetaclass);
37987330f729Sjoerg
37997330f729Sjoerg // Return null if no extension bits are used.
38007330f729Sjoerg if (layout->isNullValue() && propertyList->isNullValue()) {
38017330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
38027330f729Sjoerg }
38037330f729Sjoerg
38047330f729Sjoerg uint64_t size =
38057330f729Sjoerg CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
38067330f729Sjoerg
38077330f729Sjoerg ConstantInitBuilder builder(CGM);
38087330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ClassExtensionTy);
38097330f729Sjoerg values.addInt(ObjCTypes.IntTy, size);
38107330f729Sjoerg values.add(layout);
38117330f729Sjoerg values.add(propertyList);
38127330f729Sjoerg
38137330f729Sjoerg return CreateMetadataVar("OBJC_CLASSEXT_" + ID->getName(), values,
38147330f729Sjoerg "__OBJC,__class_ext,regular,no_dead_strip",
38157330f729Sjoerg CGM.getPointerAlign(), true);
38167330f729Sjoerg }
38177330f729Sjoerg
38187330f729Sjoerg /*
38197330f729Sjoerg struct objc_ivar {
38207330f729Sjoerg char *ivar_name;
38217330f729Sjoerg char *ivar_type;
38227330f729Sjoerg int ivar_offset;
38237330f729Sjoerg };
38247330f729Sjoerg
38257330f729Sjoerg struct objc_ivar_list {
38267330f729Sjoerg int ivar_count;
38277330f729Sjoerg struct objc_ivar list[count];
38287330f729Sjoerg };
38297330f729Sjoerg */
EmitIvarList(const ObjCImplementationDecl * ID,bool ForClass)38307330f729Sjoerg llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
38317330f729Sjoerg bool ForClass) {
38327330f729Sjoerg // When emitting the root class GCC emits ivar entries for the
38337330f729Sjoerg // actual class structure. It is not clear if we need to follow this
38347330f729Sjoerg // behavior; for now lets try and get away with not doing it. If so,
38357330f729Sjoerg // the cleanest solution would be to make up an ObjCInterfaceDecl
38367330f729Sjoerg // for the class.
38377330f729Sjoerg if (ForClass)
38387330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
38397330f729Sjoerg
38407330f729Sjoerg const ObjCInterfaceDecl *OID = ID->getClassInterface();
38417330f729Sjoerg
38427330f729Sjoerg ConstantInitBuilder builder(CGM);
38437330f729Sjoerg auto ivarList = builder.beginStruct();
38447330f729Sjoerg auto countSlot = ivarList.addPlaceholder();
38457330f729Sjoerg auto ivars = ivarList.beginArray(ObjCTypes.IvarTy);
38467330f729Sjoerg
38477330f729Sjoerg for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
38487330f729Sjoerg IVD; IVD = IVD->getNextIvar()) {
38497330f729Sjoerg // Ignore unnamed bit-fields.
38507330f729Sjoerg if (!IVD->getDeclName())
38517330f729Sjoerg continue;
38527330f729Sjoerg
38537330f729Sjoerg auto ivar = ivars.beginStruct(ObjCTypes.IvarTy);
38547330f729Sjoerg ivar.add(GetMethodVarName(IVD->getIdentifier()));
38557330f729Sjoerg ivar.add(GetMethodVarType(IVD));
38567330f729Sjoerg ivar.addInt(ObjCTypes.IntTy, ComputeIvarBaseOffset(CGM, OID, IVD));
38577330f729Sjoerg ivar.finishAndAddTo(ivars);
38587330f729Sjoerg }
38597330f729Sjoerg
38607330f729Sjoerg // Return null for empty list.
38617330f729Sjoerg auto count = ivars.size();
38627330f729Sjoerg if (count == 0) {
38637330f729Sjoerg ivars.abandon();
38647330f729Sjoerg ivarList.abandon();
38657330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
38667330f729Sjoerg }
38677330f729Sjoerg
38687330f729Sjoerg ivars.finishAndAddTo(ivarList);
38697330f729Sjoerg ivarList.fillPlaceholderWithInt(countSlot, ObjCTypes.IntTy, count);
38707330f729Sjoerg
38717330f729Sjoerg llvm::GlobalVariable *GV;
38727330f729Sjoerg if (ForClass)
38737330f729Sjoerg GV =
38747330f729Sjoerg CreateMetadataVar("OBJC_CLASS_VARIABLES_" + ID->getName(), ivarList,
38757330f729Sjoerg "__OBJC,__class_vars,regular,no_dead_strip",
38767330f729Sjoerg CGM.getPointerAlign(), true);
38777330f729Sjoerg else
38787330f729Sjoerg GV = CreateMetadataVar("OBJC_INSTANCE_VARIABLES_" + ID->getName(), ivarList,
38797330f729Sjoerg "__OBJC,__instance_vars,regular,no_dead_strip",
38807330f729Sjoerg CGM.getPointerAlign(), true);
38817330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy);
38827330f729Sjoerg }
38837330f729Sjoerg
38847330f729Sjoerg /// Build a struct objc_method_description constant for the given method.
38857330f729Sjoerg ///
38867330f729Sjoerg /// struct objc_method_description {
38877330f729Sjoerg /// SEL method_name;
38887330f729Sjoerg /// char *method_types;
38897330f729Sjoerg /// };
emitMethodDescriptionConstant(ConstantArrayBuilder & builder,const ObjCMethodDecl * MD)38907330f729Sjoerg void CGObjCMac::emitMethodDescriptionConstant(ConstantArrayBuilder &builder,
38917330f729Sjoerg const ObjCMethodDecl *MD) {
38927330f729Sjoerg auto description = builder.beginStruct(ObjCTypes.MethodDescriptionTy);
38937330f729Sjoerg description.addBitCast(GetMethodVarName(MD->getSelector()),
38947330f729Sjoerg ObjCTypes.SelectorPtrTy);
38957330f729Sjoerg description.add(GetMethodVarType(MD));
38967330f729Sjoerg description.finishAndAddTo(builder);
38977330f729Sjoerg }
38987330f729Sjoerg
38997330f729Sjoerg /// Build a struct objc_method constant for the given method.
39007330f729Sjoerg ///
39017330f729Sjoerg /// struct objc_method {
39027330f729Sjoerg /// SEL method_name;
39037330f729Sjoerg /// char *method_types;
39047330f729Sjoerg /// void *method;
39057330f729Sjoerg /// };
emitMethodConstant(ConstantArrayBuilder & builder,const ObjCMethodDecl * MD)39067330f729Sjoerg void CGObjCMac::emitMethodConstant(ConstantArrayBuilder &builder,
39077330f729Sjoerg const ObjCMethodDecl *MD) {
39087330f729Sjoerg llvm::Function *fn = GetMethodDefinition(MD);
39097330f729Sjoerg assert(fn && "no definition registered for method");
39107330f729Sjoerg
39117330f729Sjoerg auto method = builder.beginStruct(ObjCTypes.MethodTy);
39127330f729Sjoerg method.addBitCast(GetMethodVarName(MD->getSelector()),
39137330f729Sjoerg ObjCTypes.SelectorPtrTy);
39147330f729Sjoerg method.add(GetMethodVarType(MD));
39157330f729Sjoerg method.addBitCast(fn, ObjCTypes.Int8PtrTy);
39167330f729Sjoerg method.finishAndAddTo(builder);
39177330f729Sjoerg }
39187330f729Sjoerg
39197330f729Sjoerg /// Build a struct objc_method_list or struct objc_method_description_list,
39207330f729Sjoerg /// as appropriate.
39217330f729Sjoerg ///
39227330f729Sjoerg /// struct objc_method_list {
39237330f729Sjoerg /// struct objc_method_list *obsolete;
39247330f729Sjoerg /// int count;
39257330f729Sjoerg /// struct objc_method methods_list[count];
39267330f729Sjoerg /// };
39277330f729Sjoerg ///
39287330f729Sjoerg /// struct objc_method_description_list {
39297330f729Sjoerg /// int count;
39307330f729Sjoerg /// struct objc_method_description list[count];
39317330f729Sjoerg /// };
emitMethodList(Twine name,MethodListType MLT,ArrayRef<const ObjCMethodDecl * > methods)39327330f729Sjoerg llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT,
39337330f729Sjoerg ArrayRef<const ObjCMethodDecl *> methods) {
39347330f729Sjoerg StringRef prefix;
39357330f729Sjoerg StringRef section;
39367330f729Sjoerg bool forProtocol = false;
39377330f729Sjoerg switch (MLT) {
39387330f729Sjoerg case MethodListType::CategoryInstanceMethods:
39397330f729Sjoerg prefix = "OBJC_CATEGORY_INSTANCE_METHODS_";
39407330f729Sjoerg section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
39417330f729Sjoerg forProtocol = false;
39427330f729Sjoerg break;
39437330f729Sjoerg case MethodListType::CategoryClassMethods:
39447330f729Sjoerg prefix = "OBJC_CATEGORY_CLASS_METHODS_";
39457330f729Sjoerg section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
39467330f729Sjoerg forProtocol = false;
39477330f729Sjoerg break;
39487330f729Sjoerg case MethodListType::InstanceMethods:
39497330f729Sjoerg prefix = "OBJC_INSTANCE_METHODS_";
39507330f729Sjoerg section = "__OBJC,__inst_meth,regular,no_dead_strip";
39517330f729Sjoerg forProtocol = false;
39527330f729Sjoerg break;
39537330f729Sjoerg case MethodListType::ClassMethods:
39547330f729Sjoerg prefix = "OBJC_CLASS_METHODS_";
39557330f729Sjoerg section = "__OBJC,__cls_meth,regular,no_dead_strip";
39567330f729Sjoerg forProtocol = false;
39577330f729Sjoerg break;
39587330f729Sjoerg case MethodListType::ProtocolInstanceMethods:
39597330f729Sjoerg prefix = "OBJC_PROTOCOL_INSTANCE_METHODS_";
39607330f729Sjoerg section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
39617330f729Sjoerg forProtocol = true;
39627330f729Sjoerg break;
39637330f729Sjoerg case MethodListType::ProtocolClassMethods:
39647330f729Sjoerg prefix = "OBJC_PROTOCOL_CLASS_METHODS_";
39657330f729Sjoerg section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
39667330f729Sjoerg forProtocol = true;
39677330f729Sjoerg break;
39687330f729Sjoerg case MethodListType::OptionalProtocolInstanceMethods:
39697330f729Sjoerg prefix = "OBJC_PROTOCOL_INSTANCE_METHODS_OPT_";
39707330f729Sjoerg section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
39717330f729Sjoerg forProtocol = true;
39727330f729Sjoerg break;
39737330f729Sjoerg case MethodListType::OptionalProtocolClassMethods:
39747330f729Sjoerg prefix = "OBJC_PROTOCOL_CLASS_METHODS_OPT_";
39757330f729Sjoerg section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
39767330f729Sjoerg forProtocol = true;
39777330f729Sjoerg break;
39787330f729Sjoerg }
39797330f729Sjoerg
39807330f729Sjoerg // Return null for empty list.
39817330f729Sjoerg if (methods.empty())
39827330f729Sjoerg return llvm::Constant::getNullValue(forProtocol
39837330f729Sjoerg ? ObjCTypes.MethodDescriptionListPtrTy
39847330f729Sjoerg : ObjCTypes.MethodListPtrTy);
39857330f729Sjoerg
39867330f729Sjoerg // For protocols, this is an objc_method_description_list, which has
39877330f729Sjoerg // a slightly different structure.
39887330f729Sjoerg if (forProtocol) {
39897330f729Sjoerg ConstantInitBuilder builder(CGM);
39907330f729Sjoerg auto values = builder.beginStruct();
39917330f729Sjoerg values.addInt(ObjCTypes.IntTy, methods.size());
39927330f729Sjoerg auto methodArray = values.beginArray(ObjCTypes.MethodDescriptionTy);
39937330f729Sjoerg for (auto MD : methods) {
39947330f729Sjoerg emitMethodDescriptionConstant(methodArray, MD);
39957330f729Sjoerg }
39967330f729Sjoerg methodArray.finishAndAddTo(values);
39977330f729Sjoerg
39987330f729Sjoerg llvm::GlobalVariable *GV = CreateMetadataVar(prefix + name, values, section,
39997330f729Sjoerg CGM.getPointerAlign(), true);
40007330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV,
40017330f729Sjoerg ObjCTypes.MethodDescriptionListPtrTy);
40027330f729Sjoerg }
40037330f729Sjoerg
40047330f729Sjoerg // Otherwise, it's an objc_method_list.
40057330f729Sjoerg ConstantInitBuilder builder(CGM);
40067330f729Sjoerg auto values = builder.beginStruct();
40077330f729Sjoerg values.addNullPointer(ObjCTypes.Int8PtrTy);
40087330f729Sjoerg values.addInt(ObjCTypes.IntTy, methods.size());
40097330f729Sjoerg auto methodArray = values.beginArray(ObjCTypes.MethodTy);
40107330f729Sjoerg for (auto MD : methods) {
4011*e038c9c4Sjoerg if (!MD->isDirectMethod())
40127330f729Sjoerg emitMethodConstant(methodArray, MD);
40137330f729Sjoerg }
40147330f729Sjoerg methodArray.finishAndAddTo(values);
40157330f729Sjoerg
40167330f729Sjoerg llvm::GlobalVariable *GV = CreateMetadataVar(prefix + name, values, section,
40177330f729Sjoerg CGM.getPointerAlign(), true);
40187330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListPtrTy);
40197330f729Sjoerg }
40207330f729Sjoerg
GenerateMethod(const ObjCMethodDecl * OMD,const ObjCContainerDecl * CD)40217330f729Sjoerg llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
40227330f729Sjoerg const ObjCContainerDecl *CD) {
4023*e038c9c4Sjoerg llvm::Function *Method;
4024*e038c9c4Sjoerg
4025*e038c9c4Sjoerg if (OMD->isDirectMethod()) {
4026*e038c9c4Sjoerg Method = GenerateDirectMethod(OMD, CD);
4027*e038c9c4Sjoerg } else {
4028*e038c9c4Sjoerg auto Name = getSymbolNameForMethod(OMD);
40297330f729Sjoerg
40307330f729Sjoerg CodeGenTypes &Types = CGM.getTypes();
40317330f729Sjoerg llvm::FunctionType *MethodTy =
40327330f729Sjoerg Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
4033*e038c9c4Sjoerg Method =
4034*e038c9c4Sjoerg llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage,
4035*e038c9c4Sjoerg Name, &CGM.getModule());
4036*e038c9c4Sjoerg }
4037*e038c9c4Sjoerg
40387330f729Sjoerg MethodDefinitions.insert(std::make_pair(OMD, Method));
40397330f729Sjoerg
40407330f729Sjoerg return Method;
40417330f729Sjoerg }
40427330f729Sjoerg
4043*e038c9c4Sjoerg llvm::Function *
GenerateDirectMethod(const ObjCMethodDecl * OMD,const ObjCContainerDecl * CD)4044*e038c9c4Sjoerg CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD,
4045*e038c9c4Sjoerg const ObjCContainerDecl *CD) {
4046*e038c9c4Sjoerg auto *COMD = OMD->getCanonicalDecl();
4047*e038c9c4Sjoerg auto I = DirectMethodDefinitions.find(COMD);
4048*e038c9c4Sjoerg llvm::Function *OldFn = nullptr, *Fn = nullptr;
4049*e038c9c4Sjoerg
4050*e038c9c4Sjoerg if (I != DirectMethodDefinitions.end()) {
4051*e038c9c4Sjoerg // Objective-C allows for the declaration and implementation types
4052*e038c9c4Sjoerg // to differ slightly.
4053*e038c9c4Sjoerg //
4054*e038c9c4Sjoerg // If we're being asked for the Function associated for a method
4055*e038c9c4Sjoerg // implementation, a previous value might have been cached
4056*e038c9c4Sjoerg // based on the type of the canonical declaration.
4057*e038c9c4Sjoerg //
4058*e038c9c4Sjoerg // If these do not match, then we'll replace this function with
4059*e038c9c4Sjoerg // a new one that has the proper type below.
4060*e038c9c4Sjoerg if (!OMD->getBody() || COMD->getReturnType() == OMD->getReturnType())
4061*e038c9c4Sjoerg return I->second;
4062*e038c9c4Sjoerg OldFn = I->second;
4063*e038c9c4Sjoerg }
4064*e038c9c4Sjoerg
4065*e038c9c4Sjoerg CodeGenTypes &Types = CGM.getTypes();
4066*e038c9c4Sjoerg llvm::FunctionType *MethodTy =
4067*e038c9c4Sjoerg Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
4068*e038c9c4Sjoerg
4069*e038c9c4Sjoerg if (OldFn) {
4070*e038c9c4Sjoerg Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
4071*e038c9c4Sjoerg "", &CGM.getModule());
4072*e038c9c4Sjoerg Fn->takeName(OldFn);
4073*e038c9c4Sjoerg OldFn->replaceAllUsesWith(
4074*e038c9c4Sjoerg llvm::ConstantExpr::getBitCast(Fn, OldFn->getType()));
4075*e038c9c4Sjoerg OldFn->eraseFromParent();
4076*e038c9c4Sjoerg
4077*e038c9c4Sjoerg // Replace the cached function in the map.
4078*e038c9c4Sjoerg I->second = Fn;
4079*e038c9c4Sjoerg } else {
4080*e038c9c4Sjoerg auto Name = getSymbolNameForMethod(OMD, /*include category*/ false);
4081*e038c9c4Sjoerg
4082*e038c9c4Sjoerg Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
4083*e038c9c4Sjoerg Name, &CGM.getModule());
4084*e038c9c4Sjoerg DirectMethodDefinitions.insert(std::make_pair(COMD, Fn));
4085*e038c9c4Sjoerg }
4086*e038c9c4Sjoerg
4087*e038c9c4Sjoerg return Fn;
4088*e038c9c4Sjoerg }
4089*e038c9c4Sjoerg
GenerateDirectMethodPrologue(CodeGenFunction & CGF,llvm::Function * Fn,const ObjCMethodDecl * OMD,const ObjCContainerDecl * CD)4090*e038c9c4Sjoerg void CGObjCCommonMac::GenerateDirectMethodPrologue(
4091*e038c9c4Sjoerg CodeGenFunction &CGF, llvm::Function *Fn, const ObjCMethodDecl *OMD,
4092*e038c9c4Sjoerg const ObjCContainerDecl *CD) {
4093*e038c9c4Sjoerg auto &Builder = CGF.Builder;
4094*e038c9c4Sjoerg bool ReceiverCanBeNull = true;
4095*e038c9c4Sjoerg auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
4096*e038c9c4Sjoerg auto selfValue = Builder.CreateLoad(selfAddr);
4097*e038c9c4Sjoerg
4098*e038c9c4Sjoerg // Generate:
4099*e038c9c4Sjoerg //
4100*e038c9c4Sjoerg // /* for class methods only to force class lazy initialization */
4101*e038c9c4Sjoerg // self = [self self];
4102*e038c9c4Sjoerg //
4103*e038c9c4Sjoerg // /* unless the receiver is never NULL */
4104*e038c9c4Sjoerg // if (self == nil) {
4105*e038c9c4Sjoerg // return (ReturnType){ };
4106*e038c9c4Sjoerg // }
4107*e038c9c4Sjoerg //
4108*e038c9c4Sjoerg // _cmd = @selector(...)
4109*e038c9c4Sjoerg // ...
4110*e038c9c4Sjoerg
4111*e038c9c4Sjoerg if (OMD->isClassMethod()) {
4112*e038c9c4Sjoerg const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
4113*e038c9c4Sjoerg assert(OID &&
4114*e038c9c4Sjoerg "GenerateDirectMethod() should be called with the Class Interface");
4115*e038c9c4Sjoerg Selector SelfSel = GetNullarySelector("self", CGM.getContext());
4116*e038c9c4Sjoerg auto ResultType = CGF.getContext().getObjCIdType();
4117*e038c9c4Sjoerg RValue result;
4118*e038c9c4Sjoerg CallArgList Args;
4119*e038c9c4Sjoerg
4120*e038c9c4Sjoerg // TODO: If this method is inlined, the caller might know that `self` is
4121*e038c9c4Sjoerg // already initialized; for example, it might be an ordinary Objective-C
4122*e038c9c4Sjoerg // method which always receives an initialized `self`, or it might have just
4123*e038c9c4Sjoerg // forced initialization on its own.
4124*e038c9c4Sjoerg //
4125*e038c9c4Sjoerg // We should find a way to eliminate this unnecessary initialization in such
4126*e038c9c4Sjoerg // cases in LLVM.
4127*e038c9c4Sjoerg result = GeneratePossiblySpecializedMessageSend(
4128*e038c9c4Sjoerg CGF, ReturnValueSlot(), ResultType, SelfSel, selfValue, Args, OID,
4129*e038c9c4Sjoerg nullptr, true);
4130*e038c9c4Sjoerg Builder.CreateStore(result.getScalarVal(), selfAddr);
4131*e038c9c4Sjoerg
4132*e038c9c4Sjoerg // Nullable `Class` expressions cannot be messaged with a direct method
4133*e038c9c4Sjoerg // so the only reason why the receive can be null would be because
4134*e038c9c4Sjoerg // of weak linking.
4135*e038c9c4Sjoerg ReceiverCanBeNull = isWeakLinkedClass(OID);
4136*e038c9c4Sjoerg }
4137*e038c9c4Sjoerg
4138*e038c9c4Sjoerg if (ReceiverCanBeNull) {
4139*e038c9c4Sjoerg llvm::BasicBlock *SelfIsNilBlock =
4140*e038c9c4Sjoerg CGF.createBasicBlock("objc_direct_method.self_is_nil");
4141*e038c9c4Sjoerg llvm::BasicBlock *ContBlock =
4142*e038c9c4Sjoerg CGF.createBasicBlock("objc_direct_method.cont");
4143*e038c9c4Sjoerg
4144*e038c9c4Sjoerg // if (self == nil) {
4145*e038c9c4Sjoerg auto selfTy = cast<llvm::PointerType>(selfValue->getType());
4146*e038c9c4Sjoerg auto Zero = llvm::ConstantPointerNull::get(selfTy);
4147*e038c9c4Sjoerg
4148*e038c9c4Sjoerg llvm::MDBuilder MDHelper(CGM.getLLVMContext());
4149*e038c9c4Sjoerg Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero), SelfIsNilBlock,
4150*e038c9c4Sjoerg ContBlock, MDHelper.createBranchWeights(1, 1 << 20));
4151*e038c9c4Sjoerg
4152*e038c9c4Sjoerg CGF.EmitBlock(SelfIsNilBlock);
4153*e038c9c4Sjoerg
4154*e038c9c4Sjoerg // return (ReturnType){ };
4155*e038c9c4Sjoerg auto retTy = OMD->getReturnType();
4156*e038c9c4Sjoerg Builder.SetInsertPoint(SelfIsNilBlock);
4157*e038c9c4Sjoerg if (!retTy->isVoidType()) {
4158*e038c9c4Sjoerg CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
4159*e038c9c4Sjoerg }
4160*e038c9c4Sjoerg CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
4161*e038c9c4Sjoerg // }
4162*e038c9c4Sjoerg
4163*e038c9c4Sjoerg // rest of the body
4164*e038c9c4Sjoerg CGF.EmitBlock(ContBlock);
4165*e038c9c4Sjoerg Builder.SetInsertPoint(ContBlock);
4166*e038c9c4Sjoerg }
4167*e038c9c4Sjoerg
4168*e038c9c4Sjoerg // only synthesize _cmd if it's referenced
4169*e038c9c4Sjoerg if (OMD->getCmdDecl()->isUsed()) {
4170*e038c9c4Sjoerg Builder.CreateStore(GetSelector(CGF, OMD),
4171*e038c9c4Sjoerg CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
4172*e038c9c4Sjoerg }
4173*e038c9c4Sjoerg }
4174*e038c9c4Sjoerg
CreateMetadataVar(Twine Name,ConstantStructBuilder & Init,StringRef Section,CharUnits Align,bool AddToUsed)41757330f729Sjoerg llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
41767330f729Sjoerg ConstantStructBuilder &Init,
41777330f729Sjoerg StringRef Section,
41787330f729Sjoerg CharUnits Align,
41797330f729Sjoerg bool AddToUsed) {
41807330f729Sjoerg llvm::GlobalValue::LinkageTypes LT =
41817330f729Sjoerg getLinkageTypeForObjCMetadata(CGM, Section);
41827330f729Sjoerg llvm::GlobalVariable *GV =
41837330f729Sjoerg Init.finishAndCreateGlobal(Name, Align, /*constant*/ false, LT);
41847330f729Sjoerg if (!Section.empty())
41857330f729Sjoerg GV->setSection(Section);
41867330f729Sjoerg if (AddToUsed)
41877330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
41887330f729Sjoerg return GV;
41897330f729Sjoerg }
41907330f729Sjoerg
CreateMetadataVar(Twine Name,llvm::Constant * Init,StringRef Section,CharUnits Align,bool AddToUsed)41917330f729Sjoerg llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
41927330f729Sjoerg llvm::Constant *Init,
41937330f729Sjoerg StringRef Section,
41947330f729Sjoerg CharUnits Align,
41957330f729Sjoerg bool AddToUsed) {
41967330f729Sjoerg llvm::Type *Ty = Init->getType();
41977330f729Sjoerg llvm::GlobalValue::LinkageTypes LT =
41987330f729Sjoerg getLinkageTypeForObjCMetadata(CGM, Section);
41997330f729Sjoerg llvm::GlobalVariable *GV =
42007330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), Ty, false, LT, Init, Name);
42017330f729Sjoerg if (!Section.empty())
42027330f729Sjoerg GV->setSection(Section);
42037330f729Sjoerg GV->setAlignment(Align.getAsAlign());
42047330f729Sjoerg if (AddToUsed)
42057330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
42067330f729Sjoerg return GV;
42077330f729Sjoerg }
42087330f729Sjoerg
42097330f729Sjoerg llvm::GlobalVariable *
CreateCStringLiteral(StringRef Name,ObjCLabelType Type,bool ForceNonFragileABI,bool NullTerminate)42107330f729Sjoerg CGObjCCommonMac::CreateCStringLiteral(StringRef Name, ObjCLabelType Type,
42117330f729Sjoerg bool ForceNonFragileABI,
42127330f729Sjoerg bool NullTerminate) {
42137330f729Sjoerg StringRef Label;
42147330f729Sjoerg switch (Type) {
42157330f729Sjoerg case ObjCLabelType::ClassName: Label = "OBJC_CLASS_NAME_"; break;
42167330f729Sjoerg case ObjCLabelType::MethodVarName: Label = "OBJC_METH_VAR_NAME_"; break;
42177330f729Sjoerg case ObjCLabelType::MethodVarType: Label = "OBJC_METH_VAR_TYPE_"; break;
42187330f729Sjoerg case ObjCLabelType::PropertyName: Label = "OBJC_PROP_NAME_ATTR_"; break;
42197330f729Sjoerg }
42207330f729Sjoerg
42217330f729Sjoerg bool NonFragile = ForceNonFragileABI || isNonFragileABI();
42227330f729Sjoerg
42237330f729Sjoerg StringRef Section;
42247330f729Sjoerg switch (Type) {
42257330f729Sjoerg case ObjCLabelType::ClassName:
42267330f729Sjoerg Section = NonFragile ? "__TEXT,__objc_classname,cstring_literals"
42277330f729Sjoerg : "__TEXT,__cstring,cstring_literals";
42287330f729Sjoerg break;
42297330f729Sjoerg case ObjCLabelType::MethodVarName:
42307330f729Sjoerg Section = NonFragile ? "__TEXT,__objc_methname,cstring_literals"
42317330f729Sjoerg : "__TEXT,__cstring,cstring_literals";
42327330f729Sjoerg break;
42337330f729Sjoerg case ObjCLabelType::MethodVarType:
42347330f729Sjoerg Section = NonFragile ? "__TEXT,__objc_methtype,cstring_literals"
42357330f729Sjoerg : "__TEXT,__cstring,cstring_literals";
42367330f729Sjoerg break;
42377330f729Sjoerg case ObjCLabelType::PropertyName:
4238*e038c9c4Sjoerg Section = NonFragile ? "__TEXT,__objc_methname,cstring_literals"
4239*e038c9c4Sjoerg : "__TEXT,__cstring,cstring_literals";
42407330f729Sjoerg break;
42417330f729Sjoerg }
42427330f729Sjoerg
42437330f729Sjoerg llvm::Constant *Value =
42447330f729Sjoerg llvm::ConstantDataArray::getString(VMContext, Name, NullTerminate);
42457330f729Sjoerg llvm::GlobalVariable *GV =
42467330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), Value->getType(),
42477330f729Sjoerg /*isConstant=*/true,
42487330f729Sjoerg llvm::GlobalValue::PrivateLinkage, Value, Label);
42497330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO())
42507330f729Sjoerg GV->setSection(Section);
42517330f729Sjoerg GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
42527330f729Sjoerg GV->setAlignment(CharUnits::One().getAsAlign());
42537330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
42547330f729Sjoerg
42557330f729Sjoerg return GV;
42567330f729Sjoerg }
42577330f729Sjoerg
ModuleInitFunction()42587330f729Sjoerg llvm::Function *CGObjCMac::ModuleInitFunction() {
42597330f729Sjoerg // Abuse this interface function as a place to finalize.
42607330f729Sjoerg FinishModule();
42617330f729Sjoerg return nullptr;
42627330f729Sjoerg }
42637330f729Sjoerg
GetPropertyGetFunction()42647330f729Sjoerg llvm::FunctionCallee CGObjCMac::GetPropertyGetFunction() {
42657330f729Sjoerg return ObjCTypes.getGetPropertyFn();
42667330f729Sjoerg }
42677330f729Sjoerg
GetPropertySetFunction()42687330f729Sjoerg llvm::FunctionCallee CGObjCMac::GetPropertySetFunction() {
42697330f729Sjoerg return ObjCTypes.getSetPropertyFn();
42707330f729Sjoerg }
42717330f729Sjoerg
GetOptimizedPropertySetFunction(bool atomic,bool copy)42727330f729Sjoerg llvm::FunctionCallee CGObjCMac::GetOptimizedPropertySetFunction(bool atomic,
42737330f729Sjoerg bool copy) {
42747330f729Sjoerg return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
42757330f729Sjoerg }
42767330f729Sjoerg
GetGetStructFunction()42777330f729Sjoerg llvm::FunctionCallee CGObjCMac::GetGetStructFunction() {
42787330f729Sjoerg return ObjCTypes.getCopyStructFn();
42797330f729Sjoerg }
42807330f729Sjoerg
GetSetStructFunction()42817330f729Sjoerg llvm::FunctionCallee CGObjCMac::GetSetStructFunction() {
42827330f729Sjoerg return ObjCTypes.getCopyStructFn();
42837330f729Sjoerg }
42847330f729Sjoerg
GetCppAtomicObjectGetFunction()42857330f729Sjoerg llvm::FunctionCallee CGObjCMac::GetCppAtomicObjectGetFunction() {
42867330f729Sjoerg return ObjCTypes.getCppAtomicObjectFunction();
42877330f729Sjoerg }
42887330f729Sjoerg
GetCppAtomicObjectSetFunction()42897330f729Sjoerg llvm::FunctionCallee CGObjCMac::GetCppAtomicObjectSetFunction() {
42907330f729Sjoerg return ObjCTypes.getCppAtomicObjectFunction();
42917330f729Sjoerg }
42927330f729Sjoerg
EnumerationMutationFunction()42937330f729Sjoerg llvm::FunctionCallee CGObjCMac::EnumerationMutationFunction() {
42947330f729Sjoerg return ObjCTypes.getEnumerationMutationFn();
42957330f729Sjoerg }
42967330f729Sjoerg
EmitTryStmt(CodeGenFunction & CGF,const ObjCAtTryStmt & S)42977330f729Sjoerg void CGObjCMac::EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S) {
42987330f729Sjoerg return EmitTryOrSynchronizedStmt(CGF, S);
42997330f729Sjoerg }
43007330f729Sjoerg
EmitSynchronizedStmt(CodeGenFunction & CGF,const ObjCAtSynchronizedStmt & S)43017330f729Sjoerg void CGObjCMac::EmitSynchronizedStmt(CodeGenFunction &CGF,
43027330f729Sjoerg const ObjCAtSynchronizedStmt &S) {
43037330f729Sjoerg return EmitTryOrSynchronizedStmt(CGF, S);
43047330f729Sjoerg }
43057330f729Sjoerg
43067330f729Sjoerg namespace {
43077330f729Sjoerg struct PerformFragileFinally final : EHScopeStack::Cleanup {
43087330f729Sjoerg const Stmt &S;
43097330f729Sjoerg Address SyncArgSlot;
43107330f729Sjoerg Address CallTryExitVar;
43117330f729Sjoerg Address ExceptionData;
43127330f729Sjoerg ObjCTypesHelper &ObjCTypes;
PerformFragileFinally__anon0cc8f9a20811::PerformFragileFinally43137330f729Sjoerg PerformFragileFinally(const Stmt *S,
43147330f729Sjoerg Address SyncArgSlot,
43157330f729Sjoerg Address CallTryExitVar,
43167330f729Sjoerg Address ExceptionData,
43177330f729Sjoerg ObjCTypesHelper *ObjCTypes)
43187330f729Sjoerg : S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar),
43197330f729Sjoerg ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {}
43207330f729Sjoerg
Emit__anon0cc8f9a20811::PerformFragileFinally43217330f729Sjoerg void Emit(CodeGenFunction &CGF, Flags flags) override {
43227330f729Sjoerg // Check whether we need to call objc_exception_try_exit.
43237330f729Sjoerg // In optimized code, this branch will always be folded.
43247330f729Sjoerg llvm::BasicBlock *FinallyCallExit =
43257330f729Sjoerg CGF.createBasicBlock("finally.call_exit");
43267330f729Sjoerg llvm::BasicBlock *FinallyNoCallExit =
43277330f729Sjoerg CGF.createBasicBlock("finally.no_call_exit");
43287330f729Sjoerg CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CallTryExitVar),
43297330f729Sjoerg FinallyCallExit, FinallyNoCallExit);
43307330f729Sjoerg
43317330f729Sjoerg CGF.EmitBlock(FinallyCallExit);
43327330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(),
43337330f729Sjoerg ExceptionData.getPointer());
43347330f729Sjoerg
43357330f729Sjoerg CGF.EmitBlock(FinallyNoCallExit);
43367330f729Sjoerg
43377330f729Sjoerg if (isa<ObjCAtTryStmt>(S)) {
43387330f729Sjoerg if (const ObjCAtFinallyStmt* FinallyStmt =
43397330f729Sjoerg cast<ObjCAtTryStmt>(S).getFinallyStmt()) {
43407330f729Sjoerg // Don't try to do the @finally if this is an EH cleanup.
43417330f729Sjoerg if (flags.isForEHCleanup()) return;
43427330f729Sjoerg
43437330f729Sjoerg // Save the current cleanup destination in case there's
43447330f729Sjoerg // control flow inside the finally statement.
43457330f729Sjoerg llvm::Value *CurCleanupDest =
43467330f729Sjoerg CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot());
43477330f729Sjoerg
43487330f729Sjoerg CGF.EmitStmt(FinallyStmt->getFinallyBody());
43497330f729Sjoerg
43507330f729Sjoerg if (CGF.HaveInsertPoint()) {
43517330f729Sjoerg CGF.Builder.CreateStore(CurCleanupDest,
43527330f729Sjoerg CGF.getNormalCleanupDestSlot());
43537330f729Sjoerg } else {
43547330f729Sjoerg // Currently, the end of the cleanup must always exist.
43557330f729Sjoerg CGF.EnsureInsertPoint();
43567330f729Sjoerg }
43577330f729Sjoerg }
43587330f729Sjoerg } else {
43597330f729Sjoerg // Emit objc_sync_exit(expr); as finally's sole statement for
43607330f729Sjoerg // @synchronized.
43617330f729Sjoerg llvm::Value *SyncArg = CGF.Builder.CreateLoad(SyncArgSlot);
43627330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncExitFn(), SyncArg);
43637330f729Sjoerg }
43647330f729Sjoerg }
43657330f729Sjoerg };
43667330f729Sjoerg
43677330f729Sjoerg class FragileHazards {
43687330f729Sjoerg CodeGenFunction &CGF;
43697330f729Sjoerg SmallVector<llvm::Value*, 20> Locals;
43707330f729Sjoerg llvm::DenseSet<llvm::BasicBlock*> BlocksBeforeTry;
43717330f729Sjoerg
43727330f729Sjoerg llvm::InlineAsm *ReadHazard;
43737330f729Sjoerg llvm::InlineAsm *WriteHazard;
43747330f729Sjoerg
43757330f729Sjoerg llvm::FunctionType *GetAsmFnType();
43767330f729Sjoerg
43777330f729Sjoerg void collectLocals();
43787330f729Sjoerg void emitReadHazard(CGBuilderTy &Builder);
43797330f729Sjoerg
43807330f729Sjoerg public:
43817330f729Sjoerg FragileHazards(CodeGenFunction &CGF);
43827330f729Sjoerg
43837330f729Sjoerg void emitWriteHazard();
43847330f729Sjoerg void emitHazardsInNewBlocks();
43857330f729Sjoerg };
43867330f729Sjoerg } // end anonymous namespace
43877330f729Sjoerg
43887330f729Sjoerg /// Create the fragile-ABI read and write hazards based on the current
43897330f729Sjoerg /// state of the function, which is presumed to be immediately prior
43907330f729Sjoerg /// to a @try block. These hazards are used to maintain correct
43917330f729Sjoerg /// semantics in the face of optimization and the fragile ABI's
43927330f729Sjoerg /// cavalier use of setjmp/longjmp.
FragileHazards(CodeGenFunction & CGF)43937330f729Sjoerg FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
43947330f729Sjoerg collectLocals();
43957330f729Sjoerg
43967330f729Sjoerg if (Locals.empty()) return;
43977330f729Sjoerg
43987330f729Sjoerg // Collect all the blocks in the function.
43997330f729Sjoerg for (llvm::Function::iterator
44007330f729Sjoerg I = CGF.CurFn->begin(), E = CGF.CurFn->end(); I != E; ++I)
44017330f729Sjoerg BlocksBeforeTry.insert(&*I);
44027330f729Sjoerg
44037330f729Sjoerg llvm::FunctionType *AsmFnTy = GetAsmFnType();
44047330f729Sjoerg
44057330f729Sjoerg // Create a read hazard for the allocas. This inhibits dead-store
44067330f729Sjoerg // optimizations and forces the values to memory. This hazard is
44077330f729Sjoerg // inserted before any 'throwing' calls in the protected scope to
44087330f729Sjoerg // reflect the possibility that the variables might be read from the
44097330f729Sjoerg // catch block if the call throws.
44107330f729Sjoerg {
44117330f729Sjoerg std::string Constraint;
44127330f729Sjoerg for (unsigned I = 0, E = Locals.size(); I != E; ++I) {
44137330f729Sjoerg if (I) Constraint += ',';
44147330f729Sjoerg Constraint += "*m";
44157330f729Sjoerg }
44167330f729Sjoerg
44177330f729Sjoerg ReadHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false);
44187330f729Sjoerg }
44197330f729Sjoerg
44207330f729Sjoerg // Create a write hazard for the allocas. This inhibits folding
44217330f729Sjoerg // loads across the hazard. This hazard is inserted at the
44227330f729Sjoerg // beginning of the catch path to reflect the possibility that the
44237330f729Sjoerg // variables might have been written within the protected scope.
44247330f729Sjoerg {
44257330f729Sjoerg std::string Constraint;
44267330f729Sjoerg for (unsigned I = 0, E = Locals.size(); I != E; ++I) {
44277330f729Sjoerg if (I) Constraint += ',';
44287330f729Sjoerg Constraint += "=*m";
44297330f729Sjoerg }
44307330f729Sjoerg
44317330f729Sjoerg WriteHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false);
44327330f729Sjoerg }
44337330f729Sjoerg }
44347330f729Sjoerg
44357330f729Sjoerg /// Emit a write hazard at the current location.
emitWriteHazard()44367330f729Sjoerg void FragileHazards::emitWriteHazard() {
44377330f729Sjoerg if (Locals.empty()) return;
44387330f729Sjoerg
44397330f729Sjoerg CGF.EmitNounwindRuntimeCall(WriteHazard, Locals);
44407330f729Sjoerg }
44417330f729Sjoerg
emitReadHazard(CGBuilderTy & Builder)44427330f729Sjoerg void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
44437330f729Sjoerg assert(!Locals.empty());
44447330f729Sjoerg llvm::CallInst *call = Builder.CreateCall(ReadHazard, Locals);
44457330f729Sjoerg call->setDoesNotThrow();
44467330f729Sjoerg call->setCallingConv(CGF.getRuntimeCC());
44477330f729Sjoerg }
44487330f729Sjoerg
44497330f729Sjoerg /// Emit read hazards in all the protected blocks, i.e. all the blocks
44507330f729Sjoerg /// which have been inserted since the beginning of the try.
emitHazardsInNewBlocks()44517330f729Sjoerg void FragileHazards::emitHazardsInNewBlocks() {
44527330f729Sjoerg if (Locals.empty()) return;
44537330f729Sjoerg
44547330f729Sjoerg CGBuilderTy Builder(CGF, CGF.getLLVMContext());
44557330f729Sjoerg
44567330f729Sjoerg // Iterate through all blocks, skipping those prior to the try.
44577330f729Sjoerg for (llvm::Function::iterator
44587330f729Sjoerg FI = CGF.CurFn->begin(), FE = CGF.CurFn->end(); FI != FE; ++FI) {
44597330f729Sjoerg llvm::BasicBlock &BB = *FI;
44607330f729Sjoerg if (BlocksBeforeTry.count(&BB)) continue;
44617330f729Sjoerg
44627330f729Sjoerg // Walk through all the calls in the block.
44637330f729Sjoerg for (llvm::BasicBlock::iterator
44647330f729Sjoerg BI = BB.begin(), BE = BB.end(); BI != BE; ++BI) {
44657330f729Sjoerg llvm::Instruction &I = *BI;
44667330f729Sjoerg
44677330f729Sjoerg // Ignore instructions that aren't non-intrinsic calls.
44687330f729Sjoerg // These are the only calls that can possibly call longjmp.
44697330f729Sjoerg if (!isa<llvm::CallInst>(I) && !isa<llvm::InvokeInst>(I))
44707330f729Sjoerg continue;
44717330f729Sjoerg if (isa<llvm::IntrinsicInst>(I))
44727330f729Sjoerg continue;
44737330f729Sjoerg
44747330f729Sjoerg // Ignore call sites marked nounwind. This may be questionable,
44757330f729Sjoerg // since 'nounwind' doesn't necessarily mean 'does not call longjmp'.
44767330f729Sjoerg if (cast<llvm::CallBase>(I).doesNotThrow())
44777330f729Sjoerg continue;
44787330f729Sjoerg
44797330f729Sjoerg // Insert a read hazard before the call. This will ensure that
44807330f729Sjoerg // any writes to the locals are performed before making the
44817330f729Sjoerg // call. If the call throws, then this is sufficient to
44827330f729Sjoerg // guarantee correctness as long as it doesn't also write to any
44837330f729Sjoerg // locals.
44847330f729Sjoerg Builder.SetInsertPoint(&BB, BI);
44857330f729Sjoerg emitReadHazard(Builder);
44867330f729Sjoerg }
44877330f729Sjoerg }
44887330f729Sjoerg }
44897330f729Sjoerg
addIfPresent(llvm::DenseSet<llvm::Value * > & S,Address V)44907330f729Sjoerg static void addIfPresent(llvm::DenseSet<llvm::Value*> &S, Address V) {
44917330f729Sjoerg if (V.isValid()) S.insert(V.getPointer());
44927330f729Sjoerg }
44937330f729Sjoerg
collectLocals()44947330f729Sjoerg void FragileHazards::collectLocals() {
44957330f729Sjoerg // Compute a set of allocas to ignore.
44967330f729Sjoerg llvm::DenseSet<llvm::Value*> AllocasToIgnore;
44977330f729Sjoerg addIfPresent(AllocasToIgnore, CGF.ReturnValue);
44987330f729Sjoerg addIfPresent(AllocasToIgnore, CGF.NormalCleanupDest);
44997330f729Sjoerg
45007330f729Sjoerg // Collect all the allocas currently in the function. This is
45017330f729Sjoerg // probably way too aggressive.
45027330f729Sjoerg llvm::BasicBlock &Entry = CGF.CurFn->getEntryBlock();
45037330f729Sjoerg for (llvm::BasicBlock::iterator
45047330f729Sjoerg I = Entry.begin(), E = Entry.end(); I != E; ++I)
45057330f729Sjoerg if (isa<llvm::AllocaInst>(*I) && !AllocasToIgnore.count(&*I))
45067330f729Sjoerg Locals.push_back(&*I);
45077330f729Sjoerg }
45087330f729Sjoerg
GetAsmFnType()45097330f729Sjoerg llvm::FunctionType *FragileHazards::GetAsmFnType() {
45107330f729Sjoerg SmallVector<llvm::Type *, 16> tys(Locals.size());
45117330f729Sjoerg for (unsigned i = 0, e = Locals.size(); i != e; ++i)
45127330f729Sjoerg tys[i] = Locals[i]->getType();
45137330f729Sjoerg return llvm::FunctionType::get(CGF.VoidTy, tys, false);
45147330f729Sjoerg }
45157330f729Sjoerg
45167330f729Sjoerg /*
45177330f729Sjoerg
45187330f729Sjoerg Objective-C setjmp-longjmp (sjlj) Exception Handling
45197330f729Sjoerg --
45207330f729Sjoerg
45217330f729Sjoerg A catch buffer is a setjmp buffer plus:
45227330f729Sjoerg - a pointer to the exception that was caught
45237330f729Sjoerg - a pointer to the previous exception data buffer
45247330f729Sjoerg - two pointers of reserved storage
45257330f729Sjoerg Therefore catch buffers form a stack, with a pointer to the top
45267330f729Sjoerg of the stack kept in thread-local storage.
45277330f729Sjoerg
45287330f729Sjoerg objc_exception_try_enter pushes a catch buffer onto the EH stack.
45297330f729Sjoerg objc_exception_try_exit pops the given catch buffer, which is
45307330f729Sjoerg required to be the top of the EH stack.
45317330f729Sjoerg objc_exception_throw pops the top of the EH stack, writes the
45327330f729Sjoerg thrown exception into the appropriate field, and longjmps
45337330f729Sjoerg to the setjmp buffer. It crashes the process (with a printf
45347330f729Sjoerg and an abort()) if there are no catch buffers on the stack.
45357330f729Sjoerg objc_exception_extract just reads the exception pointer out of the
45367330f729Sjoerg catch buffer.
45377330f729Sjoerg
45387330f729Sjoerg There's no reason an implementation couldn't use a light-weight
45397330f729Sjoerg setjmp here --- something like __builtin_setjmp, but API-compatible
45407330f729Sjoerg with the heavyweight setjmp. This will be more important if we ever
45417330f729Sjoerg want to implement correct ObjC/C++ exception interactions for the
45427330f729Sjoerg fragile ABI.
45437330f729Sjoerg
45447330f729Sjoerg Note that for this use of setjmp/longjmp to be correct, we may need
45457330f729Sjoerg to mark some local variables volatile: if a non-volatile local
45467330f729Sjoerg variable is modified between the setjmp and the longjmp, it has
45477330f729Sjoerg indeterminate value. For the purposes of LLVM IR, it may be
45487330f729Sjoerg sufficient to make loads and stores within the @try (to variables
45497330f729Sjoerg declared outside the @try) volatile. This is necessary for
45507330f729Sjoerg optimized correctness, but is not currently being done; this is
45517330f729Sjoerg being tracked as rdar://problem/8160285
45527330f729Sjoerg
45537330f729Sjoerg The basic framework for a @try-catch-finally is as follows:
45547330f729Sjoerg {
45557330f729Sjoerg objc_exception_data d;
45567330f729Sjoerg id _rethrow = null;
45577330f729Sjoerg bool _call_try_exit = true;
45587330f729Sjoerg
45597330f729Sjoerg objc_exception_try_enter(&d);
45607330f729Sjoerg if (!setjmp(d.jmp_buf)) {
45617330f729Sjoerg ... try body ...
45627330f729Sjoerg } else {
45637330f729Sjoerg // exception path
45647330f729Sjoerg id _caught = objc_exception_extract(&d);
45657330f729Sjoerg
45667330f729Sjoerg // enter new try scope for handlers
45677330f729Sjoerg if (!setjmp(d.jmp_buf)) {
45687330f729Sjoerg ... match exception and execute catch blocks ...
45697330f729Sjoerg
45707330f729Sjoerg // fell off end, rethrow.
45717330f729Sjoerg _rethrow = _caught;
45727330f729Sjoerg ... jump-through-finally to finally_rethrow ...
45737330f729Sjoerg } else {
45747330f729Sjoerg // exception in catch block
45757330f729Sjoerg _rethrow = objc_exception_extract(&d);
45767330f729Sjoerg _call_try_exit = false;
45777330f729Sjoerg ... jump-through-finally to finally_rethrow ...
45787330f729Sjoerg }
45797330f729Sjoerg }
45807330f729Sjoerg ... jump-through-finally to finally_end ...
45817330f729Sjoerg
45827330f729Sjoerg finally:
45837330f729Sjoerg if (_call_try_exit)
45847330f729Sjoerg objc_exception_try_exit(&d);
45857330f729Sjoerg
45867330f729Sjoerg ... finally block ....
45877330f729Sjoerg ... dispatch to finally destination ...
45887330f729Sjoerg
45897330f729Sjoerg finally_rethrow:
45907330f729Sjoerg objc_exception_throw(_rethrow);
45917330f729Sjoerg
45927330f729Sjoerg finally_end:
45937330f729Sjoerg }
45947330f729Sjoerg
45957330f729Sjoerg This framework differs slightly from the one gcc uses, in that gcc
45967330f729Sjoerg uses _rethrow to determine if objc_exception_try_exit should be called
45977330f729Sjoerg and if the object should be rethrown. This breaks in the face of
45987330f729Sjoerg throwing nil and introduces unnecessary branches.
45997330f729Sjoerg
46007330f729Sjoerg We specialize this framework for a few particular circumstances:
46017330f729Sjoerg
46027330f729Sjoerg - If there are no catch blocks, then we avoid emitting the second
46037330f729Sjoerg exception handling context.
46047330f729Sjoerg
46057330f729Sjoerg - If there is a catch-all catch block (i.e. @catch(...) or @catch(id
46067330f729Sjoerg e)) we avoid emitting the code to rethrow an uncaught exception.
46077330f729Sjoerg
46087330f729Sjoerg - FIXME: If there is no @finally block we can do a few more
46097330f729Sjoerg simplifications.
46107330f729Sjoerg
46117330f729Sjoerg Rethrows and Jumps-Through-Finally
46127330f729Sjoerg --
46137330f729Sjoerg
46147330f729Sjoerg '@throw;' is supported by pushing the currently-caught exception
46157330f729Sjoerg onto ObjCEHStack while the @catch blocks are emitted.
46167330f729Sjoerg
46177330f729Sjoerg Branches through the @finally block are handled with an ordinary
46187330f729Sjoerg normal cleanup. We do not register an EH cleanup; fragile-ABI ObjC
46197330f729Sjoerg exceptions are not compatible with C++ exceptions, and this is
46207330f729Sjoerg hardly the only place where this will go wrong.
46217330f729Sjoerg
46227330f729Sjoerg @synchronized(expr) { stmt; } is emitted as if it were:
46237330f729Sjoerg id synch_value = expr;
46247330f729Sjoerg objc_sync_enter(synch_value);
46257330f729Sjoerg @try { stmt; } @finally { objc_sync_exit(synch_value); }
46267330f729Sjoerg */
46277330f729Sjoerg
EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction & CGF,const Stmt & S)46287330f729Sjoerg void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
46297330f729Sjoerg const Stmt &S) {
46307330f729Sjoerg bool isTry = isa<ObjCAtTryStmt>(S);
46317330f729Sjoerg
46327330f729Sjoerg // A destination for the fall-through edges of the catch handlers to
46337330f729Sjoerg // jump to.
46347330f729Sjoerg CodeGenFunction::JumpDest FinallyEnd =
46357330f729Sjoerg CGF.getJumpDestInCurrentScope("finally.end");
46367330f729Sjoerg
46377330f729Sjoerg // A destination for the rethrow edge of the catch handlers to jump
46387330f729Sjoerg // to.
46397330f729Sjoerg CodeGenFunction::JumpDest FinallyRethrow =
46407330f729Sjoerg CGF.getJumpDestInCurrentScope("finally.rethrow");
46417330f729Sjoerg
46427330f729Sjoerg // For @synchronized, call objc_sync_enter(sync.expr). The
46437330f729Sjoerg // evaluation of the expression must occur before we enter the
46447330f729Sjoerg // @synchronized. We can't avoid a temp here because we need the
46457330f729Sjoerg // value to be preserved. If the backend ever does liveness
46467330f729Sjoerg // correctly after setjmp, this will be unnecessary.
46477330f729Sjoerg Address SyncArgSlot = Address::invalid();
46487330f729Sjoerg if (!isTry) {
46497330f729Sjoerg llvm::Value *SyncArg =
46507330f729Sjoerg CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
46517330f729Sjoerg SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
46527330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncEnterFn(), SyncArg);
46537330f729Sjoerg
46547330f729Sjoerg SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(),
46557330f729Sjoerg CGF.getPointerAlign(), "sync.arg");
46567330f729Sjoerg CGF.Builder.CreateStore(SyncArg, SyncArgSlot);
46577330f729Sjoerg }
46587330f729Sjoerg
46597330f729Sjoerg // Allocate memory for the setjmp buffer. This needs to be kept
46607330f729Sjoerg // live throughout the try and catch blocks.
46617330f729Sjoerg Address ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
46627330f729Sjoerg CGF.getPointerAlign(),
46637330f729Sjoerg "exceptiondata.ptr");
46647330f729Sjoerg
46657330f729Sjoerg // Create the fragile hazards. Note that this will not capture any
46667330f729Sjoerg // of the allocas required for exception processing, but will
46677330f729Sjoerg // capture the current basic block (which extends all the way to the
46687330f729Sjoerg // setjmp call) as "before the @try".
46697330f729Sjoerg FragileHazards Hazards(CGF);
46707330f729Sjoerg
46717330f729Sjoerg // Create a flag indicating whether the cleanup needs to call
46727330f729Sjoerg // objc_exception_try_exit. This is true except when
46737330f729Sjoerg // - no catches match and we're branching through the cleanup
46747330f729Sjoerg // just to rethrow the exception, or
46757330f729Sjoerg // - a catch matched and we're falling out of the catch handler.
46767330f729Sjoerg // The setjmp-safety rule here is that we should always store to this
46777330f729Sjoerg // variable in a place that dominates the branch through the cleanup
46787330f729Sjoerg // without passing through any setjmps.
46797330f729Sjoerg Address CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(),
46807330f729Sjoerg CharUnits::One(),
46817330f729Sjoerg "_call_try_exit");
46827330f729Sjoerg
46837330f729Sjoerg // A slot containing the exception to rethrow. Only needed when we
46847330f729Sjoerg // have both a @catch and a @finally.
46857330f729Sjoerg Address PropagatingExnVar = Address::invalid();
46867330f729Sjoerg
46877330f729Sjoerg // Push a normal cleanup to leave the try scope.
46887330f729Sjoerg CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S,
46897330f729Sjoerg SyncArgSlot,
46907330f729Sjoerg CallTryExitVar,
46917330f729Sjoerg ExceptionData,
46927330f729Sjoerg &ObjCTypes);
46937330f729Sjoerg
46947330f729Sjoerg // Enter a try block:
46957330f729Sjoerg // - Call objc_exception_try_enter to push ExceptionData on top of
46967330f729Sjoerg // the EH stack.
46977330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
46987330f729Sjoerg ExceptionData.getPointer());
46997330f729Sjoerg
47007330f729Sjoerg // - Call setjmp on the exception data buffer.
47017330f729Sjoerg llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
47027330f729Sjoerg llvm::Value *GEPIndexes[] = { Zero, Zero, Zero };
47037330f729Sjoerg llvm::Value *SetJmpBuffer = CGF.Builder.CreateGEP(
47047330f729Sjoerg ObjCTypes.ExceptionDataTy, ExceptionData.getPointer(), GEPIndexes,
47057330f729Sjoerg "setjmp_buffer");
47067330f729Sjoerg llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall(
47077330f729Sjoerg ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
47087330f729Sjoerg SetJmpResult->setCanReturnTwice();
47097330f729Sjoerg
47107330f729Sjoerg // If setjmp returned 0, enter the protected block; otherwise,
47117330f729Sjoerg // branch to the handler.
47127330f729Sjoerg llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
47137330f729Sjoerg llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
47147330f729Sjoerg llvm::Value *DidCatch =
47157330f729Sjoerg CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
47167330f729Sjoerg CGF.Builder.CreateCondBr(DidCatch, TryHandler, TryBlock);
47177330f729Sjoerg
47187330f729Sjoerg // Emit the protected block.
47197330f729Sjoerg CGF.EmitBlock(TryBlock);
47207330f729Sjoerg CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar);
47217330f729Sjoerg CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
47227330f729Sjoerg : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
47237330f729Sjoerg
47247330f729Sjoerg CGBuilderTy::InsertPoint TryFallthroughIP = CGF.Builder.saveAndClearIP();
47257330f729Sjoerg
47267330f729Sjoerg // Emit the exception handler block.
47277330f729Sjoerg CGF.EmitBlock(TryHandler);
47287330f729Sjoerg
47297330f729Sjoerg // Don't optimize loads of the in-scope locals across this point.
47307330f729Sjoerg Hazards.emitWriteHazard();
47317330f729Sjoerg
47327330f729Sjoerg // For a @synchronized (or a @try with no catches), just branch
47337330f729Sjoerg // through the cleanup to the rethrow block.
47347330f729Sjoerg if (!isTry || !cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
47357330f729Sjoerg // Tell the cleanup not to re-pop the exit.
47367330f729Sjoerg CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
47377330f729Sjoerg CGF.EmitBranchThroughCleanup(FinallyRethrow);
47387330f729Sjoerg
47397330f729Sjoerg // Otherwise, we have to match against the caught exceptions.
47407330f729Sjoerg } else {
47417330f729Sjoerg // Retrieve the exception object. We may emit multiple blocks but
47427330f729Sjoerg // nothing can cross this so the value is already in SSA form.
47437330f729Sjoerg llvm::CallInst *Caught =
47447330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
47457330f729Sjoerg ExceptionData.getPointer(), "caught");
47467330f729Sjoerg
47477330f729Sjoerg // Push the exception to rethrow onto the EH value stack for the
47487330f729Sjoerg // benefit of any @throws in the handlers.
47497330f729Sjoerg CGF.ObjCEHValueStack.push_back(Caught);
47507330f729Sjoerg
47517330f729Sjoerg const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S);
47527330f729Sjoerg
47537330f729Sjoerg bool HasFinally = (AtTryStmt->getFinallyStmt() != nullptr);
47547330f729Sjoerg
47557330f729Sjoerg llvm::BasicBlock *CatchBlock = nullptr;
47567330f729Sjoerg llvm::BasicBlock *CatchHandler = nullptr;
47577330f729Sjoerg if (HasFinally) {
47587330f729Sjoerg // Save the currently-propagating exception before
47597330f729Sjoerg // objc_exception_try_enter clears the exception slot.
47607330f729Sjoerg PropagatingExnVar = CGF.CreateTempAlloca(Caught->getType(),
47617330f729Sjoerg CGF.getPointerAlign(),
47627330f729Sjoerg "propagating_exception");
47637330f729Sjoerg CGF.Builder.CreateStore(Caught, PropagatingExnVar);
47647330f729Sjoerg
47657330f729Sjoerg // Enter a new exception try block (in case a @catch block
47667330f729Sjoerg // throws an exception).
47677330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
47687330f729Sjoerg ExceptionData.getPointer());
47697330f729Sjoerg
47707330f729Sjoerg llvm::CallInst *SetJmpResult =
47717330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(),
47727330f729Sjoerg SetJmpBuffer, "setjmp.result");
47737330f729Sjoerg SetJmpResult->setCanReturnTwice();
47747330f729Sjoerg
47757330f729Sjoerg llvm::Value *Threw =
47767330f729Sjoerg CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
47777330f729Sjoerg
47787330f729Sjoerg CatchBlock = CGF.createBasicBlock("catch");
47797330f729Sjoerg CatchHandler = CGF.createBasicBlock("catch_for_catch");
47807330f729Sjoerg CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock);
47817330f729Sjoerg
47827330f729Sjoerg CGF.EmitBlock(CatchBlock);
47837330f729Sjoerg }
47847330f729Sjoerg
47857330f729Sjoerg CGF.Builder.CreateStore(CGF.Builder.getInt1(HasFinally), CallTryExitVar);
47867330f729Sjoerg
47877330f729Sjoerg // Handle catch list. As a special case we check if everything is
47887330f729Sjoerg // matched and avoid generating code for falling off the end if
47897330f729Sjoerg // so.
47907330f729Sjoerg bool AllMatched = false;
47917330f729Sjoerg for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) {
47927330f729Sjoerg const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I);
47937330f729Sjoerg
47947330f729Sjoerg const VarDecl *CatchParam = CatchStmt->getCatchParamDecl();
47957330f729Sjoerg const ObjCObjectPointerType *OPT = nullptr;
47967330f729Sjoerg
47977330f729Sjoerg // catch(...) always matches.
47987330f729Sjoerg if (!CatchParam) {
47997330f729Sjoerg AllMatched = true;
48007330f729Sjoerg } else {
48017330f729Sjoerg OPT = CatchParam->getType()->getAs<ObjCObjectPointerType>();
48027330f729Sjoerg
48037330f729Sjoerg // catch(id e) always matches under this ABI, since only
48047330f729Sjoerg // ObjC exceptions end up here in the first place.
48057330f729Sjoerg // FIXME: For the time being we also match id<X>; this should
48067330f729Sjoerg // be rejected by Sema instead.
48077330f729Sjoerg if (OPT && (OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()))
48087330f729Sjoerg AllMatched = true;
48097330f729Sjoerg }
48107330f729Sjoerg
48117330f729Sjoerg // If this is a catch-all, we don't need to test anything.
48127330f729Sjoerg if (AllMatched) {
48137330f729Sjoerg CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF);
48147330f729Sjoerg
48157330f729Sjoerg if (CatchParam) {
48167330f729Sjoerg CGF.EmitAutoVarDecl(*CatchParam);
48177330f729Sjoerg assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
48187330f729Sjoerg
48197330f729Sjoerg // These types work out because ConvertType(id) == i8*.
48207330f729Sjoerg EmitInitOfCatchParam(CGF, Caught, CatchParam);
48217330f729Sjoerg }
48227330f729Sjoerg
48237330f729Sjoerg CGF.EmitStmt(CatchStmt->getCatchBody());
48247330f729Sjoerg
48257330f729Sjoerg // The scope of the catch variable ends right here.
48267330f729Sjoerg CatchVarCleanups.ForceCleanup();
48277330f729Sjoerg
48287330f729Sjoerg CGF.EmitBranchThroughCleanup(FinallyEnd);
48297330f729Sjoerg break;
48307330f729Sjoerg }
48317330f729Sjoerg
48327330f729Sjoerg assert(OPT && "Unexpected non-object pointer type in @catch");
48337330f729Sjoerg const ObjCObjectType *ObjTy = OPT->getObjectType();
48347330f729Sjoerg
48357330f729Sjoerg // FIXME: @catch (Class c) ?
48367330f729Sjoerg ObjCInterfaceDecl *IDecl = ObjTy->getInterface();
48377330f729Sjoerg assert(IDecl && "Catch parameter must have Objective-C type!");
48387330f729Sjoerg
48397330f729Sjoerg // Check if the @catch block matches the exception object.
48407330f729Sjoerg llvm::Value *Class = EmitClassRef(CGF, IDecl);
48417330f729Sjoerg
48427330f729Sjoerg llvm::Value *matchArgs[] = { Class, Caught };
48437330f729Sjoerg llvm::CallInst *Match =
48447330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionMatchFn(),
48457330f729Sjoerg matchArgs, "match");
48467330f729Sjoerg
48477330f729Sjoerg llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("match");
48487330f729Sjoerg llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch.next");
48497330f729Sjoerg
48507330f729Sjoerg CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(Match, "matched"),
48517330f729Sjoerg MatchedBlock, NextCatchBlock);
48527330f729Sjoerg
48537330f729Sjoerg // Emit the @catch block.
48547330f729Sjoerg CGF.EmitBlock(MatchedBlock);
48557330f729Sjoerg
48567330f729Sjoerg // Collect any cleanups for the catch variable. The scope lasts until
48577330f729Sjoerg // the end of the catch body.
48587330f729Sjoerg CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF);
48597330f729Sjoerg
48607330f729Sjoerg CGF.EmitAutoVarDecl(*CatchParam);
48617330f729Sjoerg assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
48627330f729Sjoerg
48637330f729Sjoerg // Initialize the catch variable.
48647330f729Sjoerg llvm::Value *Tmp =
48657330f729Sjoerg CGF.Builder.CreateBitCast(Caught,
48667330f729Sjoerg CGF.ConvertType(CatchParam->getType()));
48677330f729Sjoerg EmitInitOfCatchParam(CGF, Tmp, CatchParam);
48687330f729Sjoerg
48697330f729Sjoerg CGF.EmitStmt(CatchStmt->getCatchBody());
48707330f729Sjoerg
48717330f729Sjoerg // We're done with the catch variable.
48727330f729Sjoerg CatchVarCleanups.ForceCleanup();
48737330f729Sjoerg
48747330f729Sjoerg CGF.EmitBranchThroughCleanup(FinallyEnd);
48757330f729Sjoerg
48767330f729Sjoerg CGF.EmitBlock(NextCatchBlock);
48777330f729Sjoerg }
48787330f729Sjoerg
48797330f729Sjoerg CGF.ObjCEHValueStack.pop_back();
48807330f729Sjoerg
48817330f729Sjoerg // If nothing wanted anything to do with the caught exception,
48827330f729Sjoerg // kill the extract call.
48837330f729Sjoerg if (Caught->use_empty())
48847330f729Sjoerg Caught->eraseFromParent();
48857330f729Sjoerg
48867330f729Sjoerg if (!AllMatched)
48877330f729Sjoerg CGF.EmitBranchThroughCleanup(FinallyRethrow);
48887330f729Sjoerg
48897330f729Sjoerg if (HasFinally) {
48907330f729Sjoerg // Emit the exception handler for the @catch blocks.
48917330f729Sjoerg CGF.EmitBlock(CatchHandler);
48927330f729Sjoerg
48937330f729Sjoerg // In theory we might now need a write hazard, but actually it's
48947330f729Sjoerg // unnecessary because there's no local-accessing code between
48957330f729Sjoerg // the try's write hazard and here.
48967330f729Sjoerg //Hazards.emitWriteHazard();
48977330f729Sjoerg
48987330f729Sjoerg // Extract the new exception and save it to the
48997330f729Sjoerg // propagating-exception slot.
49007330f729Sjoerg assert(PropagatingExnVar.isValid());
49017330f729Sjoerg llvm::CallInst *NewCaught =
49027330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
49037330f729Sjoerg ExceptionData.getPointer(), "caught");
49047330f729Sjoerg CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
49057330f729Sjoerg
49067330f729Sjoerg // Don't pop the catch handler; the throw already did.
49077330f729Sjoerg CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
49087330f729Sjoerg CGF.EmitBranchThroughCleanup(FinallyRethrow);
49097330f729Sjoerg }
49107330f729Sjoerg }
49117330f729Sjoerg
49127330f729Sjoerg // Insert read hazards as required in the new blocks.
49137330f729Sjoerg Hazards.emitHazardsInNewBlocks();
49147330f729Sjoerg
49157330f729Sjoerg // Pop the cleanup.
49167330f729Sjoerg CGF.Builder.restoreIP(TryFallthroughIP);
49177330f729Sjoerg if (CGF.HaveInsertPoint())
49187330f729Sjoerg CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar);
49197330f729Sjoerg CGF.PopCleanupBlock();
49207330f729Sjoerg CGF.EmitBlock(FinallyEnd.getBlock(), true);
49217330f729Sjoerg
49227330f729Sjoerg // Emit the rethrow block.
49237330f729Sjoerg CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
49247330f729Sjoerg CGF.EmitBlock(FinallyRethrow.getBlock(), true);
49257330f729Sjoerg if (CGF.HaveInsertPoint()) {
49267330f729Sjoerg // If we have a propagating-exception variable, check it.
49277330f729Sjoerg llvm::Value *PropagatingExn;
49287330f729Sjoerg if (PropagatingExnVar.isValid()) {
49297330f729Sjoerg PropagatingExn = CGF.Builder.CreateLoad(PropagatingExnVar);
49307330f729Sjoerg
49317330f729Sjoerg // Otherwise, just look in the buffer for the exception to throw.
49327330f729Sjoerg } else {
49337330f729Sjoerg llvm::CallInst *Caught =
49347330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
49357330f729Sjoerg ExceptionData.getPointer());
49367330f729Sjoerg PropagatingExn = Caught;
49377330f729Sjoerg }
49387330f729Sjoerg
49397330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionThrowFn(),
49407330f729Sjoerg PropagatingExn);
49417330f729Sjoerg CGF.Builder.CreateUnreachable();
49427330f729Sjoerg }
49437330f729Sjoerg
49447330f729Sjoerg CGF.Builder.restoreIP(SavedIP);
49457330f729Sjoerg }
49467330f729Sjoerg
EmitThrowStmt(CodeGen::CodeGenFunction & CGF,const ObjCAtThrowStmt & S,bool ClearInsertionPoint)49477330f729Sjoerg void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
49487330f729Sjoerg const ObjCAtThrowStmt &S,
49497330f729Sjoerg bool ClearInsertionPoint) {
49507330f729Sjoerg llvm::Value *ExceptionAsObject;
49517330f729Sjoerg
49527330f729Sjoerg if (const Expr *ThrowExpr = S.getThrowExpr()) {
49537330f729Sjoerg llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
49547330f729Sjoerg ExceptionAsObject =
49557330f729Sjoerg CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
49567330f729Sjoerg } else {
49577330f729Sjoerg assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
49587330f729Sjoerg "Unexpected rethrow outside @catch block.");
49597330f729Sjoerg ExceptionAsObject = CGF.ObjCEHValueStack.back();
49607330f729Sjoerg }
49617330f729Sjoerg
49627330f729Sjoerg CGF.EmitRuntimeCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
49637330f729Sjoerg ->setDoesNotReturn();
49647330f729Sjoerg CGF.Builder.CreateUnreachable();
49657330f729Sjoerg
49667330f729Sjoerg // Clear the insertion point to indicate we are in unreachable code.
49677330f729Sjoerg if (ClearInsertionPoint)
49687330f729Sjoerg CGF.Builder.ClearInsertionPoint();
49697330f729Sjoerg }
49707330f729Sjoerg
49717330f729Sjoerg /// EmitObjCWeakRead - Code gen for loading value of a __weak
49727330f729Sjoerg /// object: objc_read_weak (id *src)
49737330f729Sjoerg ///
EmitObjCWeakRead(CodeGen::CodeGenFunction & CGF,Address AddrWeakObj)49747330f729Sjoerg llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
49757330f729Sjoerg Address AddrWeakObj) {
49767330f729Sjoerg llvm::Type* DestTy = AddrWeakObj.getElementType();
49777330f729Sjoerg AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj,
49787330f729Sjoerg ObjCTypes.PtrObjectPtrTy);
49797330f729Sjoerg llvm::Value *read_weak =
49807330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
49817330f729Sjoerg AddrWeakObj.getPointer(), "weakread");
49827330f729Sjoerg read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
49837330f729Sjoerg return read_weak;
49847330f729Sjoerg }
49857330f729Sjoerg
49867330f729Sjoerg /// EmitObjCWeakAssign - Code gen for assigning to a __weak object.
49877330f729Sjoerg /// objc_assign_weak (id src, id *dst)
49887330f729Sjoerg ///
EmitObjCWeakAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst)49897330f729Sjoerg void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
49907330f729Sjoerg llvm::Value *src, Address dst) {
49917330f729Sjoerg llvm::Type * SrcTy = src->getType();
49927330f729Sjoerg if (!isa<llvm::PointerType>(SrcTy)) {
49937330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
49947330f729Sjoerg assert(Size <= 8 && "does not support size > 8");
49957330f729Sjoerg src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
49967330f729Sjoerg : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
49977330f729Sjoerg src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
49987330f729Sjoerg }
49997330f729Sjoerg src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
50007330f729Sjoerg dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
50017330f729Sjoerg llvm::Value *args[] = { src, dst.getPointer() };
50027330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
50037330f729Sjoerg args, "weakassign");
50047330f729Sjoerg }
50057330f729Sjoerg
50067330f729Sjoerg /// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
50077330f729Sjoerg /// objc_assign_global (id src, id *dst)
50087330f729Sjoerg ///
EmitObjCGlobalAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst,bool threadlocal)50097330f729Sjoerg void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
50107330f729Sjoerg llvm::Value *src, Address dst,
50117330f729Sjoerg bool threadlocal) {
50127330f729Sjoerg llvm::Type * SrcTy = src->getType();
50137330f729Sjoerg if (!isa<llvm::PointerType>(SrcTy)) {
50147330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
50157330f729Sjoerg assert(Size <= 8 && "does not support size > 8");
50167330f729Sjoerg src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
50177330f729Sjoerg : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
50187330f729Sjoerg src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
50197330f729Sjoerg }
50207330f729Sjoerg src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
50217330f729Sjoerg dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
50227330f729Sjoerg llvm::Value *args[] = { src, dst.getPointer() };
50237330f729Sjoerg if (!threadlocal)
50247330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
50257330f729Sjoerg args, "globalassign");
50267330f729Sjoerg else
50277330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
50287330f729Sjoerg args, "threadlocalassign");
50297330f729Sjoerg }
50307330f729Sjoerg
50317330f729Sjoerg /// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
50327330f729Sjoerg /// objc_assign_ivar (id src, id *dst, ptrdiff_t ivaroffset)
50337330f729Sjoerg ///
EmitObjCIvarAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst,llvm::Value * ivarOffset)50347330f729Sjoerg void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
50357330f729Sjoerg llvm::Value *src, Address dst,
50367330f729Sjoerg llvm::Value *ivarOffset) {
50377330f729Sjoerg assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
50387330f729Sjoerg llvm::Type * SrcTy = src->getType();
50397330f729Sjoerg if (!isa<llvm::PointerType>(SrcTy)) {
50407330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
50417330f729Sjoerg assert(Size <= 8 && "does not support size > 8");
50427330f729Sjoerg src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
50437330f729Sjoerg : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
50447330f729Sjoerg src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
50457330f729Sjoerg }
50467330f729Sjoerg src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
50477330f729Sjoerg dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
50487330f729Sjoerg llvm::Value *args[] = { src, dst.getPointer(), ivarOffset };
50497330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
50507330f729Sjoerg }
50517330f729Sjoerg
50527330f729Sjoerg /// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
50537330f729Sjoerg /// objc_assign_strongCast (id src, id *dst)
50547330f729Sjoerg ///
EmitObjCStrongCastAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst)50557330f729Sjoerg void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
50567330f729Sjoerg llvm::Value *src, Address dst) {
50577330f729Sjoerg llvm::Type * SrcTy = src->getType();
50587330f729Sjoerg if (!isa<llvm::PointerType>(SrcTy)) {
50597330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
50607330f729Sjoerg assert(Size <= 8 && "does not support size > 8");
50617330f729Sjoerg src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
50627330f729Sjoerg : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
50637330f729Sjoerg src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
50647330f729Sjoerg }
50657330f729Sjoerg src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
50667330f729Sjoerg dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
50677330f729Sjoerg llvm::Value *args[] = { src, dst.getPointer() };
50687330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
50697330f729Sjoerg args, "strongassign");
50707330f729Sjoerg }
50717330f729Sjoerg
EmitGCMemmoveCollectable(CodeGen::CodeGenFunction & CGF,Address DestPtr,Address SrcPtr,llvm::Value * size)50727330f729Sjoerg void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
50737330f729Sjoerg Address DestPtr,
50747330f729Sjoerg Address SrcPtr,
50757330f729Sjoerg llvm::Value *size) {
50767330f729Sjoerg SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
50777330f729Sjoerg DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
50787330f729Sjoerg llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), size };
50797330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
50807330f729Sjoerg }
50817330f729Sjoerg
50827330f729Sjoerg /// EmitObjCValueForIvar - Code Gen for ivar reference.
50837330f729Sjoerg ///
EmitObjCValueForIvar(CodeGen::CodeGenFunction & CGF,QualType ObjectTy,llvm::Value * BaseValue,const ObjCIvarDecl * Ivar,unsigned CVRQualifiers)50847330f729Sjoerg LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
50857330f729Sjoerg QualType ObjectTy,
50867330f729Sjoerg llvm::Value *BaseValue,
50877330f729Sjoerg const ObjCIvarDecl *Ivar,
50887330f729Sjoerg unsigned CVRQualifiers) {
50897330f729Sjoerg const ObjCInterfaceDecl *ID =
50907330f729Sjoerg ObjectTy->castAs<ObjCObjectType>()->getInterface();
50917330f729Sjoerg return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
50927330f729Sjoerg EmitIvarOffset(CGF, ID, Ivar));
50937330f729Sjoerg }
50947330f729Sjoerg
EmitIvarOffset(CodeGen::CodeGenFunction & CGF,const ObjCInterfaceDecl * Interface,const ObjCIvarDecl * Ivar)50957330f729Sjoerg llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
50967330f729Sjoerg const ObjCInterfaceDecl *Interface,
50977330f729Sjoerg const ObjCIvarDecl *Ivar) {
50987330f729Sjoerg uint64_t Offset = ComputeIvarBaseOffset(CGM, Interface, Ivar);
50997330f729Sjoerg return llvm::ConstantInt::get(
51007330f729Sjoerg CGM.getTypes().ConvertType(CGM.getContext().LongTy),
51017330f729Sjoerg Offset);
51027330f729Sjoerg }
51037330f729Sjoerg
51047330f729Sjoerg /* *** Private Interface *** */
51057330f729Sjoerg
GetSectionName(StringRef Section,StringRef MachOAttributes)51067330f729Sjoerg std::string CGObjCCommonMac::GetSectionName(StringRef Section,
51077330f729Sjoerg StringRef MachOAttributes) {
51087330f729Sjoerg switch (CGM.getTriple().getObjectFormat()) {
51097330f729Sjoerg case llvm::Triple::UnknownObjectFormat:
51107330f729Sjoerg llvm_unreachable("unexpected object file format");
51117330f729Sjoerg case llvm::Triple::MachO: {
51127330f729Sjoerg if (MachOAttributes.empty())
51137330f729Sjoerg return ("__DATA," + Section).str();
51147330f729Sjoerg return ("__DATA," + Section + "," + MachOAttributes).str();
51157330f729Sjoerg }
51167330f729Sjoerg case llvm::Triple::ELF:
51177330f729Sjoerg assert(Section.substr(0, 2) == "__" &&
51187330f729Sjoerg "expected the name to begin with __");
51197330f729Sjoerg return Section.substr(2).str();
51207330f729Sjoerg case llvm::Triple::COFF:
51217330f729Sjoerg assert(Section.substr(0, 2) == "__" &&
51227330f729Sjoerg "expected the name to begin with __");
51237330f729Sjoerg return ("." + Section.substr(2) + "$B").str();
51247330f729Sjoerg case llvm::Triple::Wasm:
5125*e038c9c4Sjoerg case llvm::Triple::GOFF:
51267330f729Sjoerg case llvm::Triple::XCOFF:
51277330f729Sjoerg llvm::report_fatal_error(
5128*e038c9c4Sjoerg "Objective-C support is unimplemented for object file format");
51297330f729Sjoerg }
51307330f729Sjoerg
51317330f729Sjoerg llvm_unreachable("Unhandled llvm::Triple::ObjectFormatType enum");
51327330f729Sjoerg }
51337330f729Sjoerg
51347330f729Sjoerg /// EmitImageInfo - Emit the image info marker used to encode some module
51357330f729Sjoerg /// level information.
51367330f729Sjoerg ///
51377330f729Sjoerg /// See: <rdr://4810609&4810587&4810587>
51387330f729Sjoerg /// struct IMAGE_INFO {
51397330f729Sjoerg /// unsigned version;
51407330f729Sjoerg /// unsigned flags;
51417330f729Sjoerg /// };
51427330f729Sjoerg enum ImageInfoFlags {
51437330f729Sjoerg eImageInfo_FixAndContinue = (1 << 0), // This flag is no longer set by clang.
51447330f729Sjoerg eImageInfo_GarbageCollected = (1 << 1),
51457330f729Sjoerg eImageInfo_GCOnly = (1 << 2),
51467330f729Sjoerg eImageInfo_OptimizedByDyld = (1 << 3), // This flag is set by the dyld shared cache.
51477330f729Sjoerg
51487330f729Sjoerg // A flag indicating that the module has no instances of a @synthesize of a
51497330f729Sjoerg // superclass variable. <rdar://problem/6803242>
51507330f729Sjoerg eImageInfo_CorrectedSynthesize = (1 << 4), // This flag is no longer set by clang.
51517330f729Sjoerg eImageInfo_ImageIsSimulated = (1 << 5),
51527330f729Sjoerg eImageInfo_ClassProperties = (1 << 6)
51537330f729Sjoerg };
51547330f729Sjoerg
EmitImageInfo()51557330f729Sjoerg void CGObjCCommonMac::EmitImageInfo() {
51567330f729Sjoerg unsigned version = 0; // Version is unused?
51577330f729Sjoerg std::string Section =
51587330f729Sjoerg (ObjCABI == 1)
51597330f729Sjoerg ? "__OBJC,__image_info,regular"
51607330f729Sjoerg : GetSectionName("__objc_imageinfo", "regular,no_dead_strip");
51617330f729Sjoerg
51627330f729Sjoerg // Generate module-level named metadata to convey this information to the
51637330f729Sjoerg // linker and code-gen.
51647330f729Sjoerg llvm::Module &Mod = CGM.getModule();
51657330f729Sjoerg
51667330f729Sjoerg // Add the ObjC ABI version to the module flags.
51677330f729Sjoerg Mod.addModuleFlag(llvm::Module::Error, "Objective-C Version", ObjCABI);
51687330f729Sjoerg Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
51697330f729Sjoerg version);
51707330f729Sjoerg Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
51717330f729Sjoerg llvm::MDString::get(VMContext, Section));
51727330f729Sjoerg
5173*e038c9c4Sjoerg auto Int8Ty = llvm::Type::getInt8Ty(VMContext);
51747330f729Sjoerg if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
51757330f729Sjoerg // Non-GC overrides those files which specify GC.
5176*e038c9c4Sjoerg Mod.addModuleFlag(llvm::Module::Error,
5177*e038c9c4Sjoerg "Objective-C Garbage Collection",
5178*e038c9c4Sjoerg llvm::ConstantInt::get(Int8Ty,0));
51797330f729Sjoerg } else {
51807330f729Sjoerg // Add the ObjC garbage collection value.
51817330f729Sjoerg Mod.addModuleFlag(llvm::Module::Error,
51827330f729Sjoerg "Objective-C Garbage Collection",
5183*e038c9c4Sjoerg llvm::ConstantInt::get(Int8Ty,
5184*e038c9c4Sjoerg (uint8_t)eImageInfo_GarbageCollected));
51857330f729Sjoerg
51867330f729Sjoerg if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
51877330f729Sjoerg // Add the ObjC GC Only value.
51887330f729Sjoerg Mod.addModuleFlag(llvm::Module::Error, "Objective-C GC Only",
51897330f729Sjoerg eImageInfo_GCOnly);
51907330f729Sjoerg
51917330f729Sjoerg // Require that GC be specified and set to eImageInfo_GarbageCollected.
51927330f729Sjoerg llvm::Metadata *Ops[2] = {
51937330f729Sjoerg llvm::MDString::get(VMContext, "Objective-C Garbage Collection"),
51947330f729Sjoerg llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
5195*e038c9c4Sjoerg Int8Ty, eImageInfo_GarbageCollected))};
51967330f729Sjoerg Mod.addModuleFlag(llvm::Module::Require, "Objective-C GC Only",
51977330f729Sjoerg llvm::MDNode::get(VMContext, Ops));
51987330f729Sjoerg }
51997330f729Sjoerg }
52007330f729Sjoerg
52017330f729Sjoerg // Indicate whether we're compiling this to run on a simulator.
52027330f729Sjoerg if (CGM.getTarget().getTriple().isSimulatorEnvironment())
52037330f729Sjoerg Mod.addModuleFlag(llvm::Module::Error, "Objective-C Is Simulated",
52047330f729Sjoerg eImageInfo_ImageIsSimulated);
52057330f729Sjoerg
52067330f729Sjoerg // Indicate whether we are generating class properties.
52077330f729Sjoerg Mod.addModuleFlag(llvm::Module::Error, "Objective-C Class Properties",
52087330f729Sjoerg eImageInfo_ClassProperties);
52097330f729Sjoerg }
52107330f729Sjoerg
52117330f729Sjoerg // struct objc_module {
52127330f729Sjoerg // unsigned long version;
52137330f729Sjoerg // unsigned long size;
52147330f729Sjoerg // const char *name;
52157330f729Sjoerg // Symtab symtab;
52167330f729Sjoerg // };
52177330f729Sjoerg
52187330f729Sjoerg // FIXME: Get from somewhere
52197330f729Sjoerg static const int ModuleVersion = 7;
52207330f729Sjoerg
EmitModuleInfo()52217330f729Sjoerg void CGObjCMac::EmitModuleInfo() {
52227330f729Sjoerg uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ModuleTy);
52237330f729Sjoerg
52247330f729Sjoerg ConstantInitBuilder builder(CGM);
52257330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ModuleTy);
52267330f729Sjoerg values.addInt(ObjCTypes.LongTy, ModuleVersion);
52277330f729Sjoerg values.addInt(ObjCTypes.LongTy, Size);
52287330f729Sjoerg // This used to be the filename, now it is unused. <rdr://4327263>
52297330f729Sjoerg values.add(GetClassName(StringRef("")));
52307330f729Sjoerg values.add(EmitModuleSymbols());
52317330f729Sjoerg CreateMetadataVar("OBJC_MODULES", values,
52327330f729Sjoerg "__OBJC,__module_info,regular,no_dead_strip",
52337330f729Sjoerg CGM.getPointerAlign(), true);
52347330f729Sjoerg }
52357330f729Sjoerg
EmitModuleSymbols()52367330f729Sjoerg llvm::Constant *CGObjCMac::EmitModuleSymbols() {
52377330f729Sjoerg unsigned NumClasses = DefinedClasses.size();
52387330f729Sjoerg unsigned NumCategories = DefinedCategories.size();
52397330f729Sjoerg
52407330f729Sjoerg // Return null if no symbols were defined.
52417330f729Sjoerg if (!NumClasses && !NumCategories)
52427330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.SymtabPtrTy);
52437330f729Sjoerg
52447330f729Sjoerg ConstantInitBuilder builder(CGM);
52457330f729Sjoerg auto values = builder.beginStruct();
52467330f729Sjoerg values.addInt(ObjCTypes.LongTy, 0);
52477330f729Sjoerg values.addNullPointer(ObjCTypes.SelectorPtrTy);
52487330f729Sjoerg values.addInt(ObjCTypes.ShortTy, NumClasses);
52497330f729Sjoerg values.addInt(ObjCTypes.ShortTy, NumCategories);
52507330f729Sjoerg
52517330f729Sjoerg // The runtime expects exactly the list of defined classes followed
52527330f729Sjoerg // by the list of defined categories, in a single array.
52537330f729Sjoerg auto array = values.beginArray(ObjCTypes.Int8PtrTy);
52547330f729Sjoerg for (unsigned i=0; i<NumClasses; i++) {
52557330f729Sjoerg const ObjCInterfaceDecl *ID = ImplementedClasses[i];
52567330f729Sjoerg assert(ID);
52577330f729Sjoerg if (ObjCImplementationDecl *IMP = ID->getImplementation())
52587330f729Sjoerg // We are implementing a weak imported interface. Give it external linkage
52597330f729Sjoerg if (ID->isWeakImported() && !IMP->isWeakImported())
52607330f729Sjoerg DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
52617330f729Sjoerg
52627330f729Sjoerg array.addBitCast(DefinedClasses[i], ObjCTypes.Int8PtrTy);
52637330f729Sjoerg }
52647330f729Sjoerg for (unsigned i=0; i<NumCategories; i++)
52657330f729Sjoerg array.addBitCast(DefinedCategories[i], ObjCTypes.Int8PtrTy);
52667330f729Sjoerg
52677330f729Sjoerg array.finishAndAddTo(values);
52687330f729Sjoerg
52697330f729Sjoerg llvm::GlobalVariable *GV = CreateMetadataVar(
52707330f729Sjoerg "OBJC_SYMBOLS", values, "__OBJC,__symbols,regular,no_dead_strip",
52717330f729Sjoerg CGM.getPointerAlign(), true);
52727330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
52737330f729Sjoerg }
52747330f729Sjoerg
EmitClassRefFromId(CodeGenFunction & CGF,IdentifierInfo * II)52757330f729Sjoerg llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
52767330f729Sjoerg IdentifierInfo *II) {
52777330f729Sjoerg LazySymbols.insert(II);
52787330f729Sjoerg
52797330f729Sjoerg llvm::GlobalVariable *&Entry = ClassReferences[II];
52807330f729Sjoerg
52817330f729Sjoerg if (!Entry) {
52827330f729Sjoerg llvm::Constant *Casted =
52837330f729Sjoerg llvm::ConstantExpr::getBitCast(GetClassName(II->getName()),
52847330f729Sjoerg ObjCTypes.ClassPtrTy);
52857330f729Sjoerg Entry = CreateMetadataVar(
52867330f729Sjoerg "OBJC_CLASS_REFERENCES_", Casted,
52877330f729Sjoerg "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
52887330f729Sjoerg CGM.getPointerAlign(), true);
52897330f729Sjoerg }
52907330f729Sjoerg
5291*e038c9c4Sjoerg return CGF.Builder.CreateAlignedLoad(Entry->getValueType(), Entry,
5292*e038c9c4Sjoerg CGF.getPointerAlign());
52937330f729Sjoerg }
52947330f729Sjoerg
EmitClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)52957330f729Sjoerg llvm::Value *CGObjCMac::EmitClassRef(CodeGenFunction &CGF,
52967330f729Sjoerg const ObjCInterfaceDecl *ID) {
52977330f729Sjoerg // If the class has the objc_runtime_visible attribute, we need to
52987330f729Sjoerg // use the Objective-C runtime to get the class.
52997330f729Sjoerg if (ID->hasAttr<ObjCRuntimeVisibleAttr>())
53007330f729Sjoerg return EmitClassRefViaRuntime(CGF, ID, ObjCTypes);
53017330f729Sjoerg
53027330f729Sjoerg IdentifierInfo *RuntimeName =
53037330f729Sjoerg &CGM.getContext().Idents.get(ID->getObjCRuntimeNameAsString());
53047330f729Sjoerg return EmitClassRefFromId(CGF, RuntimeName);
53057330f729Sjoerg }
53067330f729Sjoerg
EmitNSAutoreleasePoolClassRef(CodeGenFunction & CGF)53077330f729Sjoerg llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
53087330f729Sjoerg IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
53097330f729Sjoerg return EmitClassRefFromId(CGF, II);
53107330f729Sjoerg }
53117330f729Sjoerg
EmitSelector(CodeGenFunction & CGF,Selector Sel)53127330f729Sjoerg llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) {
5313*e038c9c4Sjoerg return CGF.Builder.CreateLoad(EmitSelectorAddr(Sel));
53147330f729Sjoerg }
53157330f729Sjoerg
EmitSelectorAddr(Selector Sel)5316*e038c9c4Sjoerg Address CGObjCMac::EmitSelectorAddr(Selector Sel) {
5317*e038c9c4Sjoerg CharUnits Align = CGM.getPointerAlign();
53187330f729Sjoerg
53197330f729Sjoerg llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
53207330f729Sjoerg if (!Entry) {
53217330f729Sjoerg llvm::Constant *Casted =
53227330f729Sjoerg llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
53237330f729Sjoerg ObjCTypes.SelectorPtrTy);
53247330f729Sjoerg Entry = CreateMetadataVar(
53257330f729Sjoerg "OBJC_SELECTOR_REFERENCES_", Casted,
53267330f729Sjoerg "__OBJC,__message_refs,literal_pointers,no_dead_strip", Align, true);
53277330f729Sjoerg Entry->setExternallyInitialized(true);
53287330f729Sjoerg }
53297330f729Sjoerg
53307330f729Sjoerg return Address(Entry, Align);
53317330f729Sjoerg }
53327330f729Sjoerg
GetClassName(StringRef RuntimeName)53337330f729Sjoerg llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) {
53347330f729Sjoerg llvm::GlobalVariable *&Entry = ClassNames[RuntimeName];
53357330f729Sjoerg if (!Entry)
53367330f729Sjoerg Entry = CreateCStringLiteral(RuntimeName, ObjCLabelType::ClassName);
53377330f729Sjoerg return getConstantGEP(VMContext, Entry, 0, 0);
53387330f729Sjoerg }
53397330f729Sjoerg
GetMethodDefinition(const ObjCMethodDecl * MD)53407330f729Sjoerg llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) {
53417330f729Sjoerg llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*>::iterator
53427330f729Sjoerg I = MethodDefinitions.find(MD);
53437330f729Sjoerg if (I != MethodDefinitions.end())
53447330f729Sjoerg return I->second;
53457330f729Sjoerg
53467330f729Sjoerg return nullptr;
53477330f729Sjoerg }
53487330f729Sjoerg
53497330f729Sjoerg /// GetIvarLayoutName - Returns a unique constant for the given
53507330f729Sjoerg /// ivar layout bitmap.
GetIvarLayoutName(IdentifierInfo * Ident,const ObjCCommonTypesHelper & ObjCTypes)53517330f729Sjoerg llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident,
53527330f729Sjoerg const ObjCCommonTypesHelper &ObjCTypes) {
53537330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
53547330f729Sjoerg }
53557330f729Sjoerg
visitRecord(const RecordType * RT,CharUnits offset)53567330f729Sjoerg void IvarLayoutBuilder::visitRecord(const RecordType *RT,
53577330f729Sjoerg CharUnits offset) {
53587330f729Sjoerg const RecordDecl *RD = RT->getDecl();
53597330f729Sjoerg
53607330f729Sjoerg // If this is a union, remember that we had one, because it might mess
53617330f729Sjoerg // up the ordering of layout entries.
53627330f729Sjoerg if (RD->isUnion())
53637330f729Sjoerg IsDisordered = true;
53647330f729Sjoerg
53657330f729Sjoerg const ASTRecordLayout *recLayout = nullptr;
53667330f729Sjoerg visitAggregate(RD->field_begin(), RD->field_end(), offset,
53677330f729Sjoerg [&](const FieldDecl *field) -> CharUnits {
53687330f729Sjoerg if (!recLayout)
53697330f729Sjoerg recLayout = &CGM.getContext().getASTRecordLayout(RD);
53707330f729Sjoerg auto offsetInBits = recLayout->getFieldOffset(field->getFieldIndex());
53717330f729Sjoerg return CGM.getContext().toCharUnitsFromBits(offsetInBits);
53727330f729Sjoerg });
53737330f729Sjoerg }
53747330f729Sjoerg
53757330f729Sjoerg template <class Iterator, class GetOffsetFn>
visitAggregate(Iterator begin,Iterator end,CharUnits aggregateOffset,const GetOffsetFn & getOffset)53767330f729Sjoerg void IvarLayoutBuilder::visitAggregate(Iterator begin, Iterator end,
53777330f729Sjoerg CharUnits aggregateOffset,
53787330f729Sjoerg const GetOffsetFn &getOffset) {
53797330f729Sjoerg for (; begin != end; ++begin) {
53807330f729Sjoerg auto field = *begin;
53817330f729Sjoerg
53827330f729Sjoerg // Skip over bitfields.
53837330f729Sjoerg if (field->isBitField()) {
53847330f729Sjoerg continue;
53857330f729Sjoerg }
53867330f729Sjoerg
53877330f729Sjoerg // Compute the offset of the field within the aggregate.
53887330f729Sjoerg CharUnits fieldOffset = aggregateOffset + getOffset(field);
53897330f729Sjoerg
53907330f729Sjoerg visitField(field, fieldOffset);
53917330f729Sjoerg }
53927330f729Sjoerg }
53937330f729Sjoerg
53947330f729Sjoerg /// Collect layout information for the given fields into IvarsInfo.
visitField(const FieldDecl * field,CharUnits fieldOffset)53957330f729Sjoerg void IvarLayoutBuilder::visitField(const FieldDecl *field,
53967330f729Sjoerg CharUnits fieldOffset) {
53977330f729Sjoerg QualType fieldType = field->getType();
53987330f729Sjoerg
53997330f729Sjoerg // Drill down into arrays.
54007330f729Sjoerg uint64_t numElts = 1;
54017330f729Sjoerg if (auto arrayType = CGM.getContext().getAsIncompleteArrayType(fieldType)) {
54027330f729Sjoerg numElts = 0;
54037330f729Sjoerg fieldType = arrayType->getElementType();
54047330f729Sjoerg }
54057330f729Sjoerg // Unlike incomplete arrays, constant arrays can be nested.
54067330f729Sjoerg while (auto arrayType = CGM.getContext().getAsConstantArrayType(fieldType)) {
54077330f729Sjoerg numElts *= arrayType->getSize().getZExtValue();
54087330f729Sjoerg fieldType = arrayType->getElementType();
54097330f729Sjoerg }
54107330f729Sjoerg
54117330f729Sjoerg assert(!fieldType->isArrayType() && "ivar of non-constant array type?");
54127330f729Sjoerg
54137330f729Sjoerg // If we ended up with a zero-sized array, we've done what we can do within
54147330f729Sjoerg // the limits of this layout encoding.
54157330f729Sjoerg if (numElts == 0) return;
54167330f729Sjoerg
54177330f729Sjoerg // Recurse if the base element type is a record type.
54187330f729Sjoerg if (auto recType = fieldType->getAs<RecordType>()) {
54197330f729Sjoerg size_t oldEnd = IvarsInfo.size();
54207330f729Sjoerg
54217330f729Sjoerg visitRecord(recType, fieldOffset);
54227330f729Sjoerg
54237330f729Sjoerg // If we have an array, replicate the first entry's layout information.
54247330f729Sjoerg auto numEltEntries = IvarsInfo.size() - oldEnd;
54257330f729Sjoerg if (numElts != 1 && numEltEntries != 0) {
54267330f729Sjoerg CharUnits eltSize = CGM.getContext().getTypeSizeInChars(recType);
54277330f729Sjoerg for (uint64_t eltIndex = 1; eltIndex != numElts; ++eltIndex) {
54287330f729Sjoerg // Copy the last numEltEntries onto the end of the array, adjusting
54297330f729Sjoerg // each for the element size.
54307330f729Sjoerg for (size_t i = 0; i != numEltEntries; ++i) {
54317330f729Sjoerg auto firstEntry = IvarsInfo[oldEnd + i];
54327330f729Sjoerg IvarsInfo.push_back(IvarInfo(firstEntry.Offset + eltIndex * eltSize,
54337330f729Sjoerg firstEntry.SizeInWords));
54347330f729Sjoerg }
54357330f729Sjoerg }
54367330f729Sjoerg }
54377330f729Sjoerg
54387330f729Sjoerg return;
54397330f729Sjoerg }
54407330f729Sjoerg
54417330f729Sjoerg // Classify the element type.
54427330f729Sjoerg Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), fieldType);
54437330f729Sjoerg
54447330f729Sjoerg // If it matches what we're looking for, add an entry.
54457330f729Sjoerg if ((ForStrongLayout && GCAttr == Qualifiers::Strong)
54467330f729Sjoerg || (!ForStrongLayout && GCAttr == Qualifiers::Weak)) {
54477330f729Sjoerg assert(CGM.getContext().getTypeSizeInChars(fieldType)
54487330f729Sjoerg == CGM.getPointerSize());
54497330f729Sjoerg IvarsInfo.push_back(IvarInfo(fieldOffset, numElts));
54507330f729Sjoerg }
54517330f729Sjoerg }
54527330f729Sjoerg
54537330f729Sjoerg /// buildBitmap - This routine does the horsework of taking the offsets of
54547330f729Sjoerg /// strong/weak references and creating a bitmap. The bitmap is also
54557330f729Sjoerg /// returned in the given buffer, suitable for being passed to \c dump().
buildBitmap(CGObjCCommonMac & CGObjC,llvm::SmallVectorImpl<unsigned char> & buffer)54567330f729Sjoerg llvm::Constant *IvarLayoutBuilder::buildBitmap(CGObjCCommonMac &CGObjC,
54577330f729Sjoerg llvm::SmallVectorImpl<unsigned char> &buffer) {
54587330f729Sjoerg // The bitmap is a series of skip/scan instructions, aligned to word
54597330f729Sjoerg // boundaries. The skip is performed first.
54607330f729Sjoerg const unsigned char MaxNibble = 0xF;
54617330f729Sjoerg const unsigned char SkipMask = 0xF0, SkipShift = 4;
54627330f729Sjoerg const unsigned char ScanMask = 0x0F, ScanShift = 0;
54637330f729Sjoerg
54647330f729Sjoerg assert(!IvarsInfo.empty() && "generating bitmap for no data");
54657330f729Sjoerg
54667330f729Sjoerg // Sort the ivar info on byte position in case we encounterred a
54677330f729Sjoerg // union nested in the ivar list.
54687330f729Sjoerg if (IsDisordered) {
54697330f729Sjoerg // This isn't a stable sort, but our algorithm should handle it fine.
54707330f729Sjoerg llvm::array_pod_sort(IvarsInfo.begin(), IvarsInfo.end());
54717330f729Sjoerg } else {
5472*e038c9c4Sjoerg assert(llvm::is_sorted(IvarsInfo));
54737330f729Sjoerg }
54747330f729Sjoerg assert(IvarsInfo.back().Offset < InstanceEnd);
54757330f729Sjoerg
54767330f729Sjoerg assert(buffer.empty());
54777330f729Sjoerg
54787330f729Sjoerg // Skip the next N words.
54797330f729Sjoerg auto skip = [&](unsigned numWords) {
54807330f729Sjoerg assert(numWords > 0);
54817330f729Sjoerg
54827330f729Sjoerg // Try to merge into the previous byte. Since scans happen second, we
54837330f729Sjoerg // can't do this if it includes a scan.
54847330f729Sjoerg if (!buffer.empty() && !(buffer.back() & ScanMask)) {
54857330f729Sjoerg unsigned lastSkip = buffer.back() >> SkipShift;
54867330f729Sjoerg if (lastSkip < MaxNibble) {
54877330f729Sjoerg unsigned claimed = std::min(MaxNibble - lastSkip, numWords);
54887330f729Sjoerg numWords -= claimed;
54897330f729Sjoerg lastSkip += claimed;
54907330f729Sjoerg buffer.back() = (lastSkip << SkipShift);
54917330f729Sjoerg }
54927330f729Sjoerg }
54937330f729Sjoerg
54947330f729Sjoerg while (numWords >= MaxNibble) {
54957330f729Sjoerg buffer.push_back(MaxNibble << SkipShift);
54967330f729Sjoerg numWords -= MaxNibble;
54977330f729Sjoerg }
54987330f729Sjoerg if (numWords) {
54997330f729Sjoerg buffer.push_back(numWords << SkipShift);
55007330f729Sjoerg }
55017330f729Sjoerg };
55027330f729Sjoerg
55037330f729Sjoerg // Scan the next N words.
55047330f729Sjoerg auto scan = [&](unsigned numWords) {
55057330f729Sjoerg assert(numWords > 0);
55067330f729Sjoerg
55077330f729Sjoerg // Try to merge into the previous byte. Since scans happen second, we can
55087330f729Sjoerg // do this even if it includes a skip.
55097330f729Sjoerg if (!buffer.empty()) {
55107330f729Sjoerg unsigned lastScan = (buffer.back() & ScanMask) >> ScanShift;
55117330f729Sjoerg if (lastScan < MaxNibble) {
55127330f729Sjoerg unsigned claimed = std::min(MaxNibble - lastScan, numWords);
55137330f729Sjoerg numWords -= claimed;
55147330f729Sjoerg lastScan += claimed;
55157330f729Sjoerg buffer.back() = (buffer.back() & SkipMask) | (lastScan << ScanShift);
55167330f729Sjoerg }
55177330f729Sjoerg }
55187330f729Sjoerg
55197330f729Sjoerg while (numWords >= MaxNibble) {
55207330f729Sjoerg buffer.push_back(MaxNibble << ScanShift);
55217330f729Sjoerg numWords -= MaxNibble;
55227330f729Sjoerg }
55237330f729Sjoerg if (numWords) {
55247330f729Sjoerg buffer.push_back(numWords << ScanShift);
55257330f729Sjoerg }
55267330f729Sjoerg };
55277330f729Sjoerg
55287330f729Sjoerg // One past the end of the last scan.
55297330f729Sjoerg unsigned endOfLastScanInWords = 0;
55307330f729Sjoerg const CharUnits WordSize = CGM.getPointerSize();
55317330f729Sjoerg
55327330f729Sjoerg // Consider all the scan requests.
55337330f729Sjoerg for (auto &request : IvarsInfo) {
55347330f729Sjoerg CharUnits beginOfScan = request.Offset - InstanceBegin;
55357330f729Sjoerg
55367330f729Sjoerg // Ignore scan requests that don't start at an even multiple of the
55377330f729Sjoerg // word size. We can't encode them.
55387330f729Sjoerg if ((beginOfScan % WordSize) != 0) continue;
55397330f729Sjoerg
55407330f729Sjoerg // Ignore scan requests that start before the instance start.
55417330f729Sjoerg // This assumes that scans never span that boundary. The boundary
55427330f729Sjoerg // isn't the true start of the ivars, because in the fragile-ARC case
55437330f729Sjoerg // it's rounded up to word alignment, but the test above should leave
55447330f729Sjoerg // us ignoring that possibility.
55457330f729Sjoerg if (beginOfScan.isNegative()) {
55467330f729Sjoerg assert(request.Offset + request.SizeInWords * WordSize <= InstanceBegin);
55477330f729Sjoerg continue;
55487330f729Sjoerg }
55497330f729Sjoerg
55507330f729Sjoerg unsigned beginOfScanInWords = beginOfScan / WordSize;
55517330f729Sjoerg unsigned endOfScanInWords = beginOfScanInWords + request.SizeInWords;
55527330f729Sjoerg
55537330f729Sjoerg // If the scan starts some number of words after the last one ended,
55547330f729Sjoerg // skip forward.
55557330f729Sjoerg if (beginOfScanInWords > endOfLastScanInWords) {
55567330f729Sjoerg skip(beginOfScanInWords - endOfLastScanInWords);
55577330f729Sjoerg
55587330f729Sjoerg // Otherwise, start scanning where the last left off.
55597330f729Sjoerg } else {
55607330f729Sjoerg beginOfScanInWords = endOfLastScanInWords;
55617330f729Sjoerg
55627330f729Sjoerg // If that leaves us with nothing to scan, ignore this request.
55637330f729Sjoerg if (beginOfScanInWords >= endOfScanInWords) continue;
55647330f729Sjoerg }
55657330f729Sjoerg
55667330f729Sjoerg // Scan to the end of the request.
55677330f729Sjoerg assert(beginOfScanInWords < endOfScanInWords);
55687330f729Sjoerg scan(endOfScanInWords - beginOfScanInWords);
55697330f729Sjoerg endOfLastScanInWords = endOfScanInWords;
55707330f729Sjoerg }
55717330f729Sjoerg
55727330f729Sjoerg if (buffer.empty())
55737330f729Sjoerg return llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
55747330f729Sjoerg
55757330f729Sjoerg // For GC layouts, emit a skip to the end of the allocation so that we
55767330f729Sjoerg // have precise information about the entire thing. This isn't useful
55777330f729Sjoerg // or necessary for the ARC-style layout strings.
55787330f729Sjoerg if (CGM.getLangOpts().getGC() != LangOptions::NonGC) {
55797330f729Sjoerg unsigned lastOffsetInWords =
55807330f729Sjoerg (InstanceEnd - InstanceBegin + WordSize - CharUnits::One()) / WordSize;
55817330f729Sjoerg if (lastOffsetInWords > endOfLastScanInWords) {
55827330f729Sjoerg skip(lastOffsetInWords - endOfLastScanInWords);
55837330f729Sjoerg }
55847330f729Sjoerg }
55857330f729Sjoerg
55867330f729Sjoerg // Null terminate the string.
55877330f729Sjoerg buffer.push_back(0);
55887330f729Sjoerg
55897330f729Sjoerg auto *Entry = CGObjC.CreateCStringLiteral(
55907330f729Sjoerg reinterpret_cast<char *>(buffer.data()), ObjCLabelType::ClassName);
55917330f729Sjoerg return getConstantGEP(CGM.getLLVMContext(), Entry, 0, 0);
55927330f729Sjoerg }
55937330f729Sjoerg
55947330f729Sjoerg /// BuildIvarLayout - Builds ivar layout bitmap for the class
55957330f729Sjoerg /// implementation for the __strong or __weak case.
55967330f729Sjoerg /// The layout map displays which words in ivar list must be skipped
55977330f729Sjoerg /// and which must be scanned by GC (see below). String is built of bytes.
55987330f729Sjoerg /// Each byte is divided up in two nibbles (4-bit each). Left nibble is count
55997330f729Sjoerg /// of words to skip and right nibble is count of words to scan. So, each
56007330f729Sjoerg /// nibble represents up to 15 workds to skip or scan. Skipping the rest is
56017330f729Sjoerg /// represented by a 0x00 byte which also ends the string.
56027330f729Sjoerg /// 1. when ForStrongLayout is true, following ivars are scanned:
56037330f729Sjoerg /// - id, Class
56047330f729Sjoerg /// - object *
56057330f729Sjoerg /// - __strong anything
56067330f729Sjoerg ///
56077330f729Sjoerg /// 2. When ForStrongLayout is false, following ivars are scanned:
56087330f729Sjoerg /// - __weak anything
56097330f729Sjoerg ///
56107330f729Sjoerg llvm::Constant *
BuildIvarLayout(const ObjCImplementationDecl * OMD,CharUnits beginOffset,CharUnits endOffset,bool ForStrongLayout,bool HasMRCWeakIvars)56117330f729Sjoerg CGObjCCommonMac::BuildIvarLayout(const ObjCImplementationDecl *OMD,
56127330f729Sjoerg CharUnits beginOffset, CharUnits endOffset,
56137330f729Sjoerg bool ForStrongLayout, bool HasMRCWeakIvars) {
56147330f729Sjoerg // If this is MRC, and we're either building a strong layout or there
56157330f729Sjoerg // are no weak ivars, bail out early.
56167330f729Sjoerg llvm::Type *PtrTy = CGM.Int8PtrTy;
56177330f729Sjoerg if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
56187330f729Sjoerg !CGM.getLangOpts().ObjCAutoRefCount &&
56197330f729Sjoerg (ForStrongLayout || !HasMRCWeakIvars))
56207330f729Sjoerg return llvm::Constant::getNullValue(PtrTy);
56217330f729Sjoerg
56227330f729Sjoerg const ObjCInterfaceDecl *OI = OMD->getClassInterface();
56237330f729Sjoerg SmallVector<const ObjCIvarDecl*, 32> ivars;
56247330f729Sjoerg
56257330f729Sjoerg // GC layout strings include the complete object layout, possibly
56267330f729Sjoerg // inaccurately in the non-fragile ABI; the runtime knows how to fix this
56277330f729Sjoerg // up.
56287330f729Sjoerg //
56297330f729Sjoerg // ARC layout strings only include the class's ivars. In non-fragile
56307330f729Sjoerg // runtimes, that means starting at InstanceStart, rounded up to word
56317330f729Sjoerg // alignment. In fragile runtimes, there's no InstanceStart, so it means
56327330f729Sjoerg // starting at the offset of the first ivar, rounded up to word alignment.
56337330f729Sjoerg //
56347330f729Sjoerg // MRC weak layout strings follow the ARC style.
56357330f729Sjoerg CharUnits baseOffset;
56367330f729Sjoerg if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
56377330f729Sjoerg for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
56387330f729Sjoerg IVD; IVD = IVD->getNextIvar())
56397330f729Sjoerg ivars.push_back(IVD);
56407330f729Sjoerg
56417330f729Sjoerg if (isNonFragileABI()) {
56427330f729Sjoerg baseOffset = beginOffset; // InstanceStart
56437330f729Sjoerg } else if (!ivars.empty()) {
56447330f729Sjoerg baseOffset =
56457330f729Sjoerg CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivars[0]));
56467330f729Sjoerg } else {
56477330f729Sjoerg baseOffset = CharUnits::Zero();
56487330f729Sjoerg }
56497330f729Sjoerg
56507330f729Sjoerg baseOffset = baseOffset.alignTo(CGM.getPointerAlign());
56517330f729Sjoerg }
56527330f729Sjoerg else {
56537330f729Sjoerg CGM.getContext().DeepCollectObjCIvars(OI, true, ivars);
56547330f729Sjoerg
56557330f729Sjoerg baseOffset = CharUnits::Zero();
56567330f729Sjoerg }
56577330f729Sjoerg
56587330f729Sjoerg if (ivars.empty())
56597330f729Sjoerg return llvm::Constant::getNullValue(PtrTy);
56607330f729Sjoerg
56617330f729Sjoerg IvarLayoutBuilder builder(CGM, baseOffset, endOffset, ForStrongLayout);
56627330f729Sjoerg
56637330f729Sjoerg builder.visitAggregate(ivars.begin(), ivars.end(), CharUnits::Zero(),
56647330f729Sjoerg [&](const ObjCIvarDecl *ivar) -> CharUnits {
56657330f729Sjoerg return CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivar));
56667330f729Sjoerg });
56677330f729Sjoerg
56687330f729Sjoerg if (!builder.hasBitmapData())
56697330f729Sjoerg return llvm::Constant::getNullValue(PtrTy);
56707330f729Sjoerg
56717330f729Sjoerg llvm::SmallVector<unsigned char, 4> buffer;
56727330f729Sjoerg llvm::Constant *C = builder.buildBitmap(*this, buffer);
56737330f729Sjoerg
56747330f729Sjoerg if (CGM.getLangOpts().ObjCGCBitmapPrint && !buffer.empty()) {
56757330f729Sjoerg printf("\n%s ivar layout for class '%s': ",
56767330f729Sjoerg ForStrongLayout ? "strong" : "weak",
56777330f729Sjoerg OMD->getClassInterface()->getName().str().c_str());
56787330f729Sjoerg builder.dump(buffer);
56797330f729Sjoerg }
56807330f729Sjoerg return C;
56817330f729Sjoerg }
56827330f729Sjoerg
GetMethodVarName(Selector Sel)56837330f729Sjoerg llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
56847330f729Sjoerg llvm::GlobalVariable *&Entry = MethodVarNames[Sel];
56857330f729Sjoerg // FIXME: Avoid std::string in "Sel.getAsString()"
56867330f729Sjoerg if (!Entry)
56877330f729Sjoerg Entry = CreateCStringLiteral(Sel.getAsString(), ObjCLabelType::MethodVarName);
56887330f729Sjoerg return getConstantGEP(VMContext, Entry, 0, 0);
56897330f729Sjoerg }
56907330f729Sjoerg
56917330f729Sjoerg // FIXME: Merge into a single cstring creation function.
GetMethodVarName(IdentifierInfo * ID)56927330f729Sjoerg llvm::Constant *CGObjCCommonMac::GetMethodVarName(IdentifierInfo *ID) {
56937330f729Sjoerg return GetMethodVarName(CGM.getContext().Selectors.getNullarySelector(ID));
56947330f729Sjoerg }
56957330f729Sjoerg
GetMethodVarType(const FieldDecl * Field)56967330f729Sjoerg llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
56977330f729Sjoerg std::string TypeStr;
56987330f729Sjoerg CGM.getContext().getObjCEncodingForType(Field->getType(), TypeStr, Field);
56997330f729Sjoerg
57007330f729Sjoerg llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
57017330f729Sjoerg if (!Entry)
57027330f729Sjoerg Entry = CreateCStringLiteral(TypeStr, ObjCLabelType::MethodVarType);
57037330f729Sjoerg return getConstantGEP(VMContext, Entry, 0, 0);
57047330f729Sjoerg }
57057330f729Sjoerg
GetMethodVarType(const ObjCMethodDecl * D,bool Extended)57067330f729Sjoerg llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D,
57077330f729Sjoerg bool Extended) {
57087330f729Sjoerg std::string TypeStr =
57097330f729Sjoerg CGM.getContext().getObjCEncodingForMethodDecl(D, Extended);
57107330f729Sjoerg
57117330f729Sjoerg llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
57127330f729Sjoerg if (!Entry)
57137330f729Sjoerg Entry = CreateCStringLiteral(TypeStr, ObjCLabelType::MethodVarType);
57147330f729Sjoerg return getConstantGEP(VMContext, Entry, 0, 0);
57157330f729Sjoerg }
57167330f729Sjoerg
57177330f729Sjoerg // FIXME: Merge into a single cstring creation function.
GetPropertyName(IdentifierInfo * Ident)57187330f729Sjoerg llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
57197330f729Sjoerg llvm::GlobalVariable *&Entry = PropertyNames[Ident];
57207330f729Sjoerg if (!Entry)
57217330f729Sjoerg Entry = CreateCStringLiteral(Ident->getName(), ObjCLabelType::PropertyName);
57227330f729Sjoerg return getConstantGEP(VMContext, Entry, 0, 0);
57237330f729Sjoerg }
57247330f729Sjoerg
57257330f729Sjoerg // FIXME: Merge into a single cstring creation function.
57267330f729Sjoerg // FIXME: This Decl should be more precise.
57277330f729Sjoerg llvm::Constant *
GetPropertyTypeString(const ObjCPropertyDecl * PD,const Decl * Container)57287330f729Sjoerg CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
57297330f729Sjoerg const Decl *Container) {
57307330f729Sjoerg std::string TypeStr =
57317330f729Sjoerg CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container);
57327330f729Sjoerg return GetPropertyName(&CGM.getContext().Idents.get(TypeStr));
57337330f729Sjoerg }
57347330f729Sjoerg
FinishModule()57357330f729Sjoerg void CGObjCMac::FinishModule() {
57367330f729Sjoerg EmitModuleInfo();
57377330f729Sjoerg
57387330f729Sjoerg // Emit the dummy bodies for any protocols which were referenced but
57397330f729Sjoerg // never defined.
57407330f729Sjoerg for (auto &entry : Protocols) {
57417330f729Sjoerg llvm::GlobalVariable *global = entry.second;
57427330f729Sjoerg if (global->hasInitializer())
57437330f729Sjoerg continue;
57447330f729Sjoerg
57457330f729Sjoerg ConstantInitBuilder builder(CGM);
57467330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ProtocolTy);
57477330f729Sjoerg values.addNullPointer(ObjCTypes.ProtocolExtensionPtrTy);
57487330f729Sjoerg values.add(GetClassName(entry.first->getName()));
57497330f729Sjoerg values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
57507330f729Sjoerg values.addNullPointer(ObjCTypes.MethodDescriptionListPtrTy);
57517330f729Sjoerg values.addNullPointer(ObjCTypes.MethodDescriptionListPtrTy);
57527330f729Sjoerg values.finishAndSetAsInitializer(global);
57537330f729Sjoerg CGM.addCompilerUsedGlobal(global);
57547330f729Sjoerg }
57557330f729Sjoerg
57567330f729Sjoerg // Add assembler directives to add lazy undefined symbol references
57577330f729Sjoerg // for classes which are referenced but not defined. This is
57587330f729Sjoerg // important for correct linker interaction.
57597330f729Sjoerg //
57607330f729Sjoerg // FIXME: It would be nice if we had an LLVM construct for this.
57617330f729Sjoerg if ((!LazySymbols.empty() || !DefinedSymbols.empty()) &&
57627330f729Sjoerg CGM.getTriple().isOSBinFormatMachO()) {
57637330f729Sjoerg SmallString<256> Asm;
57647330f729Sjoerg Asm += CGM.getModule().getModuleInlineAsm();
57657330f729Sjoerg if (!Asm.empty() && Asm.back() != '\n')
57667330f729Sjoerg Asm += '\n';
57677330f729Sjoerg
57687330f729Sjoerg llvm::raw_svector_ostream OS(Asm);
57697330f729Sjoerg for (const auto *Sym : DefinedSymbols)
57707330f729Sjoerg OS << "\t.objc_class_name_" << Sym->getName() << "=0\n"
57717330f729Sjoerg << "\t.globl .objc_class_name_" << Sym->getName() << "\n";
57727330f729Sjoerg for (const auto *Sym : LazySymbols)
57737330f729Sjoerg OS << "\t.lazy_reference .objc_class_name_" << Sym->getName() << "\n";
57747330f729Sjoerg for (const auto &Category : DefinedCategoryNames)
57757330f729Sjoerg OS << "\t.objc_category_name_" << Category << "=0\n"
57767330f729Sjoerg << "\t.globl .objc_category_name_" << Category << "\n";
57777330f729Sjoerg
57787330f729Sjoerg CGM.getModule().setModuleInlineAsm(OS.str());
57797330f729Sjoerg }
57807330f729Sjoerg }
57817330f729Sjoerg
CGObjCNonFragileABIMac(CodeGen::CodeGenModule & cgm)57827330f729Sjoerg CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
57837330f729Sjoerg : CGObjCCommonMac(cgm), ObjCTypes(cgm), ObjCEmptyCacheVar(nullptr),
57847330f729Sjoerg ObjCEmptyVtableVar(nullptr) {
57857330f729Sjoerg ObjCABI = 2;
57867330f729Sjoerg }
57877330f729Sjoerg
57887330f729Sjoerg /* *** */
57897330f729Sjoerg
ObjCCommonTypesHelper(CodeGen::CodeGenModule & cgm)57907330f729Sjoerg ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
57917330f729Sjoerg : VMContext(cgm.getLLVMContext()), CGM(cgm), ExternalProtocolPtrTy(nullptr)
57927330f729Sjoerg {
57937330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
57947330f729Sjoerg ASTContext &Ctx = CGM.getContext();
57957330f729Sjoerg
57967330f729Sjoerg ShortTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.ShortTy));
57977330f729Sjoerg IntTy = CGM.IntTy;
57987330f729Sjoerg LongTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.LongTy));
57997330f729Sjoerg Int8PtrTy = CGM.Int8PtrTy;
58007330f729Sjoerg Int8PtrPtrTy = CGM.Int8PtrPtrTy;
58017330f729Sjoerg
58027330f729Sjoerg // arm64 targets use "int" ivar offset variables. All others,
58037330f729Sjoerg // including OS X x86_64 and Windows x86_64, use "long" ivar offsets.
58047330f729Sjoerg if (CGM.getTarget().getTriple().getArch() == llvm::Triple::aarch64)
58057330f729Sjoerg IvarOffsetVarTy = IntTy;
58067330f729Sjoerg else
58077330f729Sjoerg IvarOffsetVarTy = LongTy;
58087330f729Sjoerg
58097330f729Sjoerg ObjectPtrTy =
58107330f729Sjoerg cast<llvm::PointerType>(Types.ConvertType(Ctx.getObjCIdType()));
58117330f729Sjoerg PtrObjectPtrTy =
58127330f729Sjoerg llvm::PointerType::getUnqual(ObjectPtrTy);
58137330f729Sjoerg SelectorPtrTy =
58147330f729Sjoerg cast<llvm::PointerType>(Types.ConvertType(Ctx.getObjCSelType()));
58157330f729Sjoerg
58167330f729Sjoerg // I'm not sure I like this. The implicit coordination is a bit
58177330f729Sjoerg // gross. We should solve this in a reasonable fashion because this
58187330f729Sjoerg // is a pretty common task (match some runtime data structure with
58197330f729Sjoerg // an LLVM data structure).
58207330f729Sjoerg
58217330f729Sjoerg // FIXME: This is leaked.
58227330f729Sjoerg // FIXME: Merge with rewriter code?
58237330f729Sjoerg
58247330f729Sjoerg // struct _objc_super {
58257330f729Sjoerg // id self;
58267330f729Sjoerg // Class cls;
58277330f729Sjoerg // }
58287330f729Sjoerg RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
58297330f729Sjoerg Ctx.getTranslationUnitDecl(),
58307330f729Sjoerg SourceLocation(), SourceLocation(),
58317330f729Sjoerg &Ctx.Idents.get("_objc_super"));
58327330f729Sjoerg RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
58337330f729Sjoerg nullptr, Ctx.getObjCIdType(), nullptr, nullptr,
58347330f729Sjoerg false, ICIS_NoInit));
58357330f729Sjoerg RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
58367330f729Sjoerg nullptr, Ctx.getObjCClassType(), nullptr,
58377330f729Sjoerg nullptr, false, ICIS_NoInit));
58387330f729Sjoerg RD->completeDefinition();
58397330f729Sjoerg
58407330f729Sjoerg SuperCTy = Ctx.getTagDeclType(RD);
58417330f729Sjoerg SuperPtrCTy = Ctx.getPointerType(SuperCTy);
58427330f729Sjoerg
58437330f729Sjoerg SuperTy = cast<llvm::StructType>(Types.ConvertType(SuperCTy));
58447330f729Sjoerg SuperPtrTy = llvm::PointerType::getUnqual(SuperTy);
58457330f729Sjoerg
58467330f729Sjoerg // struct _prop_t {
58477330f729Sjoerg // char *name;
58487330f729Sjoerg // char *attributes;
58497330f729Sjoerg // }
58507330f729Sjoerg PropertyTy = llvm::StructType::create("struct._prop_t", Int8PtrTy, Int8PtrTy);
58517330f729Sjoerg
58527330f729Sjoerg // struct _prop_list_t {
58537330f729Sjoerg // uint32_t entsize; // sizeof(struct _prop_t)
58547330f729Sjoerg // uint32_t count_of_properties;
58557330f729Sjoerg // struct _prop_t prop_list[count_of_properties];
58567330f729Sjoerg // }
58577330f729Sjoerg PropertyListTy = llvm::StructType::create(
58587330f729Sjoerg "struct._prop_list_t", IntTy, IntTy, llvm::ArrayType::get(PropertyTy, 0));
58597330f729Sjoerg // struct _prop_list_t *
58607330f729Sjoerg PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
58617330f729Sjoerg
58627330f729Sjoerg // struct _objc_method {
58637330f729Sjoerg // SEL _cmd;
58647330f729Sjoerg // char *method_type;
58657330f729Sjoerg // char *_imp;
58667330f729Sjoerg // }
58677330f729Sjoerg MethodTy = llvm::StructType::create("struct._objc_method", SelectorPtrTy,
58687330f729Sjoerg Int8PtrTy, Int8PtrTy);
58697330f729Sjoerg
58707330f729Sjoerg // struct _objc_cache *
58717330f729Sjoerg CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
58727330f729Sjoerg CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
58737330f729Sjoerg }
58747330f729Sjoerg
ObjCTypesHelper(CodeGen::CodeGenModule & cgm)58757330f729Sjoerg ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
58767330f729Sjoerg : ObjCCommonTypesHelper(cgm) {
58777330f729Sjoerg // struct _objc_method_description {
58787330f729Sjoerg // SEL name;
58797330f729Sjoerg // char *types;
58807330f729Sjoerg // }
58817330f729Sjoerg MethodDescriptionTy = llvm::StructType::create(
58827330f729Sjoerg "struct._objc_method_description", SelectorPtrTy, Int8PtrTy);
58837330f729Sjoerg
58847330f729Sjoerg // struct _objc_method_description_list {
58857330f729Sjoerg // int count;
58867330f729Sjoerg // struct _objc_method_description[1];
58877330f729Sjoerg // }
58887330f729Sjoerg MethodDescriptionListTy =
58897330f729Sjoerg llvm::StructType::create("struct._objc_method_description_list", IntTy,
58907330f729Sjoerg llvm::ArrayType::get(MethodDescriptionTy, 0));
58917330f729Sjoerg
58927330f729Sjoerg // struct _objc_method_description_list *
58937330f729Sjoerg MethodDescriptionListPtrTy =
58947330f729Sjoerg llvm::PointerType::getUnqual(MethodDescriptionListTy);
58957330f729Sjoerg
58967330f729Sjoerg // Protocol description structures
58977330f729Sjoerg
58987330f729Sjoerg // struct _objc_protocol_extension {
58997330f729Sjoerg // uint32_t size; // sizeof(struct _objc_protocol_extension)
59007330f729Sjoerg // struct _objc_method_description_list *optional_instance_methods;
59017330f729Sjoerg // struct _objc_method_description_list *optional_class_methods;
59027330f729Sjoerg // struct _objc_property_list *instance_properties;
59037330f729Sjoerg // const char ** extendedMethodTypes;
59047330f729Sjoerg // struct _objc_property_list *class_properties;
59057330f729Sjoerg // }
59067330f729Sjoerg ProtocolExtensionTy = llvm::StructType::create(
59077330f729Sjoerg "struct._objc_protocol_extension", IntTy, MethodDescriptionListPtrTy,
59087330f729Sjoerg MethodDescriptionListPtrTy, PropertyListPtrTy, Int8PtrPtrTy,
59097330f729Sjoerg PropertyListPtrTy);
59107330f729Sjoerg
59117330f729Sjoerg // struct _objc_protocol_extension *
59127330f729Sjoerg ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
59137330f729Sjoerg
59147330f729Sjoerg // Handle recursive construction of Protocol and ProtocolList types
59157330f729Sjoerg
59167330f729Sjoerg ProtocolTy =
59177330f729Sjoerg llvm::StructType::create(VMContext, "struct._objc_protocol");
59187330f729Sjoerg
59197330f729Sjoerg ProtocolListTy =
59207330f729Sjoerg llvm::StructType::create(VMContext, "struct._objc_protocol_list");
59217330f729Sjoerg ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy), LongTy,
59227330f729Sjoerg llvm::ArrayType::get(ProtocolTy, 0));
59237330f729Sjoerg
59247330f729Sjoerg // struct _objc_protocol {
59257330f729Sjoerg // struct _objc_protocol_extension *isa;
59267330f729Sjoerg // char *protocol_name;
59277330f729Sjoerg // struct _objc_protocol **_objc_protocol_list;
59287330f729Sjoerg // struct _objc_method_description_list *instance_methods;
59297330f729Sjoerg // struct _objc_method_description_list *class_methods;
59307330f729Sjoerg // }
59317330f729Sjoerg ProtocolTy->setBody(ProtocolExtensionPtrTy, Int8PtrTy,
59327330f729Sjoerg llvm::PointerType::getUnqual(ProtocolListTy),
59337330f729Sjoerg MethodDescriptionListPtrTy, MethodDescriptionListPtrTy);
59347330f729Sjoerg
59357330f729Sjoerg // struct _objc_protocol_list *
59367330f729Sjoerg ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
59377330f729Sjoerg
59387330f729Sjoerg ProtocolPtrTy = llvm::PointerType::getUnqual(ProtocolTy);
59397330f729Sjoerg
59407330f729Sjoerg // Class description structures
59417330f729Sjoerg
59427330f729Sjoerg // struct _objc_ivar {
59437330f729Sjoerg // char *ivar_name;
59447330f729Sjoerg // char *ivar_type;
59457330f729Sjoerg // int ivar_offset;
59467330f729Sjoerg // }
59477330f729Sjoerg IvarTy = llvm::StructType::create("struct._objc_ivar", Int8PtrTy, Int8PtrTy,
59487330f729Sjoerg IntTy);
59497330f729Sjoerg
59507330f729Sjoerg // struct _objc_ivar_list *
59517330f729Sjoerg IvarListTy =
59527330f729Sjoerg llvm::StructType::create(VMContext, "struct._objc_ivar_list");
59537330f729Sjoerg IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
59547330f729Sjoerg
59557330f729Sjoerg // struct _objc_method_list *
59567330f729Sjoerg MethodListTy =
59577330f729Sjoerg llvm::StructType::create(VMContext, "struct._objc_method_list");
59587330f729Sjoerg MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
59597330f729Sjoerg
59607330f729Sjoerg // struct _objc_class_extension *
59617330f729Sjoerg ClassExtensionTy = llvm::StructType::create(
59627330f729Sjoerg "struct._objc_class_extension", IntTy, Int8PtrTy, PropertyListPtrTy);
59637330f729Sjoerg ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
59647330f729Sjoerg
59657330f729Sjoerg ClassTy = llvm::StructType::create(VMContext, "struct._objc_class");
59667330f729Sjoerg
59677330f729Sjoerg // struct _objc_class {
59687330f729Sjoerg // Class isa;
59697330f729Sjoerg // Class super_class;
59707330f729Sjoerg // char *name;
59717330f729Sjoerg // long version;
59727330f729Sjoerg // long info;
59737330f729Sjoerg // long instance_size;
59747330f729Sjoerg // struct _objc_ivar_list *ivars;
59757330f729Sjoerg // struct _objc_method_list *methods;
59767330f729Sjoerg // struct _objc_cache *cache;
59777330f729Sjoerg // struct _objc_protocol_list *protocols;
59787330f729Sjoerg // char *ivar_layout;
59797330f729Sjoerg // struct _objc_class_ext *ext;
59807330f729Sjoerg // };
59817330f729Sjoerg ClassTy->setBody(llvm::PointerType::getUnqual(ClassTy),
59827330f729Sjoerg llvm::PointerType::getUnqual(ClassTy), Int8PtrTy, LongTy,
59837330f729Sjoerg LongTy, LongTy, IvarListPtrTy, MethodListPtrTy, CachePtrTy,
59847330f729Sjoerg ProtocolListPtrTy, Int8PtrTy, ClassExtensionPtrTy);
59857330f729Sjoerg
59867330f729Sjoerg ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
59877330f729Sjoerg
59887330f729Sjoerg // struct _objc_category {
59897330f729Sjoerg // char *category_name;
59907330f729Sjoerg // char *class_name;
59917330f729Sjoerg // struct _objc_method_list *instance_method;
59927330f729Sjoerg // struct _objc_method_list *class_method;
59937330f729Sjoerg // struct _objc_protocol_list *protocols;
59947330f729Sjoerg // uint32_t size; // sizeof(struct _objc_category)
59957330f729Sjoerg // struct _objc_property_list *instance_properties;// category's @property
59967330f729Sjoerg // struct _objc_property_list *class_properties;
59977330f729Sjoerg // }
59987330f729Sjoerg CategoryTy = llvm::StructType::create(
59997330f729Sjoerg "struct._objc_category", Int8PtrTy, Int8PtrTy, MethodListPtrTy,
60007330f729Sjoerg MethodListPtrTy, ProtocolListPtrTy, IntTy, PropertyListPtrTy,
60017330f729Sjoerg PropertyListPtrTy);
60027330f729Sjoerg
60037330f729Sjoerg // Global metadata structures
60047330f729Sjoerg
60057330f729Sjoerg // struct _objc_symtab {
60067330f729Sjoerg // long sel_ref_cnt;
60077330f729Sjoerg // SEL *refs;
60087330f729Sjoerg // short cls_def_cnt;
60097330f729Sjoerg // short cat_def_cnt;
60107330f729Sjoerg // char *defs[cls_def_cnt + cat_def_cnt];
60117330f729Sjoerg // }
60127330f729Sjoerg SymtabTy = llvm::StructType::create("struct._objc_symtab", LongTy,
60137330f729Sjoerg SelectorPtrTy, ShortTy, ShortTy,
60147330f729Sjoerg llvm::ArrayType::get(Int8PtrTy, 0));
60157330f729Sjoerg SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
60167330f729Sjoerg
60177330f729Sjoerg // struct _objc_module {
60187330f729Sjoerg // long version;
60197330f729Sjoerg // long size; // sizeof(struct _objc_module)
60207330f729Sjoerg // char *name;
60217330f729Sjoerg // struct _objc_symtab* symtab;
60227330f729Sjoerg // }
60237330f729Sjoerg ModuleTy = llvm::StructType::create("struct._objc_module", LongTy, LongTy,
60247330f729Sjoerg Int8PtrTy, SymtabPtrTy);
60257330f729Sjoerg
60267330f729Sjoerg // FIXME: This is the size of the setjmp buffer and should be target
60277330f729Sjoerg // specific. 18 is what's used on 32-bit X86.
60287330f729Sjoerg uint64_t SetJmpBufferSize = 18;
60297330f729Sjoerg
60307330f729Sjoerg // Exceptions
60317330f729Sjoerg llvm::Type *StackPtrTy = llvm::ArrayType::get(CGM.Int8PtrTy, 4);
60327330f729Sjoerg
60337330f729Sjoerg ExceptionDataTy = llvm::StructType::create(
60347330f729Sjoerg "struct._objc_exception_data",
60357330f729Sjoerg llvm::ArrayType::get(CGM.Int32Ty, SetJmpBufferSize), StackPtrTy);
60367330f729Sjoerg }
60377330f729Sjoerg
ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule & cgm)60387330f729Sjoerg ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm)
60397330f729Sjoerg : ObjCCommonTypesHelper(cgm) {
60407330f729Sjoerg // struct _method_list_t {
60417330f729Sjoerg // uint32_t entsize; // sizeof(struct _objc_method)
60427330f729Sjoerg // uint32_t method_count;
60437330f729Sjoerg // struct _objc_method method_list[method_count];
60447330f729Sjoerg // }
60457330f729Sjoerg MethodListnfABITy =
60467330f729Sjoerg llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
60477330f729Sjoerg llvm::ArrayType::get(MethodTy, 0));
60487330f729Sjoerg // struct method_list_t *
60497330f729Sjoerg MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
60507330f729Sjoerg
60517330f729Sjoerg // struct _protocol_t {
60527330f729Sjoerg // id isa; // NULL
60537330f729Sjoerg // const char * const protocol_name;
60547330f729Sjoerg // const struct _protocol_list_t * protocol_list; // super protocols
60557330f729Sjoerg // const struct method_list_t * const instance_methods;
60567330f729Sjoerg // const struct method_list_t * const class_methods;
60577330f729Sjoerg // const struct method_list_t *optionalInstanceMethods;
60587330f729Sjoerg // const struct method_list_t *optionalClassMethods;
60597330f729Sjoerg // const struct _prop_list_t * properties;
60607330f729Sjoerg // const uint32_t size; // sizeof(struct _protocol_t)
60617330f729Sjoerg // const uint32_t flags; // = 0
60627330f729Sjoerg // const char ** extendedMethodTypes;
60637330f729Sjoerg // const char *demangledName;
60647330f729Sjoerg // const struct _prop_list_t * class_properties;
60657330f729Sjoerg // }
60667330f729Sjoerg
60677330f729Sjoerg // Holder for struct _protocol_list_t *
60687330f729Sjoerg ProtocolListnfABITy =
60697330f729Sjoerg llvm::StructType::create(VMContext, "struct._objc_protocol_list");
60707330f729Sjoerg
60717330f729Sjoerg ProtocolnfABITy = llvm::StructType::create(
60727330f729Sjoerg "struct._protocol_t", ObjectPtrTy, Int8PtrTy,
60737330f729Sjoerg llvm::PointerType::getUnqual(ProtocolListnfABITy), MethodListnfABIPtrTy,
60747330f729Sjoerg MethodListnfABIPtrTy, MethodListnfABIPtrTy, MethodListnfABIPtrTy,
60757330f729Sjoerg PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy, Int8PtrTy,
60767330f729Sjoerg PropertyListPtrTy);
60777330f729Sjoerg
60787330f729Sjoerg // struct _protocol_t*
60797330f729Sjoerg ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
60807330f729Sjoerg
60817330f729Sjoerg // struct _protocol_list_t {
60827330f729Sjoerg // long protocol_count; // Note, this is 32/64 bit
60837330f729Sjoerg // struct _protocol_t *[protocol_count];
60847330f729Sjoerg // }
60857330f729Sjoerg ProtocolListnfABITy->setBody(LongTy,
60867330f729Sjoerg llvm::ArrayType::get(ProtocolnfABIPtrTy, 0));
60877330f729Sjoerg
60887330f729Sjoerg // struct _objc_protocol_list*
60897330f729Sjoerg ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
60907330f729Sjoerg
60917330f729Sjoerg // struct _ivar_t {
60927330f729Sjoerg // unsigned [long] int *offset; // pointer to ivar offset location
60937330f729Sjoerg // char *name;
60947330f729Sjoerg // char *type;
60957330f729Sjoerg // uint32_t alignment;
60967330f729Sjoerg // uint32_t size;
60977330f729Sjoerg // }
60987330f729Sjoerg IvarnfABITy = llvm::StructType::create(
60997330f729Sjoerg "struct._ivar_t", llvm::PointerType::getUnqual(IvarOffsetVarTy),
61007330f729Sjoerg Int8PtrTy, Int8PtrTy, IntTy, IntTy);
61017330f729Sjoerg
61027330f729Sjoerg // struct _ivar_list_t {
61037330f729Sjoerg // uint32 entsize; // sizeof(struct _ivar_t)
61047330f729Sjoerg // uint32 count;
61057330f729Sjoerg // struct _iver_t list[count];
61067330f729Sjoerg // }
61077330f729Sjoerg IvarListnfABITy =
61087330f729Sjoerg llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
61097330f729Sjoerg llvm::ArrayType::get(IvarnfABITy, 0));
61107330f729Sjoerg
61117330f729Sjoerg IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
61127330f729Sjoerg
61137330f729Sjoerg // struct _class_ro_t {
61147330f729Sjoerg // uint32_t const flags;
61157330f729Sjoerg // uint32_t const instanceStart;
61167330f729Sjoerg // uint32_t const instanceSize;
61177330f729Sjoerg // uint32_t const reserved; // only when building for 64bit targets
61187330f729Sjoerg // const uint8_t * const ivarLayout;
61197330f729Sjoerg // const char *const name;
61207330f729Sjoerg // const struct _method_list_t * const baseMethods;
61217330f729Sjoerg // const struct _objc_protocol_list *const baseProtocols;
61227330f729Sjoerg // const struct _ivar_list_t *const ivars;
61237330f729Sjoerg // const uint8_t * const weakIvarLayout;
61247330f729Sjoerg // const struct _prop_list_t * const properties;
61257330f729Sjoerg // }
61267330f729Sjoerg
61277330f729Sjoerg // FIXME. Add 'reserved' field in 64bit abi mode!
61287330f729Sjoerg ClassRonfABITy = llvm::StructType::create(
61297330f729Sjoerg "struct._class_ro_t", IntTy, IntTy, IntTy, Int8PtrTy, Int8PtrTy,
61307330f729Sjoerg MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, IvarListnfABIPtrTy,
61317330f729Sjoerg Int8PtrTy, PropertyListPtrTy);
61327330f729Sjoerg
61337330f729Sjoerg // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
61347330f729Sjoerg llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
61357330f729Sjoerg ImpnfABITy = llvm::FunctionType::get(ObjectPtrTy, params, false)
61367330f729Sjoerg ->getPointerTo();
61377330f729Sjoerg
61387330f729Sjoerg // struct _class_t {
61397330f729Sjoerg // struct _class_t *isa;
61407330f729Sjoerg // struct _class_t * const superclass;
61417330f729Sjoerg // void *cache;
61427330f729Sjoerg // IMP *vtable;
61437330f729Sjoerg // struct class_ro_t *ro;
61447330f729Sjoerg // }
61457330f729Sjoerg
61467330f729Sjoerg ClassnfABITy = llvm::StructType::create(VMContext, "struct._class_t");
61477330f729Sjoerg ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy),
61487330f729Sjoerg llvm::PointerType::getUnqual(ClassnfABITy), CachePtrTy,
61497330f729Sjoerg llvm::PointerType::getUnqual(ImpnfABITy),
61507330f729Sjoerg llvm::PointerType::getUnqual(ClassRonfABITy));
61517330f729Sjoerg
61527330f729Sjoerg // LLVM for struct _class_t *
61537330f729Sjoerg ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
61547330f729Sjoerg
61557330f729Sjoerg // struct _category_t {
61567330f729Sjoerg // const char * const name;
61577330f729Sjoerg // struct _class_t *const cls;
61587330f729Sjoerg // const struct _method_list_t * const instance_methods;
61597330f729Sjoerg // const struct _method_list_t * const class_methods;
61607330f729Sjoerg // const struct _protocol_list_t * const protocols;
61617330f729Sjoerg // const struct _prop_list_t * const properties;
61627330f729Sjoerg // const struct _prop_list_t * const class_properties;
61637330f729Sjoerg // const uint32_t size;
61647330f729Sjoerg // }
61657330f729Sjoerg CategorynfABITy = llvm::StructType::create(
61667330f729Sjoerg "struct._category_t", Int8PtrTy, ClassnfABIPtrTy, MethodListnfABIPtrTy,
61677330f729Sjoerg MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, PropertyListPtrTy,
61687330f729Sjoerg PropertyListPtrTy, IntTy);
61697330f729Sjoerg
61707330f729Sjoerg // New types for nonfragile abi messaging.
61717330f729Sjoerg CodeGen::CodeGenTypes &Types = CGM.getTypes();
61727330f729Sjoerg ASTContext &Ctx = CGM.getContext();
61737330f729Sjoerg
61747330f729Sjoerg // MessageRefTy - LLVM for:
61757330f729Sjoerg // struct _message_ref_t {
61767330f729Sjoerg // IMP messenger;
61777330f729Sjoerg // SEL name;
61787330f729Sjoerg // };
61797330f729Sjoerg
61807330f729Sjoerg // First the clang type for struct _message_ref_t
61817330f729Sjoerg RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
61827330f729Sjoerg Ctx.getTranslationUnitDecl(),
61837330f729Sjoerg SourceLocation(), SourceLocation(),
61847330f729Sjoerg &Ctx.Idents.get("_message_ref_t"));
61857330f729Sjoerg RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
61867330f729Sjoerg nullptr, Ctx.VoidPtrTy, nullptr, nullptr, false,
61877330f729Sjoerg ICIS_NoInit));
61887330f729Sjoerg RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
61897330f729Sjoerg nullptr, Ctx.getObjCSelType(), nullptr, nullptr,
61907330f729Sjoerg false, ICIS_NoInit));
61917330f729Sjoerg RD->completeDefinition();
61927330f729Sjoerg
61937330f729Sjoerg MessageRefCTy = Ctx.getTagDeclType(RD);
61947330f729Sjoerg MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy);
61957330f729Sjoerg MessageRefTy = cast<llvm::StructType>(Types.ConvertType(MessageRefCTy));
61967330f729Sjoerg
61977330f729Sjoerg // MessageRefPtrTy - LLVM for struct _message_ref_t*
61987330f729Sjoerg MessageRefPtrTy = llvm::PointerType::getUnqual(MessageRefTy);
61997330f729Sjoerg
62007330f729Sjoerg // SuperMessageRefTy - LLVM for:
62017330f729Sjoerg // struct _super_message_ref_t {
62027330f729Sjoerg // SUPER_IMP messenger;
62037330f729Sjoerg // SEL name;
62047330f729Sjoerg // };
62057330f729Sjoerg SuperMessageRefTy = llvm::StructType::create("struct._super_message_ref_t",
62067330f729Sjoerg ImpnfABITy, SelectorPtrTy);
62077330f729Sjoerg
62087330f729Sjoerg // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
62097330f729Sjoerg SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
62107330f729Sjoerg
62117330f729Sjoerg
62127330f729Sjoerg // struct objc_typeinfo {
62137330f729Sjoerg // const void** vtable; // objc_ehtype_vtable + 2
62147330f729Sjoerg // const char* name; // c++ typeinfo string
62157330f729Sjoerg // Class cls;
62167330f729Sjoerg // };
62177330f729Sjoerg EHTypeTy = llvm::StructType::create("struct._objc_typeinfo",
62187330f729Sjoerg llvm::PointerType::getUnqual(Int8PtrTy),
62197330f729Sjoerg Int8PtrTy, ClassnfABIPtrTy);
62207330f729Sjoerg EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
62217330f729Sjoerg }
62227330f729Sjoerg
ModuleInitFunction()62237330f729Sjoerg llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
62247330f729Sjoerg FinishNonFragileABIModule();
62257330f729Sjoerg
62267330f729Sjoerg return nullptr;
62277330f729Sjoerg }
62287330f729Sjoerg
AddModuleClassList(ArrayRef<llvm::GlobalValue * > Container,StringRef SymbolName,StringRef SectionName)62297330f729Sjoerg void CGObjCNonFragileABIMac::AddModuleClassList(
62307330f729Sjoerg ArrayRef<llvm::GlobalValue *> Container, StringRef SymbolName,
62317330f729Sjoerg StringRef SectionName) {
62327330f729Sjoerg unsigned NumClasses = Container.size();
62337330f729Sjoerg
62347330f729Sjoerg if (!NumClasses)
62357330f729Sjoerg return;
62367330f729Sjoerg
62377330f729Sjoerg SmallVector<llvm::Constant*, 8> Symbols(NumClasses);
62387330f729Sjoerg for (unsigned i=0; i<NumClasses; i++)
62397330f729Sjoerg Symbols[i] = llvm::ConstantExpr::getBitCast(Container[i],
62407330f729Sjoerg ObjCTypes.Int8PtrTy);
62417330f729Sjoerg llvm::Constant *Init =
62427330f729Sjoerg llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
62437330f729Sjoerg Symbols.size()),
62447330f729Sjoerg Symbols);
62457330f729Sjoerg
62467330f729Sjoerg // Section name is obtained by calling GetSectionName, which returns
62477330f729Sjoerg // sections in the __DATA segment on MachO.
62487330f729Sjoerg assert((!CGM.getTriple().isOSBinFormatMachO() ||
62497330f729Sjoerg SectionName.startswith("__DATA")) &&
62507330f729Sjoerg "SectionName expected to start with __DATA on MachO");
6251*e038c9c4Sjoerg llvm::GlobalVariable *GV = new llvm::GlobalVariable(
6252*e038c9c4Sjoerg CGM.getModule(), Init->getType(), false,
6253*e038c9c4Sjoerg llvm::GlobalValue::PrivateLinkage, Init, SymbolName);
62547330f729Sjoerg GV->setAlignment(
62557330f729Sjoerg llvm::Align(CGM.getDataLayout().getABITypeAlignment(Init->getType())));
62567330f729Sjoerg GV->setSection(SectionName);
62577330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
62587330f729Sjoerg }
62597330f729Sjoerg
FinishNonFragileABIModule()62607330f729Sjoerg void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
62617330f729Sjoerg // nonfragile abi has no module definition.
62627330f729Sjoerg
62637330f729Sjoerg // Build list of all implemented class addresses in array
62647330f729Sjoerg // L_OBJC_LABEL_CLASS_$.
62657330f729Sjoerg
62667330f729Sjoerg for (unsigned i=0, NumClasses=ImplementedClasses.size(); i<NumClasses; i++) {
62677330f729Sjoerg const ObjCInterfaceDecl *ID = ImplementedClasses[i];
62687330f729Sjoerg assert(ID);
62697330f729Sjoerg if (ObjCImplementationDecl *IMP = ID->getImplementation())
62707330f729Sjoerg // We are implementing a weak imported interface. Give it external linkage
62717330f729Sjoerg if (ID->isWeakImported() && !IMP->isWeakImported()) {
62727330f729Sjoerg DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
62737330f729Sjoerg DefinedMetaClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
62747330f729Sjoerg }
62757330f729Sjoerg }
62767330f729Sjoerg
62777330f729Sjoerg AddModuleClassList(DefinedClasses, "OBJC_LABEL_CLASS_$",
62787330f729Sjoerg GetSectionName("__objc_classlist",
62797330f729Sjoerg "regular,no_dead_strip"));
62807330f729Sjoerg
62817330f729Sjoerg AddModuleClassList(DefinedNonLazyClasses, "OBJC_LABEL_NONLAZY_CLASS_$",
62827330f729Sjoerg GetSectionName("__objc_nlclslist",
62837330f729Sjoerg "regular,no_dead_strip"));
62847330f729Sjoerg
62857330f729Sjoerg // Build list of all implemented category addresses in array
62867330f729Sjoerg // L_OBJC_LABEL_CATEGORY_$.
62877330f729Sjoerg AddModuleClassList(DefinedCategories, "OBJC_LABEL_CATEGORY_$",
62887330f729Sjoerg GetSectionName("__objc_catlist",
62897330f729Sjoerg "regular,no_dead_strip"));
62907330f729Sjoerg AddModuleClassList(DefinedStubCategories, "OBJC_LABEL_STUB_CATEGORY_$",
62917330f729Sjoerg GetSectionName("__objc_catlist2",
62927330f729Sjoerg "regular,no_dead_strip"));
62937330f729Sjoerg AddModuleClassList(DefinedNonLazyCategories, "OBJC_LABEL_NONLAZY_CATEGORY_$",
62947330f729Sjoerg GetSectionName("__objc_nlcatlist",
62957330f729Sjoerg "regular,no_dead_strip"));
62967330f729Sjoerg
62977330f729Sjoerg EmitImageInfo();
62987330f729Sjoerg }
62997330f729Sjoerg
63007330f729Sjoerg /// isVTableDispatchedSelector - Returns true if SEL is not in the list of
63017330f729Sjoerg /// VTableDispatchMethods; false otherwise. What this means is that
63027330f729Sjoerg /// except for the 19 selectors in the list, we generate 32bit-style
63037330f729Sjoerg /// message dispatch call for all the rest.
isVTableDispatchedSelector(Selector Sel)63047330f729Sjoerg bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
63057330f729Sjoerg // At various points we've experimented with using vtable-based
63067330f729Sjoerg // dispatch for all methods.
63077330f729Sjoerg switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
63087330f729Sjoerg case CodeGenOptions::Legacy:
63097330f729Sjoerg return false;
63107330f729Sjoerg case CodeGenOptions::NonLegacy:
63117330f729Sjoerg return true;
63127330f729Sjoerg case CodeGenOptions::Mixed:
63137330f729Sjoerg break;
63147330f729Sjoerg }
63157330f729Sjoerg
63167330f729Sjoerg // If so, see whether this selector is in the white-list of things which must
63177330f729Sjoerg // use the new dispatch convention. We lazily build a dense set for this.
63187330f729Sjoerg if (VTableDispatchMethods.empty()) {
63197330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("alloc"));
63207330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("class"));
63217330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("self"));
63227330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("isFlipped"));
63237330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("length"));
63247330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("count"));
63257330f729Sjoerg
63267330f729Sjoerg // These are vtable-based if GC is disabled.
63277330f729Sjoerg // Optimistically use vtable dispatch for hybrid compiles.
63287330f729Sjoerg if (CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
63297330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("retain"));
63307330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("release"));
63317330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
63327330f729Sjoerg }
63337330f729Sjoerg
63347330f729Sjoerg VTableDispatchMethods.insert(GetUnarySelector("allocWithZone"));
63357330f729Sjoerg VTableDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
63367330f729Sjoerg VTableDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
63377330f729Sjoerg VTableDispatchMethods.insert(GetUnarySelector("objectForKey"));
63387330f729Sjoerg VTableDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
63397330f729Sjoerg VTableDispatchMethods.insert(GetUnarySelector("isEqualToString"));
63407330f729Sjoerg VTableDispatchMethods.insert(GetUnarySelector("isEqual"));
63417330f729Sjoerg
63427330f729Sjoerg // These are vtable-based if GC is enabled.
63437330f729Sjoerg // Optimistically use vtable dispatch for hybrid compiles.
63447330f729Sjoerg if (CGM.getLangOpts().getGC() != LangOptions::NonGC) {
63457330f729Sjoerg VTableDispatchMethods.insert(GetNullarySelector("hash"));
63467330f729Sjoerg VTableDispatchMethods.insert(GetUnarySelector("addObject"));
63477330f729Sjoerg
63487330f729Sjoerg // "countByEnumeratingWithState:objects:count"
63497330f729Sjoerg IdentifierInfo *KeyIdents[] = {
63507330f729Sjoerg &CGM.getContext().Idents.get("countByEnumeratingWithState"),
63517330f729Sjoerg &CGM.getContext().Idents.get("objects"),
63527330f729Sjoerg &CGM.getContext().Idents.get("count")
63537330f729Sjoerg };
63547330f729Sjoerg VTableDispatchMethods.insert(
63557330f729Sjoerg CGM.getContext().Selectors.getSelector(3, KeyIdents));
63567330f729Sjoerg }
63577330f729Sjoerg }
63587330f729Sjoerg
63597330f729Sjoerg return VTableDispatchMethods.count(Sel);
63607330f729Sjoerg }
63617330f729Sjoerg
63627330f729Sjoerg /// BuildClassRoTInitializer - generate meta-data for:
63637330f729Sjoerg /// struct _class_ro_t {
63647330f729Sjoerg /// uint32_t const flags;
63657330f729Sjoerg /// uint32_t const instanceStart;
63667330f729Sjoerg /// uint32_t const instanceSize;
63677330f729Sjoerg /// uint32_t const reserved; // only when building for 64bit targets
63687330f729Sjoerg /// const uint8_t * const ivarLayout;
63697330f729Sjoerg /// const char *const name;
63707330f729Sjoerg /// const struct _method_list_t * const baseMethods;
63717330f729Sjoerg /// const struct _protocol_list_t *const baseProtocols;
63727330f729Sjoerg /// const struct _ivar_list_t *const ivars;
63737330f729Sjoerg /// const uint8_t * const weakIvarLayout;
63747330f729Sjoerg /// const struct _prop_list_t * const properties;
63757330f729Sjoerg /// }
63767330f729Sjoerg ///
BuildClassRoTInitializer(unsigned flags,unsigned InstanceStart,unsigned InstanceSize,const ObjCImplementationDecl * ID)63777330f729Sjoerg llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
63787330f729Sjoerg unsigned flags,
63797330f729Sjoerg unsigned InstanceStart,
63807330f729Sjoerg unsigned InstanceSize,
63817330f729Sjoerg const ObjCImplementationDecl *ID) {
6382*e038c9c4Sjoerg std::string ClassName = std::string(ID->getObjCRuntimeNameAsString());
63837330f729Sjoerg
63847330f729Sjoerg CharUnits beginInstance = CharUnits::fromQuantity(InstanceStart);
63857330f729Sjoerg CharUnits endInstance = CharUnits::fromQuantity(InstanceSize);
63867330f729Sjoerg
63877330f729Sjoerg bool hasMRCWeak = false;
63887330f729Sjoerg if (CGM.getLangOpts().ObjCAutoRefCount)
63897330f729Sjoerg flags |= NonFragileABI_Class_CompiledByARC;
63907330f729Sjoerg else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID)))
63917330f729Sjoerg flags |= NonFragileABI_Class_HasMRCWeakIvars;
63927330f729Sjoerg
63937330f729Sjoerg ConstantInitBuilder builder(CGM);
63947330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ClassRonfABITy);
63957330f729Sjoerg
63967330f729Sjoerg values.addInt(ObjCTypes.IntTy, flags);
63977330f729Sjoerg values.addInt(ObjCTypes.IntTy, InstanceStart);
63987330f729Sjoerg values.addInt(ObjCTypes.IntTy, InstanceSize);
63997330f729Sjoerg values.add((flags & NonFragileABI_Class_Meta)
64007330f729Sjoerg ? GetIvarLayoutName(nullptr, ObjCTypes)
64017330f729Sjoerg : BuildStrongIvarLayout(ID, beginInstance, endInstance));
64027330f729Sjoerg values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
64037330f729Sjoerg
64047330f729Sjoerg // const struct _method_list_t * const baseMethods;
64057330f729Sjoerg SmallVector<const ObjCMethodDecl*, 16> methods;
64067330f729Sjoerg if (flags & NonFragileABI_Class_Meta) {
64077330f729Sjoerg for (const auto *MD : ID->class_methods())
6408*e038c9c4Sjoerg if (!MD->isDirectMethod())
64097330f729Sjoerg methods.push_back(MD);
64107330f729Sjoerg } else {
64117330f729Sjoerg for (const auto *MD : ID->instance_methods())
6412*e038c9c4Sjoerg if (!MD->isDirectMethod())
64137330f729Sjoerg methods.push_back(MD);
64147330f729Sjoerg }
64157330f729Sjoerg
64167330f729Sjoerg values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
64177330f729Sjoerg (flags & NonFragileABI_Class_Meta)
64187330f729Sjoerg ? MethodListType::ClassMethods
64197330f729Sjoerg : MethodListType::InstanceMethods,
64207330f729Sjoerg methods));
64217330f729Sjoerg
64227330f729Sjoerg const ObjCInterfaceDecl *OID = ID->getClassInterface();
64237330f729Sjoerg assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
64247330f729Sjoerg values.add(EmitProtocolList("_OBJC_CLASS_PROTOCOLS_$_"
64257330f729Sjoerg + OID->getObjCRuntimeNameAsString(),
64267330f729Sjoerg OID->all_referenced_protocol_begin(),
64277330f729Sjoerg OID->all_referenced_protocol_end()));
64287330f729Sjoerg
64297330f729Sjoerg if (flags & NonFragileABI_Class_Meta) {
64307330f729Sjoerg values.addNullPointer(ObjCTypes.IvarListnfABIPtrTy);
64317330f729Sjoerg values.add(GetIvarLayoutName(nullptr, ObjCTypes));
64327330f729Sjoerg values.add(EmitPropertyList(
64337330f729Sjoerg "_OBJC_$_CLASS_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
64347330f729Sjoerg ID, ID->getClassInterface(), ObjCTypes, true));
64357330f729Sjoerg } else {
64367330f729Sjoerg values.add(EmitIvarList(ID));
64377330f729Sjoerg values.add(BuildWeakIvarLayout(ID, beginInstance, endInstance, hasMRCWeak));
64387330f729Sjoerg values.add(EmitPropertyList(
64397330f729Sjoerg "_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
64407330f729Sjoerg ID, ID->getClassInterface(), ObjCTypes, false));
64417330f729Sjoerg }
64427330f729Sjoerg
64437330f729Sjoerg llvm::SmallString<64> roLabel;
64447330f729Sjoerg llvm::raw_svector_ostream(roLabel)
64457330f729Sjoerg << ((flags & NonFragileABI_Class_Meta) ? "_OBJC_METACLASS_RO_$_"
64467330f729Sjoerg : "_OBJC_CLASS_RO_$_")
64477330f729Sjoerg << ClassName;
64487330f729Sjoerg
64497330f729Sjoerg return finishAndCreateGlobal(values, roLabel, CGM);
64507330f729Sjoerg }
64517330f729Sjoerg
64527330f729Sjoerg /// Build the metaclass object for a class.
64537330f729Sjoerg ///
64547330f729Sjoerg /// struct _class_t {
64557330f729Sjoerg /// struct _class_t *isa;
64567330f729Sjoerg /// struct _class_t * const superclass;
64577330f729Sjoerg /// void *cache;
64587330f729Sjoerg /// IMP *vtable;
64597330f729Sjoerg /// struct class_ro_t *ro;
64607330f729Sjoerg /// }
64617330f729Sjoerg ///
64627330f729Sjoerg llvm::GlobalVariable *
BuildClassObject(const ObjCInterfaceDecl * CI,bool isMetaclass,llvm::Constant * IsAGV,llvm::Constant * SuperClassGV,llvm::Constant * ClassRoGV,bool HiddenVisibility)64637330f729Sjoerg CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI,
64647330f729Sjoerg bool isMetaclass,
64657330f729Sjoerg llvm::Constant *IsAGV,
64667330f729Sjoerg llvm::Constant *SuperClassGV,
64677330f729Sjoerg llvm::Constant *ClassRoGV,
64687330f729Sjoerg bool HiddenVisibility) {
64697330f729Sjoerg ConstantInitBuilder builder(CGM);
64707330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ClassnfABITy);
64717330f729Sjoerg values.add(IsAGV);
64727330f729Sjoerg if (SuperClassGV) {
64737330f729Sjoerg values.add(SuperClassGV);
64747330f729Sjoerg } else {
64757330f729Sjoerg values.addNullPointer(ObjCTypes.ClassnfABIPtrTy);
64767330f729Sjoerg }
64777330f729Sjoerg values.add(ObjCEmptyCacheVar);
64787330f729Sjoerg values.add(ObjCEmptyVtableVar);
64797330f729Sjoerg values.add(ClassRoGV);
64807330f729Sjoerg
64817330f729Sjoerg llvm::GlobalVariable *GV =
64827330f729Sjoerg cast<llvm::GlobalVariable>(GetClassGlobal(CI, isMetaclass, ForDefinition));
64837330f729Sjoerg values.finishAndSetAsInitializer(GV);
64847330f729Sjoerg
64857330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO())
64867330f729Sjoerg GV->setSection("__DATA, __objc_data");
64877330f729Sjoerg GV->setAlignment(llvm::Align(
64887330f729Sjoerg CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy)));
64897330f729Sjoerg if (!CGM.getTriple().isOSBinFormatCOFF())
64907330f729Sjoerg if (HiddenVisibility)
64917330f729Sjoerg GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
64927330f729Sjoerg return GV;
64937330f729Sjoerg }
64947330f729Sjoerg
ImplementationIsNonLazy(const ObjCImplDecl * OD) const64957330f729Sjoerg bool CGObjCNonFragileABIMac::ImplementationIsNonLazy(
64967330f729Sjoerg const ObjCImplDecl *OD) const {
64977330f729Sjoerg return OD->getClassMethod(GetNullarySelector("load")) != nullptr ||
64987330f729Sjoerg OD->getClassInterface()->hasAttr<ObjCNonLazyClassAttr>() ||
64997330f729Sjoerg OD->hasAttr<ObjCNonLazyClassAttr>();
65007330f729Sjoerg }
65017330f729Sjoerg
GetClassSizeInfo(const ObjCImplementationDecl * OID,uint32_t & InstanceStart,uint32_t & InstanceSize)65027330f729Sjoerg void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
65037330f729Sjoerg uint32_t &InstanceStart,
65047330f729Sjoerg uint32_t &InstanceSize) {
65057330f729Sjoerg const ASTRecordLayout &RL =
65067330f729Sjoerg CGM.getContext().getASTObjCImplementationLayout(OID);
65077330f729Sjoerg
65087330f729Sjoerg // InstanceSize is really instance end.
65097330f729Sjoerg InstanceSize = RL.getDataSize().getQuantity();
65107330f729Sjoerg
65117330f729Sjoerg // If there are no fields, the start is the same as the end.
65127330f729Sjoerg if (!RL.getFieldCount())
65137330f729Sjoerg InstanceStart = InstanceSize;
65147330f729Sjoerg else
65157330f729Sjoerg InstanceStart = RL.getFieldOffset(0) / CGM.getContext().getCharWidth();
65167330f729Sjoerg }
65177330f729Sjoerg
getStorage(CodeGenModule & CGM,StringRef Name)65187330f729Sjoerg static llvm::GlobalValue::DLLStorageClassTypes getStorage(CodeGenModule &CGM,
65197330f729Sjoerg StringRef Name) {
65207330f729Sjoerg IdentifierInfo &II = CGM.getContext().Idents.get(Name);
65217330f729Sjoerg TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl();
65227330f729Sjoerg DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
65237330f729Sjoerg
65247330f729Sjoerg const VarDecl *VD = nullptr;
6525*e038c9c4Sjoerg for (const auto *Result : DC->lookup(&II))
65267330f729Sjoerg if ((VD = dyn_cast<VarDecl>(Result)))
65277330f729Sjoerg break;
65287330f729Sjoerg
65297330f729Sjoerg if (!VD)
65307330f729Sjoerg return llvm::GlobalValue::DLLImportStorageClass;
65317330f729Sjoerg if (VD->hasAttr<DLLExportAttr>())
65327330f729Sjoerg return llvm::GlobalValue::DLLExportStorageClass;
65337330f729Sjoerg if (VD->hasAttr<DLLImportAttr>())
65347330f729Sjoerg return llvm::GlobalValue::DLLImportStorageClass;
65357330f729Sjoerg return llvm::GlobalValue::DefaultStorageClass;
65367330f729Sjoerg }
65377330f729Sjoerg
GenerateClass(const ObjCImplementationDecl * ID)65387330f729Sjoerg void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
65397330f729Sjoerg if (!ObjCEmptyCacheVar) {
65407330f729Sjoerg ObjCEmptyCacheVar =
65417330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.CacheTy, false,
65427330f729Sjoerg llvm::GlobalValue::ExternalLinkage, nullptr,
65437330f729Sjoerg "_objc_empty_cache");
65447330f729Sjoerg if (CGM.getTriple().isOSBinFormatCOFF())
65457330f729Sjoerg ObjCEmptyCacheVar->setDLLStorageClass(getStorage(CGM, "_objc_empty_cache"));
65467330f729Sjoerg
65477330f729Sjoerg // Only OS X with deployment version <10.9 use the empty vtable symbol
65487330f729Sjoerg const llvm::Triple &Triple = CGM.getTarget().getTriple();
65497330f729Sjoerg if (Triple.isMacOSX() && Triple.isMacOSXVersionLT(10, 9))
65507330f729Sjoerg ObjCEmptyVtableVar =
65517330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ImpnfABITy, false,
65527330f729Sjoerg llvm::GlobalValue::ExternalLinkage, nullptr,
65537330f729Sjoerg "_objc_empty_vtable");
65547330f729Sjoerg else
65557330f729Sjoerg ObjCEmptyVtableVar =
65567330f729Sjoerg llvm::ConstantPointerNull::get(ObjCTypes.ImpnfABITy->getPointerTo());
65577330f729Sjoerg }
65587330f729Sjoerg
65597330f729Sjoerg // FIXME: Is this correct (that meta class size is never computed)?
65607330f729Sjoerg uint32_t InstanceStart =
65617330f729Sjoerg CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassnfABITy);
65627330f729Sjoerg uint32_t InstanceSize = InstanceStart;
65637330f729Sjoerg uint32_t flags = NonFragileABI_Class_Meta;
65647330f729Sjoerg
65657330f729Sjoerg llvm::Constant *SuperClassGV, *IsAGV;
65667330f729Sjoerg
65677330f729Sjoerg const auto *CI = ID->getClassInterface();
65687330f729Sjoerg assert(CI && "CGObjCNonFragileABIMac::GenerateClass - class is 0");
65697330f729Sjoerg
65707330f729Sjoerg // Build the flags for the metaclass.
65717330f729Sjoerg bool classIsHidden = (CGM.getTriple().isOSBinFormatCOFF())
65727330f729Sjoerg ? !CI->hasAttr<DLLExportAttr>()
65737330f729Sjoerg : CI->getVisibility() == HiddenVisibility;
65747330f729Sjoerg if (classIsHidden)
65757330f729Sjoerg flags |= NonFragileABI_Class_Hidden;
65767330f729Sjoerg
65777330f729Sjoerg // FIXME: why is this flag set on the metaclass?
65787330f729Sjoerg // ObjC metaclasses have no fields and don't really get constructed.
65797330f729Sjoerg if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
65807330f729Sjoerg flags |= NonFragileABI_Class_HasCXXStructors;
65817330f729Sjoerg if (!ID->hasNonZeroConstructors())
65827330f729Sjoerg flags |= NonFragileABI_Class_HasCXXDestructorOnly;
65837330f729Sjoerg }
65847330f729Sjoerg
65857330f729Sjoerg if (!CI->getSuperClass()) {
65867330f729Sjoerg // class is root
65877330f729Sjoerg flags |= NonFragileABI_Class_Root;
65887330f729Sjoerg
65897330f729Sjoerg SuperClassGV = GetClassGlobal(CI, /*metaclass*/ false, NotForDefinition);
65907330f729Sjoerg IsAGV = GetClassGlobal(CI, /*metaclass*/ true, NotForDefinition);
65917330f729Sjoerg } else {
65927330f729Sjoerg // Has a root. Current class is not a root.
65937330f729Sjoerg const ObjCInterfaceDecl *Root = ID->getClassInterface();
65947330f729Sjoerg while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
65957330f729Sjoerg Root = Super;
65967330f729Sjoerg
65977330f729Sjoerg const auto *Super = CI->getSuperClass();
65987330f729Sjoerg IsAGV = GetClassGlobal(Root, /*metaclass*/ true, NotForDefinition);
65997330f729Sjoerg SuperClassGV = GetClassGlobal(Super, /*metaclass*/ true, NotForDefinition);
66007330f729Sjoerg }
66017330f729Sjoerg
66027330f729Sjoerg llvm::GlobalVariable *CLASS_RO_GV =
66037330f729Sjoerg BuildClassRoTInitializer(flags, InstanceStart, InstanceSize, ID);
66047330f729Sjoerg
66057330f729Sjoerg llvm::GlobalVariable *MetaTClass =
66067330f729Sjoerg BuildClassObject(CI, /*metaclass*/ true,
66077330f729Sjoerg IsAGV, SuperClassGV, CLASS_RO_GV, classIsHidden);
66087330f729Sjoerg CGM.setGVProperties(MetaTClass, CI);
66097330f729Sjoerg DefinedMetaClasses.push_back(MetaTClass);
66107330f729Sjoerg
66117330f729Sjoerg // Metadata for the class
66127330f729Sjoerg flags = 0;
66137330f729Sjoerg if (classIsHidden)
66147330f729Sjoerg flags |= NonFragileABI_Class_Hidden;
66157330f729Sjoerg
66167330f729Sjoerg if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
66177330f729Sjoerg flags |= NonFragileABI_Class_HasCXXStructors;
66187330f729Sjoerg
66197330f729Sjoerg // Set a flag to enable a runtime optimization when a class has
66207330f729Sjoerg // fields that require destruction but which don't require
66217330f729Sjoerg // anything except zero-initialization during construction. This
66227330f729Sjoerg // is most notably true of __strong and __weak types, but you can
66237330f729Sjoerg // also imagine there being C++ types with non-trivial default
66247330f729Sjoerg // constructors that merely set all fields to null.
66257330f729Sjoerg if (!ID->hasNonZeroConstructors())
66267330f729Sjoerg flags |= NonFragileABI_Class_HasCXXDestructorOnly;
66277330f729Sjoerg }
66287330f729Sjoerg
66297330f729Sjoerg if (hasObjCExceptionAttribute(CGM.getContext(), CI))
66307330f729Sjoerg flags |= NonFragileABI_Class_Exception;
66317330f729Sjoerg
66327330f729Sjoerg if (!CI->getSuperClass()) {
66337330f729Sjoerg flags |= NonFragileABI_Class_Root;
66347330f729Sjoerg SuperClassGV = nullptr;
66357330f729Sjoerg } else {
66367330f729Sjoerg // Has a root. Current class is not a root.
66377330f729Sjoerg const auto *Super = CI->getSuperClass();
66387330f729Sjoerg SuperClassGV = GetClassGlobal(Super, /*metaclass*/ false, NotForDefinition);
66397330f729Sjoerg }
66407330f729Sjoerg
66417330f729Sjoerg GetClassSizeInfo(ID, InstanceStart, InstanceSize);
66427330f729Sjoerg CLASS_RO_GV =
66437330f729Sjoerg BuildClassRoTInitializer(flags, InstanceStart, InstanceSize, ID);
66447330f729Sjoerg
66457330f729Sjoerg llvm::GlobalVariable *ClassMD =
66467330f729Sjoerg BuildClassObject(CI, /*metaclass*/ false,
66477330f729Sjoerg MetaTClass, SuperClassGV, CLASS_RO_GV, classIsHidden);
66487330f729Sjoerg CGM.setGVProperties(ClassMD, CI);
66497330f729Sjoerg DefinedClasses.push_back(ClassMD);
66507330f729Sjoerg ImplementedClasses.push_back(CI);
66517330f729Sjoerg
66527330f729Sjoerg // Determine if this class is also "non-lazy".
66537330f729Sjoerg if (ImplementationIsNonLazy(ID))
66547330f729Sjoerg DefinedNonLazyClasses.push_back(ClassMD);
66557330f729Sjoerg
66567330f729Sjoerg // Force the definition of the EHType if necessary.
66577330f729Sjoerg if (flags & NonFragileABI_Class_Exception)
66587330f729Sjoerg (void) GetInterfaceEHType(CI, ForDefinition);
66597330f729Sjoerg // Make sure method definition entries are all clear for next implementation.
66607330f729Sjoerg MethodDefinitions.clear();
66617330f729Sjoerg }
66627330f729Sjoerg
66637330f729Sjoerg /// GenerateProtocolRef - This routine is called to generate code for
66647330f729Sjoerg /// a protocol reference expression; as in:
66657330f729Sjoerg /// @code
66667330f729Sjoerg /// @protocol(Proto1);
66677330f729Sjoerg /// @endcode
66687330f729Sjoerg /// It generates a weak reference to l_OBJC_PROTOCOL_REFERENCE_$_Proto1
66697330f729Sjoerg /// which will hold address of the protocol meta-data.
66707330f729Sjoerg ///
GenerateProtocolRef(CodeGenFunction & CGF,const ObjCProtocolDecl * PD)66717330f729Sjoerg llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
66727330f729Sjoerg const ObjCProtocolDecl *PD) {
66737330f729Sjoerg
66747330f729Sjoerg // This routine is called for @protocol only. So, we must build definition
66757330f729Sjoerg // of protocol's meta-data (not a reference to it!)
6676*e038c9c4Sjoerg assert(!PD->isNonRuntimeProtocol() &&
6677*e038c9c4Sjoerg "attempting to get a protocol ref to a static protocol.");
66787330f729Sjoerg llvm::Constant *Init =
66797330f729Sjoerg llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD),
66807330f729Sjoerg ObjCTypes.getExternalProtocolPtrTy());
66817330f729Sjoerg
66827330f729Sjoerg std::string ProtocolName("_OBJC_PROTOCOL_REFERENCE_$_");
66837330f729Sjoerg ProtocolName += PD->getObjCRuntimeNameAsString();
66847330f729Sjoerg
66857330f729Sjoerg CharUnits Align = CGF.getPointerAlign();
66867330f729Sjoerg
66877330f729Sjoerg llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
66887330f729Sjoerg if (PTGV)
6689*e038c9c4Sjoerg return CGF.Builder.CreateAlignedLoad(PTGV->getValueType(), PTGV, Align);
66907330f729Sjoerg PTGV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
66917330f729Sjoerg llvm::GlobalValue::WeakAnyLinkage, Init,
66927330f729Sjoerg ProtocolName);
66937330f729Sjoerg PTGV->setSection(GetSectionName("__objc_protorefs",
66947330f729Sjoerg "coalesced,no_dead_strip"));
66957330f729Sjoerg PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
66967330f729Sjoerg PTGV->setAlignment(Align.getAsAlign());
66977330f729Sjoerg if (!CGM.getTriple().isOSBinFormatMachO())
66987330f729Sjoerg PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolName));
66997330f729Sjoerg CGM.addUsedGlobal(PTGV);
6700*e038c9c4Sjoerg return CGF.Builder.CreateAlignedLoad(PTGV->getValueType(), PTGV, Align);
67017330f729Sjoerg }
67027330f729Sjoerg
67037330f729Sjoerg /// GenerateCategory - Build metadata for a category implementation.
67047330f729Sjoerg /// struct _category_t {
67057330f729Sjoerg /// const char * const name;
67067330f729Sjoerg /// struct _class_t *const cls;
67077330f729Sjoerg /// const struct _method_list_t * const instance_methods;
67087330f729Sjoerg /// const struct _method_list_t * const class_methods;
67097330f729Sjoerg /// const struct _protocol_list_t * const protocols;
67107330f729Sjoerg /// const struct _prop_list_t * const properties;
67117330f729Sjoerg /// const struct _prop_list_t * const class_properties;
67127330f729Sjoerg /// const uint32_t size;
67137330f729Sjoerg /// }
67147330f729Sjoerg ///
GenerateCategory(const ObjCCategoryImplDecl * OCD)67157330f729Sjoerg void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
67167330f729Sjoerg const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
67177330f729Sjoerg const char *Prefix = "_OBJC_$_CATEGORY_";
67187330f729Sjoerg
67197330f729Sjoerg llvm::SmallString<64> ExtCatName(Prefix);
67207330f729Sjoerg ExtCatName += Interface->getObjCRuntimeNameAsString();
67217330f729Sjoerg ExtCatName += "_$_";
67227330f729Sjoerg ExtCatName += OCD->getNameAsString();
67237330f729Sjoerg
67247330f729Sjoerg ConstantInitBuilder builder(CGM);
67257330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.CategorynfABITy);
67267330f729Sjoerg values.add(GetClassName(OCD->getIdentifier()->getName()));
67277330f729Sjoerg // meta-class entry symbol
67287330f729Sjoerg values.add(GetClassGlobal(Interface, /*metaclass*/ false, NotForDefinition));
67297330f729Sjoerg std::string listName =
67307330f729Sjoerg (Interface->getObjCRuntimeNameAsString() + "_$_" + OCD->getName()).str();
67317330f729Sjoerg
67327330f729Sjoerg SmallVector<const ObjCMethodDecl *, 16> instanceMethods;
67337330f729Sjoerg SmallVector<const ObjCMethodDecl *, 8> classMethods;
67347330f729Sjoerg for (const auto *MD : OCD->methods()) {
6735*e038c9c4Sjoerg if (MD->isDirectMethod())
6736*e038c9c4Sjoerg continue;
67377330f729Sjoerg if (MD->isInstanceMethod()) {
67387330f729Sjoerg instanceMethods.push_back(MD);
67397330f729Sjoerg } else {
67407330f729Sjoerg classMethods.push_back(MD);
67417330f729Sjoerg }
67427330f729Sjoerg }
67437330f729Sjoerg
67447330f729Sjoerg values.add(emitMethodList(listName, MethodListType::CategoryInstanceMethods,
67457330f729Sjoerg instanceMethods));
67467330f729Sjoerg values.add(emitMethodList(listName, MethodListType::CategoryClassMethods,
67477330f729Sjoerg classMethods));
67487330f729Sjoerg
67497330f729Sjoerg const ObjCCategoryDecl *Category =
67507330f729Sjoerg Interface->FindCategoryDeclaration(OCD->getIdentifier());
67517330f729Sjoerg if (Category) {
67527330f729Sjoerg SmallString<256> ExtName;
67537330f729Sjoerg llvm::raw_svector_ostream(ExtName) << Interface->getObjCRuntimeNameAsString() << "_$_"
67547330f729Sjoerg << OCD->getName();
67557330f729Sjoerg values.add(EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_"
67567330f729Sjoerg + Interface->getObjCRuntimeNameAsString() + "_$_"
67577330f729Sjoerg + Category->getName(),
67587330f729Sjoerg Category->protocol_begin(),
67597330f729Sjoerg Category->protocol_end()));
67607330f729Sjoerg values.add(EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(),
67617330f729Sjoerg OCD, Category, ObjCTypes, false));
67627330f729Sjoerg values.add(EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(),
67637330f729Sjoerg OCD, Category, ObjCTypes, true));
67647330f729Sjoerg } else {
67657330f729Sjoerg values.addNullPointer(ObjCTypes.ProtocolListnfABIPtrTy);
67667330f729Sjoerg values.addNullPointer(ObjCTypes.PropertyListPtrTy);
67677330f729Sjoerg values.addNullPointer(ObjCTypes.PropertyListPtrTy);
67687330f729Sjoerg }
67697330f729Sjoerg
67707330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy);
67717330f729Sjoerg values.addInt(ObjCTypes.IntTy, Size);
67727330f729Sjoerg
67737330f729Sjoerg llvm::GlobalVariable *GCATV =
67747330f729Sjoerg finishAndCreateGlobal(values, ExtCatName.str(), CGM);
67757330f729Sjoerg CGM.addCompilerUsedGlobal(GCATV);
67767330f729Sjoerg if (Interface->hasAttr<ObjCClassStubAttr>())
67777330f729Sjoerg DefinedStubCategories.push_back(GCATV);
67787330f729Sjoerg else
67797330f729Sjoerg DefinedCategories.push_back(GCATV);
67807330f729Sjoerg
67817330f729Sjoerg // Determine if this category is also "non-lazy".
67827330f729Sjoerg if (ImplementationIsNonLazy(OCD))
67837330f729Sjoerg DefinedNonLazyCategories.push_back(GCATV);
67847330f729Sjoerg // method definition entries must be clear for next implementation.
67857330f729Sjoerg MethodDefinitions.clear();
67867330f729Sjoerg }
67877330f729Sjoerg
67887330f729Sjoerg /// emitMethodConstant - Return a struct objc_method constant. If
67897330f729Sjoerg /// forProtocol is true, the implementation will be null; otherwise,
67907330f729Sjoerg /// the method must have a definition registered with the runtime.
67917330f729Sjoerg ///
67927330f729Sjoerg /// struct _objc_method {
67937330f729Sjoerg /// SEL _cmd;
67947330f729Sjoerg /// char *method_type;
67957330f729Sjoerg /// char *_imp;
67967330f729Sjoerg /// }
emitMethodConstant(ConstantArrayBuilder & builder,const ObjCMethodDecl * MD,bool forProtocol)67977330f729Sjoerg void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
67987330f729Sjoerg const ObjCMethodDecl *MD,
67997330f729Sjoerg bool forProtocol) {
68007330f729Sjoerg auto method = builder.beginStruct(ObjCTypes.MethodTy);
68017330f729Sjoerg method.addBitCast(GetMethodVarName(MD->getSelector()),
68027330f729Sjoerg ObjCTypes.SelectorPtrTy);
68037330f729Sjoerg method.add(GetMethodVarType(MD));
68047330f729Sjoerg
68057330f729Sjoerg if (forProtocol) {
68067330f729Sjoerg // Protocol methods have no implementation. So, this entry is always NULL.
68077330f729Sjoerg method.addNullPointer(ObjCTypes.Int8PtrTy);
68087330f729Sjoerg } else {
68097330f729Sjoerg llvm::Function *fn = GetMethodDefinition(MD);
68107330f729Sjoerg assert(fn && "no definition for method?");
68117330f729Sjoerg method.addBitCast(fn, ObjCTypes.Int8PtrTy);
68127330f729Sjoerg }
68137330f729Sjoerg
68147330f729Sjoerg method.finishAndAddTo(builder);
68157330f729Sjoerg }
68167330f729Sjoerg
68177330f729Sjoerg /// Build meta-data for method declarations.
68187330f729Sjoerg ///
68197330f729Sjoerg /// struct _method_list_t {
68207330f729Sjoerg /// uint32_t entsize; // sizeof(struct _objc_method)
68217330f729Sjoerg /// uint32_t method_count;
68227330f729Sjoerg /// struct _objc_method method_list[method_count];
68237330f729Sjoerg /// }
68247330f729Sjoerg ///
68257330f729Sjoerg llvm::Constant *
emitMethodList(Twine name,MethodListType kind,ArrayRef<const ObjCMethodDecl * > methods)68267330f729Sjoerg CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind,
68277330f729Sjoerg ArrayRef<const ObjCMethodDecl *> methods) {
68287330f729Sjoerg // Return null for empty list.
68297330f729Sjoerg if (methods.empty())
68307330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy);
68317330f729Sjoerg
68327330f729Sjoerg StringRef prefix;
68337330f729Sjoerg bool forProtocol;
68347330f729Sjoerg switch (kind) {
68357330f729Sjoerg case MethodListType::CategoryInstanceMethods:
68367330f729Sjoerg prefix = "_OBJC_$_CATEGORY_INSTANCE_METHODS_";
68377330f729Sjoerg forProtocol = false;
68387330f729Sjoerg break;
68397330f729Sjoerg case MethodListType::CategoryClassMethods:
68407330f729Sjoerg prefix = "_OBJC_$_CATEGORY_CLASS_METHODS_";
68417330f729Sjoerg forProtocol = false;
68427330f729Sjoerg break;
68437330f729Sjoerg case MethodListType::InstanceMethods:
68447330f729Sjoerg prefix = "_OBJC_$_INSTANCE_METHODS_";
68457330f729Sjoerg forProtocol = false;
68467330f729Sjoerg break;
68477330f729Sjoerg case MethodListType::ClassMethods:
68487330f729Sjoerg prefix = "_OBJC_$_CLASS_METHODS_";
68497330f729Sjoerg forProtocol = false;
68507330f729Sjoerg break;
68517330f729Sjoerg
68527330f729Sjoerg case MethodListType::ProtocolInstanceMethods:
68537330f729Sjoerg prefix = "_OBJC_$_PROTOCOL_INSTANCE_METHODS_";
68547330f729Sjoerg forProtocol = true;
68557330f729Sjoerg break;
68567330f729Sjoerg case MethodListType::ProtocolClassMethods:
68577330f729Sjoerg prefix = "_OBJC_$_PROTOCOL_CLASS_METHODS_";
68587330f729Sjoerg forProtocol = true;
68597330f729Sjoerg break;
68607330f729Sjoerg case MethodListType::OptionalProtocolInstanceMethods:
68617330f729Sjoerg prefix = "_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_";
68627330f729Sjoerg forProtocol = true;
68637330f729Sjoerg break;
68647330f729Sjoerg case MethodListType::OptionalProtocolClassMethods:
68657330f729Sjoerg prefix = "_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_";
68667330f729Sjoerg forProtocol = true;
68677330f729Sjoerg break;
68687330f729Sjoerg }
68697330f729Sjoerg
68707330f729Sjoerg ConstantInitBuilder builder(CGM);
68717330f729Sjoerg auto values = builder.beginStruct();
68727330f729Sjoerg
68737330f729Sjoerg // sizeof(struct _objc_method)
68747330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.MethodTy);
68757330f729Sjoerg values.addInt(ObjCTypes.IntTy, Size);
68767330f729Sjoerg // method_count
68777330f729Sjoerg values.addInt(ObjCTypes.IntTy, methods.size());
68787330f729Sjoerg auto methodArray = values.beginArray(ObjCTypes.MethodTy);
6879*e038c9c4Sjoerg for (auto MD : methods)
68807330f729Sjoerg emitMethodConstant(methodArray, MD, forProtocol);
68817330f729Sjoerg methodArray.finishAndAddTo(values);
68827330f729Sjoerg
68837330f729Sjoerg llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM);
68847330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
68857330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
68867330f729Sjoerg }
68877330f729Sjoerg
68887330f729Sjoerg /// ObjCIvarOffsetVariable - Returns the ivar offset variable for
68897330f729Sjoerg /// the given ivar.
68907330f729Sjoerg llvm::GlobalVariable *
ObjCIvarOffsetVariable(const ObjCInterfaceDecl * ID,const ObjCIvarDecl * Ivar)68917330f729Sjoerg CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
68927330f729Sjoerg const ObjCIvarDecl *Ivar) {
68937330f729Sjoerg const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
68947330f729Sjoerg llvm::SmallString<64> Name("OBJC_IVAR_$_");
68957330f729Sjoerg Name += Container->getObjCRuntimeNameAsString();
68967330f729Sjoerg Name += ".";
68977330f729Sjoerg Name += Ivar->getName();
68987330f729Sjoerg llvm::GlobalVariable *IvarOffsetGV = CGM.getModule().getGlobalVariable(Name);
68997330f729Sjoerg if (!IvarOffsetGV) {
69007330f729Sjoerg IvarOffsetGV =
69017330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.IvarOffsetVarTy,
69027330f729Sjoerg false, llvm::GlobalValue::ExternalLinkage,
69037330f729Sjoerg nullptr, Name.str());
69047330f729Sjoerg if (CGM.getTriple().isOSBinFormatCOFF()) {
69057330f729Sjoerg bool IsPrivateOrPackage =
69067330f729Sjoerg Ivar->getAccessControl() == ObjCIvarDecl::Private ||
69077330f729Sjoerg Ivar->getAccessControl() == ObjCIvarDecl::Package;
69087330f729Sjoerg
69097330f729Sjoerg const ObjCInterfaceDecl *ContainingID = Ivar->getContainingInterface();
69107330f729Sjoerg
69117330f729Sjoerg if (ContainingID->hasAttr<DLLImportAttr>())
69127330f729Sjoerg IvarOffsetGV
69137330f729Sjoerg ->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
69147330f729Sjoerg else if (ContainingID->hasAttr<DLLExportAttr>() && !IsPrivateOrPackage)
69157330f729Sjoerg IvarOffsetGV
69167330f729Sjoerg ->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
69177330f729Sjoerg }
69187330f729Sjoerg }
69197330f729Sjoerg return IvarOffsetGV;
69207330f729Sjoerg }
69217330f729Sjoerg
69227330f729Sjoerg llvm::Constant *
EmitIvarOffsetVar(const ObjCInterfaceDecl * ID,const ObjCIvarDecl * Ivar,unsigned long int Offset)69237330f729Sjoerg CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
69247330f729Sjoerg const ObjCIvarDecl *Ivar,
69257330f729Sjoerg unsigned long int Offset) {
69267330f729Sjoerg llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
69277330f729Sjoerg IvarOffsetGV->setInitializer(
69287330f729Sjoerg llvm::ConstantInt::get(ObjCTypes.IvarOffsetVarTy, Offset));
69297330f729Sjoerg IvarOffsetGV->setAlignment(llvm::Align(
69307330f729Sjoerg CGM.getDataLayout().getABITypeAlignment(ObjCTypes.IvarOffsetVarTy)));
69317330f729Sjoerg
69327330f729Sjoerg if (!CGM.getTriple().isOSBinFormatCOFF()) {
69337330f729Sjoerg // FIXME: This matches gcc, but shouldn't the visibility be set on the use
69347330f729Sjoerg // as well (i.e., in ObjCIvarOffsetVariable).
69357330f729Sjoerg if (Ivar->getAccessControl() == ObjCIvarDecl::Private ||
69367330f729Sjoerg Ivar->getAccessControl() == ObjCIvarDecl::Package ||
69377330f729Sjoerg ID->getVisibility() == HiddenVisibility)
69387330f729Sjoerg IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
69397330f729Sjoerg else
69407330f729Sjoerg IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
69417330f729Sjoerg }
69427330f729Sjoerg
69437330f729Sjoerg // If ID's layout is known, then make the global constant. This serves as a
69447330f729Sjoerg // useful assertion: we'll never use this variable to calculate ivar offsets,
69457330f729Sjoerg // so if the runtime tries to patch it then we should crash.
69467330f729Sjoerg if (isClassLayoutKnownStatically(ID))
69477330f729Sjoerg IvarOffsetGV->setConstant(true);
69487330f729Sjoerg
69497330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO())
69507330f729Sjoerg IvarOffsetGV->setSection("__DATA, __objc_ivar");
69517330f729Sjoerg return IvarOffsetGV;
69527330f729Sjoerg }
69537330f729Sjoerg
69547330f729Sjoerg /// EmitIvarList - Emit the ivar list for the given
69557330f729Sjoerg /// implementation. The return value has type
69567330f729Sjoerg /// IvarListnfABIPtrTy.
69577330f729Sjoerg /// struct _ivar_t {
69587330f729Sjoerg /// unsigned [long] int *offset; // pointer to ivar offset location
69597330f729Sjoerg /// char *name;
69607330f729Sjoerg /// char *type;
69617330f729Sjoerg /// uint32_t alignment;
69627330f729Sjoerg /// uint32_t size;
69637330f729Sjoerg /// }
69647330f729Sjoerg /// struct _ivar_list_t {
69657330f729Sjoerg /// uint32 entsize; // sizeof(struct _ivar_t)
69667330f729Sjoerg /// uint32 count;
69677330f729Sjoerg /// struct _iver_t list[count];
69687330f729Sjoerg /// }
69697330f729Sjoerg ///
69707330f729Sjoerg
EmitIvarList(const ObjCImplementationDecl * ID)69717330f729Sjoerg llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
69727330f729Sjoerg const ObjCImplementationDecl *ID) {
69737330f729Sjoerg
69747330f729Sjoerg ConstantInitBuilder builder(CGM);
69757330f729Sjoerg auto ivarList = builder.beginStruct();
69767330f729Sjoerg ivarList.addInt(ObjCTypes.IntTy,
69777330f729Sjoerg CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy));
69787330f729Sjoerg auto ivarCountSlot = ivarList.addPlaceholder();
69797330f729Sjoerg auto ivars = ivarList.beginArray(ObjCTypes.IvarnfABITy);
69807330f729Sjoerg
69817330f729Sjoerg const ObjCInterfaceDecl *OID = ID->getClassInterface();
69827330f729Sjoerg assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface");
69837330f729Sjoerg
69847330f729Sjoerg // FIXME. Consolidate this with similar code in GenerateClass.
69857330f729Sjoerg
69867330f729Sjoerg for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
69877330f729Sjoerg IVD; IVD = IVD->getNextIvar()) {
69887330f729Sjoerg // Ignore unnamed bit-fields.
69897330f729Sjoerg if (!IVD->getDeclName())
69907330f729Sjoerg continue;
69917330f729Sjoerg
69927330f729Sjoerg auto ivar = ivars.beginStruct(ObjCTypes.IvarnfABITy);
69937330f729Sjoerg ivar.add(EmitIvarOffsetVar(ID->getClassInterface(), IVD,
69947330f729Sjoerg ComputeIvarBaseOffset(CGM, ID, IVD)));
69957330f729Sjoerg ivar.add(GetMethodVarName(IVD->getIdentifier()));
69967330f729Sjoerg ivar.add(GetMethodVarType(IVD));
69977330f729Sjoerg llvm::Type *FieldTy =
69987330f729Sjoerg CGM.getTypes().ConvertTypeForMem(IVD->getType());
69997330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(FieldTy);
70007330f729Sjoerg unsigned Align = CGM.getContext().getPreferredTypeAlign(
70017330f729Sjoerg IVD->getType().getTypePtr()) >> 3;
70027330f729Sjoerg Align = llvm::Log2_32(Align);
70037330f729Sjoerg ivar.addInt(ObjCTypes.IntTy, Align);
70047330f729Sjoerg // NOTE. Size of a bitfield does not match gcc's, because of the
70057330f729Sjoerg // way bitfields are treated special in each. But I am told that
70067330f729Sjoerg // 'size' for bitfield ivars is ignored by the runtime so it does
70077330f729Sjoerg // not matter. If it matters, there is enough info to get the
70087330f729Sjoerg // bitfield right!
70097330f729Sjoerg ivar.addInt(ObjCTypes.IntTy, Size);
70107330f729Sjoerg ivar.finishAndAddTo(ivars);
70117330f729Sjoerg }
70127330f729Sjoerg // Return null for empty list.
70137330f729Sjoerg if (ivars.empty()) {
70147330f729Sjoerg ivars.abandon();
70157330f729Sjoerg ivarList.abandon();
70167330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
70177330f729Sjoerg }
70187330f729Sjoerg
70197330f729Sjoerg auto ivarCount = ivars.size();
70207330f729Sjoerg ivars.finishAndAddTo(ivarList);
70217330f729Sjoerg ivarList.fillPlaceholderWithInt(ivarCountSlot, ObjCTypes.IntTy, ivarCount);
70227330f729Sjoerg
70237330f729Sjoerg const char *Prefix = "_OBJC_$_INSTANCE_VARIABLES_";
70247330f729Sjoerg llvm::GlobalVariable *GV = finishAndCreateGlobal(
70257330f729Sjoerg ivarList, Prefix + OID->getObjCRuntimeNameAsString(), CGM);
70267330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
70277330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListnfABIPtrTy);
70287330f729Sjoerg }
70297330f729Sjoerg
GetOrEmitProtocolRef(const ObjCProtocolDecl * PD)70307330f729Sjoerg llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
70317330f729Sjoerg const ObjCProtocolDecl *PD) {
70327330f729Sjoerg llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
70337330f729Sjoerg
7034*e038c9c4Sjoerg assert(!PD->isNonRuntimeProtocol() &&
7035*e038c9c4Sjoerg "attempting to GetOrEmit a non-runtime protocol");
70367330f729Sjoerg if (!Entry) {
70377330f729Sjoerg // We use the initializer as a marker of whether this is a forward
70387330f729Sjoerg // reference or not. At module finalization we add the empty
70397330f729Sjoerg // contents for protocols which were referenced but never defined.
70407330f729Sjoerg llvm::SmallString<64> Protocol;
70417330f729Sjoerg llvm::raw_svector_ostream(Protocol) << "_OBJC_PROTOCOL_$_"
70427330f729Sjoerg << PD->getObjCRuntimeNameAsString();
70437330f729Sjoerg
70447330f729Sjoerg Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy,
70457330f729Sjoerg false, llvm::GlobalValue::ExternalLinkage,
70467330f729Sjoerg nullptr, Protocol);
70477330f729Sjoerg if (!CGM.getTriple().isOSBinFormatMachO())
70487330f729Sjoerg Entry->setComdat(CGM.getModule().getOrInsertComdat(Protocol));
70497330f729Sjoerg }
70507330f729Sjoerg
70517330f729Sjoerg return Entry;
70527330f729Sjoerg }
70537330f729Sjoerg
70547330f729Sjoerg /// GetOrEmitProtocol - Generate the protocol meta-data:
70557330f729Sjoerg /// @code
70567330f729Sjoerg /// struct _protocol_t {
70577330f729Sjoerg /// id isa; // NULL
70587330f729Sjoerg /// const char * const protocol_name;
70597330f729Sjoerg /// const struct _protocol_list_t * protocol_list; // super protocols
70607330f729Sjoerg /// const struct method_list_t * const instance_methods;
70617330f729Sjoerg /// const struct method_list_t * const class_methods;
70627330f729Sjoerg /// const struct method_list_t *optionalInstanceMethods;
70637330f729Sjoerg /// const struct method_list_t *optionalClassMethods;
70647330f729Sjoerg /// const struct _prop_list_t * properties;
70657330f729Sjoerg /// const uint32_t size; // sizeof(struct _protocol_t)
70667330f729Sjoerg /// const uint32_t flags; // = 0
70677330f729Sjoerg /// const char ** extendedMethodTypes;
70687330f729Sjoerg /// const char *demangledName;
70697330f729Sjoerg /// const struct _prop_list_t * class_properties;
70707330f729Sjoerg /// }
70717330f729Sjoerg /// @endcode
70727330f729Sjoerg ///
70737330f729Sjoerg
GetOrEmitProtocol(const ObjCProtocolDecl * PD)70747330f729Sjoerg llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
70757330f729Sjoerg const ObjCProtocolDecl *PD) {
70767330f729Sjoerg llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()];
70777330f729Sjoerg
70787330f729Sjoerg // Early exit if a defining object has already been generated.
70797330f729Sjoerg if (Entry && Entry->hasInitializer())
70807330f729Sjoerg return Entry;
70817330f729Sjoerg
70827330f729Sjoerg // Use the protocol definition, if there is one.
70837330f729Sjoerg assert(PD->hasDefinition() &&
70847330f729Sjoerg "emitting protocol metadata without definition");
70857330f729Sjoerg PD = PD->getDefinition();
70867330f729Sjoerg
70877330f729Sjoerg auto methodLists = ProtocolMethodLists::get(PD);
70887330f729Sjoerg
70897330f729Sjoerg ConstantInitBuilder builder(CGM);
70907330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.ProtocolnfABITy);
70917330f729Sjoerg
70927330f729Sjoerg // isa is NULL
70937330f729Sjoerg values.addNullPointer(ObjCTypes.ObjectPtrTy);
70947330f729Sjoerg values.add(GetClassName(PD->getObjCRuntimeNameAsString()));
70957330f729Sjoerg values.add(EmitProtocolList("_OBJC_$_PROTOCOL_REFS_"
70967330f729Sjoerg + PD->getObjCRuntimeNameAsString(),
70977330f729Sjoerg PD->protocol_begin(),
70987330f729Sjoerg PD->protocol_end()));
70997330f729Sjoerg values.add(methodLists.emitMethodList(this, PD,
71007330f729Sjoerg ProtocolMethodLists::RequiredInstanceMethods));
71017330f729Sjoerg values.add(methodLists.emitMethodList(this, PD,
71027330f729Sjoerg ProtocolMethodLists::RequiredClassMethods));
71037330f729Sjoerg values.add(methodLists.emitMethodList(this, PD,
71047330f729Sjoerg ProtocolMethodLists::OptionalInstanceMethods));
71057330f729Sjoerg values.add(methodLists.emitMethodList(this, PD,
71067330f729Sjoerg ProtocolMethodLists::OptionalClassMethods));
71077330f729Sjoerg values.add(EmitPropertyList(
71087330f729Sjoerg "_OBJC_$_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
71097330f729Sjoerg nullptr, PD, ObjCTypes, false));
71107330f729Sjoerg uint32_t Size =
71117330f729Sjoerg CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
71127330f729Sjoerg values.addInt(ObjCTypes.IntTy, Size);
71137330f729Sjoerg values.addInt(ObjCTypes.IntTy, 0);
71147330f729Sjoerg values.add(EmitProtocolMethodTypes("_OBJC_$_PROTOCOL_METHOD_TYPES_"
71157330f729Sjoerg + PD->getObjCRuntimeNameAsString(),
71167330f729Sjoerg methodLists.emitExtendedTypesArray(this),
71177330f729Sjoerg ObjCTypes));
71187330f729Sjoerg
71197330f729Sjoerg // const char *demangledName;
71207330f729Sjoerg values.addNullPointer(ObjCTypes.Int8PtrTy);
71217330f729Sjoerg
71227330f729Sjoerg values.add(EmitPropertyList(
71237330f729Sjoerg "_OBJC_$_CLASS_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
71247330f729Sjoerg nullptr, PD, ObjCTypes, true));
71257330f729Sjoerg
71267330f729Sjoerg if (Entry) {
71277330f729Sjoerg // Already created, fix the linkage and update the initializer.
71287330f729Sjoerg Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
71297330f729Sjoerg values.finishAndSetAsInitializer(Entry);
71307330f729Sjoerg } else {
71317330f729Sjoerg llvm::SmallString<64> symbolName;
71327330f729Sjoerg llvm::raw_svector_ostream(symbolName)
71337330f729Sjoerg << "_OBJC_PROTOCOL_$_" << PD->getObjCRuntimeNameAsString();
71347330f729Sjoerg
71357330f729Sjoerg Entry = values.finishAndCreateGlobal(symbolName, CGM.getPointerAlign(),
71367330f729Sjoerg /*constant*/ false,
71377330f729Sjoerg llvm::GlobalValue::WeakAnyLinkage);
71387330f729Sjoerg if (!CGM.getTriple().isOSBinFormatMachO())
71397330f729Sjoerg Entry->setComdat(CGM.getModule().getOrInsertComdat(symbolName));
71407330f729Sjoerg
71417330f729Sjoerg Protocols[PD->getIdentifier()] = Entry;
71427330f729Sjoerg }
71437330f729Sjoerg Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
71447330f729Sjoerg CGM.addUsedGlobal(Entry);
71457330f729Sjoerg
71467330f729Sjoerg // Use this protocol meta-data to build protocol list table in section
71477330f729Sjoerg // __DATA, __objc_protolist
71487330f729Sjoerg llvm::SmallString<64> ProtocolRef;
71497330f729Sjoerg llvm::raw_svector_ostream(ProtocolRef) << "_OBJC_LABEL_PROTOCOL_$_"
71507330f729Sjoerg << PD->getObjCRuntimeNameAsString();
71517330f729Sjoerg
71527330f729Sjoerg llvm::GlobalVariable *PTGV =
71537330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABIPtrTy,
71547330f729Sjoerg false, llvm::GlobalValue::WeakAnyLinkage, Entry,
71557330f729Sjoerg ProtocolRef);
71567330f729Sjoerg if (!CGM.getTriple().isOSBinFormatMachO())
71577330f729Sjoerg PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef));
71587330f729Sjoerg PTGV->setAlignment(llvm::Align(
71597330f729Sjoerg CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)));
71607330f729Sjoerg PTGV->setSection(GetSectionName("__objc_protolist",
71617330f729Sjoerg "coalesced,no_dead_strip"));
71627330f729Sjoerg PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
71637330f729Sjoerg CGM.addUsedGlobal(PTGV);
71647330f729Sjoerg return Entry;
71657330f729Sjoerg }
71667330f729Sjoerg
71677330f729Sjoerg /// EmitProtocolList - Generate protocol list meta-data:
71687330f729Sjoerg /// @code
71697330f729Sjoerg /// struct _protocol_list_t {
71707330f729Sjoerg /// long protocol_count; // Note, this is 32/64 bit
71717330f729Sjoerg /// struct _protocol_t[protocol_count];
71727330f729Sjoerg /// }
71737330f729Sjoerg /// @endcode
71747330f729Sjoerg ///
71757330f729Sjoerg llvm::Constant *
EmitProtocolList(Twine Name,ObjCProtocolDecl::protocol_iterator begin,ObjCProtocolDecl::protocol_iterator end)71767330f729Sjoerg CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
71777330f729Sjoerg ObjCProtocolDecl::protocol_iterator begin,
71787330f729Sjoerg ObjCProtocolDecl::protocol_iterator end) {
71797330f729Sjoerg // Just return null for empty protocol lists
7180*e038c9c4Sjoerg auto Protocols = GetRuntimeProtocolList(begin, end);
7181*e038c9c4Sjoerg if (Protocols.empty())
7182*e038c9c4Sjoerg return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
7183*e038c9c4Sjoerg
7184*e038c9c4Sjoerg SmallVector<llvm::Constant *, 16> ProtocolRefs;
7185*e038c9c4Sjoerg ProtocolRefs.reserve(Protocols.size());
7186*e038c9c4Sjoerg
7187*e038c9c4Sjoerg for (const auto *PD : Protocols)
7188*e038c9c4Sjoerg ProtocolRefs.push_back(GetProtocolRef(PD));
7189*e038c9c4Sjoerg
7190*e038c9c4Sjoerg // If all of the protocols in the protocol list are objc_non_runtime_protocol
7191*e038c9c4Sjoerg // just return null
7192*e038c9c4Sjoerg if (ProtocolRefs.size() == 0)
71937330f729Sjoerg return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
71947330f729Sjoerg
71957330f729Sjoerg // FIXME: We shouldn't need to do this lookup here, should we?
71967330f729Sjoerg SmallString<256> TmpName;
71977330f729Sjoerg Name.toVector(TmpName);
71987330f729Sjoerg llvm::GlobalVariable *GV =
71997330f729Sjoerg CGM.getModule().getGlobalVariable(TmpName.str(), true);
72007330f729Sjoerg if (GV)
72017330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy);
72027330f729Sjoerg
72037330f729Sjoerg ConstantInitBuilder builder(CGM);
72047330f729Sjoerg auto values = builder.beginStruct();
72057330f729Sjoerg auto countSlot = values.addPlaceholder();
72067330f729Sjoerg
72077330f729Sjoerg // A null-terminated array of protocols.
72087330f729Sjoerg auto array = values.beginArray(ObjCTypes.ProtocolnfABIPtrTy);
7209*e038c9c4Sjoerg for (auto const &proto : ProtocolRefs)
7210*e038c9c4Sjoerg array.add(proto);
72117330f729Sjoerg auto count = array.size();
72127330f729Sjoerg array.addNullPointer(ObjCTypes.ProtocolnfABIPtrTy);
72137330f729Sjoerg
72147330f729Sjoerg array.finishAndAddTo(values);
72157330f729Sjoerg values.fillPlaceholderWithInt(countSlot, ObjCTypes.LongTy, count);
72167330f729Sjoerg
72177330f729Sjoerg GV = finishAndCreateGlobal(values, Name, CGM);
72187330f729Sjoerg CGM.addCompilerUsedGlobal(GV);
72197330f729Sjoerg return llvm::ConstantExpr::getBitCast(GV,
72207330f729Sjoerg ObjCTypes.ProtocolListnfABIPtrTy);
72217330f729Sjoerg }
72227330f729Sjoerg
72237330f729Sjoerg /// EmitObjCValueForIvar - Code Gen for nonfragile ivar reference.
72247330f729Sjoerg /// This code gen. amounts to generating code for:
72257330f729Sjoerg /// @code
72267330f729Sjoerg /// (type *)((char *)base + _OBJC_IVAR_$_.ivar;
72277330f729Sjoerg /// @encode
72287330f729Sjoerg ///
EmitObjCValueForIvar(CodeGen::CodeGenFunction & CGF,QualType ObjectTy,llvm::Value * BaseValue,const ObjCIvarDecl * Ivar,unsigned CVRQualifiers)72297330f729Sjoerg LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
72307330f729Sjoerg CodeGen::CodeGenFunction &CGF,
72317330f729Sjoerg QualType ObjectTy,
72327330f729Sjoerg llvm::Value *BaseValue,
72337330f729Sjoerg const ObjCIvarDecl *Ivar,
72347330f729Sjoerg unsigned CVRQualifiers) {
72357330f729Sjoerg ObjCInterfaceDecl *ID = ObjectTy->castAs<ObjCObjectType>()->getInterface();
72367330f729Sjoerg llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
72377330f729Sjoerg return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
72387330f729Sjoerg Offset);
72397330f729Sjoerg }
72407330f729Sjoerg
72417330f729Sjoerg llvm::Value *
EmitIvarOffset(CodeGen::CodeGenFunction & CGF,const ObjCInterfaceDecl * Interface,const ObjCIvarDecl * Ivar)72427330f729Sjoerg CGObjCNonFragileABIMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
72437330f729Sjoerg const ObjCInterfaceDecl *Interface,
72447330f729Sjoerg const ObjCIvarDecl *Ivar) {
72457330f729Sjoerg llvm::Value *IvarOffsetValue;
72467330f729Sjoerg if (isClassLayoutKnownStatically(Interface)) {
72477330f729Sjoerg IvarOffsetValue = llvm::ConstantInt::get(
72487330f729Sjoerg ObjCTypes.IvarOffsetVarTy,
72497330f729Sjoerg ComputeIvarBaseOffset(CGM, Interface->getImplementation(), Ivar));
72507330f729Sjoerg } else {
72517330f729Sjoerg llvm::GlobalVariable *GV = ObjCIvarOffsetVariable(Interface, Ivar);
72527330f729Sjoerg IvarOffsetValue =
7253*e038c9c4Sjoerg CGF.Builder.CreateAlignedLoad(GV->getValueType(), GV,
7254*e038c9c4Sjoerg CGF.getSizeAlign(), "ivar");
72557330f729Sjoerg if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
72567330f729Sjoerg cast<llvm::LoadInst>(IvarOffsetValue)
72577330f729Sjoerg ->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
72587330f729Sjoerg llvm::MDNode::get(VMContext, None));
72597330f729Sjoerg }
72607330f729Sjoerg
72617330f729Sjoerg // This could be 32bit int or 64bit integer depending on the architecture.
72627330f729Sjoerg // Cast it to 64bit integer value, if it is a 32bit integer ivar offset value
72637330f729Sjoerg // as this is what caller always expects.
72647330f729Sjoerg if (ObjCTypes.IvarOffsetVarTy == ObjCTypes.IntTy)
72657330f729Sjoerg IvarOffsetValue = CGF.Builder.CreateIntCast(
72667330f729Sjoerg IvarOffsetValue, ObjCTypes.LongTy, true, "ivar.conv");
72677330f729Sjoerg return IvarOffsetValue;
72687330f729Sjoerg }
72697330f729Sjoerg
appendSelectorForMessageRefTable(std::string & buffer,Selector selector)72707330f729Sjoerg static void appendSelectorForMessageRefTable(std::string &buffer,
72717330f729Sjoerg Selector selector) {
72727330f729Sjoerg if (selector.isUnarySelector()) {
72737330f729Sjoerg buffer += selector.getNameForSlot(0);
72747330f729Sjoerg return;
72757330f729Sjoerg }
72767330f729Sjoerg
72777330f729Sjoerg for (unsigned i = 0, e = selector.getNumArgs(); i != e; ++i) {
72787330f729Sjoerg buffer += selector.getNameForSlot(i);
72797330f729Sjoerg buffer += '_';
72807330f729Sjoerg }
72817330f729Sjoerg }
72827330f729Sjoerg
72837330f729Sjoerg /// Emit a "vtable" message send. We emit a weak hidden-visibility
72847330f729Sjoerg /// struct, initially containing the selector pointer and a pointer to
72857330f729Sjoerg /// a "fixup" variant of the appropriate objc_msgSend. To call, we
72867330f729Sjoerg /// load and call the function pointer, passing the address of the
72877330f729Sjoerg /// struct as the second parameter. The runtime determines whether
72887330f729Sjoerg /// the selector is currently emitted using vtable dispatch; if so, it
72897330f729Sjoerg /// substitutes a stub function which simply tail-calls through the
72907330f729Sjoerg /// appropriate vtable slot, and if not, it substitues a stub function
72917330f729Sjoerg /// which tail-calls objc_msgSend. Both stubs adjust the selector
72927330f729Sjoerg /// argument to correctly point to the selector.
72937330f729Sjoerg RValue
EmitVTableMessageSend(CodeGenFunction & CGF,ReturnValueSlot returnSlot,QualType resultType,Selector selector,llvm::Value * arg0,QualType arg0Type,bool isSuper,const CallArgList & formalArgs,const ObjCMethodDecl * method)72947330f729Sjoerg CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
72957330f729Sjoerg ReturnValueSlot returnSlot,
72967330f729Sjoerg QualType resultType,
72977330f729Sjoerg Selector selector,
72987330f729Sjoerg llvm::Value *arg0,
72997330f729Sjoerg QualType arg0Type,
73007330f729Sjoerg bool isSuper,
73017330f729Sjoerg const CallArgList &formalArgs,
73027330f729Sjoerg const ObjCMethodDecl *method) {
73037330f729Sjoerg // Compute the actual arguments.
73047330f729Sjoerg CallArgList args;
73057330f729Sjoerg
73067330f729Sjoerg // First argument: the receiver / super-call structure.
73077330f729Sjoerg if (!isSuper)
73087330f729Sjoerg arg0 = CGF.Builder.CreateBitCast(arg0, ObjCTypes.ObjectPtrTy);
73097330f729Sjoerg args.add(RValue::get(arg0), arg0Type);
73107330f729Sjoerg
73117330f729Sjoerg // Second argument: a pointer to the message ref structure. Leave
73127330f729Sjoerg // the actual argument value blank for now.
73137330f729Sjoerg args.add(RValue::get(nullptr), ObjCTypes.MessageRefCPtrTy);
73147330f729Sjoerg
73157330f729Sjoerg args.insert(args.end(), formalArgs.begin(), formalArgs.end());
73167330f729Sjoerg
73177330f729Sjoerg MessageSendInfo MSI = getMessageSendInfo(method, resultType, args);
73187330f729Sjoerg
73197330f729Sjoerg NullReturnState nullReturn;
73207330f729Sjoerg
73217330f729Sjoerg // Find the function to call and the mangled name for the message
73227330f729Sjoerg // ref structure. Using a different mangled name wouldn't actually
73237330f729Sjoerg // be a problem; it would just be a waste.
73247330f729Sjoerg //
73257330f729Sjoerg // The runtime currently never uses vtable dispatch for anything
73267330f729Sjoerg // except normal, non-super message-sends.
73277330f729Sjoerg // FIXME: don't use this for that.
73287330f729Sjoerg llvm::FunctionCallee fn = nullptr;
73297330f729Sjoerg std::string messageRefName("_");
73307330f729Sjoerg if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
73317330f729Sjoerg if (isSuper) {
73327330f729Sjoerg fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
73337330f729Sjoerg messageRefName += "objc_msgSendSuper2_stret_fixup";
73347330f729Sjoerg } else {
73357330f729Sjoerg nullReturn.init(CGF, arg0);
73367330f729Sjoerg fn = ObjCTypes.getMessageSendStretFixupFn();
73377330f729Sjoerg messageRefName += "objc_msgSend_stret_fixup";
73387330f729Sjoerg }
73397330f729Sjoerg } else if (!isSuper && CGM.ReturnTypeUsesFPRet(resultType)) {
73407330f729Sjoerg fn = ObjCTypes.getMessageSendFpretFixupFn();
73417330f729Sjoerg messageRefName += "objc_msgSend_fpret_fixup";
73427330f729Sjoerg } else {
73437330f729Sjoerg if (isSuper) {
73447330f729Sjoerg fn = ObjCTypes.getMessageSendSuper2FixupFn();
73457330f729Sjoerg messageRefName += "objc_msgSendSuper2_fixup";
73467330f729Sjoerg } else {
73477330f729Sjoerg fn = ObjCTypes.getMessageSendFixupFn();
73487330f729Sjoerg messageRefName += "objc_msgSend_fixup";
73497330f729Sjoerg }
73507330f729Sjoerg }
73517330f729Sjoerg assert(fn && "CGObjCNonFragileABIMac::EmitMessageSend");
73527330f729Sjoerg messageRefName += '_';
73537330f729Sjoerg
73547330f729Sjoerg // Append the selector name, except use underscores anywhere we
73557330f729Sjoerg // would have used colons.
73567330f729Sjoerg appendSelectorForMessageRefTable(messageRefName, selector);
73577330f729Sjoerg
73587330f729Sjoerg llvm::GlobalVariable *messageRef
73597330f729Sjoerg = CGM.getModule().getGlobalVariable(messageRefName);
73607330f729Sjoerg if (!messageRef) {
73617330f729Sjoerg // Build the message ref structure.
73627330f729Sjoerg ConstantInitBuilder builder(CGM);
73637330f729Sjoerg auto values = builder.beginStruct();
73647330f729Sjoerg values.add(cast<llvm::Constant>(fn.getCallee()));
73657330f729Sjoerg values.add(GetMethodVarName(selector));
73667330f729Sjoerg messageRef = values.finishAndCreateGlobal(messageRefName,
73677330f729Sjoerg CharUnits::fromQuantity(16),
73687330f729Sjoerg /*constant*/ false,
73697330f729Sjoerg llvm::GlobalValue::WeakAnyLinkage);
73707330f729Sjoerg messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
73717330f729Sjoerg messageRef->setSection(GetSectionName("__objc_msgrefs", "coalesced"));
73727330f729Sjoerg }
73737330f729Sjoerg
73747330f729Sjoerg bool requiresnullCheck = false;
73757330f729Sjoerg if (CGM.getLangOpts().ObjCAutoRefCount && method)
73767330f729Sjoerg for (const auto *ParamDecl : method->parameters()) {
7377*e038c9c4Sjoerg if (ParamDecl->isDestroyedInCallee()) {
73787330f729Sjoerg if (!nullReturn.NullBB)
73797330f729Sjoerg nullReturn.init(CGF, arg0);
73807330f729Sjoerg requiresnullCheck = true;
73817330f729Sjoerg break;
73827330f729Sjoerg }
73837330f729Sjoerg }
73847330f729Sjoerg
73857330f729Sjoerg Address mref =
73867330f729Sjoerg Address(CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy),
73877330f729Sjoerg CGF.getPointerAlign());
73887330f729Sjoerg
73897330f729Sjoerg // Update the message ref argument.
73907330f729Sjoerg args[1].setRValue(RValue::get(mref.getPointer()));
73917330f729Sjoerg
73927330f729Sjoerg // Load the function to call from the message ref table.
73937330f729Sjoerg Address calleeAddr = CGF.Builder.CreateStructGEP(mref, 0);
73947330f729Sjoerg llvm::Value *calleePtr = CGF.Builder.CreateLoad(calleeAddr, "msgSend_fn");
73957330f729Sjoerg
73967330f729Sjoerg calleePtr = CGF.Builder.CreateBitCast(calleePtr, MSI.MessengerType);
73977330f729Sjoerg CGCallee callee(CGCalleeInfo(), calleePtr);
73987330f729Sjoerg
73997330f729Sjoerg RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
74007330f729Sjoerg return nullReturn.complete(CGF, returnSlot, result, resultType, formalArgs,
74017330f729Sjoerg requiresnullCheck ? method : nullptr);
74027330f729Sjoerg }
74037330f729Sjoerg
74047330f729Sjoerg /// Generate code for a message send expression in the nonfragile abi.
74057330f729Sjoerg CodeGen::RValue
GenerateMessageSend(CodeGen::CodeGenFunction & CGF,ReturnValueSlot Return,QualType ResultType,Selector Sel,llvm::Value * Receiver,const CallArgList & CallArgs,const ObjCInterfaceDecl * Class,const ObjCMethodDecl * Method)74067330f729Sjoerg CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
74077330f729Sjoerg ReturnValueSlot Return,
74087330f729Sjoerg QualType ResultType,
74097330f729Sjoerg Selector Sel,
74107330f729Sjoerg llvm::Value *Receiver,
74117330f729Sjoerg const CallArgList &CallArgs,
74127330f729Sjoerg const ObjCInterfaceDecl *Class,
74137330f729Sjoerg const ObjCMethodDecl *Method) {
74147330f729Sjoerg return isVTableDispatchedSelector(Sel)
74157330f729Sjoerg ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
74167330f729Sjoerg Receiver, CGF.getContext().getObjCIdType(),
74177330f729Sjoerg false, CallArgs, Method)
7418*e038c9c4Sjoerg : EmitMessageSend(CGF, Return, ResultType, Sel,
74197330f729Sjoerg Receiver, CGF.getContext().getObjCIdType(),
74207330f729Sjoerg false, CallArgs, Method, Class, ObjCTypes);
74217330f729Sjoerg }
74227330f729Sjoerg
74237330f729Sjoerg llvm::Constant *
GetClassGlobal(const ObjCInterfaceDecl * ID,bool metaclass,ForDefinition_t isForDefinition)74247330f729Sjoerg CGObjCNonFragileABIMac::GetClassGlobal(const ObjCInterfaceDecl *ID,
74257330f729Sjoerg bool metaclass,
74267330f729Sjoerg ForDefinition_t isForDefinition) {
74277330f729Sjoerg auto prefix =
74287330f729Sjoerg (metaclass ? getMetaclassSymbolPrefix() : getClassSymbolPrefix());
74297330f729Sjoerg return GetClassGlobal((prefix + ID->getObjCRuntimeNameAsString()).str(),
74307330f729Sjoerg isForDefinition,
74317330f729Sjoerg ID->isWeakImported(),
74327330f729Sjoerg !isForDefinition
74337330f729Sjoerg && CGM.getTriple().isOSBinFormatCOFF()
74347330f729Sjoerg && ID->hasAttr<DLLImportAttr>());
74357330f729Sjoerg }
74367330f729Sjoerg
74377330f729Sjoerg llvm::Constant *
GetClassGlobal(StringRef Name,ForDefinition_t IsForDefinition,bool Weak,bool DLLImport)74387330f729Sjoerg CGObjCNonFragileABIMac::GetClassGlobal(StringRef Name,
74397330f729Sjoerg ForDefinition_t IsForDefinition,
74407330f729Sjoerg bool Weak, bool DLLImport) {
74417330f729Sjoerg llvm::GlobalValue::LinkageTypes L =
74427330f729Sjoerg Weak ? llvm::GlobalValue::ExternalWeakLinkage
74437330f729Sjoerg : llvm::GlobalValue::ExternalLinkage;
74447330f729Sjoerg
74457330f729Sjoerg llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
74467330f729Sjoerg if (!GV || GV->getType() != ObjCTypes.ClassnfABITy->getPointerTo()) {
74477330f729Sjoerg auto *NewGV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false, L,
74487330f729Sjoerg nullptr, Name);
74497330f729Sjoerg
74507330f729Sjoerg if (DLLImport)
74517330f729Sjoerg NewGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
74527330f729Sjoerg
74537330f729Sjoerg if (GV) {
74547330f729Sjoerg GV->replaceAllUsesWith(
74557330f729Sjoerg llvm::ConstantExpr::getBitCast(NewGV, GV->getType()));
74567330f729Sjoerg GV->eraseFromParent();
74577330f729Sjoerg }
74587330f729Sjoerg GV = NewGV;
74597330f729Sjoerg CGM.getModule().getGlobalList().push_back(GV);
74607330f729Sjoerg }
74617330f729Sjoerg
74627330f729Sjoerg assert(GV->getLinkage() == L);
74637330f729Sjoerg return GV;
74647330f729Sjoerg }
74657330f729Sjoerg
74667330f729Sjoerg llvm::Constant *
GetClassGlobalForClassRef(const ObjCInterfaceDecl * ID)74677330f729Sjoerg CGObjCNonFragileABIMac::GetClassGlobalForClassRef(const ObjCInterfaceDecl *ID) {
74687330f729Sjoerg llvm::Constant *ClassGV = GetClassGlobal(ID, /*metaclass*/ false,
74697330f729Sjoerg NotForDefinition);
74707330f729Sjoerg
74717330f729Sjoerg if (!ID->hasAttr<ObjCClassStubAttr>())
74727330f729Sjoerg return ClassGV;
74737330f729Sjoerg
74747330f729Sjoerg ClassGV = llvm::ConstantExpr::getPointerCast(ClassGV, ObjCTypes.Int8PtrTy);
74757330f729Sjoerg
74767330f729Sjoerg // Stub classes are pointer-aligned. Classrefs pointing at stub classes
74777330f729Sjoerg // must set the least significant bit set to 1.
74787330f729Sjoerg auto *Idx = llvm::ConstantInt::get(CGM.Int32Ty, 1);
74797330f729Sjoerg return llvm::ConstantExpr::getGetElementPtr(CGM.Int8Ty, ClassGV, Idx);
74807330f729Sjoerg }
74817330f729Sjoerg
74827330f729Sjoerg llvm::Value *
EmitLoadOfClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID,llvm::GlobalVariable * Entry)74837330f729Sjoerg CGObjCNonFragileABIMac::EmitLoadOfClassRef(CodeGenFunction &CGF,
74847330f729Sjoerg const ObjCInterfaceDecl *ID,
74857330f729Sjoerg llvm::GlobalVariable *Entry) {
74867330f729Sjoerg if (ID && ID->hasAttr<ObjCClassStubAttr>()) {
74877330f729Sjoerg // Classrefs pointing at Objective-C stub classes must be loaded by calling
74887330f729Sjoerg // a special runtime function.
74897330f729Sjoerg return CGF.EmitRuntimeCall(
74907330f729Sjoerg ObjCTypes.getLoadClassrefFn(), Entry, "load_classref_result");
74917330f729Sjoerg }
74927330f729Sjoerg
74937330f729Sjoerg CharUnits Align = CGF.getPointerAlign();
7494*e038c9c4Sjoerg return CGF.Builder.CreateAlignedLoad(Entry->getValueType(), Entry, Align);
74957330f729Sjoerg }
74967330f729Sjoerg
74977330f729Sjoerg llvm::Value *
EmitClassRefFromId(CodeGenFunction & CGF,IdentifierInfo * II,const ObjCInterfaceDecl * ID)74987330f729Sjoerg CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
74997330f729Sjoerg IdentifierInfo *II,
75007330f729Sjoerg const ObjCInterfaceDecl *ID) {
75017330f729Sjoerg llvm::GlobalVariable *&Entry = ClassReferences[II];
75027330f729Sjoerg
75037330f729Sjoerg if (!Entry) {
75047330f729Sjoerg llvm::Constant *ClassGV;
75057330f729Sjoerg if (ID) {
75067330f729Sjoerg ClassGV = GetClassGlobalForClassRef(ID);
75077330f729Sjoerg } else {
75087330f729Sjoerg ClassGV = GetClassGlobal((getClassSymbolPrefix() + II->getName()).str(),
75097330f729Sjoerg NotForDefinition);
75107330f729Sjoerg assert(ClassGV->getType() == ObjCTypes.ClassnfABIPtrTy &&
75117330f729Sjoerg "classref was emitted with the wrong type?");
75127330f729Sjoerg }
75137330f729Sjoerg
75147330f729Sjoerg std::string SectionName =
75157330f729Sjoerg GetSectionName("__objc_classrefs", "regular,no_dead_strip");
75167330f729Sjoerg Entry = new llvm::GlobalVariable(
75177330f729Sjoerg CGM.getModule(), ClassGV->getType(), false,
75187330f729Sjoerg getLinkageTypeForObjCMetadata(CGM, SectionName), ClassGV,
75197330f729Sjoerg "OBJC_CLASSLIST_REFERENCES_$_");
75207330f729Sjoerg Entry->setAlignment(CGF.getPointerAlign().getAsAlign());
75217330f729Sjoerg if (!ID || !ID->hasAttr<ObjCClassStubAttr>())
75227330f729Sjoerg Entry->setSection(SectionName);
75237330f729Sjoerg
75247330f729Sjoerg CGM.addCompilerUsedGlobal(Entry);
75257330f729Sjoerg }
75267330f729Sjoerg
75277330f729Sjoerg return EmitLoadOfClassRef(CGF, ID, Entry);
75287330f729Sjoerg }
75297330f729Sjoerg
EmitClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)75307330f729Sjoerg llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
75317330f729Sjoerg const ObjCInterfaceDecl *ID) {
75327330f729Sjoerg // If the class has the objc_runtime_visible attribute, we need to
75337330f729Sjoerg // use the Objective-C runtime to get the class.
75347330f729Sjoerg if (ID->hasAttr<ObjCRuntimeVisibleAttr>())
75357330f729Sjoerg return EmitClassRefViaRuntime(CGF, ID, ObjCTypes);
75367330f729Sjoerg
75377330f729Sjoerg return EmitClassRefFromId(CGF, ID->getIdentifier(), ID);
75387330f729Sjoerg }
75397330f729Sjoerg
EmitNSAutoreleasePoolClassRef(CodeGenFunction & CGF)75407330f729Sjoerg llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
75417330f729Sjoerg CodeGenFunction &CGF) {
75427330f729Sjoerg IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
75437330f729Sjoerg return EmitClassRefFromId(CGF, II, nullptr);
75447330f729Sjoerg }
75457330f729Sjoerg
75467330f729Sjoerg llvm::Value *
EmitSuperClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)75477330f729Sjoerg CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
75487330f729Sjoerg const ObjCInterfaceDecl *ID) {
75497330f729Sjoerg llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
75507330f729Sjoerg
75517330f729Sjoerg if (!Entry) {
75527330f729Sjoerg llvm::Constant *ClassGV = GetClassGlobalForClassRef(ID);
75537330f729Sjoerg std::string SectionName =
75547330f729Sjoerg GetSectionName("__objc_superrefs", "regular,no_dead_strip");
7555*e038c9c4Sjoerg Entry = new llvm::GlobalVariable(CGM.getModule(), ClassGV->getType(), false,
7556*e038c9c4Sjoerg llvm::GlobalValue::PrivateLinkage, ClassGV,
75577330f729Sjoerg "OBJC_CLASSLIST_SUP_REFS_$_");
75587330f729Sjoerg Entry->setAlignment(CGF.getPointerAlign().getAsAlign());
75597330f729Sjoerg Entry->setSection(SectionName);
75607330f729Sjoerg CGM.addCompilerUsedGlobal(Entry);
75617330f729Sjoerg }
75627330f729Sjoerg
75637330f729Sjoerg return EmitLoadOfClassRef(CGF, ID, Entry);
75647330f729Sjoerg }
75657330f729Sjoerg
75667330f729Sjoerg /// EmitMetaClassRef - Return a Value * of the address of _class_t
75677330f729Sjoerg /// meta-data
75687330f729Sjoerg ///
EmitMetaClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID,bool Weak)75697330f729Sjoerg llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
75707330f729Sjoerg const ObjCInterfaceDecl *ID,
75717330f729Sjoerg bool Weak) {
75727330f729Sjoerg CharUnits Align = CGF.getPointerAlign();
75737330f729Sjoerg llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
75747330f729Sjoerg if (!Entry) {
75757330f729Sjoerg auto MetaClassGV = GetClassGlobal(ID, /*metaclass*/ true, NotForDefinition);
75767330f729Sjoerg std::string SectionName =
75777330f729Sjoerg GetSectionName("__objc_superrefs", "regular,no_dead_strip");
7578*e038c9c4Sjoerg Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
7579*e038c9c4Sjoerg false, llvm::GlobalValue::PrivateLinkage,
7580*e038c9c4Sjoerg MetaClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
75817330f729Sjoerg Entry->setAlignment(Align.getAsAlign());
75827330f729Sjoerg Entry->setSection(SectionName);
75837330f729Sjoerg CGM.addCompilerUsedGlobal(Entry);
75847330f729Sjoerg }
75857330f729Sjoerg
7586*e038c9c4Sjoerg return CGF.Builder.CreateAlignedLoad(ObjCTypes.ClassnfABIPtrTy, Entry, Align);
75877330f729Sjoerg }
75887330f729Sjoerg
75897330f729Sjoerg /// GetClass - Return a reference to the class for the given interface
75907330f729Sjoerg /// decl.
GetClass(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)75917330f729Sjoerg llvm::Value *CGObjCNonFragileABIMac::GetClass(CodeGenFunction &CGF,
75927330f729Sjoerg const ObjCInterfaceDecl *ID) {
75937330f729Sjoerg if (ID->isWeakImported()) {
75947330f729Sjoerg auto ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition);
75957330f729Sjoerg (void)ClassGV;
75967330f729Sjoerg assert(!isa<llvm::GlobalVariable>(ClassGV) ||
75977330f729Sjoerg cast<llvm::GlobalVariable>(ClassGV)->hasExternalWeakLinkage());
75987330f729Sjoerg }
75997330f729Sjoerg
76007330f729Sjoerg return EmitClassRef(CGF, ID);
76017330f729Sjoerg }
76027330f729Sjoerg
76037330f729Sjoerg /// Generates a message send where the super is the receiver. This is
76047330f729Sjoerg /// a message send to self with special delivery semantics indicating
76057330f729Sjoerg /// which class's method should be called.
76067330f729Sjoerg CodeGen::RValue
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)76077330f729Sjoerg CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
76087330f729Sjoerg ReturnValueSlot Return,
76097330f729Sjoerg QualType ResultType,
76107330f729Sjoerg Selector Sel,
76117330f729Sjoerg const ObjCInterfaceDecl *Class,
76127330f729Sjoerg bool isCategoryImpl,
76137330f729Sjoerg llvm::Value *Receiver,
76147330f729Sjoerg bool IsClassMessage,
76157330f729Sjoerg const CodeGen::CallArgList &CallArgs,
76167330f729Sjoerg const ObjCMethodDecl *Method) {
76177330f729Sjoerg // ...
76187330f729Sjoerg // Create and init a super structure; this is a (receiver, class)
76197330f729Sjoerg // pair we will pass to objc_msgSendSuper.
76207330f729Sjoerg Address ObjCSuper =
76217330f729Sjoerg CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(),
76227330f729Sjoerg "objc_super");
76237330f729Sjoerg
76247330f729Sjoerg llvm::Value *ReceiverAsObject =
76257330f729Sjoerg CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
76267330f729Sjoerg CGF.Builder.CreateStore(ReceiverAsObject,
76277330f729Sjoerg CGF.Builder.CreateStructGEP(ObjCSuper, 0));
76287330f729Sjoerg
76297330f729Sjoerg // If this is a class message the metaclass is passed as the target.
76307330f729Sjoerg llvm::Value *Target;
76317330f729Sjoerg if (IsClassMessage)
76327330f729Sjoerg Target = EmitMetaClassRef(CGF, Class, Class->isWeakImported());
76337330f729Sjoerg else
76347330f729Sjoerg Target = EmitSuperClassRef(CGF, Class);
76357330f729Sjoerg
76367330f729Sjoerg // FIXME: We shouldn't need to do this cast, rectify the ASTContext and
76377330f729Sjoerg // ObjCTypes types.
76387330f729Sjoerg llvm::Type *ClassTy =
76397330f729Sjoerg CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
76407330f729Sjoerg Target = CGF.Builder.CreateBitCast(Target, ClassTy);
76417330f729Sjoerg CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1));
76427330f729Sjoerg
76437330f729Sjoerg return (isVTableDispatchedSelector(Sel))
76447330f729Sjoerg ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
76457330f729Sjoerg ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
76467330f729Sjoerg true, CallArgs, Method)
7647*e038c9c4Sjoerg : EmitMessageSend(CGF, Return, ResultType, Sel,
76487330f729Sjoerg ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
76497330f729Sjoerg true, CallArgs, Method, Class, ObjCTypes);
76507330f729Sjoerg }
76517330f729Sjoerg
EmitSelector(CodeGenFunction & CGF,Selector Sel)76527330f729Sjoerg llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
76537330f729Sjoerg Selector Sel) {
7654*e038c9c4Sjoerg Address Addr = EmitSelectorAddr(Sel);
76557330f729Sjoerg
76567330f729Sjoerg llvm::LoadInst* LI = CGF.Builder.CreateLoad(Addr);
76577330f729Sjoerg LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
76587330f729Sjoerg llvm::MDNode::get(VMContext, None));
76597330f729Sjoerg return LI;
76607330f729Sjoerg }
76617330f729Sjoerg
EmitSelectorAddr(Selector Sel)7662*e038c9c4Sjoerg Address CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) {
76637330f729Sjoerg llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
7664*e038c9c4Sjoerg CharUnits Align = CGM.getPointerAlign();
76657330f729Sjoerg if (!Entry) {
76667330f729Sjoerg llvm::Constant *Casted =
76677330f729Sjoerg llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
76687330f729Sjoerg ObjCTypes.SelectorPtrTy);
76697330f729Sjoerg std::string SectionName =
76707330f729Sjoerg GetSectionName("__objc_selrefs", "literal_pointers,no_dead_strip");
76717330f729Sjoerg Entry = new llvm::GlobalVariable(
76727330f729Sjoerg CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
76737330f729Sjoerg getLinkageTypeForObjCMetadata(CGM, SectionName), Casted,
76747330f729Sjoerg "OBJC_SELECTOR_REFERENCES_");
76757330f729Sjoerg Entry->setExternallyInitialized(true);
76767330f729Sjoerg Entry->setSection(SectionName);
76777330f729Sjoerg Entry->setAlignment(Align.getAsAlign());
76787330f729Sjoerg CGM.addCompilerUsedGlobal(Entry);
76797330f729Sjoerg }
76807330f729Sjoerg
76817330f729Sjoerg return Address(Entry, Align);
76827330f729Sjoerg }
76837330f729Sjoerg
76847330f729Sjoerg /// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
76857330f729Sjoerg /// objc_assign_ivar (id src, id *dst, ptrdiff_t)
76867330f729Sjoerg ///
EmitObjCIvarAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst,llvm::Value * ivarOffset)76877330f729Sjoerg void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
76887330f729Sjoerg llvm::Value *src,
76897330f729Sjoerg Address dst,
76907330f729Sjoerg llvm::Value *ivarOffset) {
76917330f729Sjoerg llvm::Type * SrcTy = src->getType();
76927330f729Sjoerg if (!isa<llvm::PointerType>(SrcTy)) {
76937330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
76947330f729Sjoerg assert(Size <= 8 && "does not support size > 8");
76957330f729Sjoerg src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
76967330f729Sjoerg : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
76977330f729Sjoerg src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
76987330f729Sjoerg }
76997330f729Sjoerg src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
77007330f729Sjoerg dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
77017330f729Sjoerg llvm::Value *args[] = { src, dst.getPointer(), ivarOffset };
77027330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
77037330f729Sjoerg }
77047330f729Sjoerg
77057330f729Sjoerg /// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
77067330f729Sjoerg /// objc_assign_strongCast (id src, id *dst)
77077330f729Sjoerg ///
EmitObjCStrongCastAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst)77087330f729Sjoerg void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
77097330f729Sjoerg CodeGen::CodeGenFunction &CGF,
77107330f729Sjoerg llvm::Value *src, Address dst) {
77117330f729Sjoerg llvm::Type * SrcTy = src->getType();
77127330f729Sjoerg if (!isa<llvm::PointerType>(SrcTy)) {
77137330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
77147330f729Sjoerg assert(Size <= 8 && "does not support size > 8");
77157330f729Sjoerg src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
77167330f729Sjoerg : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
77177330f729Sjoerg src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
77187330f729Sjoerg }
77197330f729Sjoerg src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
77207330f729Sjoerg dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
77217330f729Sjoerg llvm::Value *args[] = { src, dst.getPointer() };
77227330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
77237330f729Sjoerg args, "weakassign");
77247330f729Sjoerg }
77257330f729Sjoerg
EmitGCMemmoveCollectable(CodeGen::CodeGenFunction & CGF,Address DestPtr,Address SrcPtr,llvm::Value * Size)77267330f729Sjoerg void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
77277330f729Sjoerg CodeGen::CodeGenFunction &CGF,
77287330f729Sjoerg Address DestPtr,
77297330f729Sjoerg Address SrcPtr,
77307330f729Sjoerg llvm::Value *Size) {
77317330f729Sjoerg SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
77327330f729Sjoerg DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
77337330f729Sjoerg llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), Size };
77347330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
77357330f729Sjoerg }
77367330f729Sjoerg
77377330f729Sjoerg /// EmitObjCWeakRead - Code gen for loading value of a __weak
77387330f729Sjoerg /// object: objc_read_weak (id *src)
77397330f729Sjoerg ///
EmitObjCWeakRead(CodeGen::CodeGenFunction & CGF,Address AddrWeakObj)77407330f729Sjoerg llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
77417330f729Sjoerg CodeGen::CodeGenFunction &CGF,
77427330f729Sjoerg Address AddrWeakObj) {
77437330f729Sjoerg llvm::Type *DestTy = AddrWeakObj.getElementType();
77447330f729Sjoerg AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
77457330f729Sjoerg llvm::Value *read_weak =
77467330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
77477330f729Sjoerg AddrWeakObj.getPointer(), "weakread");
77487330f729Sjoerg read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
77497330f729Sjoerg return read_weak;
77507330f729Sjoerg }
77517330f729Sjoerg
77527330f729Sjoerg /// EmitObjCWeakAssign - Code gen for assigning to a __weak object.
77537330f729Sjoerg /// objc_assign_weak (id src, id *dst)
77547330f729Sjoerg ///
EmitObjCWeakAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst)77557330f729Sjoerg void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
77567330f729Sjoerg llvm::Value *src, Address dst) {
77577330f729Sjoerg llvm::Type * SrcTy = src->getType();
77587330f729Sjoerg if (!isa<llvm::PointerType>(SrcTy)) {
77597330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
77607330f729Sjoerg assert(Size <= 8 && "does not support size > 8");
77617330f729Sjoerg src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
77627330f729Sjoerg : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
77637330f729Sjoerg src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
77647330f729Sjoerg }
77657330f729Sjoerg src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
77667330f729Sjoerg dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
77677330f729Sjoerg llvm::Value *args[] = { src, dst.getPointer() };
77687330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
77697330f729Sjoerg args, "weakassign");
77707330f729Sjoerg }
77717330f729Sjoerg
77727330f729Sjoerg /// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
77737330f729Sjoerg /// objc_assign_global (id src, id *dst)
77747330f729Sjoerg ///
EmitObjCGlobalAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst,bool threadlocal)77757330f729Sjoerg void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
77767330f729Sjoerg llvm::Value *src, Address dst,
77777330f729Sjoerg bool threadlocal) {
77787330f729Sjoerg llvm::Type * SrcTy = src->getType();
77797330f729Sjoerg if (!isa<llvm::PointerType>(SrcTy)) {
77807330f729Sjoerg unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
77817330f729Sjoerg assert(Size <= 8 && "does not support size > 8");
77827330f729Sjoerg src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
77837330f729Sjoerg : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
77847330f729Sjoerg src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
77857330f729Sjoerg }
77867330f729Sjoerg src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
77877330f729Sjoerg dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
77887330f729Sjoerg llvm::Value *args[] = { src, dst.getPointer() };
77897330f729Sjoerg if (!threadlocal)
77907330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
77917330f729Sjoerg args, "globalassign");
77927330f729Sjoerg else
77937330f729Sjoerg CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
77947330f729Sjoerg args, "threadlocalassign");
77957330f729Sjoerg }
77967330f729Sjoerg
77977330f729Sjoerg void
EmitSynchronizedStmt(CodeGen::CodeGenFunction & CGF,const ObjCAtSynchronizedStmt & S)77987330f729Sjoerg CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
77997330f729Sjoerg const ObjCAtSynchronizedStmt &S) {
78007330f729Sjoerg EmitAtSynchronizedStmt(CGF, S, ObjCTypes.getSyncEnterFn(),
78017330f729Sjoerg ObjCTypes.getSyncExitFn());
78027330f729Sjoerg }
78037330f729Sjoerg
78047330f729Sjoerg llvm::Constant *
GetEHType(QualType T)78057330f729Sjoerg CGObjCNonFragileABIMac::GetEHType(QualType T) {
78067330f729Sjoerg // There's a particular fixed type info for 'id'.
78077330f729Sjoerg if (T->isObjCIdType() || T->isObjCQualifiedIdType()) {
78087330f729Sjoerg auto *IDEHType = CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
78097330f729Sjoerg if (!IDEHType) {
78107330f729Sjoerg IDEHType =
78117330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
78127330f729Sjoerg llvm::GlobalValue::ExternalLinkage, nullptr,
78137330f729Sjoerg "OBJC_EHTYPE_id");
78147330f729Sjoerg if (CGM.getTriple().isOSBinFormatCOFF())
78157330f729Sjoerg IDEHType->setDLLStorageClass(getStorage(CGM, "OBJC_EHTYPE_id"));
78167330f729Sjoerg }
78177330f729Sjoerg return IDEHType;
78187330f729Sjoerg }
78197330f729Sjoerg
78207330f729Sjoerg // All other types should be Objective-C interface pointer types.
78217330f729Sjoerg const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
78227330f729Sjoerg assert(PT && "Invalid @catch type.");
78237330f729Sjoerg
78247330f729Sjoerg const ObjCInterfaceType *IT = PT->getInterfaceType();
78257330f729Sjoerg assert(IT && "Invalid @catch type.");
78267330f729Sjoerg
78277330f729Sjoerg return GetInterfaceEHType(IT->getDecl(), NotForDefinition);
78287330f729Sjoerg }
78297330f729Sjoerg
EmitTryStmt(CodeGen::CodeGenFunction & CGF,const ObjCAtTryStmt & S)78307330f729Sjoerg void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
78317330f729Sjoerg const ObjCAtTryStmt &S) {
78327330f729Sjoerg EmitTryCatchStmt(CGF, S, ObjCTypes.getObjCBeginCatchFn(),
78337330f729Sjoerg ObjCTypes.getObjCEndCatchFn(),
78347330f729Sjoerg ObjCTypes.getExceptionRethrowFn());
78357330f729Sjoerg }
78367330f729Sjoerg
78377330f729Sjoerg /// EmitThrowStmt - Generate code for a throw statement.
EmitThrowStmt(CodeGen::CodeGenFunction & CGF,const ObjCAtThrowStmt & S,bool ClearInsertionPoint)78387330f729Sjoerg void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
78397330f729Sjoerg const ObjCAtThrowStmt &S,
78407330f729Sjoerg bool ClearInsertionPoint) {
78417330f729Sjoerg if (const Expr *ThrowExpr = S.getThrowExpr()) {
78427330f729Sjoerg llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
78437330f729Sjoerg Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
78447330f729Sjoerg llvm::CallBase *Call =
78457330f729Sjoerg CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception);
78467330f729Sjoerg Call->setDoesNotReturn();
78477330f729Sjoerg } else {
78487330f729Sjoerg llvm::CallBase *Call =
78497330f729Sjoerg CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionRethrowFn());
78507330f729Sjoerg Call->setDoesNotReturn();
78517330f729Sjoerg }
78527330f729Sjoerg
78537330f729Sjoerg CGF.Builder.CreateUnreachable();
78547330f729Sjoerg if (ClearInsertionPoint)
78557330f729Sjoerg CGF.Builder.ClearInsertionPoint();
78567330f729Sjoerg }
78577330f729Sjoerg
78587330f729Sjoerg llvm::Constant *
GetInterfaceEHType(const ObjCInterfaceDecl * ID,ForDefinition_t IsForDefinition)78597330f729Sjoerg CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
78607330f729Sjoerg ForDefinition_t IsForDefinition) {
78617330f729Sjoerg llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()];
78627330f729Sjoerg StringRef ClassName = ID->getObjCRuntimeNameAsString();
78637330f729Sjoerg
78647330f729Sjoerg // If we don't need a definition, return the entry if found or check
78657330f729Sjoerg // if we use an external reference.
78667330f729Sjoerg if (!IsForDefinition) {
78677330f729Sjoerg if (Entry)
78687330f729Sjoerg return Entry;
78697330f729Sjoerg
78707330f729Sjoerg // If this type (or a super class) has the __objc_exception__
78717330f729Sjoerg // attribute, emit an external reference.
78727330f729Sjoerg if (hasObjCExceptionAttribute(CGM.getContext(), ID)) {
78737330f729Sjoerg std::string EHTypeName = ("OBJC_EHTYPE_$_" + ClassName).str();
78747330f729Sjoerg Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
78757330f729Sjoerg false, llvm::GlobalValue::ExternalLinkage,
78767330f729Sjoerg nullptr, EHTypeName);
78777330f729Sjoerg CGM.setGVProperties(Entry, ID);
78787330f729Sjoerg return Entry;
78797330f729Sjoerg }
78807330f729Sjoerg }
78817330f729Sjoerg
78827330f729Sjoerg // Otherwise we need to either make a new entry or fill in the initializer.
78837330f729Sjoerg assert((!Entry || !Entry->hasInitializer()) && "Duplicate EHType definition");
78847330f729Sjoerg
78857330f729Sjoerg std::string VTableName = "objc_ehtype_vtable";
78867330f729Sjoerg auto *VTableGV = CGM.getModule().getGlobalVariable(VTableName);
78877330f729Sjoerg if (!VTableGV) {
78887330f729Sjoerg VTableGV =
78897330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.Int8PtrTy, false,
78907330f729Sjoerg llvm::GlobalValue::ExternalLinkage, nullptr,
78917330f729Sjoerg VTableName);
78927330f729Sjoerg if (CGM.getTriple().isOSBinFormatCOFF())
78937330f729Sjoerg VTableGV->setDLLStorageClass(getStorage(CGM, VTableName));
78947330f729Sjoerg }
78957330f729Sjoerg
78967330f729Sjoerg llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
78977330f729Sjoerg ConstantInitBuilder builder(CGM);
78987330f729Sjoerg auto values = builder.beginStruct(ObjCTypes.EHTypeTy);
78997330f729Sjoerg values.add(
79007330f729Sjoerg llvm::ConstantExpr::getInBoundsGetElementPtr(VTableGV->getValueType(),
79017330f729Sjoerg VTableGV, VTableIdx));
79027330f729Sjoerg values.add(GetClassName(ClassName));
79037330f729Sjoerg values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition));
79047330f729Sjoerg
79057330f729Sjoerg llvm::GlobalValue::LinkageTypes L = IsForDefinition
79067330f729Sjoerg ? llvm::GlobalValue::ExternalLinkage
79077330f729Sjoerg : llvm::GlobalValue::WeakAnyLinkage;
79087330f729Sjoerg if (Entry) {
79097330f729Sjoerg values.finishAndSetAsInitializer(Entry);
79107330f729Sjoerg Entry->setAlignment(CGM.getPointerAlign().getAsAlign());
79117330f729Sjoerg } else {
79127330f729Sjoerg Entry = values.finishAndCreateGlobal("OBJC_EHTYPE_$_" + ClassName,
79137330f729Sjoerg CGM.getPointerAlign(),
79147330f729Sjoerg /*constant*/ false,
79157330f729Sjoerg L);
79167330f729Sjoerg if (hasObjCExceptionAttribute(CGM.getContext(), ID))
79177330f729Sjoerg CGM.setGVProperties(Entry, ID);
79187330f729Sjoerg }
79197330f729Sjoerg assert(Entry->getLinkage() == L);
79207330f729Sjoerg
79217330f729Sjoerg if (!CGM.getTriple().isOSBinFormatCOFF())
79227330f729Sjoerg if (ID->getVisibility() == HiddenVisibility)
79237330f729Sjoerg Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
79247330f729Sjoerg
79257330f729Sjoerg if (IsForDefinition)
79267330f729Sjoerg if (CGM.getTriple().isOSBinFormatMachO())
79277330f729Sjoerg Entry->setSection("__DATA,__objc_const");
79287330f729Sjoerg
79297330f729Sjoerg return Entry;
79307330f729Sjoerg }
79317330f729Sjoerg
79327330f729Sjoerg /* *** */
79337330f729Sjoerg
79347330f729Sjoerg CodeGen::CGObjCRuntime *
CreateMacObjCRuntime(CodeGen::CodeGenModule & CGM)79357330f729Sjoerg CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
79367330f729Sjoerg switch (CGM.getLangOpts().ObjCRuntime.getKind()) {
79377330f729Sjoerg case ObjCRuntime::FragileMacOSX:
79387330f729Sjoerg return new CGObjCMac(CGM);
79397330f729Sjoerg
79407330f729Sjoerg case ObjCRuntime::MacOSX:
79417330f729Sjoerg case ObjCRuntime::iOS:
79427330f729Sjoerg case ObjCRuntime::WatchOS:
79437330f729Sjoerg return new CGObjCNonFragileABIMac(CGM);
79447330f729Sjoerg
79457330f729Sjoerg case ObjCRuntime::GNUstep:
79467330f729Sjoerg case ObjCRuntime::GCC:
79477330f729Sjoerg case ObjCRuntime::ObjFW:
79487330f729Sjoerg llvm_unreachable("these runtimes are not Mac runtimes");
79497330f729Sjoerg }
79507330f729Sjoerg llvm_unreachable("bad runtime");
79517330f729Sjoerg }
7952