1e5dd7070Spatrick //===------- CGObjCMac.cpp - Interface to Apple Objective-C Runtime -------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This provides Objective-C code generation targeting the Apple runtime.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "CGBlocks.h"
14e5dd7070Spatrick #include "CGCleanup.h"
15e5dd7070Spatrick #include "CGObjCRuntime.h"
16e5dd7070Spatrick #include "CGRecordLayout.h"
17e5dd7070Spatrick #include "CodeGenFunction.h"
18e5dd7070Spatrick #include "CodeGenModule.h"
19e5dd7070Spatrick #include "clang/AST/ASTContext.h"
20e5dd7070Spatrick #include "clang/AST/Attr.h"
21e5dd7070Spatrick #include "clang/AST/Decl.h"
22e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
23a9ac8606Spatrick #include "clang/AST/Mangle.h"
24e5dd7070Spatrick #include "clang/AST/RecordLayout.h"
25e5dd7070Spatrick #include "clang/AST/StmtObjC.h"
26e5dd7070Spatrick #include "clang/Basic/CodeGenOptions.h"
27e5dd7070Spatrick #include "clang/Basic/LangOptions.h"
28e5dd7070Spatrick #include "clang/CodeGen/CGFunctionInfo.h"
29e5dd7070Spatrick #include "clang/CodeGen/ConstantInitBuilder.h"
30e5dd7070Spatrick #include "llvm/ADT/CachedHashString.h"
31e5dd7070Spatrick #include "llvm/ADT/DenseSet.h"
32e5dd7070Spatrick #include "llvm/ADT/SetVector.h"
33e5dd7070Spatrick #include "llvm/ADT/SmallPtrSet.h"
34e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
35a9ac8606Spatrick #include "llvm/ADT/UniqueVector.h"
36e5dd7070Spatrick #include "llvm/IR/DataLayout.h"
37e5dd7070Spatrick #include "llvm/IR/InlineAsm.h"
38e5dd7070Spatrick #include "llvm/IR/IntrinsicInst.h"
39e5dd7070Spatrick #include "llvm/IR/LLVMContext.h"
40e5dd7070Spatrick #include "llvm/IR/Module.h"
41e5dd7070Spatrick #include "llvm/Support/ScopedPrinter.h"
42e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
43e5dd7070Spatrick #include <cstdio>
44e5dd7070Spatrick
45e5dd7070Spatrick using namespace clang;
46e5dd7070Spatrick using namespace CodeGen;
47e5dd7070Spatrick
48e5dd7070Spatrick namespace {
49e5dd7070Spatrick
50e5dd7070Spatrick // FIXME: We should find a nicer way to make the labels for metadata, string
51e5dd7070Spatrick // concatenation is lame.
52e5dd7070Spatrick
53e5dd7070Spatrick class ObjCCommonTypesHelper {
54e5dd7070Spatrick protected:
55e5dd7070Spatrick llvm::LLVMContext &VMContext;
56e5dd7070Spatrick
57e5dd7070Spatrick private:
58e5dd7070Spatrick // The types of these functions don't really matter because we
59e5dd7070Spatrick // should always bitcast before calling them.
60e5dd7070Spatrick
61e5dd7070Spatrick /// id objc_msgSend (id, SEL, ...)
62e5dd7070Spatrick ///
63e5dd7070Spatrick /// The default messenger, used for sends whose ABI is unchanged from
64e5dd7070Spatrick /// the all-integer/pointer case.
getMessageSendFn() const65e5dd7070Spatrick llvm::FunctionCallee getMessageSendFn() const {
66e5dd7070Spatrick // Add the non-lazy-bind attribute, since objc_msgSend is likely to
67e5dd7070Spatrick // be called a lot.
68e5dd7070Spatrick llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
69e5dd7070Spatrick return CGM.CreateRuntimeFunction(
70e5dd7070Spatrick llvm::FunctionType::get(ObjectPtrTy, params, true), "objc_msgSend",
71e5dd7070Spatrick llvm::AttributeList::get(CGM.getLLVMContext(),
72e5dd7070Spatrick llvm::AttributeList::FunctionIndex,
73e5dd7070Spatrick llvm::Attribute::NonLazyBind));
74e5dd7070Spatrick }
75e5dd7070Spatrick
76e5dd7070Spatrick /// void objc_msgSend_stret (id, SEL, ...)
77e5dd7070Spatrick ///
78e5dd7070Spatrick /// The messenger used when the return value is an aggregate returned
79e5dd7070Spatrick /// by indirect reference in the first argument, and therefore the
80e5dd7070Spatrick /// self and selector parameters are shifted over by one.
getMessageSendStretFn() const81e5dd7070Spatrick llvm::FunctionCallee getMessageSendStretFn() const {
82e5dd7070Spatrick llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
83e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy,
84e5dd7070Spatrick params, true),
85e5dd7070Spatrick "objc_msgSend_stret");
86e5dd7070Spatrick }
87e5dd7070Spatrick
88e5dd7070Spatrick /// [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
89e5dd7070Spatrick ///
90e5dd7070Spatrick /// The messenger used when the return value is returned on the x87
91e5dd7070Spatrick /// floating-point stack; without a special entrypoint, the nil case
92e5dd7070Spatrick /// would be unbalanced.
getMessageSendFpretFn() const93e5dd7070Spatrick llvm::FunctionCallee getMessageSendFpretFn() const {
94e5dd7070Spatrick llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
95e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.DoubleTy,
96e5dd7070Spatrick params, true),
97e5dd7070Spatrick "objc_msgSend_fpret");
98e5dd7070Spatrick }
99e5dd7070Spatrick
100e5dd7070Spatrick /// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
101e5dd7070Spatrick ///
102e5dd7070Spatrick /// The messenger used when the return value is returned in two values on the
103e5dd7070Spatrick /// x87 floating point stack; without a special entrypoint, the nil case
104e5dd7070Spatrick /// would be unbalanced. Only used on 64-bit X86.
getMessageSendFp2retFn() const105e5dd7070Spatrick llvm::FunctionCallee getMessageSendFp2retFn() const {
106e5dd7070Spatrick llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
107e5dd7070Spatrick llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
108e5dd7070Spatrick llvm::Type *resultType =
109e5dd7070Spatrick llvm::StructType::get(longDoubleType, longDoubleType);
110e5dd7070Spatrick
111e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
112e5dd7070Spatrick params, true),
113e5dd7070Spatrick "objc_msgSend_fp2ret");
114e5dd7070Spatrick }
115e5dd7070Spatrick
116e5dd7070Spatrick /// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
117e5dd7070Spatrick ///
118e5dd7070Spatrick /// The messenger used for super calls, which have different dispatch
119e5dd7070Spatrick /// semantics. The class passed is the superclass of the current
120e5dd7070Spatrick /// class.
getMessageSendSuperFn() const121e5dd7070Spatrick llvm::FunctionCallee getMessageSendSuperFn() const {
122e5dd7070Spatrick llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
123e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
124e5dd7070Spatrick params, true),
125e5dd7070Spatrick "objc_msgSendSuper");
126e5dd7070Spatrick }
127e5dd7070Spatrick
128e5dd7070Spatrick /// id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
129e5dd7070Spatrick ///
130e5dd7070Spatrick /// A slightly different messenger used for super calls. The class
131e5dd7070Spatrick /// passed is the current class.
getMessageSendSuperFn2() const132e5dd7070Spatrick llvm::FunctionCallee getMessageSendSuperFn2() const {
133e5dd7070Spatrick llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
134e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
135e5dd7070Spatrick params, true),
136e5dd7070Spatrick "objc_msgSendSuper2");
137e5dd7070Spatrick }
138e5dd7070Spatrick
139e5dd7070Spatrick /// void objc_msgSendSuper_stret(void *stretAddr, struct objc_super *super,
140e5dd7070Spatrick /// SEL op, ...)
141e5dd7070Spatrick ///
142e5dd7070Spatrick /// The messenger used for super calls which return an aggregate indirectly.
getMessageSendSuperStretFn() const143e5dd7070Spatrick llvm::FunctionCallee getMessageSendSuperStretFn() const {
144e5dd7070Spatrick llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
145e5dd7070Spatrick return CGM.CreateRuntimeFunction(
146e5dd7070Spatrick llvm::FunctionType::get(CGM.VoidTy, params, true),
147e5dd7070Spatrick "objc_msgSendSuper_stret");
148e5dd7070Spatrick }
149e5dd7070Spatrick
150e5dd7070Spatrick /// void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
151e5dd7070Spatrick /// SEL op, ...)
152e5dd7070Spatrick ///
153e5dd7070Spatrick /// objc_msgSendSuper_stret with the super2 semantics.
getMessageSendSuperStretFn2() const154e5dd7070Spatrick llvm::FunctionCallee getMessageSendSuperStretFn2() const {
155e5dd7070Spatrick llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
156e5dd7070Spatrick return CGM.CreateRuntimeFunction(
157e5dd7070Spatrick llvm::FunctionType::get(CGM.VoidTy, params, true),
158e5dd7070Spatrick "objc_msgSendSuper2_stret");
159e5dd7070Spatrick }
160e5dd7070Spatrick
getMessageSendSuperFpretFn() const161e5dd7070Spatrick llvm::FunctionCallee getMessageSendSuperFpretFn() const {
162e5dd7070Spatrick // There is no objc_msgSendSuper_fpret? How can that work?
163e5dd7070Spatrick return getMessageSendSuperFn();
164e5dd7070Spatrick }
165e5dd7070Spatrick
getMessageSendSuperFpretFn2() const166e5dd7070Spatrick llvm::FunctionCallee getMessageSendSuperFpretFn2() const {
167e5dd7070Spatrick // There is no objc_msgSendSuper_fpret? How can that work?
168e5dd7070Spatrick return getMessageSendSuperFn2();
169e5dd7070Spatrick }
170e5dd7070Spatrick
171e5dd7070Spatrick protected:
172e5dd7070Spatrick CodeGen::CodeGenModule &CGM;
173e5dd7070Spatrick
174e5dd7070Spatrick public:
175e5dd7070Spatrick llvm::IntegerType *ShortTy, *IntTy, *LongTy;
176e5dd7070Spatrick llvm::PointerType *Int8PtrTy, *Int8PtrPtrTy;
177*12c85518Srobert llvm::PointerType *Int8PtrProgramASTy;
178e5dd7070Spatrick llvm::Type *IvarOffsetVarTy;
179e5dd7070Spatrick
180e5dd7070Spatrick /// ObjectPtrTy - LLVM type for object handles (typeof(id))
181e5dd7070Spatrick llvm::PointerType *ObjectPtrTy;
182e5dd7070Spatrick
183e5dd7070Spatrick /// PtrObjectPtrTy - LLVM type for id *
184e5dd7070Spatrick llvm::PointerType *PtrObjectPtrTy;
185e5dd7070Spatrick
186e5dd7070Spatrick /// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
187e5dd7070Spatrick llvm::PointerType *SelectorPtrTy;
188e5dd7070Spatrick
189e5dd7070Spatrick private:
190e5dd7070Spatrick /// ProtocolPtrTy - LLVM type for external protocol handles
191e5dd7070Spatrick /// (typeof(Protocol))
192e5dd7070Spatrick llvm::Type *ExternalProtocolPtrTy;
193e5dd7070Spatrick
194e5dd7070Spatrick public:
getExternalProtocolPtrTy()195e5dd7070Spatrick llvm::Type *getExternalProtocolPtrTy() {
196e5dd7070Spatrick if (!ExternalProtocolPtrTy) {
197e5dd7070Spatrick // FIXME: It would be nice to unify this with the opaque type, so that the
198e5dd7070Spatrick // IR comes out a bit cleaner.
199e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
200e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
201e5dd7070Spatrick llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
202e5dd7070Spatrick ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
203e5dd7070Spatrick }
204e5dd7070Spatrick
205e5dd7070Spatrick return ExternalProtocolPtrTy;
206e5dd7070Spatrick }
207e5dd7070Spatrick
208e5dd7070Spatrick // SuperCTy - clang type for struct objc_super.
209e5dd7070Spatrick QualType SuperCTy;
210e5dd7070Spatrick // SuperPtrCTy - clang type for struct objc_super *.
211e5dd7070Spatrick QualType SuperPtrCTy;
212e5dd7070Spatrick
213e5dd7070Spatrick /// SuperTy - LLVM type for struct objc_super.
214e5dd7070Spatrick llvm::StructType *SuperTy;
215e5dd7070Spatrick /// SuperPtrTy - LLVM type for struct objc_super *.
216e5dd7070Spatrick llvm::PointerType *SuperPtrTy;
217e5dd7070Spatrick
218e5dd7070Spatrick /// PropertyTy - LLVM type for struct objc_property (struct _prop_t
219e5dd7070Spatrick /// in GCC parlance).
220e5dd7070Spatrick llvm::StructType *PropertyTy;
221e5dd7070Spatrick
222e5dd7070Spatrick /// PropertyListTy - LLVM type for struct objc_property_list
223e5dd7070Spatrick /// (_prop_list_t in GCC parlance).
224e5dd7070Spatrick llvm::StructType *PropertyListTy;
225e5dd7070Spatrick /// PropertyListPtrTy - LLVM type for struct objc_property_list*.
226e5dd7070Spatrick llvm::PointerType *PropertyListPtrTy;
227e5dd7070Spatrick
228e5dd7070Spatrick // MethodTy - LLVM type for struct objc_method.
229e5dd7070Spatrick llvm::StructType *MethodTy;
230e5dd7070Spatrick
231e5dd7070Spatrick /// CacheTy - LLVM type for struct objc_cache.
232e5dd7070Spatrick llvm::Type *CacheTy;
233e5dd7070Spatrick /// CachePtrTy - LLVM type for struct objc_cache *.
234e5dd7070Spatrick llvm::PointerType *CachePtrTy;
235e5dd7070Spatrick
getGetPropertyFn()236e5dd7070Spatrick llvm::FunctionCallee getGetPropertyFn() {
237e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
238e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
239e5dd7070Spatrick // id objc_getProperty (id, SEL, ptrdiff_t, bool)
240e5dd7070Spatrick CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
241e5dd7070Spatrick CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
242e5dd7070Spatrick CanQualType Params[] = {
243e5dd7070Spatrick IdType, SelType,
244e5dd7070Spatrick Ctx.getPointerDiffType()->getCanonicalTypeUnqualified(), Ctx.BoolTy};
245e5dd7070Spatrick llvm::FunctionType *FTy =
246e5dd7070Spatrick Types.GetFunctionType(
247e5dd7070Spatrick Types.arrangeBuiltinFunctionDeclaration(IdType, Params));
248e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
249e5dd7070Spatrick }
250e5dd7070Spatrick
getSetPropertyFn()251e5dd7070Spatrick llvm::FunctionCallee getSetPropertyFn() {
252e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
253e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
254e5dd7070Spatrick // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
255e5dd7070Spatrick CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
256e5dd7070Spatrick CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
257e5dd7070Spatrick CanQualType Params[] = {
258e5dd7070Spatrick IdType,
259e5dd7070Spatrick SelType,
260e5dd7070Spatrick Ctx.getPointerDiffType()->getCanonicalTypeUnqualified(),
261e5dd7070Spatrick IdType,
262e5dd7070Spatrick Ctx.BoolTy,
263e5dd7070Spatrick Ctx.BoolTy};
264e5dd7070Spatrick llvm::FunctionType *FTy =
265e5dd7070Spatrick Types.GetFunctionType(
266e5dd7070Spatrick Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
267e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
268e5dd7070Spatrick }
269e5dd7070Spatrick
getOptimizedSetPropertyFn(bool atomic,bool copy)270e5dd7070Spatrick llvm::FunctionCallee getOptimizedSetPropertyFn(bool atomic, bool copy) {
271e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
272e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
273e5dd7070Spatrick // void objc_setProperty_atomic(id self, SEL _cmd,
274e5dd7070Spatrick // id newValue, ptrdiff_t offset);
275e5dd7070Spatrick // void objc_setProperty_nonatomic(id self, SEL _cmd,
276e5dd7070Spatrick // id newValue, ptrdiff_t offset);
277e5dd7070Spatrick // void objc_setProperty_atomic_copy(id self, SEL _cmd,
278e5dd7070Spatrick // id newValue, ptrdiff_t offset);
279e5dd7070Spatrick // void objc_setProperty_nonatomic_copy(id self, SEL _cmd,
280e5dd7070Spatrick // id newValue, ptrdiff_t offset);
281e5dd7070Spatrick
282e5dd7070Spatrick SmallVector<CanQualType,4> Params;
283e5dd7070Spatrick CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
284e5dd7070Spatrick CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
285e5dd7070Spatrick Params.push_back(IdType);
286e5dd7070Spatrick Params.push_back(SelType);
287e5dd7070Spatrick Params.push_back(IdType);
288e5dd7070Spatrick Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
289e5dd7070Spatrick llvm::FunctionType *FTy =
290e5dd7070Spatrick Types.GetFunctionType(
291e5dd7070Spatrick Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
292e5dd7070Spatrick const char *name;
293e5dd7070Spatrick if (atomic && copy)
294e5dd7070Spatrick name = "objc_setProperty_atomic_copy";
295e5dd7070Spatrick else if (atomic && !copy)
296e5dd7070Spatrick name = "objc_setProperty_atomic";
297e5dd7070Spatrick else if (!atomic && copy)
298e5dd7070Spatrick name = "objc_setProperty_nonatomic_copy";
299e5dd7070Spatrick else
300e5dd7070Spatrick name = "objc_setProperty_nonatomic";
301e5dd7070Spatrick
302e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, name);
303e5dd7070Spatrick }
304e5dd7070Spatrick
getCopyStructFn()305e5dd7070Spatrick llvm::FunctionCallee getCopyStructFn() {
306e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
307e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
308e5dd7070Spatrick // void objc_copyStruct (void *, const void *, size_t, bool, bool)
309e5dd7070Spatrick SmallVector<CanQualType,5> Params;
310e5dd7070Spatrick Params.push_back(Ctx.VoidPtrTy);
311e5dd7070Spatrick Params.push_back(Ctx.VoidPtrTy);
312e5dd7070Spatrick Params.push_back(Ctx.getSizeType());
313e5dd7070Spatrick Params.push_back(Ctx.BoolTy);
314e5dd7070Spatrick Params.push_back(Ctx.BoolTy);
315e5dd7070Spatrick llvm::FunctionType *FTy =
316e5dd7070Spatrick Types.GetFunctionType(
317e5dd7070Spatrick Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
318e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
319e5dd7070Spatrick }
320e5dd7070Spatrick
321e5dd7070Spatrick /// This routine declares and returns address of:
322e5dd7070Spatrick /// void objc_copyCppObjectAtomic(
323e5dd7070Spatrick /// void *dest, const void *src,
324e5dd7070Spatrick /// void (*copyHelper) (void *dest, const void *source));
getCppAtomicObjectFunction()325e5dd7070Spatrick llvm::FunctionCallee getCppAtomicObjectFunction() {
326e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
327e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
328e5dd7070Spatrick /// void objc_copyCppObjectAtomic(void *dest, const void *src, void *helper);
329e5dd7070Spatrick SmallVector<CanQualType,3> Params;
330e5dd7070Spatrick Params.push_back(Ctx.VoidPtrTy);
331e5dd7070Spatrick Params.push_back(Ctx.VoidPtrTy);
332e5dd7070Spatrick Params.push_back(Ctx.VoidPtrTy);
333e5dd7070Spatrick llvm::FunctionType *FTy =
334e5dd7070Spatrick Types.GetFunctionType(
335e5dd7070Spatrick Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
336e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
337e5dd7070Spatrick }
338e5dd7070Spatrick
getEnumerationMutationFn()339e5dd7070Spatrick llvm::FunctionCallee getEnumerationMutationFn() {
340e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
341e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
342e5dd7070Spatrick // void objc_enumerationMutation (id)
343e5dd7070Spatrick SmallVector<CanQualType,1> Params;
344e5dd7070Spatrick Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
345e5dd7070Spatrick llvm::FunctionType *FTy =
346e5dd7070Spatrick Types.GetFunctionType(
347e5dd7070Spatrick Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
348e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
349e5dd7070Spatrick }
350e5dd7070Spatrick
getLookUpClassFn()351e5dd7070Spatrick llvm::FunctionCallee getLookUpClassFn() {
352e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
353e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
354e5dd7070Spatrick // Class objc_lookUpClass (const char *)
355e5dd7070Spatrick SmallVector<CanQualType,1> Params;
356e5dd7070Spatrick Params.push_back(
357e5dd7070Spatrick Ctx.getCanonicalType(Ctx.getPointerType(Ctx.CharTy.withConst())));
358e5dd7070Spatrick llvm::FunctionType *FTy =
359e5dd7070Spatrick Types.GetFunctionType(Types.arrangeBuiltinFunctionDeclaration(
360e5dd7070Spatrick Ctx.getCanonicalType(Ctx.getObjCClassType()),
361e5dd7070Spatrick Params));
362e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_lookUpClass");
363e5dd7070Spatrick }
364e5dd7070Spatrick
365e5dd7070Spatrick /// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
getGcReadWeakFn()366e5dd7070Spatrick llvm::FunctionCallee getGcReadWeakFn() {
367e5dd7070Spatrick // id objc_read_weak (id *)
368e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
369e5dd7070Spatrick llvm::FunctionType *FTy =
370e5dd7070Spatrick llvm::FunctionType::get(ObjectPtrTy, args, false);
371e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
372e5dd7070Spatrick }
373e5dd7070Spatrick
374e5dd7070Spatrick /// GcAssignWeakFn -- LLVM objc_assign_weak function.
getGcAssignWeakFn()375e5dd7070Spatrick llvm::FunctionCallee getGcAssignWeakFn() {
376e5dd7070Spatrick // id objc_assign_weak (id, id *)
377e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
378e5dd7070Spatrick llvm::FunctionType *FTy =
379e5dd7070Spatrick llvm::FunctionType::get(ObjectPtrTy, args, false);
380e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
381e5dd7070Spatrick }
382e5dd7070Spatrick
383e5dd7070Spatrick /// GcAssignGlobalFn -- LLVM objc_assign_global function.
getGcAssignGlobalFn()384e5dd7070Spatrick llvm::FunctionCallee getGcAssignGlobalFn() {
385e5dd7070Spatrick // id objc_assign_global(id, id *)
386e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
387e5dd7070Spatrick llvm::FunctionType *FTy =
388e5dd7070Spatrick llvm::FunctionType::get(ObjectPtrTy, args, false);
389e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
390e5dd7070Spatrick }
391e5dd7070Spatrick
392e5dd7070Spatrick /// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function.
getGcAssignThreadLocalFn()393e5dd7070Spatrick llvm::FunctionCallee getGcAssignThreadLocalFn() {
394e5dd7070Spatrick // id objc_assign_threadlocal(id src, id * dest)
395e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
396e5dd7070Spatrick llvm::FunctionType *FTy =
397e5dd7070Spatrick llvm::FunctionType::get(ObjectPtrTy, args, false);
398e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
399e5dd7070Spatrick }
400e5dd7070Spatrick
401e5dd7070Spatrick /// GcAssignIvarFn -- LLVM objc_assign_ivar function.
getGcAssignIvarFn()402e5dd7070Spatrick llvm::FunctionCallee getGcAssignIvarFn() {
403e5dd7070Spatrick // id objc_assign_ivar(id, id *, ptrdiff_t)
404e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
405e5dd7070Spatrick CGM.PtrDiffTy };
406e5dd7070Spatrick llvm::FunctionType *FTy =
407e5dd7070Spatrick llvm::FunctionType::get(ObjectPtrTy, args, false);
408e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
409e5dd7070Spatrick }
410e5dd7070Spatrick
411e5dd7070Spatrick /// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function.
GcMemmoveCollectableFn()412e5dd7070Spatrick llvm::FunctionCallee GcMemmoveCollectableFn() {
413e5dd7070Spatrick // void *objc_memmove_collectable(void *dst, const void *src, size_t size)
414e5dd7070Spatrick llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
415e5dd7070Spatrick llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false);
416e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
417e5dd7070Spatrick }
418e5dd7070Spatrick
419e5dd7070Spatrick /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
getGcAssignStrongCastFn()420e5dd7070Spatrick llvm::FunctionCallee getGcAssignStrongCastFn() {
421e5dd7070Spatrick // id objc_assign_strongCast(id, id *)
422e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
423e5dd7070Spatrick llvm::FunctionType *FTy =
424e5dd7070Spatrick llvm::FunctionType::get(ObjectPtrTy, args, false);
425e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
426e5dd7070Spatrick }
427e5dd7070Spatrick
428e5dd7070Spatrick /// ExceptionThrowFn - LLVM objc_exception_throw function.
getExceptionThrowFn()429e5dd7070Spatrick llvm::FunctionCallee getExceptionThrowFn() {
430e5dd7070Spatrick // void objc_exception_throw(id)
431e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy };
432e5dd7070Spatrick llvm::FunctionType *FTy =
433e5dd7070Spatrick llvm::FunctionType::get(CGM.VoidTy, args, false);
434e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
435e5dd7070Spatrick }
436e5dd7070Spatrick
437e5dd7070Spatrick /// ExceptionRethrowFn - LLVM objc_exception_rethrow function.
getExceptionRethrowFn()438e5dd7070Spatrick llvm::FunctionCallee getExceptionRethrowFn() {
439e5dd7070Spatrick // void objc_exception_rethrow(void)
440e5dd7070Spatrick llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
441e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow");
442e5dd7070Spatrick }
443e5dd7070Spatrick
444e5dd7070Spatrick /// SyncEnterFn - LLVM object_sync_enter function.
getSyncEnterFn()445e5dd7070Spatrick llvm::FunctionCallee getSyncEnterFn() {
446e5dd7070Spatrick // int objc_sync_enter (id)
447e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy };
448e5dd7070Spatrick llvm::FunctionType *FTy =
449e5dd7070Spatrick llvm::FunctionType::get(CGM.IntTy, args, false);
450e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
451e5dd7070Spatrick }
452e5dd7070Spatrick
453e5dd7070Spatrick /// SyncExitFn - LLVM object_sync_exit function.
getSyncExitFn()454e5dd7070Spatrick llvm::FunctionCallee getSyncExitFn() {
455e5dd7070Spatrick // int objc_sync_exit (id)
456e5dd7070Spatrick llvm::Type *args[] = { ObjectPtrTy };
457e5dd7070Spatrick llvm::FunctionType *FTy =
458e5dd7070Spatrick llvm::FunctionType::get(CGM.IntTy, args, false);
459e5dd7070Spatrick return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
460e5dd7070Spatrick }
461e5dd7070Spatrick
getSendFn(bool IsSuper) const462e5dd7070Spatrick llvm::FunctionCallee getSendFn(bool IsSuper) const {
463e5dd7070Spatrick return IsSuper ? getMessageSendSuperFn() : getMessageSendFn();
464e5dd7070Spatrick }
465e5dd7070Spatrick
getSendFn2(bool IsSuper) const466e5dd7070Spatrick llvm::FunctionCallee getSendFn2(bool IsSuper) const {
467e5dd7070Spatrick return IsSuper ? getMessageSendSuperFn2() : getMessageSendFn();
468e5dd7070Spatrick }
469e5dd7070Spatrick
getSendStretFn(bool IsSuper) const470e5dd7070Spatrick llvm::FunctionCallee getSendStretFn(bool IsSuper) const {
471e5dd7070Spatrick return IsSuper ? getMessageSendSuperStretFn() : getMessageSendStretFn();
472e5dd7070Spatrick }
473e5dd7070Spatrick
getSendStretFn2(bool IsSuper) const474e5dd7070Spatrick llvm::FunctionCallee getSendStretFn2(bool IsSuper) const {
475e5dd7070Spatrick return IsSuper ? getMessageSendSuperStretFn2() : getMessageSendStretFn();
476e5dd7070Spatrick }
477e5dd7070Spatrick
getSendFpretFn(bool IsSuper) const478e5dd7070Spatrick llvm::FunctionCallee getSendFpretFn(bool IsSuper) const {
479e5dd7070Spatrick return IsSuper ? getMessageSendSuperFpretFn() : getMessageSendFpretFn();
480e5dd7070Spatrick }
481e5dd7070Spatrick
getSendFpretFn2(bool IsSuper) const482e5dd7070Spatrick llvm::FunctionCallee getSendFpretFn2(bool IsSuper) const {
483e5dd7070Spatrick return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn();
484e5dd7070Spatrick }
485e5dd7070Spatrick
getSendFp2retFn(bool IsSuper) const486e5dd7070Spatrick llvm::FunctionCallee getSendFp2retFn(bool IsSuper) const {
487e5dd7070Spatrick return IsSuper ? getMessageSendSuperFn() : getMessageSendFp2retFn();
488e5dd7070Spatrick }
489e5dd7070Spatrick
getSendFp2RetFn2(bool IsSuper) const490e5dd7070Spatrick llvm::FunctionCallee getSendFp2RetFn2(bool IsSuper) const {
491e5dd7070Spatrick return IsSuper ? getMessageSendSuperFn2() : getMessageSendFp2retFn();
492e5dd7070Spatrick }
493e5dd7070Spatrick
494e5dd7070Spatrick ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
495e5dd7070Spatrick };
496e5dd7070Spatrick
497e5dd7070Spatrick /// ObjCTypesHelper - Helper class that encapsulates lazy
498e5dd7070Spatrick /// construction of varies types used during ObjC generation.
499e5dd7070Spatrick class ObjCTypesHelper : public ObjCCommonTypesHelper {
500e5dd7070Spatrick public:
501e5dd7070Spatrick /// SymtabTy - LLVM type for struct objc_symtab.
502e5dd7070Spatrick llvm::StructType *SymtabTy;
503e5dd7070Spatrick /// SymtabPtrTy - LLVM type for struct objc_symtab *.
504e5dd7070Spatrick llvm::PointerType *SymtabPtrTy;
505e5dd7070Spatrick /// ModuleTy - LLVM type for struct objc_module.
506e5dd7070Spatrick llvm::StructType *ModuleTy;
507e5dd7070Spatrick
508e5dd7070Spatrick /// ProtocolTy - LLVM type for struct objc_protocol.
509e5dd7070Spatrick llvm::StructType *ProtocolTy;
510e5dd7070Spatrick /// ProtocolPtrTy - LLVM type for struct objc_protocol *.
511e5dd7070Spatrick llvm::PointerType *ProtocolPtrTy;
512e5dd7070Spatrick /// ProtocolExtensionTy - LLVM type for struct
513e5dd7070Spatrick /// objc_protocol_extension.
514e5dd7070Spatrick llvm::StructType *ProtocolExtensionTy;
515e5dd7070Spatrick /// ProtocolExtensionTy - LLVM type for struct
516e5dd7070Spatrick /// objc_protocol_extension *.
517e5dd7070Spatrick llvm::PointerType *ProtocolExtensionPtrTy;
518e5dd7070Spatrick /// MethodDescriptionTy - LLVM type for struct
519e5dd7070Spatrick /// objc_method_description.
520e5dd7070Spatrick llvm::StructType *MethodDescriptionTy;
521e5dd7070Spatrick /// MethodDescriptionListTy - LLVM type for struct
522e5dd7070Spatrick /// objc_method_description_list.
523e5dd7070Spatrick llvm::StructType *MethodDescriptionListTy;
524e5dd7070Spatrick /// MethodDescriptionListPtrTy - LLVM type for struct
525e5dd7070Spatrick /// objc_method_description_list *.
526e5dd7070Spatrick llvm::PointerType *MethodDescriptionListPtrTy;
527e5dd7070Spatrick /// ProtocolListTy - LLVM type for struct objc_property_list.
528e5dd7070Spatrick llvm::StructType *ProtocolListTy;
529e5dd7070Spatrick /// ProtocolListPtrTy - LLVM type for struct objc_property_list*.
530e5dd7070Spatrick llvm::PointerType *ProtocolListPtrTy;
531e5dd7070Spatrick /// CategoryTy - LLVM type for struct objc_category.
532e5dd7070Spatrick llvm::StructType *CategoryTy;
533e5dd7070Spatrick /// ClassTy - LLVM type for struct objc_class.
534e5dd7070Spatrick llvm::StructType *ClassTy;
535e5dd7070Spatrick /// ClassPtrTy - LLVM type for struct objc_class *.
536e5dd7070Spatrick llvm::PointerType *ClassPtrTy;
537e5dd7070Spatrick /// ClassExtensionTy - LLVM type for struct objc_class_ext.
538e5dd7070Spatrick llvm::StructType *ClassExtensionTy;
539e5dd7070Spatrick /// ClassExtensionPtrTy - LLVM type for struct objc_class_ext *.
540e5dd7070Spatrick llvm::PointerType *ClassExtensionPtrTy;
541e5dd7070Spatrick // IvarTy - LLVM type for struct objc_ivar.
542e5dd7070Spatrick llvm::StructType *IvarTy;
543e5dd7070Spatrick /// IvarListTy - LLVM type for struct objc_ivar_list.
544e5dd7070Spatrick llvm::StructType *IvarListTy;
545e5dd7070Spatrick /// IvarListPtrTy - LLVM type for struct objc_ivar_list *.
546e5dd7070Spatrick llvm::PointerType *IvarListPtrTy;
547e5dd7070Spatrick /// MethodListTy - LLVM type for struct objc_method_list.
548e5dd7070Spatrick llvm::StructType *MethodListTy;
549e5dd7070Spatrick /// MethodListPtrTy - LLVM type for struct objc_method_list *.
550e5dd7070Spatrick llvm::PointerType *MethodListPtrTy;
551e5dd7070Spatrick
552e5dd7070Spatrick /// ExceptionDataTy - LLVM type for struct _objc_exception_data.
553e5dd7070Spatrick llvm::StructType *ExceptionDataTy;
554e5dd7070Spatrick
555e5dd7070Spatrick /// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
getExceptionTryEnterFn()556e5dd7070Spatrick llvm::FunctionCallee getExceptionTryEnterFn() {
557e5dd7070Spatrick llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
558e5dd7070Spatrick return CGM.CreateRuntimeFunction(
559e5dd7070Spatrick llvm::FunctionType::get(CGM.VoidTy, params, false),
560e5dd7070Spatrick "objc_exception_try_enter");
561e5dd7070Spatrick }
562e5dd7070Spatrick
563e5dd7070Spatrick /// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
getExceptionTryExitFn()564e5dd7070Spatrick llvm::FunctionCallee getExceptionTryExitFn() {
565e5dd7070Spatrick llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
566e5dd7070Spatrick return CGM.CreateRuntimeFunction(
567e5dd7070Spatrick llvm::FunctionType::get(CGM.VoidTy, params, false),
568e5dd7070Spatrick "objc_exception_try_exit");
569e5dd7070Spatrick }
570e5dd7070Spatrick
571e5dd7070Spatrick /// ExceptionExtractFn - LLVM objc_exception_extract function.
getExceptionExtractFn()572e5dd7070Spatrick llvm::FunctionCallee getExceptionExtractFn() {
573e5dd7070Spatrick llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
574e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
575e5dd7070Spatrick params, false),
576e5dd7070Spatrick "objc_exception_extract");
577e5dd7070Spatrick }
578e5dd7070Spatrick
579e5dd7070Spatrick /// ExceptionMatchFn - LLVM objc_exception_match function.
getExceptionMatchFn()580e5dd7070Spatrick llvm::FunctionCallee getExceptionMatchFn() {
581e5dd7070Spatrick llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
582e5dd7070Spatrick return CGM.CreateRuntimeFunction(
583e5dd7070Spatrick llvm::FunctionType::get(CGM.Int32Ty, params, false),
584e5dd7070Spatrick "objc_exception_match");
585e5dd7070Spatrick }
586e5dd7070Spatrick
587e5dd7070Spatrick /// SetJmpFn - LLVM _setjmp function.
getSetJmpFn()588e5dd7070Spatrick llvm::FunctionCallee getSetJmpFn() {
589e5dd7070Spatrick // This is specifically the prototype for x86.
590e5dd7070Spatrick llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
591e5dd7070Spatrick return CGM.CreateRuntimeFunction(
592e5dd7070Spatrick llvm::FunctionType::get(CGM.Int32Ty, params, false), "_setjmp",
593e5dd7070Spatrick llvm::AttributeList::get(CGM.getLLVMContext(),
594e5dd7070Spatrick llvm::AttributeList::FunctionIndex,
595e5dd7070Spatrick llvm::Attribute::NonLazyBind));
596e5dd7070Spatrick }
597e5dd7070Spatrick
598e5dd7070Spatrick public:
599e5dd7070Spatrick ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
600e5dd7070Spatrick };
601e5dd7070Spatrick
602e5dd7070Spatrick /// ObjCNonFragileABITypesHelper - will have all types needed by objective-c's
603e5dd7070Spatrick /// modern abi
604e5dd7070Spatrick class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper {
605e5dd7070Spatrick public:
606e5dd7070Spatrick // MethodListnfABITy - LLVM for struct _method_list_t
607e5dd7070Spatrick llvm::StructType *MethodListnfABITy;
608e5dd7070Spatrick
609e5dd7070Spatrick // MethodListnfABIPtrTy - LLVM for struct _method_list_t*
610e5dd7070Spatrick llvm::PointerType *MethodListnfABIPtrTy;
611e5dd7070Spatrick
612e5dd7070Spatrick // ProtocolnfABITy = LLVM for struct _protocol_t
613e5dd7070Spatrick llvm::StructType *ProtocolnfABITy;
614e5dd7070Spatrick
615e5dd7070Spatrick // ProtocolnfABIPtrTy = LLVM for struct _protocol_t*
616e5dd7070Spatrick llvm::PointerType *ProtocolnfABIPtrTy;
617e5dd7070Spatrick
618e5dd7070Spatrick // ProtocolListnfABITy - LLVM for struct _objc_protocol_list
619e5dd7070Spatrick llvm::StructType *ProtocolListnfABITy;
620e5dd7070Spatrick
621e5dd7070Spatrick // ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list*
622e5dd7070Spatrick llvm::PointerType *ProtocolListnfABIPtrTy;
623e5dd7070Spatrick
624e5dd7070Spatrick // ClassnfABITy - LLVM for struct _class_t
625e5dd7070Spatrick llvm::StructType *ClassnfABITy;
626e5dd7070Spatrick
627e5dd7070Spatrick // ClassnfABIPtrTy - LLVM for struct _class_t*
628e5dd7070Spatrick llvm::PointerType *ClassnfABIPtrTy;
629e5dd7070Spatrick
630e5dd7070Spatrick // IvarnfABITy - LLVM for struct _ivar_t
631e5dd7070Spatrick llvm::StructType *IvarnfABITy;
632e5dd7070Spatrick
633e5dd7070Spatrick // IvarListnfABITy - LLVM for struct _ivar_list_t
634e5dd7070Spatrick llvm::StructType *IvarListnfABITy;
635e5dd7070Spatrick
636e5dd7070Spatrick // IvarListnfABIPtrTy = LLVM for struct _ivar_list_t*
637e5dd7070Spatrick llvm::PointerType *IvarListnfABIPtrTy;
638e5dd7070Spatrick
639e5dd7070Spatrick // ClassRonfABITy - LLVM for struct _class_ro_t
640e5dd7070Spatrick llvm::StructType *ClassRonfABITy;
641e5dd7070Spatrick
642e5dd7070Spatrick // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
643e5dd7070Spatrick llvm::PointerType *ImpnfABITy;
644e5dd7070Spatrick
645e5dd7070Spatrick // CategorynfABITy - LLVM for struct _category_t
646e5dd7070Spatrick llvm::StructType *CategorynfABITy;
647e5dd7070Spatrick
648e5dd7070Spatrick // New types for nonfragile abi messaging.
649e5dd7070Spatrick
650e5dd7070Spatrick // MessageRefTy - LLVM for:
651e5dd7070Spatrick // struct _message_ref_t {
652e5dd7070Spatrick // IMP messenger;
653e5dd7070Spatrick // SEL name;
654e5dd7070Spatrick // };
655e5dd7070Spatrick llvm::StructType *MessageRefTy;
656e5dd7070Spatrick // MessageRefCTy - clang type for struct _message_ref_t
657e5dd7070Spatrick QualType MessageRefCTy;
658e5dd7070Spatrick
659e5dd7070Spatrick // MessageRefPtrTy - LLVM for struct _message_ref_t*
660e5dd7070Spatrick llvm::Type *MessageRefPtrTy;
661e5dd7070Spatrick // MessageRefCPtrTy - clang type for struct _message_ref_t*
662e5dd7070Spatrick QualType MessageRefCPtrTy;
663e5dd7070Spatrick
664e5dd7070Spatrick // SuperMessageRefTy - LLVM for:
665e5dd7070Spatrick // struct _super_message_ref_t {
666e5dd7070Spatrick // SUPER_IMP messenger;
667e5dd7070Spatrick // SEL name;
668e5dd7070Spatrick // };
669e5dd7070Spatrick llvm::StructType *SuperMessageRefTy;
670e5dd7070Spatrick
671e5dd7070Spatrick // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
672e5dd7070Spatrick llvm::PointerType *SuperMessageRefPtrTy;
673e5dd7070Spatrick
getMessageSendFixupFn()674e5dd7070Spatrick llvm::FunctionCallee getMessageSendFixupFn() {
675e5dd7070Spatrick // id objc_msgSend_fixup(id, struct message_ref_t*, ...)
676e5dd7070Spatrick llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
677e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
678e5dd7070Spatrick params, true),
679e5dd7070Spatrick "objc_msgSend_fixup");
680e5dd7070Spatrick }
681e5dd7070Spatrick
getMessageSendFpretFixupFn()682e5dd7070Spatrick llvm::FunctionCallee getMessageSendFpretFixupFn() {
683e5dd7070Spatrick // id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
684e5dd7070Spatrick llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
685e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
686e5dd7070Spatrick params, true),
687e5dd7070Spatrick "objc_msgSend_fpret_fixup");
688e5dd7070Spatrick }
689e5dd7070Spatrick
getMessageSendStretFixupFn()690e5dd7070Spatrick llvm::FunctionCallee getMessageSendStretFixupFn() {
691e5dd7070Spatrick // id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...)
692e5dd7070Spatrick llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
693e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
694e5dd7070Spatrick params, true),
695e5dd7070Spatrick "objc_msgSend_stret_fixup");
696e5dd7070Spatrick }
697e5dd7070Spatrick
getMessageSendSuper2FixupFn()698e5dd7070Spatrick llvm::FunctionCallee getMessageSendSuper2FixupFn() {
699e5dd7070Spatrick // id objc_msgSendSuper2_fixup (struct objc_super *,
700e5dd7070Spatrick // struct _super_message_ref_t*, ...)
701e5dd7070Spatrick llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
702e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
703e5dd7070Spatrick params, true),
704e5dd7070Spatrick "objc_msgSendSuper2_fixup");
705e5dd7070Spatrick }
706e5dd7070Spatrick
getMessageSendSuper2StretFixupFn()707e5dd7070Spatrick llvm::FunctionCallee getMessageSendSuper2StretFixupFn() {
708e5dd7070Spatrick // id objc_msgSendSuper2_stret_fixup(struct objc_super *,
709e5dd7070Spatrick // struct _super_message_ref_t*, ...)
710e5dd7070Spatrick llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
711e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
712e5dd7070Spatrick params, true),
713e5dd7070Spatrick "objc_msgSendSuper2_stret_fixup");
714e5dd7070Spatrick }
715e5dd7070Spatrick
getObjCEndCatchFn()716e5dd7070Spatrick llvm::FunctionCallee getObjCEndCatchFn() {
717e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy, false),
718e5dd7070Spatrick "objc_end_catch");
719e5dd7070Spatrick }
720e5dd7070Spatrick
getObjCBeginCatchFn()721e5dd7070Spatrick llvm::FunctionCallee getObjCBeginCatchFn() {
722e5dd7070Spatrick llvm::Type *params[] = { Int8PtrTy };
723e5dd7070Spatrick return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy,
724e5dd7070Spatrick params, false),
725e5dd7070Spatrick "objc_begin_catch");
726e5dd7070Spatrick }
727e5dd7070Spatrick
728e5dd7070Spatrick /// Class objc_loadClassref (void *)
729e5dd7070Spatrick ///
730e5dd7070Spatrick /// Loads from a classref. For Objective-C stub classes, this invokes the
731e5dd7070Spatrick /// initialization callback stored inside the stub. For all other classes
732e5dd7070Spatrick /// this simply dereferences the pointer.
getLoadClassrefFn() const733e5dd7070Spatrick llvm::FunctionCallee getLoadClassrefFn() const {
734e5dd7070Spatrick // Add the non-lazy-bind attribute, since objc_loadClassref is likely to
735e5dd7070Spatrick // be called a lot.
736e5dd7070Spatrick //
737e5dd7070Spatrick // Also it is safe to make it readnone, since we never load or store the
738e5dd7070Spatrick // classref except by calling this function.
739e5dd7070Spatrick llvm::Type *params[] = { Int8PtrPtrTy };
740*12c85518Srobert llvm::LLVMContext &C = CGM.getLLVMContext();
741*12c85518Srobert llvm::AttributeSet AS = llvm::AttributeSet::get(C, {
742*12c85518Srobert llvm::Attribute::get(C, llvm::Attribute::NonLazyBind),
743*12c85518Srobert llvm::Attribute::getWithMemoryEffects(C, llvm::MemoryEffects::none()),
744*12c85518Srobert llvm::Attribute::get(C, llvm::Attribute::NoUnwind),
745*12c85518Srobert });
746e5dd7070Spatrick llvm::FunctionCallee F = CGM.CreateRuntimeFunction(
747e5dd7070Spatrick llvm::FunctionType::get(ClassnfABIPtrTy, params, false),
748e5dd7070Spatrick "objc_loadClassref",
749e5dd7070Spatrick llvm::AttributeList::get(CGM.getLLVMContext(),
750*12c85518Srobert llvm::AttributeList::FunctionIndex, AS));
751e5dd7070Spatrick if (!CGM.getTriple().isOSBinFormatCOFF())
752e5dd7070Spatrick cast<llvm::Function>(F.getCallee())->setLinkage(
753e5dd7070Spatrick llvm::Function::ExternalWeakLinkage);
754e5dd7070Spatrick
755e5dd7070Spatrick return F;
756e5dd7070Spatrick }
757e5dd7070Spatrick
758e5dd7070Spatrick llvm::StructType *EHTypeTy;
759e5dd7070Spatrick llvm::Type *EHTypePtrTy;
760e5dd7070Spatrick
761e5dd7070Spatrick ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
762e5dd7070Spatrick };
763e5dd7070Spatrick
764e5dd7070Spatrick enum class ObjCLabelType {
765e5dd7070Spatrick ClassName,
766e5dd7070Spatrick MethodVarName,
767e5dd7070Spatrick MethodVarType,
768e5dd7070Spatrick PropertyName,
769e5dd7070Spatrick };
770e5dd7070Spatrick
771e5dd7070Spatrick class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
772e5dd7070Spatrick public:
773e5dd7070Spatrick class SKIP_SCAN {
774e5dd7070Spatrick public:
775e5dd7070Spatrick unsigned skip;
776e5dd7070Spatrick unsigned scan;
SKIP_SCAN(unsigned _skip=0,unsigned _scan=0)777e5dd7070Spatrick SKIP_SCAN(unsigned _skip = 0, unsigned _scan = 0)
778e5dd7070Spatrick : skip(_skip), scan(_scan) {}
779e5dd7070Spatrick };
780e5dd7070Spatrick
781e5dd7070Spatrick /// opcode for captured block variables layout 'instructions'.
782e5dd7070Spatrick /// In the following descriptions, 'I' is the value of the immediate field.
783e5dd7070Spatrick /// (field following the opcode).
784e5dd7070Spatrick ///
785e5dd7070Spatrick enum BLOCK_LAYOUT_OPCODE {
786e5dd7070Spatrick /// An operator which affects how the following layout should be
787e5dd7070Spatrick /// interpreted.
788e5dd7070Spatrick /// I == 0: Halt interpretation and treat everything else as
789e5dd7070Spatrick /// a non-pointer. Note that this instruction is equal
790e5dd7070Spatrick /// to '\0'.
791e5dd7070Spatrick /// I != 0: Currently unused.
792e5dd7070Spatrick BLOCK_LAYOUT_OPERATOR = 0,
793e5dd7070Spatrick
794e5dd7070Spatrick /// The next I+1 bytes do not contain a value of object pointer type.
795e5dd7070Spatrick /// Note that this can leave the stream unaligned, meaning that
796e5dd7070Spatrick /// subsequent word-size instructions do not begin at a multiple of
797e5dd7070Spatrick /// the pointer size.
798e5dd7070Spatrick BLOCK_LAYOUT_NON_OBJECT_BYTES = 1,
799e5dd7070Spatrick
800e5dd7070Spatrick /// The next I+1 words do not contain a value of object pointer type.
801e5dd7070Spatrick /// This is simply an optimized version of BLOCK_LAYOUT_BYTES for
802e5dd7070Spatrick /// when the required skip quantity is a multiple of the pointer size.
803e5dd7070Spatrick BLOCK_LAYOUT_NON_OBJECT_WORDS = 2,
804e5dd7070Spatrick
805e5dd7070Spatrick /// The next I+1 words are __strong pointers to Objective-C
806e5dd7070Spatrick /// objects or blocks.
807e5dd7070Spatrick BLOCK_LAYOUT_STRONG = 3,
808e5dd7070Spatrick
809e5dd7070Spatrick /// The next I+1 words are pointers to __block variables.
810e5dd7070Spatrick BLOCK_LAYOUT_BYREF = 4,
811e5dd7070Spatrick
812e5dd7070Spatrick /// The next I+1 words are __weak pointers to Objective-C
813e5dd7070Spatrick /// objects or blocks.
814e5dd7070Spatrick BLOCK_LAYOUT_WEAK = 5,
815e5dd7070Spatrick
816e5dd7070Spatrick /// The next I+1 words are __unsafe_unretained pointers to
817e5dd7070Spatrick /// Objective-C objects or blocks.
818e5dd7070Spatrick BLOCK_LAYOUT_UNRETAINED = 6
819e5dd7070Spatrick
820e5dd7070Spatrick /// The next I+1 words are block or object pointers with some
821e5dd7070Spatrick /// as-yet-unspecified ownership semantics. If we add more
822e5dd7070Spatrick /// flavors of ownership semantics, values will be taken from
823e5dd7070Spatrick /// this range.
824e5dd7070Spatrick ///
825e5dd7070Spatrick /// This is included so that older tools can at least continue
826e5dd7070Spatrick /// processing the layout past such things.
827e5dd7070Spatrick //BLOCK_LAYOUT_OWNERSHIP_UNKNOWN = 7..10,
828e5dd7070Spatrick
829e5dd7070Spatrick /// All other opcodes are reserved. Halt interpretation and
830e5dd7070Spatrick /// treat everything else as opaque.
831e5dd7070Spatrick };
832e5dd7070Spatrick
833e5dd7070Spatrick class RUN_SKIP {
834e5dd7070Spatrick public:
835e5dd7070Spatrick enum BLOCK_LAYOUT_OPCODE opcode;
836e5dd7070Spatrick CharUnits block_var_bytepos;
837e5dd7070Spatrick CharUnits block_var_size;
RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode=BLOCK_LAYOUT_OPERATOR,CharUnits BytePos=CharUnits::Zero (),CharUnits Size=CharUnits::Zero ())838e5dd7070Spatrick RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode = BLOCK_LAYOUT_OPERATOR,
839e5dd7070Spatrick CharUnits BytePos = CharUnits::Zero(),
840e5dd7070Spatrick CharUnits Size = CharUnits::Zero())
841e5dd7070Spatrick : opcode(Opcode), block_var_bytepos(BytePos), block_var_size(Size) {}
842e5dd7070Spatrick
843e5dd7070Spatrick // Allow sorting based on byte pos.
operator <(const RUN_SKIP & b) const844e5dd7070Spatrick bool operator<(const RUN_SKIP &b) const {
845e5dd7070Spatrick return block_var_bytepos < b.block_var_bytepos;
846e5dd7070Spatrick }
847e5dd7070Spatrick };
848e5dd7070Spatrick
849e5dd7070Spatrick protected:
850e5dd7070Spatrick llvm::LLVMContext &VMContext;
851e5dd7070Spatrick // FIXME! May not be needing this after all.
852e5dd7070Spatrick unsigned ObjCABI;
853e5dd7070Spatrick
854e5dd7070Spatrick // arc/mrr layout of captured block literal variables.
855e5dd7070Spatrick SmallVector<RUN_SKIP, 16> RunSkipBlockVars;
856e5dd7070Spatrick
857e5dd7070Spatrick /// LazySymbols - Symbols to generate a lazy reference for. See
858e5dd7070Spatrick /// DefinedSymbols and FinishModule().
859e5dd7070Spatrick llvm::SetVector<IdentifierInfo*> LazySymbols;
860e5dd7070Spatrick
861e5dd7070Spatrick /// DefinedSymbols - External symbols which are defined by this
862e5dd7070Spatrick /// module. The symbols in this list and LazySymbols are used to add
863e5dd7070Spatrick /// special linker symbols which ensure that Objective-C modules are
864e5dd7070Spatrick /// linked properly.
865e5dd7070Spatrick llvm::SetVector<IdentifierInfo*> DefinedSymbols;
866e5dd7070Spatrick
867e5dd7070Spatrick /// ClassNames - uniqued class names.
868e5dd7070Spatrick llvm::StringMap<llvm::GlobalVariable*> ClassNames;
869e5dd7070Spatrick
870e5dd7070Spatrick /// MethodVarNames - uniqued method variable names.
871e5dd7070Spatrick llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
872e5dd7070Spatrick
873e5dd7070Spatrick /// DefinedCategoryNames - list of category names in form Class_Category.
874e5dd7070Spatrick llvm::SmallSetVector<llvm::CachedHashString, 16> DefinedCategoryNames;
875e5dd7070Spatrick
876e5dd7070Spatrick /// MethodVarTypes - uniqued method type signatures. We have to use
877e5dd7070Spatrick /// a StringMap here because have no other unique reference.
878e5dd7070Spatrick llvm::StringMap<llvm::GlobalVariable*> MethodVarTypes;
879e5dd7070Spatrick
880e5dd7070Spatrick /// MethodDefinitions - map of methods which have been defined in
881e5dd7070Spatrick /// this translation unit.
882e5dd7070Spatrick llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
883e5dd7070Spatrick
884e5dd7070Spatrick /// DirectMethodDefinitions - map of direct methods which have been defined in
885e5dd7070Spatrick /// this translation unit.
886e5dd7070Spatrick llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> DirectMethodDefinitions;
887e5dd7070Spatrick
888e5dd7070Spatrick /// PropertyNames - uniqued method variable names.
889e5dd7070Spatrick llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
890e5dd7070Spatrick
891e5dd7070Spatrick /// ClassReferences - uniqued class references.
892e5dd7070Spatrick llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassReferences;
893e5dd7070Spatrick
894e5dd7070Spatrick /// SelectorReferences - uniqued selector references.
895e5dd7070Spatrick llvm::DenseMap<Selector, llvm::GlobalVariable*> SelectorReferences;
896e5dd7070Spatrick
897e5dd7070Spatrick /// Protocols - Protocols for which an objc_protocol structure has
898e5dd7070Spatrick /// been emitted. Forward declarations are handled by creating an
899e5dd7070Spatrick /// empty structure whose initializer is filled in when/if defined.
900e5dd7070Spatrick llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> Protocols;
901e5dd7070Spatrick
902e5dd7070Spatrick /// DefinedProtocols - Protocols which have actually been
903e5dd7070Spatrick /// defined. We should not need this, see FIXME in GenerateProtocol.
904e5dd7070Spatrick llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
905e5dd7070Spatrick
906e5dd7070Spatrick /// DefinedClasses - List of defined classes.
907e5dd7070Spatrick SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
908e5dd7070Spatrick
909e5dd7070Spatrick /// ImplementedClasses - List of @implemented classes.
910e5dd7070Spatrick SmallVector<const ObjCInterfaceDecl*, 16> ImplementedClasses;
911e5dd7070Spatrick
912e5dd7070Spatrick /// DefinedNonLazyClasses - List of defined "non-lazy" classes.
913e5dd7070Spatrick SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
914e5dd7070Spatrick
915e5dd7070Spatrick /// DefinedCategories - List of defined categories.
916e5dd7070Spatrick SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
917e5dd7070Spatrick
918e5dd7070Spatrick /// DefinedStubCategories - List of defined categories on class stubs.
919e5dd7070Spatrick SmallVector<llvm::GlobalValue*, 16> DefinedStubCategories;
920e5dd7070Spatrick
921e5dd7070Spatrick /// DefinedNonLazyCategories - List of defined "non-lazy" categories.
922e5dd7070Spatrick SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
923e5dd7070Spatrick
924e5dd7070Spatrick /// Cached reference to the class for constant strings. This value has type
925e5dd7070Spatrick /// int * but is actually an Obj-C class pointer.
926e5dd7070Spatrick llvm::WeakTrackingVH ConstantStringClassRef;
927e5dd7070Spatrick
928e5dd7070Spatrick /// The LLVM type corresponding to NSConstantString.
929e5dd7070Spatrick llvm::StructType *NSConstantStringType = nullptr;
930e5dd7070Spatrick
931e5dd7070Spatrick llvm::StringMap<llvm::GlobalVariable *> NSConstantStringMap;
932e5dd7070Spatrick
933e5dd7070Spatrick /// GetMethodVarName - Return a unique constant for the given
934e5dd7070Spatrick /// selector's name. The return value has type char *.
935e5dd7070Spatrick llvm::Constant *GetMethodVarName(Selector Sel);
936e5dd7070Spatrick llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
937e5dd7070Spatrick
938e5dd7070Spatrick /// GetMethodVarType - Return a unique constant for the given
939e5dd7070Spatrick /// method's type encoding string. The return value has type char *.
940e5dd7070Spatrick
941e5dd7070Spatrick // FIXME: This is a horrible name.
942e5dd7070Spatrick llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D,
943e5dd7070Spatrick bool Extended = false);
944e5dd7070Spatrick llvm::Constant *GetMethodVarType(const FieldDecl *D);
945e5dd7070Spatrick
946e5dd7070Spatrick /// GetPropertyName - Return a unique constant for the given
947e5dd7070Spatrick /// name. The return value has type char *.
948e5dd7070Spatrick llvm::Constant *GetPropertyName(IdentifierInfo *Ident);
949e5dd7070Spatrick
950e5dd7070Spatrick // FIXME: This can be dropped once string functions are unified.
951e5dd7070Spatrick llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD,
952e5dd7070Spatrick const Decl *Container);
953e5dd7070Spatrick
954e5dd7070Spatrick /// GetClassName - Return a unique constant for the given selector's
955e5dd7070Spatrick /// runtime name (which may change via use of objc_runtime_name attribute on
956e5dd7070Spatrick /// class or protocol definition. The return value has type char *.
957e5dd7070Spatrick llvm::Constant *GetClassName(StringRef RuntimeName);
958e5dd7070Spatrick
959e5dd7070Spatrick llvm::Function *GetMethodDefinition(const ObjCMethodDecl *MD);
960e5dd7070Spatrick
961e5dd7070Spatrick /// BuildIvarLayout - Builds ivar layout bitmap for the class
962e5dd7070Spatrick /// implementation for the __strong or __weak case.
963e5dd7070Spatrick ///
964e5dd7070Spatrick /// \param hasMRCWeakIvars - Whether we are compiling in MRC and there
965e5dd7070Spatrick /// are any weak ivars defined directly in the class. Meaningless unless
966e5dd7070Spatrick /// building a weak layout. Does not guarantee that the layout will
967e5dd7070Spatrick /// actually have any entries, because the ivar might be under-aligned.
968e5dd7070Spatrick llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI,
969e5dd7070Spatrick CharUnits beginOffset,
970e5dd7070Spatrick CharUnits endOffset,
971e5dd7070Spatrick bool forStrongLayout,
972e5dd7070Spatrick bool hasMRCWeakIvars);
973e5dd7070Spatrick
BuildStrongIvarLayout(const ObjCImplementationDecl * OI,CharUnits beginOffset,CharUnits endOffset)974e5dd7070Spatrick llvm::Constant *BuildStrongIvarLayout(const ObjCImplementationDecl *OI,
975e5dd7070Spatrick CharUnits beginOffset,
976e5dd7070Spatrick CharUnits endOffset) {
977e5dd7070Spatrick return BuildIvarLayout(OI, beginOffset, endOffset, true, false);
978e5dd7070Spatrick }
979e5dd7070Spatrick
BuildWeakIvarLayout(const ObjCImplementationDecl * OI,CharUnits beginOffset,CharUnits endOffset,bool hasMRCWeakIvars)980e5dd7070Spatrick llvm::Constant *BuildWeakIvarLayout(const ObjCImplementationDecl *OI,
981e5dd7070Spatrick CharUnits beginOffset,
982e5dd7070Spatrick CharUnits endOffset,
983e5dd7070Spatrick bool hasMRCWeakIvars) {
984e5dd7070Spatrick return BuildIvarLayout(OI, beginOffset, endOffset, false, hasMRCWeakIvars);
985e5dd7070Spatrick }
986e5dd7070Spatrick
987e5dd7070Spatrick Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT, bool ByrefLayout);
988e5dd7070Spatrick
989e5dd7070Spatrick void UpdateRunSkipBlockVars(bool IsByref,
990e5dd7070Spatrick Qualifiers::ObjCLifetime LifeTime,
991e5dd7070Spatrick CharUnits FieldOffset,
992e5dd7070Spatrick CharUnits FieldSize);
993e5dd7070Spatrick
994e5dd7070Spatrick void BuildRCBlockVarRecordLayout(const RecordType *RT,
995e5dd7070Spatrick CharUnits BytePos, bool &HasUnion,
996e5dd7070Spatrick bool ByrefLayout=false);
997e5dd7070Spatrick
998e5dd7070Spatrick void BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
999e5dd7070Spatrick const RecordDecl *RD,
1000e5dd7070Spatrick ArrayRef<const FieldDecl*> RecFields,
1001e5dd7070Spatrick CharUnits BytePos, bool &HasUnion,
1002e5dd7070Spatrick bool ByrefLayout);
1003e5dd7070Spatrick
1004e5dd7070Spatrick uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
1005e5dd7070Spatrick
1006e5dd7070Spatrick llvm::Constant *getBitmapBlockLayout(bool ComputeByrefLayout);
1007e5dd7070Spatrick
1008e5dd7070Spatrick /// GetIvarLayoutName - Returns a unique constant for the given
1009e5dd7070Spatrick /// ivar layout bitmap.
1010e5dd7070Spatrick llvm::Constant *GetIvarLayoutName(IdentifierInfo *Ident,
1011e5dd7070Spatrick const ObjCCommonTypesHelper &ObjCTypes);
1012e5dd7070Spatrick
1013e5dd7070Spatrick /// EmitPropertyList - Emit the given property list. The return
1014e5dd7070Spatrick /// value has type PropertyListPtrTy.
1015e5dd7070Spatrick llvm::Constant *EmitPropertyList(Twine Name,
1016e5dd7070Spatrick const Decl *Container,
1017e5dd7070Spatrick const ObjCContainerDecl *OCD,
1018e5dd7070Spatrick const ObjCCommonTypesHelper &ObjCTypes,
1019e5dd7070Spatrick bool IsClassProperty);
1020e5dd7070Spatrick
1021e5dd7070Spatrick /// EmitProtocolMethodTypes - Generate the array of extended method type
1022e5dd7070Spatrick /// strings. The return value has type Int8PtrPtrTy.
1023e5dd7070Spatrick llvm::Constant *EmitProtocolMethodTypes(Twine Name,
1024e5dd7070Spatrick ArrayRef<llvm::Constant*> MethodTypes,
1025e5dd7070Spatrick const ObjCCommonTypesHelper &ObjCTypes);
1026e5dd7070Spatrick
1027e5dd7070Spatrick /// GetProtocolRef - Return a reference to the internal protocol
1028e5dd7070Spatrick /// description, creating an empty one if it has not been
1029e5dd7070Spatrick /// defined. The return value has type ProtocolPtrTy.
1030e5dd7070Spatrick llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
1031e5dd7070Spatrick
1032e5dd7070Spatrick /// Return a reference to the given Class using runtime calls rather than
1033e5dd7070Spatrick /// by a symbol reference.
1034e5dd7070Spatrick llvm::Value *EmitClassRefViaRuntime(CodeGenFunction &CGF,
1035e5dd7070Spatrick const ObjCInterfaceDecl *ID,
1036e5dd7070Spatrick ObjCCommonTypesHelper &ObjCTypes);
1037e5dd7070Spatrick
1038e5dd7070Spatrick std::string GetSectionName(StringRef Section, StringRef MachOAttributes);
1039e5dd7070Spatrick
1040e5dd7070Spatrick public:
1041e5dd7070Spatrick /// CreateMetadataVar - Create a global variable with internal
1042e5dd7070Spatrick /// linkage for use by the Objective-C runtime.
1043e5dd7070Spatrick ///
1044e5dd7070Spatrick /// This is a convenience wrapper which not only creates the
1045e5dd7070Spatrick /// variable, but also sets the section and alignment and adds the
1046e5dd7070Spatrick /// global to the "llvm.used" list.
1047e5dd7070Spatrick ///
1048e5dd7070Spatrick /// \param Name - The variable name.
1049e5dd7070Spatrick /// \param Init - The variable initializer; this is also used to
1050e5dd7070Spatrick /// define the type of the variable.
1051e5dd7070Spatrick /// \param Section - The section the variable should go into, or empty.
1052e5dd7070Spatrick /// \param Align - The alignment for the variable, or 0.
1053e5dd7070Spatrick /// \param AddToUsed - Whether the variable should be added to
1054e5dd7070Spatrick /// "llvm.used".
1055e5dd7070Spatrick llvm::GlobalVariable *CreateMetadataVar(Twine Name,
1056e5dd7070Spatrick ConstantStructBuilder &Init,
1057e5dd7070Spatrick StringRef Section, CharUnits Align,
1058e5dd7070Spatrick bool AddToUsed);
1059e5dd7070Spatrick llvm::GlobalVariable *CreateMetadataVar(Twine Name,
1060e5dd7070Spatrick llvm::Constant *Init,
1061e5dd7070Spatrick StringRef Section, CharUnits Align,
1062e5dd7070Spatrick bool AddToUsed);
1063e5dd7070Spatrick
1064e5dd7070Spatrick llvm::GlobalVariable *CreateCStringLiteral(StringRef Name,
1065e5dd7070Spatrick ObjCLabelType LabelType,
1066e5dd7070Spatrick bool ForceNonFragileABI = false,
1067e5dd7070Spatrick bool NullTerminate = true);
1068e5dd7070Spatrick
1069e5dd7070Spatrick protected:
1070e5dd7070Spatrick CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
1071e5dd7070Spatrick ReturnValueSlot Return,
1072e5dd7070Spatrick QualType ResultType,
1073e5dd7070Spatrick Selector Sel,
1074e5dd7070Spatrick llvm::Value *Arg0,
1075e5dd7070Spatrick QualType Arg0Ty,
1076e5dd7070Spatrick bool IsSuper,
1077e5dd7070Spatrick const CallArgList &CallArgs,
1078e5dd7070Spatrick const ObjCMethodDecl *OMD,
1079e5dd7070Spatrick const ObjCInterfaceDecl *ClassReceiver,
1080e5dd7070Spatrick const ObjCCommonTypesHelper &ObjCTypes);
1081e5dd7070Spatrick
1082e5dd7070Spatrick /// EmitImageInfo - Emit the image info marker used to encode some module
1083e5dd7070Spatrick /// level information.
1084e5dd7070Spatrick void EmitImageInfo();
1085e5dd7070Spatrick
1086e5dd7070Spatrick public:
CGObjCCommonMac(CodeGen::CodeGenModule & cgm)1087a9ac8606Spatrick CGObjCCommonMac(CodeGen::CodeGenModule &cgm)
1088a9ac8606Spatrick : CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) {}
1089e5dd7070Spatrick
isNonFragileABI() const1090e5dd7070Spatrick bool isNonFragileABI() const {
1091e5dd7070Spatrick return ObjCABI == 2;
1092e5dd7070Spatrick }
1093e5dd7070Spatrick
1094e5dd7070Spatrick ConstantAddress GenerateConstantString(const StringLiteral *SL) override;
1095e5dd7070Spatrick ConstantAddress GenerateConstantNSString(const StringLiteral *SL);
1096e5dd7070Spatrick
1097e5dd7070Spatrick llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
1098e5dd7070Spatrick const ObjCContainerDecl *CD=nullptr) override;
1099e5dd7070Spatrick
1100e5dd7070Spatrick llvm::Function *GenerateDirectMethod(const ObjCMethodDecl *OMD,
1101e5dd7070Spatrick const ObjCContainerDecl *CD);
1102e5dd7070Spatrick
1103e5dd7070Spatrick void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
1104e5dd7070Spatrick const ObjCMethodDecl *OMD,
1105e5dd7070Spatrick const ObjCContainerDecl *CD) override;
1106e5dd7070Spatrick
1107e5dd7070Spatrick void GenerateProtocol(const ObjCProtocolDecl *PD) override;
1108e5dd7070Spatrick
1109e5dd7070Spatrick /// GetOrEmitProtocolRef - Get a forward reference to the protocol
1110e5dd7070Spatrick /// object for the given declaration, emitting it if needed. These
1111e5dd7070Spatrick /// forward references will be filled in with empty bodies if no
1112e5dd7070Spatrick /// definition is seen. The return value has type ProtocolPtrTy.
1113e5dd7070Spatrick virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
1114e5dd7070Spatrick
1115e5dd7070Spatrick virtual llvm::Constant *getNSConstantStringClassRef() = 0;
1116e5dd7070Spatrick
1117e5dd7070Spatrick llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
1118e5dd7070Spatrick const CGBlockInfo &blockInfo) override;
1119e5dd7070Spatrick llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
1120e5dd7070Spatrick const CGBlockInfo &blockInfo) override;
1121e5dd7070Spatrick std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM,
1122e5dd7070Spatrick const CGBlockInfo &blockInfo) override;
1123e5dd7070Spatrick
1124e5dd7070Spatrick llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
1125e5dd7070Spatrick QualType T) override;
1126e5dd7070Spatrick
1127e5dd7070Spatrick private:
1128e5dd7070Spatrick void fillRunSkipBlockVars(CodeGenModule &CGM, const CGBlockInfo &blockInfo);
1129e5dd7070Spatrick };
1130e5dd7070Spatrick
1131e5dd7070Spatrick namespace {
1132e5dd7070Spatrick
1133e5dd7070Spatrick enum class MethodListType {
1134e5dd7070Spatrick CategoryInstanceMethods,
1135e5dd7070Spatrick CategoryClassMethods,
1136e5dd7070Spatrick InstanceMethods,
1137e5dd7070Spatrick ClassMethods,
1138e5dd7070Spatrick ProtocolInstanceMethods,
1139e5dd7070Spatrick ProtocolClassMethods,
1140e5dd7070Spatrick OptionalProtocolInstanceMethods,
1141e5dd7070Spatrick OptionalProtocolClassMethods,
1142e5dd7070Spatrick };
1143e5dd7070Spatrick
1144e5dd7070Spatrick /// A convenience class for splitting the methods of a protocol into
1145e5dd7070Spatrick /// the four interesting groups.
1146e5dd7070Spatrick class ProtocolMethodLists {
1147e5dd7070Spatrick public:
1148e5dd7070Spatrick enum Kind {
1149e5dd7070Spatrick RequiredInstanceMethods,
1150e5dd7070Spatrick RequiredClassMethods,
1151e5dd7070Spatrick OptionalInstanceMethods,
1152e5dd7070Spatrick OptionalClassMethods
1153e5dd7070Spatrick };
1154e5dd7070Spatrick enum {
1155e5dd7070Spatrick NumProtocolMethodLists = 4
1156e5dd7070Spatrick };
1157e5dd7070Spatrick
getMethodListKind(Kind kind)1158e5dd7070Spatrick static MethodListType getMethodListKind(Kind kind) {
1159e5dd7070Spatrick switch (kind) {
1160e5dd7070Spatrick case RequiredInstanceMethods:
1161e5dd7070Spatrick return MethodListType::ProtocolInstanceMethods;
1162e5dd7070Spatrick case RequiredClassMethods:
1163e5dd7070Spatrick return MethodListType::ProtocolClassMethods;
1164e5dd7070Spatrick case OptionalInstanceMethods:
1165e5dd7070Spatrick return MethodListType::OptionalProtocolInstanceMethods;
1166e5dd7070Spatrick case OptionalClassMethods:
1167e5dd7070Spatrick return MethodListType::OptionalProtocolClassMethods;
1168e5dd7070Spatrick }
1169e5dd7070Spatrick llvm_unreachable("bad kind");
1170e5dd7070Spatrick }
1171e5dd7070Spatrick
1172e5dd7070Spatrick SmallVector<const ObjCMethodDecl *, 4> Methods[NumProtocolMethodLists];
1173e5dd7070Spatrick
get(const ObjCProtocolDecl * PD)1174e5dd7070Spatrick static ProtocolMethodLists get(const ObjCProtocolDecl *PD) {
1175e5dd7070Spatrick ProtocolMethodLists result;
1176e5dd7070Spatrick
1177*12c85518Srobert for (auto *MD : PD->methods()) {
1178e5dd7070Spatrick size_t index = (2 * size_t(MD->isOptional()))
1179e5dd7070Spatrick + (size_t(MD->isClassMethod()));
1180e5dd7070Spatrick result.Methods[index].push_back(MD);
1181e5dd7070Spatrick }
1182e5dd7070Spatrick
1183e5dd7070Spatrick return result;
1184e5dd7070Spatrick }
1185e5dd7070Spatrick
1186e5dd7070Spatrick template <class Self>
emitExtendedTypesArray(Self * self) const1187e5dd7070Spatrick SmallVector<llvm::Constant*, 8> emitExtendedTypesArray(Self *self) const {
1188e5dd7070Spatrick // In both ABIs, the method types list is parallel with the
1189e5dd7070Spatrick // concatenation of the methods arrays in the following order:
1190e5dd7070Spatrick // instance methods
1191e5dd7070Spatrick // class methods
1192e5dd7070Spatrick // optional instance methods
1193e5dd7070Spatrick // optional class methods
1194e5dd7070Spatrick SmallVector<llvm::Constant*, 8> result;
1195e5dd7070Spatrick
1196e5dd7070Spatrick // Methods is already in the correct order for both ABIs.
1197e5dd7070Spatrick for (auto &list : Methods) {
1198e5dd7070Spatrick for (auto MD : list) {
1199e5dd7070Spatrick result.push_back(self->GetMethodVarType(MD, true));
1200e5dd7070Spatrick }
1201e5dd7070Spatrick }
1202e5dd7070Spatrick
1203e5dd7070Spatrick return result;
1204e5dd7070Spatrick }
1205e5dd7070Spatrick
1206e5dd7070Spatrick template <class Self>
emitMethodList(Self * self,const ObjCProtocolDecl * PD,Kind kind) const1207e5dd7070Spatrick llvm::Constant *emitMethodList(Self *self, const ObjCProtocolDecl *PD,
1208e5dd7070Spatrick Kind kind) const {
1209e5dd7070Spatrick return self->emitMethodList(PD->getObjCRuntimeNameAsString(),
1210e5dd7070Spatrick getMethodListKind(kind), Methods[kind]);
1211e5dd7070Spatrick }
1212e5dd7070Spatrick };
1213e5dd7070Spatrick
1214e5dd7070Spatrick } // end anonymous namespace
1215e5dd7070Spatrick
1216e5dd7070Spatrick class CGObjCMac : public CGObjCCommonMac {
1217e5dd7070Spatrick private:
1218e5dd7070Spatrick friend ProtocolMethodLists;
1219e5dd7070Spatrick
1220e5dd7070Spatrick ObjCTypesHelper ObjCTypes;
1221e5dd7070Spatrick
1222e5dd7070Spatrick /// EmitModuleInfo - Another marker encoding module level
1223e5dd7070Spatrick /// information.
1224e5dd7070Spatrick void EmitModuleInfo();
1225e5dd7070Spatrick
1226e5dd7070Spatrick /// EmitModuleSymols - Emit module symbols, the list of defined
1227e5dd7070Spatrick /// classes and categories. The result has type SymtabPtrTy.
1228e5dd7070Spatrick llvm::Constant *EmitModuleSymbols();
1229e5dd7070Spatrick
1230e5dd7070Spatrick /// FinishModule - Write out global data structures at the end of
1231e5dd7070Spatrick /// processing a translation unit.
1232e5dd7070Spatrick void FinishModule();
1233e5dd7070Spatrick
1234e5dd7070Spatrick /// EmitClassExtension - Generate the class extension structure used
1235e5dd7070Spatrick /// to store the weak ivar layout and properties. The return value
1236e5dd7070Spatrick /// has type ClassExtensionPtrTy.
1237e5dd7070Spatrick llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID,
1238e5dd7070Spatrick CharUnits instanceSize,
1239e5dd7070Spatrick bool hasMRCWeakIvars,
1240e5dd7070Spatrick bool isMetaclass);
1241e5dd7070Spatrick
1242e5dd7070Spatrick /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
1243e5dd7070Spatrick /// for the given class.
1244e5dd7070Spatrick llvm::Value *EmitClassRef(CodeGenFunction &CGF,
1245e5dd7070Spatrick const ObjCInterfaceDecl *ID);
1246e5dd7070Spatrick
1247e5dd7070Spatrick llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
1248e5dd7070Spatrick IdentifierInfo *II);
1249e5dd7070Spatrick
1250e5dd7070Spatrick llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
1251e5dd7070Spatrick
1252e5dd7070Spatrick /// EmitSuperClassRef - Emits reference to class's main metadata class.
1253e5dd7070Spatrick llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
1254e5dd7070Spatrick
1255e5dd7070Spatrick /// EmitIvarList - Emit the ivar list for the given
1256e5dd7070Spatrick /// implementation. If ForClass is true the list of class ivars
1257e5dd7070Spatrick /// (i.e. metaclass ivars) is emitted, otherwise the list of
1258e5dd7070Spatrick /// interface ivars will be emitted. The return value has type
1259e5dd7070Spatrick /// IvarListPtrTy.
1260e5dd7070Spatrick llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID,
1261e5dd7070Spatrick bool ForClass);
1262e5dd7070Spatrick
1263e5dd7070Spatrick /// EmitMetaClass - Emit a forward reference to the class structure
1264e5dd7070Spatrick /// for the metaclass of the given interface. The return value has
1265e5dd7070Spatrick /// type ClassPtrTy.
1266e5dd7070Spatrick llvm::Constant *EmitMetaClassRef(const ObjCInterfaceDecl *ID);
1267e5dd7070Spatrick
1268e5dd7070Spatrick /// EmitMetaClass - Emit a class structure for the metaclass of the
1269e5dd7070Spatrick /// given implementation. The return value has type ClassPtrTy.
1270e5dd7070Spatrick llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
1271e5dd7070Spatrick llvm::Constant *Protocols,
1272e5dd7070Spatrick ArrayRef<const ObjCMethodDecl *> Methods);
1273e5dd7070Spatrick
1274e5dd7070Spatrick void emitMethodConstant(ConstantArrayBuilder &builder,
1275e5dd7070Spatrick const ObjCMethodDecl *MD);
1276e5dd7070Spatrick
1277e5dd7070Spatrick void emitMethodDescriptionConstant(ConstantArrayBuilder &builder,
1278e5dd7070Spatrick const ObjCMethodDecl *MD);
1279e5dd7070Spatrick
1280e5dd7070Spatrick /// EmitMethodList - Emit the method list for the given
1281e5dd7070Spatrick /// implementation. The return value has type MethodListPtrTy.
1282e5dd7070Spatrick llvm::Constant *emitMethodList(Twine Name, MethodListType MLT,
1283e5dd7070Spatrick ArrayRef<const ObjCMethodDecl *> Methods);
1284e5dd7070Spatrick
1285e5dd7070Spatrick /// GetOrEmitProtocol - Get the protocol object for the given
1286e5dd7070Spatrick /// declaration, emitting it if necessary. The return value has type
1287e5dd7070Spatrick /// ProtocolPtrTy.
1288e5dd7070Spatrick llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override;
1289e5dd7070Spatrick
1290e5dd7070Spatrick /// GetOrEmitProtocolRef - Get a forward reference to the protocol
1291e5dd7070Spatrick /// object for the given declaration, emitting it if needed. These
1292e5dd7070Spatrick /// forward references will be filled in with empty bodies if no
1293e5dd7070Spatrick /// definition is seen. The return value has type ProtocolPtrTy.
1294e5dd7070Spatrick llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) override;
1295e5dd7070Spatrick
1296e5dd7070Spatrick /// EmitProtocolExtension - Generate the protocol extension
1297e5dd7070Spatrick /// structure used to store optional instance and class methods, and
1298e5dd7070Spatrick /// protocol properties. The return value has type
1299e5dd7070Spatrick /// ProtocolExtensionPtrTy.
1300e5dd7070Spatrick llvm::Constant *
1301e5dd7070Spatrick EmitProtocolExtension(const ObjCProtocolDecl *PD,
1302e5dd7070Spatrick const ProtocolMethodLists &methodLists);
1303e5dd7070Spatrick
1304e5dd7070Spatrick /// EmitProtocolList - Generate the list of referenced
1305e5dd7070Spatrick /// protocols. The return value has type ProtocolListPtrTy.
1306e5dd7070Spatrick llvm::Constant *EmitProtocolList(Twine Name,
1307e5dd7070Spatrick ObjCProtocolDecl::protocol_iterator begin,
1308e5dd7070Spatrick ObjCProtocolDecl::protocol_iterator end);
1309e5dd7070Spatrick
1310e5dd7070Spatrick /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
1311e5dd7070Spatrick /// for the given selector.
1312e5dd7070Spatrick llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
1313e5dd7070Spatrick Address EmitSelectorAddr(Selector Sel);
1314e5dd7070Spatrick
1315e5dd7070Spatrick public:
1316e5dd7070Spatrick CGObjCMac(CodeGen::CodeGenModule &cgm);
1317e5dd7070Spatrick
1318e5dd7070Spatrick llvm::Constant *getNSConstantStringClassRef() override;
1319e5dd7070Spatrick
1320e5dd7070Spatrick llvm::Function *ModuleInitFunction() override;
1321e5dd7070Spatrick
1322e5dd7070Spatrick CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
1323e5dd7070Spatrick ReturnValueSlot Return,
1324e5dd7070Spatrick QualType ResultType,
1325e5dd7070Spatrick Selector Sel, llvm::Value *Receiver,
1326e5dd7070Spatrick const CallArgList &CallArgs,
1327e5dd7070Spatrick const ObjCInterfaceDecl *Class,
1328e5dd7070Spatrick const ObjCMethodDecl *Method) override;
1329e5dd7070Spatrick
1330e5dd7070Spatrick CodeGen::RValue
1331e5dd7070Spatrick GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
1332e5dd7070Spatrick ReturnValueSlot Return, QualType ResultType,
1333e5dd7070Spatrick Selector Sel, const ObjCInterfaceDecl *Class,
1334e5dd7070Spatrick bool isCategoryImpl, llvm::Value *Receiver,
1335e5dd7070Spatrick bool IsClassMessage, const CallArgList &CallArgs,
1336e5dd7070Spatrick const ObjCMethodDecl *Method) override;
1337e5dd7070Spatrick
1338e5dd7070Spatrick llvm::Value *GetClass(CodeGenFunction &CGF,
1339e5dd7070Spatrick const ObjCInterfaceDecl *ID) override;
1340e5dd7070Spatrick
1341e5dd7070Spatrick llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override;
1342e5dd7070Spatrick Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override;
1343e5dd7070Spatrick
1344e5dd7070Spatrick /// The NeXT/Apple runtimes do not support typed selectors; just emit an
1345e5dd7070Spatrick /// untyped one.
1346e5dd7070Spatrick llvm::Value *GetSelector(CodeGenFunction &CGF,
1347e5dd7070Spatrick const ObjCMethodDecl *Method) override;
1348e5dd7070Spatrick
1349e5dd7070Spatrick llvm::Constant *GetEHType(QualType T) override;
1350e5dd7070Spatrick
1351e5dd7070Spatrick void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
1352e5dd7070Spatrick
1353e5dd7070Spatrick void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
1354e5dd7070Spatrick
RegisterAlias(const ObjCCompatibleAliasDecl * OAD)1355e5dd7070Spatrick void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override {}
1356e5dd7070Spatrick
1357e5dd7070Spatrick llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
1358e5dd7070Spatrick const ObjCProtocolDecl *PD) override;
1359e5dd7070Spatrick
1360e5dd7070Spatrick llvm::FunctionCallee GetPropertyGetFunction() override;
1361e5dd7070Spatrick llvm::FunctionCallee GetPropertySetFunction() override;
1362e5dd7070Spatrick llvm::FunctionCallee GetOptimizedPropertySetFunction(bool atomic,
1363e5dd7070Spatrick bool copy) override;
1364e5dd7070Spatrick llvm::FunctionCallee GetGetStructFunction() override;
1365e5dd7070Spatrick llvm::FunctionCallee GetSetStructFunction() override;
1366e5dd7070Spatrick llvm::FunctionCallee GetCppAtomicObjectGetFunction() override;
1367e5dd7070Spatrick llvm::FunctionCallee GetCppAtomicObjectSetFunction() override;
1368e5dd7070Spatrick llvm::FunctionCallee EnumerationMutationFunction() override;
1369e5dd7070Spatrick
1370e5dd7070Spatrick void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
1371e5dd7070Spatrick const ObjCAtTryStmt &S) override;
1372e5dd7070Spatrick void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
1373e5dd7070Spatrick const ObjCAtSynchronizedStmt &S) override;
1374e5dd7070Spatrick void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S);
1375e5dd7070Spatrick void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
1376e5dd7070Spatrick bool ClearInsertionPoint=true) override;
1377e5dd7070Spatrick llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
1378e5dd7070Spatrick Address AddrWeakObj) override;
1379e5dd7070Spatrick void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
1380e5dd7070Spatrick llvm::Value *src, Address dst) override;
1381e5dd7070Spatrick void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
1382e5dd7070Spatrick llvm::Value *src, Address dest,
1383e5dd7070Spatrick bool threadlocal = false) override;
1384e5dd7070Spatrick void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
1385e5dd7070Spatrick llvm::Value *src, Address dest,
1386e5dd7070Spatrick llvm::Value *ivarOffset) override;
1387e5dd7070Spatrick void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
1388e5dd7070Spatrick llvm::Value *src, Address dest) override;
1389e5dd7070Spatrick void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
1390e5dd7070Spatrick Address dest, Address src,
1391e5dd7070Spatrick llvm::Value *size) override;
1392e5dd7070Spatrick
1393e5dd7070Spatrick LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
1394e5dd7070Spatrick llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
1395e5dd7070Spatrick unsigned CVRQualifiers) override;
1396e5dd7070Spatrick llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
1397e5dd7070Spatrick const ObjCInterfaceDecl *Interface,
1398e5dd7070Spatrick const ObjCIvarDecl *Ivar) override;
1399e5dd7070Spatrick };
1400e5dd7070Spatrick
1401e5dd7070Spatrick class CGObjCNonFragileABIMac : public CGObjCCommonMac {
1402e5dd7070Spatrick private:
1403e5dd7070Spatrick friend ProtocolMethodLists;
1404e5dd7070Spatrick ObjCNonFragileABITypesHelper ObjCTypes;
1405e5dd7070Spatrick llvm::GlobalVariable* ObjCEmptyCacheVar;
1406e5dd7070Spatrick llvm::Constant* ObjCEmptyVtableVar;
1407e5dd7070Spatrick
1408e5dd7070Spatrick /// SuperClassReferences - uniqued super class references.
1409e5dd7070Spatrick llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> SuperClassReferences;
1410e5dd7070Spatrick
1411e5dd7070Spatrick /// MetaClassReferences - uniqued meta class references.
1412e5dd7070Spatrick llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> MetaClassReferences;
1413e5dd7070Spatrick
1414e5dd7070Spatrick /// EHTypeReferences - uniqued class ehtype references.
1415e5dd7070Spatrick llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
1416e5dd7070Spatrick
1417e5dd7070Spatrick /// VTableDispatchMethods - List of methods for which we generate
1418e5dd7070Spatrick /// vtable-based message dispatch.
1419e5dd7070Spatrick llvm::DenseSet<Selector> VTableDispatchMethods;
1420e5dd7070Spatrick
1421e5dd7070Spatrick /// DefinedMetaClasses - List of defined meta-classes.
1422e5dd7070Spatrick std::vector<llvm::GlobalValue*> DefinedMetaClasses;
1423e5dd7070Spatrick
1424e5dd7070Spatrick /// isVTableDispatchedSelector - Returns true if SEL is a
1425e5dd7070Spatrick /// vtable-based selector.
1426e5dd7070Spatrick bool isVTableDispatchedSelector(Selector Sel);
1427e5dd7070Spatrick
1428e5dd7070Spatrick /// FinishNonFragileABIModule - Write out global data structures at the end of
1429e5dd7070Spatrick /// processing a translation unit.
1430e5dd7070Spatrick void FinishNonFragileABIModule();
1431e5dd7070Spatrick
1432e5dd7070Spatrick /// AddModuleClassList - Add the given list of class pointers to the
1433e5dd7070Spatrick /// module with the provided symbol and section names.
1434e5dd7070Spatrick void AddModuleClassList(ArrayRef<llvm::GlobalValue *> Container,
1435e5dd7070Spatrick StringRef SymbolName, StringRef SectionName);
1436e5dd7070Spatrick
1437e5dd7070Spatrick llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags,
1438e5dd7070Spatrick unsigned InstanceStart,
1439e5dd7070Spatrick unsigned InstanceSize,
1440e5dd7070Spatrick const ObjCImplementationDecl *ID);
1441e5dd7070Spatrick llvm::GlobalVariable *BuildClassObject(const ObjCInterfaceDecl *CI,
1442e5dd7070Spatrick bool isMetaclass,
1443e5dd7070Spatrick llvm::Constant *IsAGV,
1444e5dd7070Spatrick llvm::Constant *SuperClassGV,
1445e5dd7070Spatrick llvm::Constant *ClassRoGV,
1446e5dd7070Spatrick bool HiddenVisibility);
1447e5dd7070Spatrick
1448e5dd7070Spatrick void emitMethodConstant(ConstantArrayBuilder &builder,
1449e5dd7070Spatrick const ObjCMethodDecl *MD,
1450e5dd7070Spatrick bool forProtocol);
1451e5dd7070Spatrick
1452e5dd7070Spatrick /// Emit the method list for the given implementation. The return value
1453e5dd7070Spatrick /// has type MethodListnfABITy.
1454e5dd7070Spatrick llvm::Constant *emitMethodList(Twine Name, MethodListType MLT,
1455e5dd7070Spatrick ArrayRef<const ObjCMethodDecl *> Methods);
1456e5dd7070Spatrick
1457e5dd7070Spatrick /// EmitIvarList - Emit the ivar list for the given
1458e5dd7070Spatrick /// implementation. If ForClass is true the list of class ivars
1459e5dd7070Spatrick /// (i.e. metaclass ivars) is emitted, otherwise the list of
1460e5dd7070Spatrick /// interface ivars will be emitted. The return value has type
1461e5dd7070Spatrick /// IvarListnfABIPtrTy.
1462e5dd7070Spatrick llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID);
1463e5dd7070Spatrick
1464e5dd7070Spatrick llvm::Constant *EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
1465e5dd7070Spatrick const ObjCIvarDecl *Ivar,
1466e5dd7070Spatrick unsigned long int offset);
1467e5dd7070Spatrick
1468e5dd7070Spatrick /// GetOrEmitProtocol - Get the protocol object for the given
1469e5dd7070Spatrick /// declaration, emitting it if necessary. The return value has type
1470e5dd7070Spatrick /// ProtocolPtrTy.
1471e5dd7070Spatrick llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override;
1472e5dd7070Spatrick
1473e5dd7070Spatrick /// GetOrEmitProtocolRef - Get a forward reference to the protocol
1474e5dd7070Spatrick /// object for the given declaration, emitting it if needed. These
1475e5dd7070Spatrick /// forward references will be filled in with empty bodies if no
1476e5dd7070Spatrick /// definition is seen. The return value has type ProtocolPtrTy.
1477e5dd7070Spatrick llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) override;
1478e5dd7070Spatrick
1479e5dd7070Spatrick /// EmitProtocolList - Generate the list of referenced
1480e5dd7070Spatrick /// protocols. The return value has type ProtocolListPtrTy.
1481e5dd7070Spatrick llvm::Constant *EmitProtocolList(Twine Name,
1482e5dd7070Spatrick ObjCProtocolDecl::protocol_iterator begin,
1483e5dd7070Spatrick ObjCProtocolDecl::protocol_iterator end);
1484e5dd7070Spatrick
1485e5dd7070Spatrick CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF,
1486e5dd7070Spatrick ReturnValueSlot Return,
1487e5dd7070Spatrick QualType ResultType,
1488e5dd7070Spatrick Selector Sel,
1489e5dd7070Spatrick llvm::Value *Receiver,
1490e5dd7070Spatrick QualType Arg0Ty,
1491e5dd7070Spatrick bool IsSuper,
1492e5dd7070Spatrick const CallArgList &CallArgs,
1493e5dd7070Spatrick const ObjCMethodDecl *Method);
1494e5dd7070Spatrick
1495e5dd7070Spatrick /// GetClassGlobal - Return the global variable for the Objective-C
1496e5dd7070Spatrick /// class of the given name.
1497e5dd7070Spatrick llvm::Constant *GetClassGlobal(StringRef Name,
1498e5dd7070Spatrick ForDefinition_t IsForDefinition,
1499e5dd7070Spatrick bool Weak = false, bool DLLImport = false);
1500e5dd7070Spatrick llvm::Constant *GetClassGlobal(const ObjCInterfaceDecl *ID,
1501e5dd7070Spatrick bool isMetaclass,
1502e5dd7070Spatrick ForDefinition_t isForDefinition);
1503e5dd7070Spatrick
1504e5dd7070Spatrick llvm::Constant *GetClassGlobalForClassRef(const ObjCInterfaceDecl *ID);
1505e5dd7070Spatrick
1506e5dd7070Spatrick llvm::Value *EmitLoadOfClassRef(CodeGenFunction &CGF,
1507e5dd7070Spatrick const ObjCInterfaceDecl *ID,
1508e5dd7070Spatrick llvm::GlobalVariable *Entry);
1509e5dd7070Spatrick
1510e5dd7070Spatrick /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
1511e5dd7070Spatrick /// for the given class reference.
1512e5dd7070Spatrick llvm::Value *EmitClassRef(CodeGenFunction &CGF,
1513e5dd7070Spatrick const ObjCInterfaceDecl *ID);
1514e5dd7070Spatrick
1515e5dd7070Spatrick llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
1516e5dd7070Spatrick IdentifierInfo *II,
1517e5dd7070Spatrick const ObjCInterfaceDecl *ID);
1518e5dd7070Spatrick
1519e5dd7070Spatrick llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
1520e5dd7070Spatrick
1521e5dd7070Spatrick /// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
1522e5dd7070Spatrick /// for the given super class reference.
1523e5dd7070Spatrick llvm::Value *EmitSuperClassRef(CodeGenFunction &CGF,
1524e5dd7070Spatrick const ObjCInterfaceDecl *ID);
1525e5dd7070Spatrick
1526e5dd7070Spatrick /// EmitMetaClassRef - Return a Value * of the address of _class_t
1527e5dd7070Spatrick /// meta-data
1528e5dd7070Spatrick llvm::Value *EmitMetaClassRef(CodeGenFunction &CGF,
1529e5dd7070Spatrick const ObjCInterfaceDecl *ID, bool Weak);
1530e5dd7070Spatrick
1531e5dd7070Spatrick /// ObjCIvarOffsetVariable - Returns the ivar offset variable for
1532e5dd7070Spatrick /// the given ivar.
1533e5dd7070Spatrick ///
1534e5dd7070Spatrick llvm::GlobalVariable * ObjCIvarOffsetVariable(
1535e5dd7070Spatrick const ObjCInterfaceDecl *ID,
1536e5dd7070Spatrick const ObjCIvarDecl *Ivar);
1537e5dd7070Spatrick
1538e5dd7070Spatrick /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
1539e5dd7070Spatrick /// for the given selector.
1540e5dd7070Spatrick llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
1541e5dd7070Spatrick Address EmitSelectorAddr(Selector Sel);
1542e5dd7070Spatrick
1543e5dd7070Spatrick /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
1544e5dd7070Spatrick /// interface. The return value has type EHTypePtrTy.
1545e5dd7070Spatrick llvm::Constant *GetInterfaceEHType(const ObjCInterfaceDecl *ID,
1546e5dd7070Spatrick ForDefinition_t IsForDefinition);
1547e5dd7070Spatrick
getMetaclassSymbolPrefix() const1548e5dd7070Spatrick StringRef getMetaclassSymbolPrefix() const { return "OBJC_METACLASS_$_"; }
1549e5dd7070Spatrick
getClassSymbolPrefix() const1550e5dd7070Spatrick StringRef getClassSymbolPrefix() const { return "OBJC_CLASS_$_"; }
1551e5dd7070Spatrick
1552e5dd7070Spatrick void GetClassSizeInfo(const ObjCImplementationDecl *OID,
1553e5dd7070Spatrick uint32_t &InstanceStart,
1554e5dd7070Spatrick uint32_t &InstanceSize);
1555e5dd7070Spatrick
1556e5dd7070Spatrick // Shamelessly stolen from Analysis/CFRefCount.cpp
GetNullarySelector(const char * name) const1557e5dd7070Spatrick Selector GetNullarySelector(const char* name) const {
1558e5dd7070Spatrick IdentifierInfo* II = &CGM.getContext().Idents.get(name);
1559e5dd7070Spatrick return CGM.getContext().Selectors.getSelector(0, &II);
1560e5dd7070Spatrick }
1561e5dd7070Spatrick
GetUnarySelector(const char * name) const1562e5dd7070Spatrick Selector GetUnarySelector(const char* name) const {
1563e5dd7070Spatrick IdentifierInfo* II = &CGM.getContext().Idents.get(name);
1564e5dd7070Spatrick return CGM.getContext().Selectors.getSelector(1, &II);
1565e5dd7070Spatrick }
1566e5dd7070Spatrick
1567e5dd7070Spatrick /// ImplementationIsNonLazy - Check whether the given category or
1568e5dd7070Spatrick /// class implementation is "non-lazy".
1569e5dd7070Spatrick bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const;
1570e5dd7070Spatrick
IsIvarOffsetKnownIdempotent(const CodeGen::CodeGenFunction & CGF,const ObjCIvarDecl * IV)1571e5dd7070Spatrick bool IsIvarOffsetKnownIdempotent(const CodeGen::CodeGenFunction &CGF,
1572e5dd7070Spatrick const ObjCIvarDecl *IV) {
1573e5dd7070Spatrick // Annotate the load as an invariant load iff inside an instance method
1574e5dd7070Spatrick // and ivar belongs to instance method's class and one of its super class.
1575e5dd7070Spatrick // This check is needed because the ivar offset is a lazily
1576e5dd7070Spatrick // initialised value that may depend on objc_msgSend to perform a fixup on
1577e5dd7070Spatrick // the first message dispatch.
1578e5dd7070Spatrick //
1579e5dd7070Spatrick // An additional opportunity to mark the load as invariant arises when the
1580e5dd7070Spatrick // base of the ivar access is a parameter to an Objective C method.
1581e5dd7070Spatrick // However, because the parameters are not available in the current
1582e5dd7070Spatrick // interface, we cannot perform this check.
1583e5dd7070Spatrick //
1584e5dd7070Spatrick // Note that for direct methods, because objc_msgSend is skipped,
1585e5dd7070Spatrick // and that the method may be inlined, this optimization actually
1586e5dd7070Spatrick // can't be performed.
1587e5dd7070Spatrick if (const ObjCMethodDecl *MD =
1588e5dd7070Spatrick dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
1589e5dd7070Spatrick if (MD->isInstanceMethod() && !MD->isDirectMethod())
1590e5dd7070Spatrick if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
1591e5dd7070Spatrick return IV->getContainingInterface()->isSuperClassOf(ID);
1592e5dd7070Spatrick return false;
1593e5dd7070Spatrick }
1594e5dd7070Spatrick
isClassLayoutKnownStatically(const ObjCInterfaceDecl * ID)1595e5dd7070Spatrick bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
1596e5dd7070Spatrick // NSObject is a fixed size. If we can see the @implementation of a class
1597e5dd7070Spatrick // which inherits from NSObject then we know that all it's offsets also must
1598e5dd7070Spatrick // be fixed. FIXME: Can we do this if see a chain of super classes with
1599e5dd7070Spatrick // implementations leading to NSObject?
1600e5dd7070Spatrick return ID->getImplementation() && ID->getSuperClass() &&
1601e5dd7070Spatrick ID->getSuperClass()->getName() == "NSObject";
1602e5dd7070Spatrick }
1603e5dd7070Spatrick
1604e5dd7070Spatrick public:
1605e5dd7070Spatrick CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
1606e5dd7070Spatrick
1607e5dd7070Spatrick llvm::Constant *getNSConstantStringClassRef() override;
1608e5dd7070Spatrick
1609e5dd7070Spatrick llvm::Function *ModuleInitFunction() override;
1610e5dd7070Spatrick
1611e5dd7070Spatrick CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
1612e5dd7070Spatrick ReturnValueSlot Return,
1613e5dd7070Spatrick QualType ResultType, Selector Sel,
1614e5dd7070Spatrick llvm::Value *Receiver,
1615e5dd7070Spatrick const CallArgList &CallArgs,
1616e5dd7070Spatrick const ObjCInterfaceDecl *Class,
1617e5dd7070Spatrick const ObjCMethodDecl *Method) override;
1618e5dd7070Spatrick
1619e5dd7070Spatrick CodeGen::RValue
1620e5dd7070Spatrick GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
1621e5dd7070Spatrick ReturnValueSlot Return, QualType ResultType,
1622e5dd7070Spatrick Selector Sel, const ObjCInterfaceDecl *Class,
1623e5dd7070Spatrick bool isCategoryImpl, llvm::Value *Receiver,
1624e5dd7070Spatrick bool IsClassMessage, const CallArgList &CallArgs,
1625e5dd7070Spatrick const ObjCMethodDecl *Method) override;
1626e5dd7070Spatrick
1627e5dd7070Spatrick llvm::Value *GetClass(CodeGenFunction &CGF,
1628e5dd7070Spatrick const ObjCInterfaceDecl *ID) override;
1629e5dd7070Spatrick
GetSelector(CodeGenFunction & CGF,Selector Sel)1630e5dd7070Spatrick llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override
1631e5dd7070Spatrick { return EmitSelector(CGF, Sel); }
GetAddrOfSelector(CodeGenFunction & CGF,Selector Sel)1632e5dd7070Spatrick Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override
1633e5dd7070Spatrick { return EmitSelectorAddr(Sel); }
1634e5dd7070Spatrick
1635e5dd7070Spatrick /// The NeXT/Apple runtimes do not support typed selectors; just emit an
1636e5dd7070Spatrick /// untyped one.
GetSelector(CodeGenFunction & CGF,const ObjCMethodDecl * Method)1637e5dd7070Spatrick llvm::Value *GetSelector(CodeGenFunction &CGF,
1638e5dd7070Spatrick const ObjCMethodDecl *Method) override
1639e5dd7070Spatrick { return EmitSelector(CGF, Method->getSelector()); }
1640e5dd7070Spatrick
1641e5dd7070Spatrick void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
1642e5dd7070Spatrick
1643e5dd7070Spatrick void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
1644e5dd7070Spatrick
RegisterAlias(const ObjCCompatibleAliasDecl * OAD)1645e5dd7070Spatrick void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override {}
1646e5dd7070Spatrick
1647e5dd7070Spatrick llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
1648e5dd7070Spatrick const ObjCProtocolDecl *PD) override;
1649e5dd7070Spatrick
1650e5dd7070Spatrick llvm::Constant *GetEHType(QualType T) override;
1651e5dd7070Spatrick
GetPropertyGetFunction()1652e5dd7070Spatrick llvm::FunctionCallee GetPropertyGetFunction() override {
1653e5dd7070Spatrick return ObjCTypes.getGetPropertyFn();
1654e5dd7070Spatrick }
GetPropertySetFunction()1655e5dd7070Spatrick llvm::FunctionCallee GetPropertySetFunction() override {
1656e5dd7070Spatrick return ObjCTypes.getSetPropertyFn();
1657e5dd7070Spatrick }
1658e5dd7070Spatrick
GetOptimizedPropertySetFunction(bool atomic,bool copy)1659e5dd7070Spatrick llvm::FunctionCallee GetOptimizedPropertySetFunction(bool atomic,
1660e5dd7070Spatrick bool copy) override {
1661e5dd7070Spatrick return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
1662e5dd7070Spatrick }
1663e5dd7070Spatrick
GetSetStructFunction()1664e5dd7070Spatrick llvm::FunctionCallee GetSetStructFunction() override {
1665e5dd7070Spatrick return ObjCTypes.getCopyStructFn();
1666e5dd7070Spatrick }
1667e5dd7070Spatrick
GetGetStructFunction()1668e5dd7070Spatrick llvm::FunctionCallee GetGetStructFunction() override {
1669e5dd7070Spatrick return ObjCTypes.getCopyStructFn();
1670e5dd7070Spatrick }
1671e5dd7070Spatrick
GetCppAtomicObjectSetFunction()1672e5dd7070Spatrick llvm::FunctionCallee GetCppAtomicObjectSetFunction() override {
1673e5dd7070Spatrick return ObjCTypes.getCppAtomicObjectFunction();
1674e5dd7070Spatrick }
1675e5dd7070Spatrick
GetCppAtomicObjectGetFunction()1676e5dd7070Spatrick llvm::FunctionCallee GetCppAtomicObjectGetFunction() override {
1677e5dd7070Spatrick return ObjCTypes.getCppAtomicObjectFunction();
1678e5dd7070Spatrick }
1679e5dd7070Spatrick
EnumerationMutationFunction()1680e5dd7070Spatrick llvm::FunctionCallee EnumerationMutationFunction() override {
1681e5dd7070Spatrick return ObjCTypes.getEnumerationMutationFn();
1682e5dd7070Spatrick }
1683e5dd7070Spatrick
1684e5dd7070Spatrick void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
1685e5dd7070Spatrick const ObjCAtTryStmt &S) override;
1686e5dd7070Spatrick void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
1687e5dd7070Spatrick const ObjCAtSynchronizedStmt &S) override;
1688e5dd7070Spatrick void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
1689e5dd7070Spatrick bool ClearInsertionPoint=true) override;
1690e5dd7070Spatrick llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
1691e5dd7070Spatrick Address AddrWeakObj) override;
1692e5dd7070Spatrick void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
1693e5dd7070Spatrick llvm::Value *src, Address edst) override;
1694e5dd7070Spatrick void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
1695e5dd7070Spatrick llvm::Value *src, Address dest,
1696e5dd7070Spatrick bool threadlocal = false) override;
1697e5dd7070Spatrick void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
1698e5dd7070Spatrick llvm::Value *src, Address dest,
1699e5dd7070Spatrick llvm::Value *ivarOffset) override;
1700e5dd7070Spatrick void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
1701e5dd7070Spatrick llvm::Value *src, Address dest) override;
1702e5dd7070Spatrick void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
1703e5dd7070Spatrick Address dest, Address src,
1704e5dd7070Spatrick llvm::Value *size) override;
1705e5dd7070Spatrick LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
1706e5dd7070Spatrick llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
1707e5dd7070Spatrick unsigned CVRQualifiers) override;
1708e5dd7070Spatrick llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
1709e5dd7070Spatrick const ObjCInterfaceDecl *Interface,
1710e5dd7070Spatrick const ObjCIvarDecl *Ivar) override;
1711e5dd7070Spatrick };
1712e5dd7070Spatrick
1713e5dd7070Spatrick /// A helper class for performing the null-initialization of a return
1714e5dd7070Spatrick /// value.
1715e5dd7070Spatrick struct NullReturnState {
1716e5dd7070Spatrick llvm::BasicBlock *NullBB;
NullReturnState__anon288f636e0111::NullReturnState1717e5dd7070Spatrick NullReturnState() : NullBB(nullptr) {}
1718e5dd7070Spatrick
1719e5dd7070Spatrick /// Perform a null-check of the given receiver.
init__anon288f636e0111::NullReturnState1720e5dd7070Spatrick void init(CodeGenFunction &CGF, llvm::Value *receiver) {
1721e5dd7070Spatrick // Make blocks for the null-receiver and call edges.
1722e5dd7070Spatrick NullBB = CGF.createBasicBlock("msgSend.null-receiver");
1723e5dd7070Spatrick llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call");
1724e5dd7070Spatrick
1725e5dd7070Spatrick // Check for a null receiver and, if there is one, jump to the
1726e5dd7070Spatrick // null-receiver block. There's no point in trying to avoid it:
1727e5dd7070Spatrick // we're always going to put *something* there, because otherwise
1728e5dd7070Spatrick // we shouldn't have done this null-check in the first place.
1729e5dd7070Spatrick llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
1730e5dd7070Spatrick CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
1731e5dd7070Spatrick
1732e5dd7070Spatrick // Otherwise, start performing the call.
1733e5dd7070Spatrick CGF.EmitBlock(callBB);
1734e5dd7070Spatrick }
1735e5dd7070Spatrick
1736e5dd7070Spatrick /// Complete the null-return operation. It is valid to call this
1737e5dd7070Spatrick /// regardless of whether 'init' has been called.
complete__anon288f636e0111::NullReturnState1738e5dd7070Spatrick RValue complete(CodeGenFunction &CGF,
1739e5dd7070Spatrick ReturnValueSlot returnSlot,
1740e5dd7070Spatrick RValue result,
1741e5dd7070Spatrick QualType resultType,
1742e5dd7070Spatrick const CallArgList &CallArgs,
1743e5dd7070Spatrick const ObjCMethodDecl *Method) {
1744e5dd7070Spatrick // If we never had to do a null-check, just use the raw result.
1745e5dd7070Spatrick if (!NullBB) return result;
1746e5dd7070Spatrick
1747e5dd7070Spatrick // The continuation block. This will be left null if we don't have an
1748e5dd7070Spatrick // IP, which can happen if the method we're calling is marked noreturn.
1749e5dd7070Spatrick llvm::BasicBlock *contBB = nullptr;
1750e5dd7070Spatrick
1751e5dd7070Spatrick // Finish the call path.
1752e5dd7070Spatrick llvm::BasicBlock *callBB = CGF.Builder.GetInsertBlock();
1753e5dd7070Spatrick if (callBB) {
1754e5dd7070Spatrick contBB = CGF.createBasicBlock("msgSend.cont");
1755e5dd7070Spatrick CGF.Builder.CreateBr(contBB);
1756e5dd7070Spatrick }
1757e5dd7070Spatrick
1758e5dd7070Spatrick // Okay, start emitting the null-receiver block.
1759e5dd7070Spatrick CGF.EmitBlock(NullBB);
1760e5dd7070Spatrick
1761*12c85518Srobert // Destroy any consumed arguments we've got.
1762e5dd7070Spatrick if (Method) {
1763*12c85518Srobert CGObjCRuntime::destroyCalleeDestroyedArguments(CGF, Method, CallArgs);
1764e5dd7070Spatrick }
1765e5dd7070Spatrick
1766e5dd7070Spatrick // The phi code below assumes that we haven't needed any control flow yet.
1767e5dd7070Spatrick assert(CGF.Builder.GetInsertBlock() == NullBB);
1768e5dd7070Spatrick
1769e5dd7070Spatrick // If we've got a void return, just jump to the continuation block.
1770e5dd7070Spatrick if (result.isScalar() && resultType->isVoidType()) {
1771e5dd7070Spatrick // No jumps required if the message-send was noreturn.
1772e5dd7070Spatrick if (contBB) CGF.EmitBlock(contBB);
1773e5dd7070Spatrick return result;
1774e5dd7070Spatrick }
1775e5dd7070Spatrick
1776e5dd7070Spatrick // If we've got a scalar return, build a phi.
1777e5dd7070Spatrick if (result.isScalar()) {
1778e5dd7070Spatrick // Derive the null-initialization value.
1779a9ac8606Spatrick llvm::Value *null =
1780a9ac8606Spatrick CGF.EmitFromMemory(CGF.CGM.EmitNullConstant(resultType), resultType);
1781e5dd7070Spatrick
1782e5dd7070Spatrick // If no join is necessary, just flow out.
1783e5dd7070Spatrick if (!contBB) return RValue::get(null);
1784e5dd7070Spatrick
1785e5dd7070Spatrick // Otherwise, build a phi.
1786e5dd7070Spatrick CGF.EmitBlock(contBB);
1787e5dd7070Spatrick llvm::PHINode *phi = CGF.Builder.CreatePHI(null->getType(), 2);
1788e5dd7070Spatrick phi->addIncoming(result.getScalarVal(), callBB);
1789e5dd7070Spatrick phi->addIncoming(null, NullBB);
1790e5dd7070Spatrick return RValue::get(phi);
1791e5dd7070Spatrick }
1792e5dd7070Spatrick
1793e5dd7070Spatrick // If we've got an aggregate return, null the buffer out.
1794e5dd7070Spatrick // FIXME: maybe we should be doing things differently for all the
1795e5dd7070Spatrick // cases where the ABI has us returning (1) non-agg values in
1796e5dd7070Spatrick // memory or (2) agg values in registers.
1797e5dd7070Spatrick if (result.isAggregate()) {
1798e5dd7070Spatrick assert(result.isAggregate() && "null init of non-aggregate result?");
1799e5dd7070Spatrick if (!returnSlot.isUnused())
1800e5dd7070Spatrick CGF.EmitNullInitialization(result.getAggregateAddress(), resultType);
1801e5dd7070Spatrick if (contBB) CGF.EmitBlock(contBB);
1802e5dd7070Spatrick return result;
1803e5dd7070Spatrick }
1804e5dd7070Spatrick
1805e5dd7070Spatrick // Complex types.
1806e5dd7070Spatrick CGF.EmitBlock(contBB);
1807e5dd7070Spatrick CodeGenFunction::ComplexPairTy callResult = result.getComplexVal();
1808e5dd7070Spatrick
1809e5dd7070Spatrick // Find the scalar type and its zero value.
1810e5dd7070Spatrick llvm::Type *scalarTy = callResult.first->getType();
1811e5dd7070Spatrick llvm::Constant *scalarZero = llvm::Constant::getNullValue(scalarTy);
1812e5dd7070Spatrick
1813e5dd7070Spatrick // Build phis for both coordinates.
1814e5dd7070Spatrick llvm::PHINode *real = CGF.Builder.CreatePHI(scalarTy, 2);
1815e5dd7070Spatrick real->addIncoming(callResult.first, callBB);
1816e5dd7070Spatrick real->addIncoming(scalarZero, NullBB);
1817e5dd7070Spatrick llvm::PHINode *imag = CGF.Builder.CreatePHI(scalarTy, 2);
1818e5dd7070Spatrick imag->addIncoming(callResult.second, callBB);
1819e5dd7070Spatrick imag->addIncoming(scalarZero, NullBB);
1820e5dd7070Spatrick return RValue::getComplex(real, imag);
1821e5dd7070Spatrick }
1822e5dd7070Spatrick };
1823e5dd7070Spatrick
1824e5dd7070Spatrick } // end anonymous namespace
1825e5dd7070Spatrick
1826e5dd7070Spatrick /* *** Helper Functions *** */
1827e5dd7070Spatrick
1828e5dd7070Spatrick /// getConstantGEP() - Help routine to construct simple GEPs.
getConstantGEP(llvm::LLVMContext & VMContext,llvm::GlobalVariable * C,unsigned idx0,unsigned idx1)1829e5dd7070Spatrick static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext,
1830e5dd7070Spatrick llvm::GlobalVariable *C, unsigned idx0,
1831e5dd7070Spatrick unsigned idx1) {
1832e5dd7070Spatrick llvm::Value *Idxs[] = {
1833e5dd7070Spatrick llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0),
1834e5dd7070Spatrick llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx1)
1835e5dd7070Spatrick };
1836e5dd7070Spatrick return llvm::ConstantExpr::getGetElementPtr(C->getValueType(), C, Idxs);
1837e5dd7070Spatrick }
1838e5dd7070Spatrick
1839e5dd7070Spatrick /// hasObjCExceptionAttribute - Return true if this class or any super
1840e5dd7070Spatrick /// class has the __objc_exception__ attribute.
hasObjCExceptionAttribute(ASTContext & Context,const ObjCInterfaceDecl * OID)1841e5dd7070Spatrick static bool hasObjCExceptionAttribute(ASTContext &Context,
1842e5dd7070Spatrick const ObjCInterfaceDecl *OID) {
1843e5dd7070Spatrick if (OID->hasAttr<ObjCExceptionAttr>())
1844e5dd7070Spatrick return true;
1845e5dd7070Spatrick if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
1846e5dd7070Spatrick return hasObjCExceptionAttribute(Context, Super);
1847e5dd7070Spatrick return false;
1848e5dd7070Spatrick }
1849e5dd7070Spatrick
1850e5dd7070Spatrick static llvm::GlobalValue::LinkageTypes
getLinkageTypeForObjCMetadata(CodeGenModule & CGM,StringRef Section)1851e5dd7070Spatrick getLinkageTypeForObjCMetadata(CodeGenModule &CGM, StringRef Section) {
1852e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO() &&
1853e5dd7070Spatrick (Section.empty() || Section.startswith("__DATA")))
1854e5dd7070Spatrick return llvm::GlobalValue::InternalLinkage;
1855e5dd7070Spatrick return llvm::GlobalValue::PrivateLinkage;
1856e5dd7070Spatrick }
1857e5dd7070Spatrick
1858e5dd7070Spatrick /// A helper function to create an internal or private global variable.
1859e5dd7070Spatrick static llvm::GlobalVariable *
finishAndCreateGlobal(ConstantInitBuilder::StructBuilder & Builder,const llvm::Twine & Name,CodeGenModule & CGM)1860e5dd7070Spatrick finishAndCreateGlobal(ConstantInitBuilder::StructBuilder &Builder,
1861e5dd7070Spatrick const llvm::Twine &Name, CodeGenModule &CGM) {
1862e5dd7070Spatrick std::string SectionName;
1863e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO())
1864e5dd7070Spatrick SectionName = "__DATA, __objc_const";
1865e5dd7070Spatrick auto *GV = Builder.finishAndCreateGlobal(
1866e5dd7070Spatrick Name, CGM.getPointerAlign(), /*constant*/ false,
1867e5dd7070Spatrick getLinkageTypeForObjCMetadata(CGM, SectionName));
1868e5dd7070Spatrick GV->setSection(SectionName);
1869e5dd7070Spatrick return GV;
1870e5dd7070Spatrick }
1871e5dd7070Spatrick
1872e5dd7070Spatrick /* *** CGObjCMac Public Interface *** */
1873e5dd7070Spatrick
CGObjCMac(CodeGen::CodeGenModule & cgm)1874e5dd7070Spatrick CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
1875e5dd7070Spatrick ObjCTypes(cgm) {
1876e5dd7070Spatrick ObjCABI = 1;
1877e5dd7070Spatrick EmitImageInfo();
1878e5dd7070Spatrick }
1879e5dd7070Spatrick
1880e5dd7070Spatrick /// GetClass - Return a reference to the class for the given interface
1881e5dd7070Spatrick /// decl.
GetClass(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)1882e5dd7070Spatrick llvm::Value *CGObjCMac::GetClass(CodeGenFunction &CGF,
1883e5dd7070Spatrick const ObjCInterfaceDecl *ID) {
1884e5dd7070Spatrick return EmitClassRef(CGF, ID);
1885e5dd7070Spatrick }
1886e5dd7070Spatrick
1887e5dd7070Spatrick /// GetSelector - Return the pointer to the unique'd string for this selector.
GetSelector(CodeGenFunction & CGF,Selector Sel)1888e5dd7070Spatrick llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel) {
1889e5dd7070Spatrick return EmitSelector(CGF, Sel);
1890e5dd7070Spatrick }
GetAddrOfSelector(CodeGenFunction & CGF,Selector Sel)1891e5dd7070Spatrick Address CGObjCMac::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) {
1892e5dd7070Spatrick return EmitSelectorAddr(Sel);
1893e5dd7070Spatrick }
GetSelector(CodeGenFunction & CGF,const ObjCMethodDecl * Method)1894e5dd7070Spatrick llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
1895e5dd7070Spatrick *Method) {
1896e5dd7070Spatrick return EmitSelector(CGF, Method->getSelector());
1897e5dd7070Spatrick }
1898e5dd7070Spatrick
GetEHType(QualType T)1899e5dd7070Spatrick llvm::Constant *CGObjCMac::GetEHType(QualType T) {
1900e5dd7070Spatrick if (T->isObjCIdType() ||
1901e5dd7070Spatrick T->isObjCQualifiedIdType()) {
1902e5dd7070Spatrick return CGM.GetAddrOfRTTIDescriptor(
1903e5dd7070Spatrick CGM.getContext().getObjCIdRedefinitionType(), /*ForEH=*/true);
1904e5dd7070Spatrick }
1905e5dd7070Spatrick if (T->isObjCClassType() ||
1906e5dd7070Spatrick T->isObjCQualifiedClassType()) {
1907e5dd7070Spatrick return CGM.GetAddrOfRTTIDescriptor(
1908e5dd7070Spatrick CGM.getContext().getObjCClassRedefinitionType(), /*ForEH=*/true);
1909e5dd7070Spatrick }
1910e5dd7070Spatrick if (T->isObjCObjectPointerType())
1911e5dd7070Spatrick return CGM.GetAddrOfRTTIDescriptor(T, /*ForEH=*/true);
1912e5dd7070Spatrick
1913e5dd7070Spatrick llvm_unreachable("asking for catch type for ObjC type in fragile runtime");
1914e5dd7070Spatrick }
1915e5dd7070Spatrick
1916e5dd7070Spatrick /// Generate a constant CFString object.
1917e5dd7070Spatrick /*
1918e5dd7070Spatrick struct __builtin_CFString {
1919e5dd7070Spatrick const int *isa; // point to __CFConstantStringClassReference
1920e5dd7070Spatrick int flags;
1921e5dd7070Spatrick const char *str;
1922e5dd7070Spatrick long length;
1923e5dd7070Spatrick };
1924e5dd7070Spatrick */
1925e5dd7070Spatrick
1926e5dd7070Spatrick /// or Generate a constant NSString object.
1927e5dd7070Spatrick /*
1928e5dd7070Spatrick struct __builtin_NSString {
1929e5dd7070Spatrick const int *isa; // point to __NSConstantStringClassReference
1930e5dd7070Spatrick const char *str;
1931e5dd7070Spatrick unsigned int length;
1932e5dd7070Spatrick };
1933e5dd7070Spatrick */
1934e5dd7070Spatrick
1935e5dd7070Spatrick ConstantAddress
GenerateConstantString(const StringLiteral * SL)1936e5dd7070Spatrick CGObjCCommonMac::GenerateConstantString(const StringLiteral *SL) {
1937e5dd7070Spatrick return (!CGM.getLangOpts().NoConstantCFStrings
1938e5dd7070Spatrick ? CGM.GetAddrOfConstantCFString(SL)
1939e5dd7070Spatrick : GenerateConstantNSString(SL));
1940e5dd7070Spatrick }
1941e5dd7070Spatrick
1942e5dd7070Spatrick static llvm::StringMapEntry<llvm::GlobalVariable *> &
GetConstantStringEntry(llvm::StringMap<llvm::GlobalVariable * > & Map,const StringLiteral * Literal,unsigned & StringLength)1943e5dd7070Spatrick GetConstantStringEntry(llvm::StringMap<llvm::GlobalVariable *> &Map,
1944e5dd7070Spatrick const StringLiteral *Literal, unsigned &StringLength) {
1945e5dd7070Spatrick StringRef String = Literal->getString();
1946e5dd7070Spatrick StringLength = String.size();
1947e5dd7070Spatrick return *Map.insert(std::make_pair(String, nullptr)).first;
1948e5dd7070Spatrick }
1949e5dd7070Spatrick
getNSConstantStringClassRef()1950e5dd7070Spatrick llvm::Constant *CGObjCMac::getNSConstantStringClassRef() {
1951e5dd7070Spatrick if (llvm::Value *V = ConstantStringClassRef)
1952e5dd7070Spatrick return cast<llvm::Constant>(V);
1953e5dd7070Spatrick
1954e5dd7070Spatrick auto &StringClass = CGM.getLangOpts().ObjCConstantStringClass;
1955e5dd7070Spatrick std::string str =
1956e5dd7070Spatrick StringClass.empty() ? "_NSConstantStringClassReference"
1957e5dd7070Spatrick : "_" + StringClass + "ClassReference";
1958e5dd7070Spatrick
1959e5dd7070Spatrick llvm::Type *PTy = llvm::ArrayType::get(CGM.IntTy, 0);
1960e5dd7070Spatrick auto GV = CGM.CreateRuntimeVariable(PTy, str);
1961e5dd7070Spatrick auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo());
1962e5dd7070Spatrick ConstantStringClassRef = V;
1963e5dd7070Spatrick return V;
1964e5dd7070Spatrick }
1965e5dd7070Spatrick
getNSConstantStringClassRef()1966e5dd7070Spatrick llvm::Constant *CGObjCNonFragileABIMac::getNSConstantStringClassRef() {
1967e5dd7070Spatrick if (llvm::Value *V = ConstantStringClassRef)
1968e5dd7070Spatrick return cast<llvm::Constant>(V);
1969e5dd7070Spatrick
1970e5dd7070Spatrick auto &StringClass = CGM.getLangOpts().ObjCConstantStringClass;
1971e5dd7070Spatrick std::string str =
1972e5dd7070Spatrick StringClass.empty() ? "OBJC_CLASS_$_NSConstantString"
1973e5dd7070Spatrick : "OBJC_CLASS_$_" + StringClass;
1974e5dd7070Spatrick llvm::Constant *GV = GetClassGlobal(str, NotForDefinition);
1975e5dd7070Spatrick
1976e5dd7070Spatrick // Make sure the result is of the correct type.
1977e5dd7070Spatrick auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo());
1978e5dd7070Spatrick
1979e5dd7070Spatrick ConstantStringClassRef = V;
1980e5dd7070Spatrick return V;
1981e5dd7070Spatrick }
1982e5dd7070Spatrick
1983e5dd7070Spatrick ConstantAddress
GenerateConstantNSString(const StringLiteral * Literal)1984e5dd7070Spatrick CGObjCCommonMac::GenerateConstantNSString(const StringLiteral *Literal) {
1985e5dd7070Spatrick unsigned StringLength = 0;
1986e5dd7070Spatrick llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
1987e5dd7070Spatrick GetConstantStringEntry(NSConstantStringMap, Literal, StringLength);
1988e5dd7070Spatrick
1989e5dd7070Spatrick if (auto *C = Entry.second)
1990*12c85518Srobert return ConstantAddress(
1991*12c85518Srobert C, C->getValueType(), CharUnits::fromQuantity(C->getAlignment()));
1992e5dd7070Spatrick
1993e5dd7070Spatrick // If we don't already have it, get _NSConstantStringClassReference.
1994e5dd7070Spatrick llvm::Constant *Class = getNSConstantStringClassRef();
1995e5dd7070Spatrick
1996e5dd7070Spatrick // If we don't already have it, construct the type for a constant NSString.
1997e5dd7070Spatrick if (!NSConstantStringType) {
1998e5dd7070Spatrick NSConstantStringType =
1999e5dd7070Spatrick llvm::StructType::create({
2000e5dd7070Spatrick CGM.Int32Ty->getPointerTo(),
2001e5dd7070Spatrick CGM.Int8PtrTy,
2002e5dd7070Spatrick CGM.IntTy
2003e5dd7070Spatrick }, "struct.__builtin_NSString");
2004e5dd7070Spatrick }
2005e5dd7070Spatrick
2006e5dd7070Spatrick ConstantInitBuilder Builder(CGM);
2007e5dd7070Spatrick auto Fields = Builder.beginStruct(NSConstantStringType);
2008e5dd7070Spatrick
2009e5dd7070Spatrick // Class pointer.
2010e5dd7070Spatrick Fields.add(Class);
2011e5dd7070Spatrick
2012e5dd7070Spatrick // String pointer.
2013e5dd7070Spatrick llvm::Constant *C =
2014e5dd7070Spatrick llvm::ConstantDataArray::getString(VMContext, Entry.first());
2015e5dd7070Spatrick
2016e5dd7070Spatrick llvm::GlobalValue::LinkageTypes Linkage = llvm::GlobalValue::PrivateLinkage;
2017e5dd7070Spatrick bool isConstant = !CGM.getLangOpts().WritableStrings;
2018e5dd7070Spatrick
2019e5dd7070Spatrick auto *GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), isConstant,
2020e5dd7070Spatrick Linkage, C, ".str");
2021e5dd7070Spatrick GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
2022e5dd7070Spatrick // Don't enforce the target's minimum global alignment, since the only use
2023e5dd7070Spatrick // of the string is via this class initializer.
2024ec727ea7Spatrick GV->setAlignment(llvm::Align(1));
2025e5dd7070Spatrick Fields.addBitCast(GV, CGM.Int8PtrTy);
2026e5dd7070Spatrick
2027e5dd7070Spatrick // String length.
2028e5dd7070Spatrick Fields.addInt(CGM.IntTy, StringLength);
2029e5dd7070Spatrick
2030e5dd7070Spatrick // The struct.
2031e5dd7070Spatrick CharUnits Alignment = CGM.getPointerAlign();
2032e5dd7070Spatrick GV = Fields.finishAndCreateGlobal("_unnamed_nsstring_", Alignment,
2033e5dd7070Spatrick /*constant*/ true,
2034e5dd7070Spatrick llvm::GlobalVariable::PrivateLinkage);
2035e5dd7070Spatrick const char *NSStringSection = "__OBJC,__cstring_object,regular,no_dead_strip";
2036e5dd7070Spatrick const char *NSStringNonFragileABISection =
2037e5dd7070Spatrick "__DATA,__objc_stringobj,regular,no_dead_strip";
2038e5dd7070Spatrick // FIXME. Fix section.
2039e5dd7070Spatrick GV->setSection(CGM.getLangOpts().ObjCRuntime.isNonFragile()
2040e5dd7070Spatrick ? NSStringNonFragileABISection
2041e5dd7070Spatrick : NSStringSection);
2042e5dd7070Spatrick Entry.second = GV;
2043e5dd7070Spatrick
2044*12c85518Srobert return ConstantAddress(GV, GV->getValueType(), Alignment);
2045e5dd7070Spatrick }
2046e5dd7070Spatrick
2047e5dd7070Spatrick enum {
2048e5dd7070Spatrick kCFTaggedObjectID_Integer = (1 << 1) + 1
2049e5dd7070Spatrick };
2050e5dd7070Spatrick
2051e5dd7070Spatrick /// Generates a message send where the super is the receiver. This is
2052e5dd7070Spatrick /// a message send to self with special delivery semantics indicating
2053e5dd7070Spatrick /// which class's method should be called.
2054e5dd7070Spatrick 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)2055e5dd7070Spatrick CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
2056e5dd7070Spatrick ReturnValueSlot Return,
2057e5dd7070Spatrick QualType ResultType,
2058e5dd7070Spatrick Selector Sel,
2059e5dd7070Spatrick const ObjCInterfaceDecl *Class,
2060e5dd7070Spatrick bool isCategoryImpl,
2061e5dd7070Spatrick llvm::Value *Receiver,
2062e5dd7070Spatrick bool IsClassMessage,
2063e5dd7070Spatrick const CodeGen::CallArgList &CallArgs,
2064e5dd7070Spatrick const ObjCMethodDecl *Method) {
2065e5dd7070Spatrick // Create and init a super structure; this is a (receiver, class)
2066e5dd7070Spatrick // pair we will pass to objc_msgSendSuper.
2067e5dd7070Spatrick Address ObjCSuper =
2068e5dd7070Spatrick CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(),
2069e5dd7070Spatrick "objc_super");
2070e5dd7070Spatrick llvm::Value *ReceiverAsObject =
2071e5dd7070Spatrick CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
2072e5dd7070Spatrick CGF.Builder.CreateStore(ReceiverAsObject,
2073e5dd7070Spatrick CGF.Builder.CreateStructGEP(ObjCSuper, 0));
2074e5dd7070Spatrick
2075e5dd7070Spatrick // If this is a class message the metaclass is passed as the target.
2076a9ac8606Spatrick llvm::Type *ClassTyPtr = llvm::PointerType::getUnqual(ObjCTypes.ClassTy);
2077e5dd7070Spatrick llvm::Value *Target;
2078e5dd7070Spatrick if (IsClassMessage) {
2079e5dd7070Spatrick if (isCategoryImpl) {
2080e5dd7070Spatrick // Message sent to 'super' in a class method defined in a category
2081e5dd7070Spatrick // implementation requires an odd treatment.
2082e5dd7070Spatrick // If we are in a class method, we must retrieve the
2083e5dd7070Spatrick // _metaclass_ for the current class, pointed at by
2084e5dd7070Spatrick // the class's "isa" pointer. The following assumes that
2085e5dd7070Spatrick // isa" is the first ivar in a class (which it must be).
2086e5dd7070Spatrick Target = EmitClassRef(CGF, Class->getSuperClass());
2087e5dd7070Spatrick Target = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, Target, 0);
2088a9ac8606Spatrick Target = CGF.Builder.CreateAlignedLoad(ClassTyPtr, Target,
2089a9ac8606Spatrick CGF.getPointerAlign());
2090e5dd7070Spatrick } else {
2091e5dd7070Spatrick llvm::Constant *MetaClassPtr = EmitMetaClassRef(Class);
2092e5dd7070Spatrick llvm::Value *SuperPtr =
2093e5dd7070Spatrick CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, MetaClassPtr, 1);
2094a9ac8606Spatrick llvm::Value *Super = CGF.Builder.CreateAlignedLoad(ClassTyPtr, SuperPtr,
2095a9ac8606Spatrick CGF.getPointerAlign());
2096e5dd7070Spatrick Target = Super;
2097e5dd7070Spatrick }
2098e5dd7070Spatrick } else if (isCategoryImpl)
2099e5dd7070Spatrick Target = EmitClassRef(CGF, Class->getSuperClass());
2100e5dd7070Spatrick else {
2101e5dd7070Spatrick llvm::Value *ClassPtr = EmitSuperClassRef(Class);
2102e5dd7070Spatrick ClassPtr = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, ClassPtr, 1);
2103a9ac8606Spatrick Target = CGF.Builder.CreateAlignedLoad(ClassTyPtr, ClassPtr,
2104a9ac8606Spatrick CGF.getPointerAlign());
2105e5dd7070Spatrick }
2106e5dd7070Spatrick // FIXME: We shouldn't need to do this cast, rectify the ASTContext and
2107e5dd7070Spatrick // ObjCTypes types.
2108e5dd7070Spatrick llvm::Type *ClassTy =
2109e5dd7070Spatrick CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
2110e5dd7070Spatrick Target = CGF.Builder.CreateBitCast(Target, ClassTy);
2111e5dd7070Spatrick CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1));
2112e5dd7070Spatrick return EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper.getPointer(),
2113e5dd7070Spatrick ObjCTypes.SuperPtrCTy, true, CallArgs, Method, Class,
2114e5dd7070Spatrick ObjCTypes);
2115e5dd7070Spatrick }
2116e5dd7070Spatrick
2117e5dd7070Spatrick /// 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)2118e5dd7070Spatrick CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
2119e5dd7070Spatrick ReturnValueSlot Return,
2120e5dd7070Spatrick QualType ResultType,
2121e5dd7070Spatrick Selector Sel,
2122e5dd7070Spatrick llvm::Value *Receiver,
2123e5dd7070Spatrick const CallArgList &CallArgs,
2124e5dd7070Spatrick const ObjCInterfaceDecl *Class,
2125e5dd7070Spatrick const ObjCMethodDecl *Method) {
2126e5dd7070Spatrick return EmitMessageSend(CGF, Return, ResultType, Sel, Receiver,
2127e5dd7070Spatrick CGF.getContext().getObjCIdType(), false, CallArgs,
2128e5dd7070Spatrick Method, Class, ObjCTypes);
2129e5dd7070Spatrick }
2130e5dd7070Spatrick
2131e5dd7070Spatrick 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)2132e5dd7070Spatrick CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
2133e5dd7070Spatrick ReturnValueSlot Return,
2134e5dd7070Spatrick QualType ResultType,
2135e5dd7070Spatrick Selector Sel,
2136e5dd7070Spatrick llvm::Value *Arg0,
2137e5dd7070Spatrick QualType Arg0Ty,
2138e5dd7070Spatrick bool IsSuper,
2139e5dd7070Spatrick const CallArgList &CallArgs,
2140e5dd7070Spatrick const ObjCMethodDecl *Method,
2141e5dd7070Spatrick const ObjCInterfaceDecl *ClassReceiver,
2142e5dd7070Spatrick const ObjCCommonTypesHelper &ObjCTypes) {
2143e5dd7070Spatrick CodeGenTypes &Types = CGM.getTypes();
2144e5dd7070Spatrick auto selTy = CGF.getContext().getObjCSelType();
2145*12c85518Srobert llvm::Value *SelValue = llvm::UndefValue::get(Types.ConvertType(selTy));
2146e5dd7070Spatrick
2147e5dd7070Spatrick CallArgList ActualArgs;
2148e5dd7070Spatrick if (!IsSuper)
2149e5dd7070Spatrick Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
2150e5dd7070Spatrick ActualArgs.add(RValue::get(Arg0), Arg0Ty);
2151*12c85518Srobert if (!Method || !Method->isDirectMethod())
2152e5dd7070Spatrick ActualArgs.add(RValue::get(SelValue), selTy);
2153e5dd7070Spatrick ActualArgs.addFrom(CallArgs);
2154e5dd7070Spatrick
2155e5dd7070Spatrick // If we're calling a method, use the formal signature.
2156e5dd7070Spatrick MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
2157e5dd7070Spatrick
2158e5dd7070Spatrick if (Method)
2159e5dd7070Spatrick assert(CGM.getContext().getCanonicalType(Method->getReturnType()) ==
2160e5dd7070Spatrick CGM.getContext().getCanonicalType(ResultType) &&
2161e5dd7070Spatrick "Result type mismatch!");
2162e5dd7070Spatrick
2163*12c85518Srobert bool ReceiverCanBeNull =
2164*12c85518Srobert canMessageReceiverBeNull(CGF, Method, IsSuper, ClassReceiver, Arg0);
2165e5dd7070Spatrick
2166e5dd7070Spatrick bool RequiresNullCheck = false;
2167*12c85518Srobert bool RequiresSelValue = true;
2168e5dd7070Spatrick
2169e5dd7070Spatrick llvm::FunctionCallee Fn = nullptr;
2170e5dd7070Spatrick if (Method && Method->isDirectMethod()) {
2171*12c85518Srobert assert(!IsSuper);
2172e5dd7070Spatrick Fn = GenerateDirectMethod(Method, Method->getClassInterface());
2173*12c85518Srobert // Direct methods will synthesize the proper `_cmd` internally,
2174*12c85518Srobert // so just don't bother with setting the `_cmd` argument.
2175*12c85518Srobert RequiresSelValue = false;
2176e5dd7070Spatrick } else if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
2177e5dd7070Spatrick if (ReceiverCanBeNull) RequiresNullCheck = true;
2178e5dd7070Spatrick Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
2179e5dd7070Spatrick : ObjCTypes.getSendStretFn(IsSuper);
2180e5dd7070Spatrick } else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
2181e5dd7070Spatrick Fn = (ObjCABI == 2) ? ObjCTypes.getSendFpretFn2(IsSuper)
2182e5dd7070Spatrick : ObjCTypes.getSendFpretFn(IsSuper);
2183e5dd7070Spatrick } else if (CGM.ReturnTypeUsesFP2Ret(ResultType)) {
2184e5dd7070Spatrick Fn = (ObjCABI == 2) ? ObjCTypes.getSendFp2RetFn2(IsSuper)
2185e5dd7070Spatrick : ObjCTypes.getSendFp2retFn(IsSuper);
2186e5dd7070Spatrick } else {
2187e5dd7070Spatrick // arm64 uses objc_msgSend for stret methods and yet null receiver check
2188e5dd7070Spatrick // must be made for it.
2189e5dd7070Spatrick if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
2190e5dd7070Spatrick RequiresNullCheck = true;
2191e5dd7070Spatrick Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
2192e5dd7070Spatrick : ObjCTypes.getSendFn(IsSuper);
2193e5dd7070Spatrick }
2194e5dd7070Spatrick
2195e5dd7070Spatrick // Cast function to proper signature
2196e5dd7070Spatrick llvm::Constant *BitcastFn = cast<llvm::Constant>(
2197e5dd7070Spatrick CGF.Builder.CreateBitCast(Fn.getCallee(), MSI.MessengerType));
2198e5dd7070Spatrick
2199e5dd7070Spatrick // We don't need to emit a null check to zero out an indirect result if the
2200e5dd7070Spatrick // result is ignored.
2201e5dd7070Spatrick if (Return.isUnused())
2202e5dd7070Spatrick RequiresNullCheck = false;
2203e5dd7070Spatrick
2204e5dd7070Spatrick // Emit a null-check if there's a consumed argument other than the receiver.
2205*12c85518Srobert if (!RequiresNullCheck && Method && Method->hasParamDestroyedInCallee())
2206e5dd7070Spatrick RequiresNullCheck = true;
2207e5dd7070Spatrick
2208e5dd7070Spatrick NullReturnState nullReturn;
2209e5dd7070Spatrick if (RequiresNullCheck) {
2210e5dd7070Spatrick nullReturn.init(CGF, Arg0);
2211e5dd7070Spatrick }
2212e5dd7070Spatrick
2213*12c85518Srobert // If a selector value needs to be passed, emit the load before the call.
2214*12c85518Srobert if (RequiresSelValue) {
2215*12c85518Srobert SelValue = GetSelector(CGF, Sel);
2216*12c85518Srobert ActualArgs[1] = CallArg(RValue::get(SelValue), selTy);
2217*12c85518Srobert }
2218*12c85518Srobert
2219e5dd7070Spatrick llvm::CallBase *CallSite;
2220e5dd7070Spatrick CGCallee Callee = CGCallee::forDirect(BitcastFn);
2221e5dd7070Spatrick RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs,
2222e5dd7070Spatrick &CallSite);
2223e5dd7070Spatrick
2224e5dd7070Spatrick // Mark the call as noreturn if the method is marked noreturn and the
2225e5dd7070Spatrick // receiver cannot be null.
2226e5dd7070Spatrick if (Method && Method->hasAttr<NoReturnAttr>() && !ReceiverCanBeNull) {
2227e5dd7070Spatrick CallSite->setDoesNotReturn();
2228e5dd7070Spatrick }
2229e5dd7070Spatrick
2230e5dd7070Spatrick return nullReturn.complete(CGF, Return, rvalue, ResultType, CallArgs,
2231e5dd7070Spatrick RequiresNullCheck ? Method : nullptr);
2232e5dd7070Spatrick }
2233e5dd7070Spatrick
GetGCAttrTypeForType(ASTContext & Ctx,QualType FQT,bool pointee=false)2234e5dd7070Spatrick static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT,
2235e5dd7070Spatrick bool pointee = false) {
2236e5dd7070Spatrick // Note that GC qualification applies recursively to C pointer types
2237e5dd7070Spatrick // that aren't otherwise decorated. This is weird, but it's probably
2238e5dd7070Spatrick // an intentional workaround to the unreliable placement of GC qualifiers.
2239e5dd7070Spatrick if (FQT.isObjCGCStrong())
2240e5dd7070Spatrick return Qualifiers::Strong;
2241e5dd7070Spatrick
2242e5dd7070Spatrick if (FQT.isObjCGCWeak())
2243e5dd7070Spatrick return Qualifiers::Weak;
2244e5dd7070Spatrick
2245e5dd7070Spatrick if (auto ownership = FQT.getObjCLifetime()) {
2246e5dd7070Spatrick // Ownership does not apply recursively to C pointer types.
2247e5dd7070Spatrick if (pointee) return Qualifiers::GCNone;
2248e5dd7070Spatrick switch (ownership) {
2249e5dd7070Spatrick case Qualifiers::OCL_Weak: return Qualifiers::Weak;
2250e5dd7070Spatrick case Qualifiers::OCL_Strong: return Qualifiers::Strong;
2251e5dd7070Spatrick case Qualifiers::OCL_ExplicitNone: return Qualifiers::GCNone;
2252e5dd7070Spatrick case Qualifiers::OCL_Autoreleasing: llvm_unreachable("autoreleasing ivar?");
2253e5dd7070Spatrick case Qualifiers::OCL_None: llvm_unreachable("known nonzero");
2254e5dd7070Spatrick }
2255e5dd7070Spatrick llvm_unreachable("bad objc ownership");
2256e5dd7070Spatrick }
2257e5dd7070Spatrick
2258e5dd7070Spatrick // Treat unqualified retainable pointers as strong.
2259e5dd7070Spatrick if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
2260e5dd7070Spatrick return Qualifiers::Strong;
2261e5dd7070Spatrick
2262e5dd7070Spatrick // Walk into C pointer types, but only in GC.
2263e5dd7070Spatrick if (Ctx.getLangOpts().getGC() != LangOptions::NonGC) {
2264e5dd7070Spatrick if (const PointerType *PT = FQT->getAs<PointerType>())
2265e5dd7070Spatrick return GetGCAttrTypeForType(Ctx, PT->getPointeeType(), /*pointee*/ true);
2266e5dd7070Spatrick }
2267e5dd7070Spatrick
2268e5dd7070Spatrick return Qualifiers::GCNone;
2269e5dd7070Spatrick }
2270e5dd7070Spatrick
2271e5dd7070Spatrick namespace {
2272e5dd7070Spatrick struct IvarInfo {
2273e5dd7070Spatrick CharUnits Offset;
2274e5dd7070Spatrick uint64_t SizeInWords;
IvarInfo__anon288f636e0511::IvarInfo2275e5dd7070Spatrick IvarInfo(CharUnits offset, uint64_t sizeInWords)
2276e5dd7070Spatrick : Offset(offset), SizeInWords(sizeInWords) {}
2277e5dd7070Spatrick
2278e5dd7070Spatrick // Allow sorting based on byte pos.
operator <__anon288f636e0511::IvarInfo2279e5dd7070Spatrick bool operator<(const IvarInfo &other) const {
2280e5dd7070Spatrick return Offset < other.Offset;
2281e5dd7070Spatrick }
2282e5dd7070Spatrick };
2283e5dd7070Spatrick
2284e5dd7070Spatrick /// A helper class for building GC layout strings.
2285e5dd7070Spatrick class IvarLayoutBuilder {
2286e5dd7070Spatrick CodeGenModule &CGM;
2287e5dd7070Spatrick
2288e5dd7070Spatrick /// The start of the layout. Offsets will be relative to this value,
2289e5dd7070Spatrick /// and entries less than this value will be silently discarded.
2290e5dd7070Spatrick CharUnits InstanceBegin;
2291e5dd7070Spatrick
2292e5dd7070Spatrick /// The end of the layout. Offsets will never exceed this value.
2293e5dd7070Spatrick CharUnits InstanceEnd;
2294e5dd7070Spatrick
2295e5dd7070Spatrick /// Whether we're generating the strong layout or the weak layout.
2296e5dd7070Spatrick bool ForStrongLayout;
2297e5dd7070Spatrick
2298e5dd7070Spatrick /// Whether the offsets in IvarsInfo might be out-of-order.
2299e5dd7070Spatrick bool IsDisordered = false;
2300e5dd7070Spatrick
2301e5dd7070Spatrick llvm::SmallVector<IvarInfo, 8> IvarsInfo;
2302e5dd7070Spatrick
2303e5dd7070Spatrick public:
IvarLayoutBuilder(CodeGenModule & CGM,CharUnits instanceBegin,CharUnits instanceEnd,bool forStrongLayout)2304e5dd7070Spatrick IvarLayoutBuilder(CodeGenModule &CGM, CharUnits instanceBegin,
2305e5dd7070Spatrick CharUnits instanceEnd, bool forStrongLayout)
2306e5dd7070Spatrick : CGM(CGM), InstanceBegin(instanceBegin), InstanceEnd(instanceEnd),
2307e5dd7070Spatrick ForStrongLayout(forStrongLayout) {
2308e5dd7070Spatrick }
2309e5dd7070Spatrick
2310e5dd7070Spatrick void visitRecord(const RecordType *RT, CharUnits offset);
2311e5dd7070Spatrick
2312e5dd7070Spatrick template <class Iterator, class GetOffsetFn>
2313e5dd7070Spatrick void visitAggregate(Iterator begin, Iterator end,
2314e5dd7070Spatrick CharUnits aggrOffset,
2315e5dd7070Spatrick const GetOffsetFn &getOffset);
2316e5dd7070Spatrick
2317e5dd7070Spatrick void visitField(const FieldDecl *field, CharUnits offset);
2318e5dd7070Spatrick
2319e5dd7070Spatrick /// Add the layout of a block implementation.
2320e5dd7070Spatrick void visitBlock(const CGBlockInfo &blockInfo);
2321e5dd7070Spatrick
2322e5dd7070Spatrick /// Is there any information for an interesting bitmap?
hasBitmapData() const2323e5dd7070Spatrick bool hasBitmapData() const { return !IvarsInfo.empty(); }
2324e5dd7070Spatrick
2325e5dd7070Spatrick llvm::Constant *buildBitmap(CGObjCCommonMac &CGObjC,
2326e5dd7070Spatrick llvm::SmallVectorImpl<unsigned char> &buffer);
2327e5dd7070Spatrick
dump(ArrayRef<unsigned char> buffer)2328e5dd7070Spatrick static void dump(ArrayRef<unsigned char> buffer) {
2329e5dd7070Spatrick const unsigned char *s = buffer.data();
2330e5dd7070Spatrick for (unsigned i = 0, e = buffer.size(); i < e; i++)
2331e5dd7070Spatrick if (!(s[i] & 0xf0))
2332e5dd7070Spatrick printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
2333e5dd7070Spatrick else
2334e5dd7070Spatrick printf("0x%x%s", s[i], s[i] != 0 ? ", " : "");
2335e5dd7070Spatrick printf("\n");
2336e5dd7070Spatrick }
2337e5dd7070Spatrick };
2338e5dd7070Spatrick } // end anonymous namespace
2339e5dd7070Spatrick
BuildGCBlockLayout(CodeGenModule & CGM,const CGBlockInfo & blockInfo)2340e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
2341e5dd7070Spatrick const CGBlockInfo &blockInfo) {
2342e5dd7070Spatrick
2343e5dd7070Spatrick llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
2344e5dd7070Spatrick if (CGM.getLangOpts().getGC() == LangOptions::NonGC)
2345e5dd7070Spatrick return nullPtr;
2346e5dd7070Spatrick
2347e5dd7070Spatrick IvarLayoutBuilder builder(CGM, CharUnits::Zero(), blockInfo.BlockSize,
2348e5dd7070Spatrick /*for strong layout*/ true);
2349e5dd7070Spatrick
2350e5dd7070Spatrick builder.visitBlock(blockInfo);
2351e5dd7070Spatrick
2352e5dd7070Spatrick if (!builder.hasBitmapData())
2353e5dd7070Spatrick return nullPtr;
2354e5dd7070Spatrick
2355e5dd7070Spatrick llvm::SmallVector<unsigned char, 32> buffer;
2356e5dd7070Spatrick llvm::Constant *C = builder.buildBitmap(*this, buffer);
2357e5dd7070Spatrick if (CGM.getLangOpts().ObjCGCBitmapPrint && !buffer.empty()) {
2358e5dd7070Spatrick printf("\n block variable layout for block: ");
2359e5dd7070Spatrick builder.dump(buffer);
2360e5dd7070Spatrick }
2361e5dd7070Spatrick
2362e5dd7070Spatrick return C;
2363e5dd7070Spatrick }
2364e5dd7070Spatrick
visitBlock(const CGBlockInfo & blockInfo)2365e5dd7070Spatrick void IvarLayoutBuilder::visitBlock(const CGBlockInfo &blockInfo) {
2366e5dd7070Spatrick // __isa is the first field in block descriptor and must assume by runtime's
2367e5dd7070Spatrick // convention that it is GC'able.
2368e5dd7070Spatrick IvarsInfo.push_back(IvarInfo(CharUnits::Zero(), 1));
2369e5dd7070Spatrick
2370e5dd7070Spatrick const BlockDecl *blockDecl = blockInfo.getBlockDecl();
2371e5dd7070Spatrick
2372e5dd7070Spatrick // Ignore the optional 'this' capture: C++ objects are not assumed
2373e5dd7070Spatrick // to be GC'ed.
2374e5dd7070Spatrick
2375e5dd7070Spatrick CharUnits lastFieldOffset;
2376e5dd7070Spatrick
2377e5dd7070Spatrick // Walk the captured variables.
2378e5dd7070Spatrick for (const auto &CI : blockDecl->captures()) {
2379e5dd7070Spatrick const VarDecl *variable = CI.getVariable();
2380e5dd7070Spatrick QualType type = variable->getType();
2381e5dd7070Spatrick
2382e5dd7070Spatrick const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
2383e5dd7070Spatrick
2384e5dd7070Spatrick // Ignore constant captures.
2385e5dd7070Spatrick if (capture.isConstant()) continue;
2386e5dd7070Spatrick
2387e5dd7070Spatrick CharUnits fieldOffset = capture.getOffset();
2388e5dd7070Spatrick
2389e5dd7070Spatrick // Block fields are not necessarily ordered; if we detect that we're
2390e5dd7070Spatrick // adding them out-of-order, make sure we sort later.
2391e5dd7070Spatrick if (fieldOffset < lastFieldOffset)
2392e5dd7070Spatrick IsDisordered = true;
2393e5dd7070Spatrick lastFieldOffset = fieldOffset;
2394e5dd7070Spatrick
2395e5dd7070Spatrick // __block variables are passed by their descriptor address.
2396e5dd7070Spatrick if (CI.isByRef()) {
2397e5dd7070Spatrick IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
2398e5dd7070Spatrick continue;
2399e5dd7070Spatrick }
2400e5dd7070Spatrick
2401e5dd7070Spatrick assert(!type->isArrayType() && "array variable should not be caught");
2402e5dd7070Spatrick if (const RecordType *record = type->getAs<RecordType>()) {
2403e5dd7070Spatrick visitRecord(record, fieldOffset);
2404e5dd7070Spatrick continue;
2405e5dd7070Spatrick }
2406e5dd7070Spatrick
2407e5dd7070Spatrick Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), type);
2408e5dd7070Spatrick
2409e5dd7070Spatrick if (GCAttr == Qualifiers::Strong) {
2410*12c85518Srobert assert(CGM.getContext().getTypeSize(type) ==
2411*12c85518Srobert CGM.getTarget().getPointerWidth(LangAS::Default));
2412e5dd7070Spatrick IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
2413e5dd7070Spatrick }
2414e5dd7070Spatrick }
2415e5dd7070Spatrick }
2416e5dd7070Spatrick
2417e5dd7070Spatrick /// getBlockCaptureLifetime - This routine returns life time of the captured
2418e5dd7070Spatrick /// block variable for the purpose of block layout meta-data generation. FQT is
2419e5dd7070Spatrick /// the type of the variable captured in the block.
getBlockCaptureLifetime(QualType FQT,bool ByrefLayout)2420e5dd7070Spatrick Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT,
2421e5dd7070Spatrick bool ByrefLayout) {
2422e5dd7070Spatrick // If it has an ownership qualifier, we're done.
2423e5dd7070Spatrick if (auto lifetime = FQT.getObjCLifetime())
2424e5dd7070Spatrick return lifetime;
2425e5dd7070Spatrick
2426e5dd7070Spatrick // If it doesn't, and this is ARC, it has no ownership.
2427e5dd7070Spatrick if (CGM.getLangOpts().ObjCAutoRefCount)
2428e5dd7070Spatrick return Qualifiers::OCL_None;
2429e5dd7070Spatrick
2430e5dd7070Spatrick // In MRC, retainable pointers are owned by non-__block variables.
2431e5dd7070Spatrick if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
2432e5dd7070Spatrick return ByrefLayout ? Qualifiers::OCL_ExplicitNone : Qualifiers::OCL_Strong;
2433e5dd7070Spatrick
2434e5dd7070Spatrick return Qualifiers::OCL_None;
2435e5dd7070Spatrick }
2436e5dd7070Spatrick
UpdateRunSkipBlockVars(bool IsByref,Qualifiers::ObjCLifetime LifeTime,CharUnits FieldOffset,CharUnits FieldSize)2437e5dd7070Spatrick void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref,
2438e5dd7070Spatrick Qualifiers::ObjCLifetime LifeTime,
2439e5dd7070Spatrick CharUnits FieldOffset,
2440e5dd7070Spatrick CharUnits FieldSize) {
2441e5dd7070Spatrick // __block variables are passed by their descriptor address.
2442e5dd7070Spatrick if (IsByref)
2443e5dd7070Spatrick RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, FieldOffset,
2444e5dd7070Spatrick FieldSize));
2445e5dd7070Spatrick else if (LifeTime == Qualifiers::OCL_Strong)
2446e5dd7070Spatrick RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, FieldOffset,
2447e5dd7070Spatrick FieldSize));
2448e5dd7070Spatrick else if (LifeTime == Qualifiers::OCL_Weak)
2449e5dd7070Spatrick RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, FieldOffset,
2450e5dd7070Spatrick FieldSize));
2451e5dd7070Spatrick else if (LifeTime == Qualifiers::OCL_ExplicitNone)
2452e5dd7070Spatrick RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, FieldOffset,
2453e5dd7070Spatrick FieldSize));
2454e5dd7070Spatrick else
2455e5dd7070Spatrick RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES,
2456e5dd7070Spatrick FieldOffset,
2457e5dd7070Spatrick FieldSize));
2458e5dd7070Spatrick }
2459e5dd7070Spatrick
BuildRCRecordLayout(const llvm::StructLayout * RecLayout,const RecordDecl * RD,ArrayRef<const FieldDecl * > RecFields,CharUnits BytePos,bool & HasUnion,bool ByrefLayout)2460e5dd7070Spatrick void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
2461e5dd7070Spatrick const RecordDecl *RD,
2462e5dd7070Spatrick ArrayRef<const FieldDecl*> RecFields,
2463e5dd7070Spatrick CharUnits BytePos, bool &HasUnion,
2464e5dd7070Spatrick bool ByrefLayout) {
2465e5dd7070Spatrick bool IsUnion = (RD && RD->isUnion());
2466e5dd7070Spatrick CharUnits MaxUnionSize = CharUnits::Zero();
2467e5dd7070Spatrick const FieldDecl *MaxField = nullptr;
2468e5dd7070Spatrick const FieldDecl *LastFieldBitfieldOrUnnamed = nullptr;
2469e5dd7070Spatrick CharUnits MaxFieldOffset = CharUnits::Zero();
2470e5dd7070Spatrick CharUnits LastBitfieldOrUnnamedOffset = CharUnits::Zero();
2471e5dd7070Spatrick
2472e5dd7070Spatrick if (RecFields.empty())
2473e5dd7070Spatrick return;
2474e5dd7070Spatrick unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
2475e5dd7070Spatrick
2476e5dd7070Spatrick for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
2477e5dd7070Spatrick const FieldDecl *Field = RecFields[i];
2478e5dd7070Spatrick // Note that 'i' here is actually the field index inside RD of Field,
2479e5dd7070Spatrick // although this dependency is hidden.
2480e5dd7070Spatrick const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
2481e5dd7070Spatrick CharUnits FieldOffset =
2482e5dd7070Spatrick CGM.getContext().toCharUnitsFromBits(RL.getFieldOffset(i));
2483e5dd7070Spatrick
2484e5dd7070Spatrick // Skip over unnamed or bitfields
2485e5dd7070Spatrick if (!Field->getIdentifier() || Field->isBitField()) {
2486e5dd7070Spatrick LastFieldBitfieldOrUnnamed = Field;
2487e5dd7070Spatrick LastBitfieldOrUnnamedOffset = FieldOffset;
2488e5dd7070Spatrick continue;
2489e5dd7070Spatrick }
2490e5dd7070Spatrick
2491e5dd7070Spatrick LastFieldBitfieldOrUnnamed = nullptr;
2492e5dd7070Spatrick QualType FQT = Field->getType();
2493e5dd7070Spatrick if (FQT->isRecordType() || FQT->isUnionType()) {
2494e5dd7070Spatrick if (FQT->isUnionType())
2495e5dd7070Spatrick HasUnion = true;
2496e5dd7070Spatrick
2497*12c85518Srobert BuildRCBlockVarRecordLayout(FQT->castAs<RecordType>(),
2498e5dd7070Spatrick BytePos + FieldOffset, HasUnion);
2499e5dd7070Spatrick continue;
2500e5dd7070Spatrick }
2501e5dd7070Spatrick
2502e5dd7070Spatrick if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
2503e5dd7070Spatrick auto *CArray = cast<ConstantArrayType>(Array);
2504e5dd7070Spatrick uint64_t ElCount = CArray->getSize().getZExtValue();
2505e5dd7070Spatrick assert(CArray && "only array with known element size is supported");
2506e5dd7070Spatrick FQT = CArray->getElementType();
2507e5dd7070Spatrick while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
2508e5dd7070Spatrick auto *CArray = cast<ConstantArrayType>(Array);
2509e5dd7070Spatrick ElCount *= CArray->getSize().getZExtValue();
2510e5dd7070Spatrick FQT = CArray->getElementType();
2511e5dd7070Spatrick }
2512e5dd7070Spatrick if (FQT->isRecordType() && ElCount) {
2513e5dd7070Spatrick int OldIndex = RunSkipBlockVars.size() - 1;
2514ec727ea7Spatrick auto *RT = FQT->castAs<RecordType>();
2515ec727ea7Spatrick BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset, HasUnion);
2516e5dd7070Spatrick
2517e5dd7070Spatrick // Replicate layout information for each array element. Note that
2518e5dd7070Spatrick // one element is already done.
2519e5dd7070Spatrick uint64_t ElIx = 1;
2520e5dd7070Spatrick for (int FirstIndex = RunSkipBlockVars.size() - 1 ;ElIx < ElCount; ElIx++) {
2521e5dd7070Spatrick CharUnits Size = CGM.getContext().getTypeSizeInChars(RT);
2522e5dd7070Spatrick for (int i = OldIndex+1; i <= FirstIndex; ++i)
2523e5dd7070Spatrick RunSkipBlockVars.push_back(
2524e5dd7070Spatrick RUN_SKIP(RunSkipBlockVars[i].opcode,
2525e5dd7070Spatrick RunSkipBlockVars[i].block_var_bytepos + Size*ElIx,
2526e5dd7070Spatrick RunSkipBlockVars[i].block_var_size));
2527e5dd7070Spatrick }
2528e5dd7070Spatrick continue;
2529e5dd7070Spatrick }
2530e5dd7070Spatrick }
2531e5dd7070Spatrick CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(Field->getType());
2532e5dd7070Spatrick if (IsUnion) {
2533e5dd7070Spatrick CharUnits UnionIvarSize = FieldSize;
2534e5dd7070Spatrick if (UnionIvarSize > MaxUnionSize) {
2535e5dd7070Spatrick MaxUnionSize = UnionIvarSize;
2536e5dd7070Spatrick MaxField = Field;
2537e5dd7070Spatrick MaxFieldOffset = FieldOffset;
2538e5dd7070Spatrick }
2539e5dd7070Spatrick } else {
2540e5dd7070Spatrick UpdateRunSkipBlockVars(false,
2541e5dd7070Spatrick getBlockCaptureLifetime(FQT, ByrefLayout),
2542e5dd7070Spatrick BytePos + FieldOffset,
2543e5dd7070Spatrick FieldSize);
2544e5dd7070Spatrick }
2545e5dd7070Spatrick }
2546e5dd7070Spatrick
2547e5dd7070Spatrick if (LastFieldBitfieldOrUnnamed) {
2548e5dd7070Spatrick if (LastFieldBitfieldOrUnnamed->isBitField()) {
2549e5dd7070Spatrick // Last field was a bitfield. Must update the info.
2550e5dd7070Spatrick uint64_t BitFieldSize
2551e5dd7070Spatrick = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
2552e5dd7070Spatrick unsigned UnsSize = (BitFieldSize / ByteSizeInBits) +
2553e5dd7070Spatrick ((BitFieldSize % ByteSizeInBits) != 0);
2554e5dd7070Spatrick CharUnits Size = CharUnits::fromQuantity(UnsSize);
2555e5dd7070Spatrick Size += LastBitfieldOrUnnamedOffset;
2556e5dd7070Spatrick UpdateRunSkipBlockVars(false,
2557e5dd7070Spatrick getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
2558e5dd7070Spatrick ByrefLayout),
2559e5dd7070Spatrick BytePos + LastBitfieldOrUnnamedOffset,
2560e5dd7070Spatrick Size);
2561e5dd7070Spatrick } else {
2562e5dd7070Spatrick assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed");
2563e5dd7070Spatrick // Last field was unnamed. Must update skip info.
2564e5dd7070Spatrick CharUnits FieldSize
2565e5dd7070Spatrick = CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
2566e5dd7070Spatrick UpdateRunSkipBlockVars(false,
2567e5dd7070Spatrick getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
2568e5dd7070Spatrick ByrefLayout),
2569e5dd7070Spatrick BytePos + LastBitfieldOrUnnamedOffset,
2570e5dd7070Spatrick FieldSize);
2571e5dd7070Spatrick }
2572e5dd7070Spatrick }
2573e5dd7070Spatrick
2574e5dd7070Spatrick if (MaxField)
2575e5dd7070Spatrick UpdateRunSkipBlockVars(false,
2576e5dd7070Spatrick getBlockCaptureLifetime(MaxField->getType(), ByrefLayout),
2577e5dd7070Spatrick BytePos + MaxFieldOffset,
2578e5dd7070Spatrick MaxUnionSize);
2579e5dd7070Spatrick }
2580e5dd7070Spatrick
BuildRCBlockVarRecordLayout(const RecordType * RT,CharUnits BytePos,bool & HasUnion,bool ByrefLayout)2581e5dd7070Spatrick void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
2582e5dd7070Spatrick CharUnits BytePos,
2583e5dd7070Spatrick bool &HasUnion,
2584e5dd7070Spatrick bool ByrefLayout) {
2585e5dd7070Spatrick const RecordDecl *RD = RT->getDecl();
2586e5dd7070Spatrick SmallVector<const FieldDecl*, 16> Fields(RD->fields());
2587e5dd7070Spatrick llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
2588e5dd7070Spatrick const llvm::StructLayout *RecLayout =
2589e5dd7070Spatrick CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
2590e5dd7070Spatrick
2591e5dd7070Spatrick BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion, ByrefLayout);
2592e5dd7070Spatrick }
2593e5dd7070Spatrick
2594e5dd7070Spatrick /// InlineLayoutInstruction - This routine produce an inline instruction for the
2595e5dd7070Spatrick /// block variable layout if it can. If not, it returns 0. Rules are as follow:
2596e5dd7070Spatrick /// If ((uintptr_t) layout) < (1 << 12), the layout is inline. In the 64bit world,
2597e5dd7070Spatrick /// an inline layout of value 0x0000000000000xyz is interpreted as follows:
2598e5dd7070Spatrick /// x captured object pointers of BLOCK_LAYOUT_STRONG. Followed by
2599e5dd7070Spatrick /// y captured object of BLOCK_LAYOUT_BYREF. Followed by
2600e5dd7070Spatrick /// z captured object of BLOCK_LAYOUT_WEAK. If any of the above is missing, zero
2601e5dd7070Spatrick /// replaces it. For example, 0x00000x00 means x BLOCK_LAYOUT_STRONG and no
2602e5dd7070Spatrick /// BLOCK_LAYOUT_BYREF and no BLOCK_LAYOUT_WEAK objects are captured.
InlineLayoutInstruction(SmallVectorImpl<unsigned char> & Layout)2603e5dd7070Spatrick uint64_t CGObjCCommonMac::InlineLayoutInstruction(
2604e5dd7070Spatrick SmallVectorImpl<unsigned char> &Layout) {
2605e5dd7070Spatrick uint64_t Result = 0;
2606e5dd7070Spatrick if (Layout.size() <= 3) {
2607e5dd7070Spatrick unsigned size = Layout.size();
2608e5dd7070Spatrick unsigned strong_word_count = 0, byref_word_count=0, weak_word_count=0;
2609e5dd7070Spatrick unsigned char inst;
2610e5dd7070Spatrick enum BLOCK_LAYOUT_OPCODE opcode ;
2611e5dd7070Spatrick switch (size) {
2612e5dd7070Spatrick case 3:
2613e5dd7070Spatrick inst = Layout[0];
2614e5dd7070Spatrick opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2615e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_STRONG)
2616e5dd7070Spatrick strong_word_count = (inst & 0xF)+1;
2617e5dd7070Spatrick else
2618e5dd7070Spatrick return 0;
2619e5dd7070Spatrick inst = Layout[1];
2620e5dd7070Spatrick opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2621e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_BYREF)
2622e5dd7070Spatrick byref_word_count = (inst & 0xF)+1;
2623e5dd7070Spatrick else
2624e5dd7070Spatrick return 0;
2625e5dd7070Spatrick inst = Layout[2];
2626e5dd7070Spatrick opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2627e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_WEAK)
2628e5dd7070Spatrick weak_word_count = (inst & 0xF)+1;
2629e5dd7070Spatrick else
2630e5dd7070Spatrick return 0;
2631e5dd7070Spatrick break;
2632e5dd7070Spatrick
2633e5dd7070Spatrick case 2:
2634e5dd7070Spatrick inst = Layout[0];
2635e5dd7070Spatrick opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2636e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_STRONG) {
2637e5dd7070Spatrick strong_word_count = (inst & 0xF)+1;
2638e5dd7070Spatrick inst = Layout[1];
2639e5dd7070Spatrick opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2640e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_BYREF)
2641e5dd7070Spatrick byref_word_count = (inst & 0xF)+1;
2642e5dd7070Spatrick else if (opcode == BLOCK_LAYOUT_WEAK)
2643e5dd7070Spatrick weak_word_count = (inst & 0xF)+1;
2644e5dd7070Spatrick else
2645e5dd7070Spatrick return 0;
2646e5dd7070Spatrick }
2647e5dd7070Spatrick else if (opcode == BLOCK_LAYOUT_BYREF) {
2648e5dd7070Spatrick byref_word_count = (inst & 0xF)+1;
2649e5dd7070Spatrick inst = Layout[1];
2650e5dd7070Spatrick opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2651e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_WEAK)
2652e5dd7070Spatrick weak_word_count = (inst & 0xF)+1;
2653e5dd7070Spatrick else
2654e5dd7070Spatrick return 0;
2655e5dd7070Spatrick }
2656e5dd7070Spatrick else
2657e5dd7070Spatrick return 0;
2658e5dd7070Spatrick break;
2659e5dd7070Spatrick
2660e5dd7070Spatrick case 1:
2661e5dd7070Spatrick inst = Layout[0];
2662e5dd7070Spatrick opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2663e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_STRONG)
2664e5dd7070Spatrick strong_word_count = (inst & 0xF)+1;
2665e5dd7070Spatrick else if (opcode == BLOCK_LAYOUT_BYREF)
2666e5dd7070Spatrick byref_word_count = (inst & 0xF)+1;
2667e5dd7070Spatrick else if (opcode == BLOCK_LAYOUT_WEAK)
2668e5dd7070Spatrick weak_word_count = (inst & 0xF)+1;
2669e5dd7070Spatrick else
2670e5dd7070Spatrick return 0;
2671e5dd7070Spatrick break;
2672e5dd7070Spatrick
2673e5dd7070Spatrick default:
2674e5dd7070Spatrick return 0;
2675e5dd7070Spatrick }
2676e5dd7070Spatrick
2677e5dd7070Spatrick // Cannot inline when any of the word counts is 15. Because this is one less
2678e5dd7070Spatrick // than the actual work count (so 15 means 16 actual word counts),
2679e5dd7070Spatrick // and we can only display 0 thru 15 word counts.
2680e5dd7070Spatrick if (strong_word_count == 16 || byref_word_count == 16 || weak_word_count == 16)
2681e5dd7070Spatrick return 0;
2682e5dd7070Spatrick
2683e5dd7070Spatrick unsigned count =
2684e5dd7070Spatrick (strong_word_count != 0) + (byref_word_count != 0) + (weak_word_count != 0);
2685e5dd7070Spatrick
2686e5dd7070Spatrick if (size == count) {
2687e5dd7070Spatrick if (strong_word_count)
2688e5dd7070Spatrick Result = strong_word_count;
2689e5dd7070Spatrick Result <<= 4;
2690e5dd7070Spatrick if (byref_word_count)
2691e5dd7070Spatrick Result += byref_word_count;
2692e5dd7070Spatrick Result <<= 4;
2693e5dd7070Spatrick if (weak_word_count)
2694e5dd7070Spatrick Result += weak_word_count;
2695e5dd7070Spatrick }
2696e5dd7070Spatrick }
2697e5dd7070Spatrick return Result;
2698e5dd7070Spatrick }
2699e5dd7070Spatrick
getBitmapBlockLayout(bool ComputeByrefLayout)2700e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
2701e5dd7070Spatrick llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
2702e5dd7070Spatrick if (RunSkipBlockVars.empty())
2703e5dd7070Spatrick return nullPtr;
2704*12c85518Srobert unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(LangAS::Default);
2705e5dd7070Spatrick unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
2706e5dd7070Spatrick unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
2707e5dd7070Spatrick
2708e5dd7070Spatrick // Sort on byte position; captures might not be allocated in order,
2709e5dd7070Spatrick // and unions can do funny things.
2710e5dd7070Spatrick llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end());
2711e5dd7070Spatrick SmallVector<unsigned char, 16> Layout;
2712e5dd7070Spatrick
2713e5dd7070Spatrick unsigned size = RunSkipBlockVars.size();
2714e5dd7070Spatrick for (unsigned i = 0; i < size; i++) {
2715e5dd7070Spatrick enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode;
2716e5dd7070Spatrick CharUnits start_byte_pos = RunSkipBlockVars[i].block_var_bytepos;
2717e5dd7070Spatrick CharUnits end_byte_pos = start_byte_pos;
2718e5dd7070Spatrick unsigned j = i+1;
2719e5dd7070Spatrick while (j < size) {
2720e5dd7070Spatrick if (opcode == RunSkipBlockVars[j].opcode) {
2721e5dd7070Spatrick end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos;
2722e5dd7070Spatrick i++;
2723e5dd7070Spatrick }
2724e5dd7070Spatrick else
2725e5dd7070Spatrick break;
2726e5dd7070Spatrick }
2727e5dd7070Spatrick CharUnits size_in_bytes =
2728e5dd7070Spatrick end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size;
2729e5dd7070Spatrick if (j < size) {
2730e5dd7070Spatrick CharUnits gap =
2731e5dd7070Spatrick RunSkipBlockVars[j].block_var_bytepos -
2732e5dd7070Spatrick RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size;
2733e5dd7070Spatrick size_in_bytes += gap;
2734e5dd7070Spatrick }
2735e5dd7070Spatrick CharUnits residue_in_bytes = CharUnits::Zero();
2736e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) {
2737e5dd7070Spatrick residue_in_bytes = size_in_bytes % WordSizeInBytes;
2738e5dd7070Spatrick size_in_bytes -= residue_in_bytes;
2739e5dd7070Spatrick opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS;
2740e5dd7070Spatrick }
2741e5dd7070Spatrick
2742e5dd7070Spatrick unsigned size_in_words = size_in_bytes.getQuantity() / WordSizeInBytes;
2743e5dd7070Spatrick while (size_in_words >= 16) {
2744e5dd7070Spatrick // Note that value in imm. is one less that the actual
2745e5dd7070Spatrick // value. So, 0xf means 16 words follow!
2746e5dd7070Spatrick unsigned char inst = (opcode << 4) | 0xf;
2747e5dd7070Spatrick Layout.push_back(inst);
2748e5dd7070Spatrick size_in_words -= 16;
2749e5dd7070Spatrick }
2750e5dd7070Spatrick if (size_in_words > 0) {
2751e5dd7070Spatrick // Note that value in imm. is one less that the actual
2752e5dd7070Spatrick // value. So, we subtract 1 away!
2753e5dd7070Spatrick unsigned char inst = (opcode << 4) | (size_in_words-1);
2754e5dd7070Spatrick Layout.push_back(inst);
2755e5dd7070Spatrick }
2756e5dd7070Spatrick if (residue_in_bytes > CharUnits::Zero()) {
2757e5dd7070Spatrick unsigned char inst =
2758e5dd7070Spatrick (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
2759e5dd7070Spatrick Layout.push_back(inst);
2760e5dd7070Spatrick }
2761e5dd7070Spatrick }
2762e5dd7070Spatrick
2763e5dd7070Spatrick while (!Layout.empty()) {
2764e5dd7070Spatrick unsigned char inst = Layout.back();
2765e5dd7070Spatrick enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2766e5dd7070Spatrick if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS)
2767e5dd7070Spatrick Layout.pop_back();
2768e5dd7070Spatrick else
2769e5dd7070Spatrick break;
2770e5dd7070Spatrick }
2771e5dd7070Spatrick
2772e5dd7070Spatrick uint64_t Result = InlineLayoutInstruction(Layout);
2773e5dd7070Spatrick if (Result != 0) {
2774e5dd7070Spatrick // Block variable layout instruction has been inlined.
2775e5dd7070Spatrick if (CGM.getLangOpts().ObjCGCBitmapPrint) {
2776e5dd7070Spatrick if (ComputeByrefLayout)
2777e5dd7070Spatrick printf("\n Inline BYREF variable layout: ");
2778e5dd7070Spatrick else
2779e5dd7070Spatrick printf("\n Inline block variable layout: ");
2780e5dd7070Spatrick printf("0x0%" PRIx64 "", Result);
2781e5dd7070Spatrick if (auto numStrong = (Result & 0xF00) >> 8)
2782e5dd7070Spatrick printf(", BL_STRONG:%d", (int) numStrong);
2783e5dd7070Spatrick if (auto numByref = (Result & 0x0F0) >> 4)
2784e5dd7070Spatrick printf(", BL_BYREF:%d", (int) numByref);
2785e5dd7070Spatrick if (auto numWeak = (Result & 0x00F) >> 0)
2786e5dd7070Spatrick printf(", BL_WEAK:%d", (int) numWeak);
2787e5dd7070Spatrick printf(", BL_OPERATOR:0\n");
2788e5dd7070Spatrick }
2789e5dd7070Spatrick return llvm::ConstantInt::get(CGM.IntPtrTy, Result);
2790e5dd7070Spatrick }
2791e5dd7070Spatrick
2792e5dd7070Spatrick unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
2793e5dd7070Spatrick Layout.push_back(inst);
2794e5dd7070Spatrick std::string BitMap;
2795e5dd7070Spatrick for (unsigned i = 0, e = Layout.size(); i != e; i++)
2796e5dd7070Spatrick BitMap += Layout[i];
2797e5dd7070Spatrick
2798e5dd7070Spatrick if (CGM.getLangOpts().ObjCGCBitmapPrint) {
2799e5dd7070Spatrick if (ComputeByrefLayout)
2800e5dd7070Spatrick printf("\n Byref variable layout: ");
2801e5dd7070Spatrick else
2802e5dd7070Spatrick printf("\n Block variable layout: ");
2803e5dd7070Spatrick for (unsigned i = 0, e = BitMap.size(); i != e; i++) {
2804e5dd7070Spatrick unsigned char inst = BitMap[i];
2805e5dd7070Spatrick enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
2806e5dd7070Spatrick unsigned delta = 1;
2807e5dd7070Spatrick switch (opcode) {
2808e5dd7070Spatrick case BLOCK_LAYOUT_OPERATOR:
2809e5dd7070Spatrick printf("BL_OPERATOR:");
2810e5dd7070Spatrick delta = 0;
2811e5dd7070Spatrick break;
2812e5dd7070Spatrick case BLOCK_LAYOUT_NON_OBJECT_BYTES:
2813e5dd7070Spatrick printf("BL_NON_OBJECT_BYTES:");
2814e5dd7070Spatrick break;
2815e5dd7070Spatrick case BLOCK_LAYOUT_NON_OBJECT_WORDS:
2816e5dd7070Spatrick printf("BL_NON_OBJECT_WORD:");
2817e5dd7070Spatrick break;
2818e5dd7070Spatrick case BLOCK_LAYOUT_STRONG:
2819e5dd7070Spatrick printf("BL_STRONG:");
2820e5dd7070Spatrick break;
2821e5dd7070Spatrick case BLOCK_LAYOUT_BYREF:
2822e5dd7070Spatrick printf("BL_BYREF:");
2823e5dd7070Spatrick break;
2824e5dd7070Spatrick case BLOCK_LAYOUT_WEAK:
2825e5dd7070Spatrick printf("BL_WEAK:");
2826e5dd7070Spatrick break;
2827e5dd7070Spatrick case BLOCK_LAYOUT_UNRETAINED:
2828e5dd7070Spatrick printf("BL_UNRETAINED:");
2829e5dd7070Spatrick break;
2830e5dd7070Spatrick }
2831e5dd7070Spatrick // Actual value of word count is one more that what is in the imm.
2832e5dd7070Spatrick // field of the instruction
2833e5dd7070Spatrick printf("%d", (inst & 0xf) + delta);
2834e5dd7070Spatrick if (i < e-1)
2835e5dd7070Spatrick printf(", ");
2836e5dd7070Spatrick else
2837e5dd7070Spatrick printf("\n");
2838e5dd7070Spatrick }
2839e5dd7070Spatrick }
2840e5dd7070Spatrick
2841e5dd7070Spatrick auto *Entry = CreateCStringLiteral(BitMap, ObjCLabelType::ClassName,
2842e5dd7070Spatrick /*ForceNonFragileABI=*/true,
2843e5dd7070Spatrick /*NullTerminate=*/false);
2844e5dd7070Spatrick return getConstantGEP(VMContext, Entry, 0, 0);
2845e5dd7070Spatrick }
2846e5dd7070Spatrick
getBlockLayoutInfoString(const SmallVectorImpl<CGObjCCommonMac::RUN_SKIP> & RunSkipBlockVars,bool HasCopyDisposeHelpers)2847e5dd7070Spatrick static std::string getBlockLayoutInfoString(
2848e5dd7070Spatrick const SmallVectorImpl<CGObjCCommonMac::RUN_SKIP> &RunSkipBlockVars,
2849e5dd7070Spatrick bool HasCopyDisposeHelpers) {
2850e5dd7070Spatrick std::string Str;
2851e5dd7070Spatrick for (const CGObjCCommonMac::RUN_SKIP &R : RunSkipBlockVars) {
2852e5dd7070Spatrick if (R.opcode == CGObjCCommonMac::BLOCK_LAYOUT_UNRETAINED) {
2853e5dd7070Spatrick // Copy/dispose helpers don't have any information about
2854e5dd7070Spatrick // __unsafe_unretained captures, so unconditionally concatenate a string.
2855e5dd7070Spatrick Str += "u";
2856e5dd7070Spatrick } else if (HasCopyDisposeHelpers) {
2857e5dd7070Spatrick // Information about __strong, __weak, or byref captures has already been
2858e5dd7070Spatrick // encoded into the names of the copy/dispose helpers. We have to add a
2859e5dd7070Spatrick // string here only when the copy/dispose helpers aren't generated (which
2860e5dd7070Spatrick // happens when the block is non-escaping).
2861e5dd7070Spatrick continue;
2862e5dd7070Spatrick } else {
2863e5dd7070Spatrick switch (R.opcode) {
2864e5dd7070Spatrick case CGObjCCommonMac::BLOCK_LAYOUT_STRONG:
2865e5dd7070Spatrick Str += "s";
2866e5dd7070Spatrick break;
2867e5dd7070Spatrick case CGObjCCommonMac::BLOCK_LAYOUT_BYREF:
2868e5dd7070Spatrick Str += "r";
2869e5dd7070Spatrick break;
2870e5dd7070Spatrick case CGObjCCommonMac::BLOCK_LAYOUT_WEAK:
2871e5dd7070Spatrick Str += "w";
2872e5dd7070Spatrick break;
2873e5dd7070Spatrick default:
2874e5dd7070Spatrick continue;
2875e5dd7070Spatrick }
2876e5dd7070Spatrick }
2877e5dd7070Spatrick Str += llvm::to_string(R.block_var_bytepos.getQuantity());
2878e5dd7070Spatrick Str += "l" + llvm::to_string(R.block_var_size.getQuantity());
2879e5dd7070Spatrick }
2880e5dd7070Spatrick return Str;
2881e5dd7070Spatrick }
2882e5dd7070Spatrick
fillRunSkipBlockVars(CodeGenModule & CGM,const CGBlockInfo & blockInfo)2883e5dd7070Spatrick void CGObjCCommonMac::fillRunSkipBlockVars(CodeGenModule &CGM,
2884e5dd7070Spatrick const CGBlockInfo &blockInfo) {
2885e5dd7070Spatrick assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
2886e5dd7070Spatrick
2887e5dd7070Spatrick RunSkipBlockVars.clear();
2888e5dd7070Spatrick bool hasUnion = false;
2889e5dd7070Spatrick
2890*12c85518Srobert unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(LangAS::Default);
2891e5dd7070Spatrick unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
2892e5dd7070Spatrick unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
2893e5dd7070Spatrick
2894e5dd7070Spatrick const BlockDecl *blockDecl = blockInfo.getBlockDecl();
2895e5dd7070Spatrick
2896e5dd7070Spatrick // Calculate the basic layout of the block structure.
2897e5dd7070Spatrick const llvm::StructLayout *layout =
2898e5dd7070Spatrick CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
2899e5dd7070Spatrick
2900e5dd7070Spatrick // Ignore the optional 'this' capture: C++ objects are not assumed
2901e5dd7070Spatrick // to be GC'ed.
2902e5dd7070Spatrick if (blockInfo.BlockHeaderForcedGapSize != CharUnits::Zero())
2903e5dd7070Spatrick UpdateRunSkipBlockVars(false, Qualifiers::OCL_None,
2904e5dd7070Spatrick blockInfo.BlockHeaderForcedGapOffset,
2905e5dd7070Spatrick blockInfo.BlockHeaderForcedGapSize);
2906e5dd7070Spatrick // Walk the captured variables.
2907e5dd7070Spatrick for (const auto &CI : blockDecl->captures()) {
2908e5dd7070Spatrick const VarDecl *variable = CI.getVariable();
2909e5dd7070Spatrick QualType type = variable->getType();
2910e5dd7070Spatrick
2911e5dd7070Spatrick const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
2912e5dd7070Spatrick
2913e5dd7070Spatrick // Ignore constant captures.
2914e5dd7070Spatrick if (capture.isConstant()) continue;
2915e5dd7070Spatrick
2916e5dd7070Spatrick CharUnits fieldOffset =
2917e5dd7070Spatrick CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
2918e5dd7070Spatrick
2919e5dd7070Spatrick assert(!type->isArrayType() && "array variable should not be caught");
2920e5dd7070Spatrick if (!CI.isByRef())
2921e5dd7070Spatrick if (const RecordType *record = type->getAs<RecordType>()) {
2922e5dd7070Spatrick BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
2923e5dd7070Spatrick continue;
2924e5dd7070Spatrick }
2925e5dd7070Spatrick CharUnits fieldSize;
2926e5dd7070Spatrick if (CI.isByRef())
2927e5dd7070Spatrick fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
2928e5dd7070Spatrick else
2929e5dd7070Spatrick fieldSize = CGM.getContext().getTypeSizeInChars(type);
2930e5dd7070Spatrick UpdateRunSkipBlockVars(CI.isByRef(), getBlockCaptureLifetime(type, false),
2931e5dd7070Spatrick fieldOffset, fieldSize);
2932e5dd7070Spatrick }
2933e5dd7070Spatrick }
2934e5dd7070Spatrick
2935e5dd7070Spatrick llvm::Constant *
BuildRCBlockLayout(CodeGenModule & CGM,const CGBlockInfo & blockInfo)2936e5dd7070Spatrick CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
2937e5dd7070Spatrick const CGBlockInfo &blockInfo) {
2938e5dd7070Spatrick fillRunSkipBlockVars(CGM, blockInfo);
2939e5dd7070Spatrick return getBitmapBlockLayout(false);
2940e5dd7070Spatrick }
2941e5dd7070Spatrick
getRCBlockLayoutStr(CodeGenModule & CGM,const CGBlockInfo & blockInfo)2942e5dd7070Spatrick std::string CGObjCCommonMac::getRCBlockLayoutStr(CodeGenModule &CGM,
2943e5dd7070Spatrick const CGBlockInfo &blockInfo) {
2944e5dd7070Spatrick fillRunSkipBlockVars(CGM, blockInfo);
2945*12c85518Srobert return getBlockLayoutInfoString(RunSkipBlockVars, blockInfo.NeedsCopyDispose);
2946e5dd7070Spatrick }
2947e5dd7070Spatrick
BuildByrefLayout(CodeGen::CodeGenModule & CGM,QualType T)2948e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
2949e5dd7070Spatrick QualType T) {
2950e5dd7070Spatrick assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
2951e5dd7070Spatrick assert(!T->isArrayType() && "__block array variable should not be caught");
2952e5dd7070Spatrick CharUnits fieldOffset;
2953e5dd7070Spatrick RunSkipBlockVars.clear();
2954e5dd7070Spatrick bool hasUnion = false;
2955e5dd7070Spatrick if (const RecordType *record = T->getAs<RecordType>()) {
2956e5dd7070Spatrick BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */);
2957e5dd7070Spatrick llvm::Constant *Result = getBitmapBlockLayout(true);
2958e5dd7070Spatrick if (isa<llvm::ConstantInt>(Result))
2959e5dd7070Spatrick Result = llvm::ConstantExpr::getIntToPtr(Result, CGM.Int8PtrTy);
2960e5dd7070Spatrick return Result;
2961e5dd7070Spatrick }
2962e5dd7070Spatrick llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
2963e5dd7070Spatrick return nullPtr;
2964e5dd7070Spatrick }
2965e5dd7070Spatrick
GenerateProtocolRef(CodeGenFunction & CGF,const ObjCProtocolDecl * PD)2966e5dd7070Spatrick llvm::Value *CGObjCMac::GenerateProtocolRef(CodeGenFunction &CGF,
2967e5dd7070Spatrick const ObjCProtocolDecl *PD) {
2968e5dd7070Spatrick // FIXME: I don't understand why gcc generates this, or where it is
2969e5dd7070Spatrick // resolved. Investigate. Its also wasteful to look this up over and over.
2970e5dd7070Spatrick LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
2971e5dd7070Spatrick
2972e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
2973e5dd7070Spatrick ObjCTypes.getExternalProtocolPtrTy());
2974e5dd7070Spatrick }
2975e5dd7070Spatrick
GenerateProtocol(const ObjCProtocolDecl * PD)2976e5dd7070Spatrick void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
2977e5dd7070Spatrick // FIXME: We shouldn't need this, the protocol decl should contain enough
2978e5dd7070Spatrick // information to tell us whether this was a declaration or a definition.
2979e5dd7070Spatrick DefinedProtocols.insert(PD->getIdentifier());
2980e5dd7070Spatrick
2981e5dd7070Spatrick // If we have generated a forward reference to this protocol, emit
2982e5dd7070Spatrick // it now. Otherwise do nothing, the protocol objects are lazily
2983e5dd7070Spatrick // emitted.
2984e5dd7070Spatrick if (Protocols.count(PD->getIdentifier()))
2985e5dd7070Spatrick GetOrEmitProtocol(PD);
2986e5dd7070Spatrick }
2987e5dd7070Spatrick
GetProtocolRef(const ObjCProtocolDecl * PD)2988e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
2989e5dd7070Spatrick if (DefinedProtocols.count(PD->getIdentifier()))
2990e5dd7070Spatrick return GetOrEmitProtocol(PD);
2991e5dd7070Spatrick
2992e5dd7070Spatrick return GetOrEmitProtocolRef(PD);
2993e5dd7070Spatrick }
2994e5dd7070Spatrick
EmitClassRefViaRuntime(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID,ObjCCommonTypesHelper & ObjCTypes)2995e5dd7070Spatrick llvm::Value *CGObjCCommonMac::EmitClassRefViaRuntime(
2996e5dd7070Spatrick CodeGenFunction &CGF,
2997e5dd7070Spatrick const ObjCInterfaceDecl *ID,
2998e5dd7070Spatrick ObjCCommonTypesHelper &ObjCTypes) {
2999e5dd7070Spatrick llvm::FunctionCallee lookUpClassFn = ObjCTypes.getLookUpClassFn();
3000e5dd7070Spatrick
3001ec727ea7Spatrick llvm::Value *className = CGF.CGM
3002ec727ea7Spatrick .GetAddrOfConstantCString(std::string(
3003ec727ea7Spatrick ID->getObjCRuntimeNameAsString()))
3004e5dd7070Spatrick .getPointer();
3005e5dd7070Spatrick ASTContext &ctx = CGF.CGM.getContext();
3006e5dd7070Spatrick className =
3007e5dd7070Spatrick CGF.Builder.CreateBitCast(className,
3008e5dd7070Spatrick CGF.ConvertType(
3009e5dd7070Spatrick ctx.getPointerType(ctx.CharTy.withConst())));
3010e5dd7070Spatrick llvm::CallInst *call = CGF.Builder.CreateCall(lookUpClassFn, className);
3011e5dd7070Spatrick call->setDoesNotThrow();
3012e5dd7070Spatrick return call;
3013e5dd7070Spatrick }
3014e5dd7070Spatrick
3015e5dd7070Spatrick /*
3016e5dd7070Spatrick // Objective-C 1.0 extensions
3017e5dd7070Spatrick struct _objc_protocol {
3018e5dd7070Spatrick struct _objc_protocol_extension *isa;
3019e5dd7070Spatrick char *protocol_name;
3020e5dd7070Spatrick struct _objc_protocol_list *protocol_list;
3021e5dd7070Spatrick struct _objc__method_prototype_list *instance_methods;
3022e5dd7070Spatrick struct _objc__method_prototype_list *class_methods
3023e5dd7070Spatrick };
3024e5dd7070Spatrick
3025e5dd7070Spatrick See EmitProtocolExtension().
3026e5dd7070Spatrick */
GetOrEmitProtocol(const ObjCProtocolDecl * PD)3027e5dd7070Spatrick llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
3028e5dd7070Spatrick llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()];
3029e5dd7070Spatrick
3030e5dd7070Spatrick // Early exit if a defining object has already been generated.
3031e5dd7070Spatrick if (Entry && Entry->hasInitializer())
3032e5dd7070Spatrick return Entry;
3033e5dd7070Spatrick
3034e5dd7070Spatrick // Use the protocol definition, if there is one.
3035e5dd7070Spatrick if (const ObjCProtocolDecl *Def = PD->getDefinition())
3036e5dd7070Spatrick PD = Def;
3037e5dd7070Spatrick
3038e5dd7070Spatrick // FIXME: I don't understand why gcc generates this, or where it is
3039e5dd7070Spatrick // resolved. Investigate. Its also wasteful to look this up over and over.
3040e5dd7070Spatrick LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
3041e5dd7070Spatrick
3042e5dd7070Spatrick // Construct method lists.
3043e5dd7070Spatrick auto methodLists = ProtocolMethodLists::get(PD);
3044e5dd7070Spatrick
3045e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3046e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ProtocolTy);
3047e5dd7070Spatrick values.add(EmitProtocolExtension(PD, methodLists));
3048e5dd7070Spatrick values.add(GetClassName(PD->getObjCRuntimeNameAsString()));
3049e5dd7070Spatrick values.add(EmitProtocolList("OBJC_PROTOCOL_REFS_" + PD->getName(),
3050e5dd7070Spatrick PD->protocol_begin(), PD->protocol_end()));
3051e5dd7070Spatrick values.add(methodLists.emitMethodList(this, PD,
3052e5dd7070Spatrick ProtocolMethodLists::RequiredInstanceMethods));
3053e5dd7070Spatrick values.add(methodLists.emitMethodList(this, PD,
3054e5dd7070Spatrick ProtocolMethodLists::RequiredClassMethods));
3055e5dd7070Spatrick
3056e5dd7070Spatrick if (Entry) {
3057e5dd7070Spatrick // Already created, update the initializer.
3058e5dd7070Spatrick assert(Entry->hasPrivateLinkage());
3059e5dd7070Spatrick values.finishAndSetAsInitializer(Entry);
3060e5dd7070Spatrick } else {
3061e5dd7070Spatrick Entry = values.finishAndCreateGlobal("OBJC_PROTOCOL_" + PD->getName(),
3062e5dd7070Spatrick CGM.getPointerAlign(),
3063e5dd7070Spatrick /*constant*/ false,
3064e5dd7070Spatrick llvm::GlobalValue::PrivateLinkage);
3065e5dd7070Spatrick Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
3066e5dd7070Spatrick
3067e5dd7070Spatrick Protocols[PD->getIdentifier()] = Entry;
3068e5dd7070Spatrick }
3069e5dd7070Spatrick CGM.addCompilerUsedGlobal(Entry);
3070e5dd7070Spatrick
3071e5dd7070Spatrick return Entry;
3072e5dd7070Spatrick }
3073e5dd7070Spatrick
GetOrEmitProtocolRef(const ObjCProtocolDecl * PD)3074e5dd7070Spatrick llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
3075e5dd7070Spatrick llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
3076e5dd7070Spatrick
3077e5dd7070Spatrick if (!Entry) {
3078e5dd7070Spatrick // We use the initializer as a marker of whether this is a forward
3079e5dd7070Spatrick // reference or not. At module finalization we add the empty
3080e5dd7070Spatrick // contents for protocols which were referenced but never defined.
3081e5dd7070Spatrick Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy,
3082e5dd7070Spatrick false, llvm::GlobalValue::PrivateLinkage,
3083e5dd7070Spatrick nullptr, "OBJC_PROTOCOL_" + PD->getName());
3084e5dd7070Spatrick Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
3085e5dd7070Spatrick // FIXME: Is this necessary? Why only for protocol?
3086e5dd7070Spatrick Entry->setAlignment(llvm::Align(4));
3087e5dd7070Spatrick }
3088e5dd7070Spatrick
3089e5dd7070Spatrick return Entry;
3090e5dd7070Spatrick }
3091e5dd7070Spatrick
3092e5dd7070Spatrick /*
3093e5dd7070Spatrick struct _objc_protocol_extension {
3094e5dd7070Spatrick uint32_t size;
3095e5dd7070Spatrick struct objc_method_description_list *optional_instance_methods;
3096e5dd7070Spatrick struct objc_method_description_list *optional_class_methods;
3097e5dd7070Spatrick struct objc_property_list *instance_properties;
3098e5dd7070Spatrick const char ** extendedMethodTypes;
3099e5dd7070Spatrick struct objc_property_list *class_properties;
3100e5dd7070Spatrick };
3101e5dd7070Spatrick */
3102e5dd7070Spatrick llvm::Constant *
EmitProtocolExtension(const ObjCProtocolDecl * PD,const ProtocolMethodLists & methodLists)3103e5dd7070Spatrick CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
3104e5dd7070Spatrick const ProtocolMethodLists &methodLists) {
3105e5dd7070Spatrick auto optInstanceMethods =
3106e5dd7070Spatrick methodLists.emitMethodList(this, PD,
3107e5dd7070Spatrick ProtocolMethodLists::OptionalInstanceMethods);
3108e5dd7070Spatrick auto optClassMethods =
3109e5dd7070Spatrick methodLists.emitMethodList(this, PD,
3110e5dd7070Spatrick ProtocolMethodLists::OptionalClassMethods);
3111e5dd7070Spatrick
3112e5dd7070Spatrick auto extendedMethodTypes =
3113e5dd7070Spatrick EmitProtocolMethodTypes("OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
3114e5dd7070Spatrick methodLists.emitExtendedTypesArray(this),
3115e5dd7070Spatrick ObjCTypes);
3116e5dd7070Spatrick
3117e5dd7070Spatrick auto instanceProperties =
3118e5dd7070Spatrick EmitPropertyList("OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr, PD,
3119e5dd7070Spatrick ObjCTypes, false);
3120e5dd7070Spatrick auto classProperties =
3121e5dd7070Spatrick EmitPropertyList("OBJC_$_CLASS_PROP_PROTO_LIST_" + PD->getName(), nullptr,
3122e5dd7070Spatrick PD, ObjCTypes, true);
3123e5dd7070Spatrick
3124e5dd7070Spatrick // Return null if no extension bits are used.
3125e5dd7070Spatrick if (optInstanceMethods->isNullValue() &&
3126e5dd7070Spatrick optClassMethods->isNullValue() &&
3127e5dd7070Spatrick extendedMethodTypes->isNullValue() &&
3128e5dd7070Spatrick instanceProperties->isNullValue() &&
3129e5dd7070Spatrick classProperties->isNullValue()) {
3130e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
3131e5dd7070Spatrick }
3132e5dd7070Spatrick
3133e5dd7070Spatrick uint64_t size =
3134e5dd7070Spatrick CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
3135e5dd7070Spatrick
3136e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3137e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ProtocolExtensionTy);
3138e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, size);
3139e5dd7070Spatrick values.add(optInstanceMethods);
3140e5dd7070Spatrick values.add(optClassMethods);
3141e5dd7070Spatrick values.add(instanceProperties);
3142e5dd7070Spatrick values.add(extendedMethodTypes);
3143e5dd7070Spatrick values.add(classProperties);
3144e5dd7070Spatrick
3145e5dd7070Spatrick // No special section, but goes in llvm.used
3146e5dd7070Spatrick return CreateMetadataVar("_OBJC_PROTOCOLEXT_" + PD->getName(), values,
3147e5dd7070Spatrick StringRef(), CGM.getPointerAlign(), true);
3148e5dd7070Spatrick }
3149e5dd7070Spatrick
3150e5dd7070Spatrick /*
3151e5dd7070Spatrick struct objc_protocol_list {
3152e5dd7070Spatrick struct objc_protocol_list *next;
3153e5dd7070Spatrick long count;
3154e5dd7070Spatrick Protocol *list[];
3155e5dd7070Spatrick };
3156e5dd7070Spatrick */
3157e5dd7070Spatrick llvm::Constant *
EmitProtocolList(Twine name,ObjCProtocolDecl::protocol_iterator begin,ObjCProtocolDecl::protocol_iterator end)3158e5dd7070Spatrick CGObjCMac::EmitProtocolList(Twine name,
3159e5dd7070Spatrick ObjCProtocolDecl::protocol_iterator begin,
3160e5dd7070Spatrick ObjCProtocolDecl::protocol_iterator end) {
3161e5dd7070Spatrick // Just return null for empty protocol lists
3162a9ac8606Spatrick auto PDs = GetRuntimeProtocolList(begin, end);
3163a9ac8606Spatrick if (PDs.empty())
3164e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
3165e5dd7070Spatrick
3166e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3167e5dd7070Spatrick auto values = builder.beginStruct();
3168e5dd7070Spatrick
3169e5dd7070Spatrick // This field is only used by the runtime.
3170e5dd7070Spatrick values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
3171e5dd7070Spatrick
3172e5dd7070Spatrick // Reserve a slot for the count.
3173e5dd7070Spatrick auto countSlot = values.addPlaceholder();
3174e5dd7070Spatrick
3175e5dd7070Spatrick auto refsArray = values.beginArray(ObjCTypes.ProtocolPtrTy);
3176a9ac8606Spatrick for (const auto *Proto : PDs)
3177a9ac8606Spatrick refsArray.add(GetProtocolRef(Proto));
3178a9ac8606Spatrick
3179e5dd7070Spatrick auto count = refsArray.size();
3180e5dd7070Spatrick
3181e5dd7070Spatrick // This list is null terminated.
3182e5dd7070Spatrick refsArray.addNullPointer(ObjCTypes.ProtocolPtrTy);
3183e5dd7070Spatrick
3184e5dd7070Spatrick refsArray.finishAndAddTo(values);
3185e5dd7070Spatrick values.fillPlaceholderWithInt(countSlot, ObjCTypes.LongTy, count);
3186e5dd7070Spatrick
3187e5dd7070Spatrick StringRef section;
3188e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO())
3189e5dd7070Spatrick section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
3190e5dd7070Spatrick
3191e5dd7070Spatrick llvm::GlobalVariable *GV =
3192e5dd7070Spatrick CreateMetadataVar(name, values, section, CGM.getPointerAlign(), false);
3193e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
3194e5dd7070Spatrick }
3195e5dd7070Spatrick
3196e5dd7070Spatrick static void
PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo *,16> & PropertySet,SmallVectorImpl<const ObjCPropertyDecl * > & Properties,const ObjCProtocolDecl * Proto,bool IsClassProperty)3197e5dd7070Spatrick PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
3198e5dd7070Spatrick SmallVectorImpl<const ObjCPropertyDecl *> &Properties,
3199e5dd7070Spatrick const ObjCProtocolDecl *Proto,
3200e5dd7070Spatrick bool IsClassProperty) {
3201e5dd7070Spatrick for (const auto *PD : Proto->properties()) {
3202e5dd7070Spatrick if (IsClassProperty != PD->isClassProperty())
3203e5dd7070Spatrick continue;
3204e5dd7070Spatrick if (!PropertySet.insert(PD->getIdentifier()).second)
3205e5dd7070Spatrick continue;
3206e5dd7070Spatrick Properties.push_back(PD);
3207e5dd7070Spatrick }
3208e5dd7070Spatrick
3209e5dd7070Spatrick for (const auto *P : Proto->protocols())
3210e5dd7070Spatrick PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
3211e5dd7070Spatrick }
3212e5dd7070Spatrick
3213e5dd7070Spatrick /*
3214e5dd7070Spatrick struct _objc_property {
3215e5dd7070Spatrick const char * const name;
3216e5dd7070Spatrick const char * const attributes;
3217e5dd7070Spatrick };
3218e5dd7070Spatrick
3219e5dd7070Spatrick struct _objc_property_list {
3220e5dd7070Spatrick uint32_t entsize; // sizeof (struct _objc_property)
3221e5dd7070Spatrick uint32_t prop_count;
3222e5dd7070Spatrick struct _objc_property[prop_count];
3223e5dd7070Spatrick };
3224e5dd7070Spatrick */
EmitPropertyList(Twine Name,const Decl * Container,const ObjCContainerDecl * OCD,const ObjCCommonTypesHelper & ObjCTypes,bool IsClassProperty)3225e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
3226e5dd7070Spatrick const Decl *Container,
3227e5dd7070Spatrick const ObjCContainerDecl *OCD,
3228e5dd7070Spatrick const ObjCCommonTypesHelper &ObjCTypes,
3229e5dd7070Spatrick bool IsClassProperty) {
3230e5dd7070Spatrick if (IsClassProperty) {
3231e5dd7070Spatrick // Make this entry NULL for OS X with deployment target < 10.11, for iOS
3232e5dd7070Spatrick // with deployment target < 9.0.
3233e5dd7070Spatrick const llvm::Triple &Triple = CGM.getTarget().getTriple();
3234e5dd7070Spatrick if ((Triple.isMacOSX() && Triple.isMacOSXVersionLT(10, 11)) ||
3235e5dd7070Spatrick (Triple.isiOS() && Triple.isOSVersionLT(9)))
3236e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
3237e5dd7070Spatrick }
3238e5dd7070Spatrick
3239e5dd7070Spatrick SmallVector<const ObjCPropertyDecl *, 16> Properties;
3240e5dd7070Spatrick llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
3241e5dd7070Spatrick
3242e5dd7070Spatrick if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
3243e5dd7070Spatrick for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
3244e5dd7070Spatrick for (auto *PD : ClassExt->properties()) {
3245e5dd7070Spatrick if (IsClassProperty != PD->isClassProperty())
3246e5dd7070Spatrick continue;
3247ec727ea7Spatrick if (PD->isDirectProperty())
3248ec727ea7Spatrick continue;
3249e5dd7070Spatrick PropertySet.insert(PD->getIdentifier());
3250e5dd7070Spatrick Properties.push_back(PD);
3251e5dd7070Spatrick }
3252e5dd7070Spatrick
3253e5dd7070Spatrick for (const auto *PD : OCD->properties()) {
3254e5dd7070Spatrick if (IsClassProperty != PD->isClassProperty())
3255e5dd7070Spatrick continue;
3256e5dd7070Spatrick // Don't emit duplicate metadata for properties that were already in a
3257e5dd7070Spatrick // class extension.
3258e5dd7070Spatrick if (!PropertySet.insert(PD->getIdentifier()).second)
3259e5dd7070Spatrick continue;
3260ec727ea7Spatrick if (PD->isDirectProperty())
3261ec727ea7Spatrick continue;
3262e5dd7070Spatrick Properties.push_back(PD);
3263e5dd7070Spatrick }
3264e5dd7070Spatrick
3265e5dd7070Spatrick if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
3266e5dd7070Spatrick for (const auto *P : OID->all_referenced_protocols())
3267e5dd7070Spatrick PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
3268e5dd7070Spatrick }
3269e5dd7070Spatrick else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD)) {
3270e5dd7070Spatrick for (const auto *P : CD->protocols())
3271e5dd7070Spatrick PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
3272e5dd7070Spatrick }
3273e5dd7070Spatrick
3274e5dd7070Spatrick // Return null for empty list.
3275e5dd7070Spatrick if (Properties.empty())
3276e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
3277e5dd7070Spatrick
3278e5dd7070Spatrick unsigned propertySize =
3279e5dd7070Spatrick CGM.getDataLayout().getTypeAllocSize(ObjCTypes.PropertyTy);
3280e5dd7070Spatrick
3281e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3282e5dd7070Spatrick auto values = builder.beginStruct();
3283e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, propertySize);
3284e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, Properties.size());
3285e5dd7070Spatrick auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy);
3286e5dd7070Spatrick for (auto PD : Properties) {
3287e5dd7070Spatrick auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy);
3288e5dd7070Spatrick property.add(GetPropertyName(PD->getIdentifier()));
3289e5dd7070Spatrick property.add(GetPropertyTypeString(PD, Container));
3290e5dd7070Spatrick property.finishAndAddTo(propertiesArray);
3291e5dd7070Spatrick }
3292e5dd7070Spatrick propertiesArray.finishAndAddTo(values);
3293e5dd7070Spatrick
3294e5dd7070Spatrick StringRef Section;
3295e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO())
3296e5dd7070Spatrick Section = (ObjCABI == 2) ? "__DATA, __objc_const"
3297e5dd7070Spatrick : "__OBJC,__property,regular,no_dead_strip";
3298e5dd7070Spatrick
3299e5dd7070Spatrick llvm::GlobalVariable *GV =
3300e5dd7070Spatrick CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true);
3301e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy);
3302e5dd7070Spatrick }
3303e5dd7070Spatrick
3304e5dd7070Spatrick llvm::Constant *
EmitProtocolMethodTypes(Twine Name,ArrayRef<llvm::Constant * > MethodTypes,const ObjCCommonTypesHelper & ObjCTypes)3305e5dd7070Spatrick CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name,
3306e5dd7070Spatrick ArrayRef<llvm::Constant*> MethodTypes,
3307e5dd7070Spatrick const ObjCCommonTypesHelper &ObjCTypes) {
3308e5dd7070Spatrick // Return null for empty list.
3309e5dd7070Spatrick if (MethodTypes.empty())
3310e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.Int8PtrPtrTy);
3311e5dd7070Spatrick
3312e5dd7070Spatrick llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
3313e5dd7070Spatrick MethodTypes.size());
3314e5dd7070Spatrick llvm::Constant *Init = llvm::ConstantArray::get(AT, MethodTypes);
3315e5dd7070Spatrick
3316e5dd7070Spatrick StringRef Section;
3317e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO() && ObjCABI == 2)
3318e5dd7070Spatrick Section = "__DATA, __objc_const";
3319e5dd7070Spatrick
3320e5dd7070Spatrick llvm::GlobalVariable *GV =
3321e5dd7070Spatrick CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true);
3322e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy);
3323e5dd7070Spatrick }
3324e5dd7070Spatrick
3325e5dd7070Spatrick /*
3326e5dd7070Spatrick struct _objc_category {
3327e5dd7070Spatrick char *category_name;
3328e5dd7070Spatrick char *class_name;
3329e5dd7070Spatrick struct _objc_method_list *instance_methods;
3330e5dd7070Spatrick struct _objc_method_list *class_methods;
3331e5dd7070Spatrick struct _objc_protocol_list *protocols;
3332e5dd7070Spatrick uint32_t size; // <rdar://4585769>
3333e5dd7070Spatrick struct _objc_property_list *instance_properties;
3334e5dd7070Spatrick struct _objc_property_list *class_properties;
3335e5dd7070Spatrick };
3336e5dd7070Spatrick */
GenerateCategory(const ObjCCategoryImplDecl * OCD)3337e5dd7070Spatrick void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
3338e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategoryTy);
3339e5dd7070Spatrick
3340e5dd7070Spatrick // FIXME: This is poor design, the OCD should have a pointer to the category
3341e5dd7070Spatrick // decl. Additionally, note that Category can be null for the @implementation
3342e5dd7070Spatrick // w/o an @interface case. Sema should just create one for us as it does for
3343e5dd7070Spatrick // @implementation so everyone else can live life under a clear blue sky.
3344e5dd7070Spatrick const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
3345e5dd7070Spatrick const ObjCCategoryDecl *Category =
3346e5dd7070Spatrick Interface->FindCategoryDeclaration(OCD->getIdentifier());
3347e5dd7070Spatrick
3348e5dd7070Spatrick SmallString<256> ExtName;
3349e5dd7070Spatrick llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_'
3350e5dd7070Spatrick << OCD->getName();
3351e5dd7070Spatrick
3352e5dd7070Spatrick ConstantInitBuilder Builder(CGM);
3353e5dd7070Spatrick auto Values = Builder.beginStruct(ObjCTypes.CategoryTy);
3354e5dd7070Spatrick
3355e5dd7070Spatrick enum {
3356e5dd7070Spatrick InstanceMethods,
3357e5dd7070Spatrick ClassMethods,
3358e5dd7070Spatrick NumMethodLists
3359e5dd7070Spatrick };
3360e5dd7070Spatrick SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
3361e5dd7070Spatrick for (const auto *MD : OCD->methods()) {
3362e5dd7070Spatrick if (!MD->isDirectMethod())
3363e5dd7070Spatrick Methods[unsigned(MD->isClassMethod())].push_back(MD);
3364e5dd7070Spatrick }
3365e5dd7070Spatrick
3366e5dd7070Spatrick Values.add(GetClassName(OCD->getName()));
3367e5dd7070Spatrick Values.add(GetClassName(Interface->getObjCRuntimeNameAsString()));
3368e5dd7070Spatrick LazySymbols.insert(Interface->getIdentifier());
3369e5dd7070Spatrick
3370e5dd7070Spatrick Values.add(emitMethodList(ExtName, MethodListType::CategoryInstanceMethods,
3371e5dd7070Spatrick Methods[InstanceMethods]));
3372e5dd7070Spatrick Values.add(emitMethodList(ExtName, MethodListType::CategoryClassMethods,
3373e5dd7070Spatrick Methods[ClassMethods]));
3374e5dd7070Spatrick if (Category) {
3375e5dd7070Spatrick Values.add(
3376e5dd7070Spatrick EmitProtocolList("OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(),
3377e5dd7070Spatrick Category->protocol_begin(), Category->protocol_end()));
3378e5dd7070Spatrick } else {
3379e5dd7070Spatrick Values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
3380e5dd7070Spatrick }
3381e5dd7070Spatrick Values.addInt(ObjCTypes.IntTy, Size);
3382e5dd7070Spatrick
3383e5dd7070Spatrick // If there is no category @interface then there can be no properties.
3384e5dd7070Spatrick if (Category) {
3385e5dd7070Spatrick Values.add(EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(),
3386e5dd7070Spatrick OCD, Category, ObjCTypes, false));
3387e5dd7070Spatrick Values.add(EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(),
3388e5dd7070Spatrick OCD, Category, ObjCTypes, true));
3389e5dd7070Spatrick } else {
3390e5dd7070Spatrick Values.addNullPointer(ObjCTypes.PropertyListPtrTy);
3391e5dd7070Spatrick Values.addNullPointer(ObjCTypes.PropertyListPtrTy);
3392e5dd7070Spatrick }
3393e5dd7070Spatrick
3394e5dd7070Spatrick llvm::GlobalVariable *GV =
3395e5dd7070Spatrick CreateMetadataVar("OBJC_CATEGORY_" + ExtName.str(), Values,
3396e5dd7070Spatrick "__OBJC,__category,regular,no_dead_strip",
3397e5dd7070Spatrick CGM.getPointerAlign(), true);
3398e5dd7070Spatrick DefinedCategories.push_back(GV);
3399e5dd7070Spatrick DefinedCategoryNames.insert(llvm::CachedHashString(ExtName));
3400e5dd7070Spatrick // method definition entries must be clear for next implementation.
3401e5dd7070Spatrick MethodDefinitions.clear();
3402e5dd7070Spatrick }
3403e5dd7070Spatrick
3404e5dd7070Spatrick enum FragileClassFlags {
3405e5dd7070Spatrick /// Apparently: is not a meta-class.
3406e5dd7070Spatrick FragileABI_Class_Factory = 0x00001,
3407e5dd7070Spatrick
3408e5dd7070Spatrick /// Is a meta-class.
3409e5dd7070Spatrick FragileABI_Class_Meta = 0x00002,
3410e5dd7070Spatrick
3411e5dd7070Spatrick /// Has a non-trivial constructor or destructor.
3412e5dd7070Spatrick FragileABI_Class_HasCXXStructors = 0x02000,
3413e5dd7070Spatrick
3414e5dd7070Spatrick /// Has hidden visibility.
3415e5dd7070Spatrick FragileABI_Class_Hidden = 0x20000,
3416e5dd7070Spatrick
3417e5dd7070Spatrick /// Class implementation was compiled under ARC.
3418e5dd7070Spatrick FragileABI_Class_CompiledByARC = 0x04000000,
3419e5dd7070Spatrick
3420e5dd7070Spatrick /// Class implementation was compiled under MRC and has MRC weak ivars.
3421e5dd7070Spatrick /// Exclusive with CompiledByARC.
3422e5dd7070Spatrick FragileABI_Class_HasMRCWeakIvars = 0x08000000,
3423e5dd7070Spatrick };
3424e5dd7070Spatrick
3425e5dd7070Spatrick enum NonFragileClassFlags {
3426e5dd7070Spatrick /// Is a meta-class.
3427e5dd7070Spatrick NonFragileABI_Class_Meta = 0x00001,
3428e5dd7070Spatrick
3429e5dd7070Spatrick /// Is a root class.
3430e5dd7070Spatrick NonFragileABI_Class_Root = 0x00002,
3431e5dd7070Spatrick
3432e5dd7070Spatrick /// Has a non-trivial constructor or destructor.
3433e5dd7070Spatrick NonFragileABI_Class_HasCXXStructors = 0x00004,
3434e5dd7070Spatrick
3435e5dd7070Spatrick /// Has hidden visibility.
3436e5dd7070Spatrick NonFragileABI_Class_Hidden = 0x00010,
3437e5dd7070Spatrick
3438e5dd7070Spatrick /// Has the exception attribute.
3439e5dd7070Spatrick NonFragileABI_Class_Exception = 0x00020,
3440e5dd7070Spatrick
3441e5dd7070Spatrick /// (Obsolete) ARC-specific: this class has a .release_ivars method
3442e5dd7070Spatrick NonFragileABI_Class_HasIvarReleaser = 0x00040,
3443e5dd7070Spatrick
3444e5dd7070Spatrick /// Class implementation was compiled under ARC.
3445e5dd7070Spatrick NonFragileABI_Class_CompiledByARC = 0x00080,
3446e5dd7070Spatrick
3447e5dd7070Spatrick /// Class has non-trivial destructors, but zero-initialization is okay.
3448e5dd7070Spatrick NonFragileABI_Class_HasCXXDestructorOnly = 0x00100,
3449e5dd7070Spatrick
3450e5dd7070Spatrick /// Class implementation was compiled under MRC and has MRC weak ivars.
3451e5dd7070Spatrick /// Exclusive with CompiledByARC.
3452e5dd7070Spatrick NonFragileABI_Class_HasMRCWeakIvars = 0x00200,
3453e5dd7070Spatrick };
3454e5dd7070Spatrick
hasWeakMember(QualType type)3455e5dd7070Spatrick static bool hasWeakMember(QualType type) {
3456e5dd7070Spatrick if (type.getObjCLifetime() == Qualifiers::OCL_Weak) {
3457e5dd7070Spatrick return true;
3458e5dd7070Spatrick }
3459e5dd7070Spatrick
3460e5dd7070Spatrick if (auto recType = type->getAs<RecordType>()) {
3461*12c85518Srobert for (auto *field : recType->getDecl()->fields()) {
3462e5dd7070Spatrick if (hasWeakMember(field->getType()))
3463e5dd7070Spatrick return true;
3464e5dd7070Spatrick }
3465e5dd7070Spatrick }
3466e5dd7070Spatrick
3467e5dd7070Spatrick return false;
3468e5dd7070Spatrick }
3469e5dd7070Spatrick
3470e5dd7070Spatrick /// For compatibility, we only want to set the "HasMRCWeakIvars" flag
3471e5dd7070Spatrick /// (and actually fill in a layout string) if we really do have any
3472e5dd7070Spatrick /// __weak ivars.
hasMRCWeakIvars(CodeGenModule & CGM,const ObjCImplementationDecl * ID)3473e5dd7070Spatrick static bool hasMRCWeakIvars(CodeGenModule &CGM,
3474e5dd7070Spatrick const ObjCImplementationDecl *ID) {
3475e5dd7070Spatrick if (!CGM.getLangOpts().ObjCWeak) return false;
3476e5dd7070Spatrick assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
3477e5dd7070Spatrick
3478e5dd7070Spatrick for (const ObjCIvarDecl *ivar =
3479e5dd7070Spatrick ID->getClassInterface()->all_declared_ivar_begin();
3480e5dd7070Spatrick ivar; ivar = ivar->getNextIvar()) {
3481e5dd7070Spatrick if (hasWeakMember(ivar->getType()))
3482e5dd7070Spatrick return true;
3483e5dd7070Spatrick }
3484e5dd7070Spatrick
3485e5dd7070Spatrick return false;
3486e5dd7070Spatrick }
3487e5dd7070Spatrick
3488e5dd7070Spatrick /*
3489e5dd7070Spatrick struct _objc_class {
3490e5dd7070Spatrick Class isa;
3491e5dd7070Spatrick Class super_class;
3492e5dd7070Spatrick const char *name;
3493e5dd7070Spatrick long version;
3494e5dd7070Spatrick long info;
3495e5dd7070Spatrick long instance_size;
3496e5dd7070Spatrick struct _objc_ivar_list *ivars;
3497e5dd7070Spatrick struct _objc_method_list *methods;
3498e5dd7070Spatrick struct _objc_cache *cache;
3499e5dd7070Spatrick struct _objc_protocol_list *protocols;
3500e5dd7070Spatrick // Objective-C 1.0 extensions (<rdr://4585769>)
3501e5dd7070Spatrick const char *ivar_layout;
3502e5dd7070Spatrick struct _objc_class_ext *ext;
3503e5dd7070Spatrick };
3504e5dd7070Spatrick
3505e5dd7070Spatrick See EmitClassExtension();
3506e5dd7070Spatrick */
GenerateClass(const ObjCImplementationDecl * ID)3507e5dd7070Spatrick void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
3508e5dd7070Spatrick IdentifierInfo *RuntimeName =
3509e5dd7070Spatrick &CGM.getContext().Idents.get(ID->getObjCRuntimeNameAsString());
3510e5dd7070Spatrick DefinedSymbols.insert(RuntimeName);
3511e5dd7070Spatrick
3512e5dd7070Spatrick std::string ClassName = ID->getNameAsString();
3513e5dd7070Spatrick // FIXME: Gross
3514e5dd7070Spatrick ObjCInterfaceDecl *Interface =
3515e5dd7070Spatrick const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
3516e5dd7070Spatrick llvm::Constant *Protocols =
3517e5dd7070Spatrick EmitProtocolList("OBJC_CLASS_PROTOCOLS_" + ID->getName(),
3518e5dd7070Spatrick Interface->all_referenced_protocol_begin(),
3519e5dd7070Spatrick Interface->all_referenced_protocol_end());
3520e5dd7070Spatrick unsigned Flags = FragileABI_Class_Factory;
3521e5dd7070Spatrick if (ID->hasNonZeroConstructors() || ID->hasDestructors())
3522e5dd7070Spatrick Flags |= FragileABI_Class_HasCXXStructors;
3523e5dd7070Spatrick
3524e5dd7070Spatrick bool hasMRCWeak = false;
3525e5dd7070Spatrick
3526e5dd7070Spatrick if (CGM.getLangOpts().ObjCAutoRefCount)
3527e5dd7070Spatrick Flags |= FragileABI_Class_CompiledByARC;
3528e5dd7070Spatrick else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID)))
3529e5dd7070Spatrick Flags |= FragileABI_Class_HasMRCWeakIvars;
3530e5dd7070Spatrick
3531e5dd7070Spatrick CharUnits Size =
3532e5dd7070Spatrick CGM.getContext().getASTObjCImplementationLayout(ID).getSize();
3533e5dd7070Spatrick
3534e5dd7070Spatrick // FIXME: Set CXX-structors flag.
3535e5dd7070Spatrick if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
3536e5dd7070Spatrick Flags |= FragileABI_Class_Hidden;
3537e5dd7070Spatrick
3538e5dd7070Spatrick enum {
3539e5dd7070Spatrick InstanceMethods,
3540e5dd7070Spatrick ClassMethods,
3541e5dd7070Spatrick NumMethodLists
3542e5dd7070Spatrick };
3543e5dd7070Spatrick SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
3544e5dd7070Spatrick for (const auto *MD : ID->methods()) {
3545e5dd7070Spatrick if (!MD->isDirectMethod())
3546e5dd7070Spatrick Methods[unsigned(MD->isClassMethod())].push_back(MD);
3547e5dd7070Spatrick }
3548e5dd7070Spatrick
3549e5dd7070Spatrick for (const auto *PID : ID->property_impls()) {
3550e5dd7070Spatrick if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
3551e5dd7070Spatrick if (PID->getPropertyDecl()->isDirectProperty())
3552e5dd7070Spatrick continue;
3553e5dd7070Spatrick if (ObjCMethodDecl *MD = PID->getGetterMethodDecl())
3554e5dd7070Spatrick if (GetMethodDefinition(MD))
3555e5dd7070Spatrick Methods[InstanceMethods].push_back(MD);
3556e5dd7070Spatrick if (ObjCMethodDecl *MD = PID->getSetterMethodDecl())
3557e5dd7070Spatrick if (GetMethodDefinition(MD))
3558e5dd7070Spatrick Methods[InstanceMethods].push_back(MD);
3559e5dd7070Spatrick }
3560e5dd7070Spatrick }
3561e5dd7070Spatrick
3562e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3563e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ClassTy);
3564e5dd7070Spatrick values.add(EmitMetaClass(ID, Protocols, Methods[ClassMethods]));
3565e5dd7070Spatrick if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) {
3566e5dd7070Spatrick // Record a reference to the super class.
3567e5dd7070Spatrick LazySymbols.insert(Super->getIdentifier());
3568e5dd7070Spatrick
3569e5dd7070Spatrick values.addBitCast(GetClassName(Super->getObjCRuntimeNameAsString()),
3570e5dd7070Spatrick ObjCTypes.ClassPtrTy);
3571e5dd7070Spatrick } else {
3572e5dd7070Spatrick values.addNullPointer(ObjCTypes.ClassPtrTy);
3573e5dd7070Spatrick }
3574e5dd7070Spatrick values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
3575e5dd7070Spatrick // Version is always 0.
3576e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, 0);
3577e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, Flags);
3578e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, Size.getQuantity());
3579e5dd7070Spatrick values.add(EmitIvarList(ID, false));
3580e5dd7070Spatrick values.add(emitMethodList(ID->getName(), MethodListType::InstanceMethods,
3581e5dd7070Spatrick Methods[InstanceMethods]));
3582e5dd7070Spatrick // cache is always NULL.
3583e5dd7070Spatrick values.addNullPointer(ObjCTypes.CachePtrTy);
3584e5dd7070Spatrick values.add(Protocols);
3585e5dd7070Spatrick values.add(BuildStrongIvarLayout(ID, CharUnits::Zero(), Size));
3586e5dd7070Spatrick values.add(EmitClassExtension(ID, Size, hasMRCWeak,
3587e5dd7070Spatrick /*isMetaclass*/ false));
3588e5dd7070Spatrick
3589e5dd7070Spatrick std::string Name("OBJC_CLASS_");
3590e5dd7070Spatrick Name += ClassName;
3591e5dd7070Spatrick const char *Section = "__OBJC,__class,regular,no_dead_strip";
3592e5dd7070Spatrick // Check for a forward reference.
3593e5dd7070Spatrick llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
3594e5dd7070Spatrick if (GV) {
3595ec727ea7Spatrick assert(GV->getValueType() == ObjCTypes.ClassTy &&
3596e5dd7070Spatrick "Forward metaclass reference has incorrect type.");
3597e5dd7070Spatrick values.finishAndSetAsInitializer(GV);
3598e5dd7070Spatrick GV->setSection(Section);
3599e5dd7070Spatrick GV->setAlignment(CGM.getPointerAlign().getAsAlign());
3600e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
3601e5dd7070Spatrick } else
3602e5dd7070Spatrick GV = CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true);
3603e5dd7070Spatrick DefinedClasses.push_back(GV);
3604e5dd7070Spatrick ImplementedClasses.push_back(Interface);
3605e5dd7070Spatrick // method definition entries must be clear for next implementation.
3606e5dd7070Spatrick MethodDefinitions.clear();
3607e5dd7070Spatrick }
3608e5dd7070Spatrick
EmitMetaClass(const ObjCImplementationDecl * ID,llvm::Constant * Protocols,ArrayRef<const ObjCMethodDecl * > Methods)3609e5dd7070Spatrick llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
3610e5dd7070Spatrick llvm::Constant *Protocols,
3611e5dd7070Spatrick ArrayRef<const ObjCMethodDecl*> Methods) {
3612e5dd7070Spatrick unsigned Flags = FragileABI_Class_Meta;
3613e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassTy);
3614e5dd7070Spatrick
3615e5dd7070Spatrick if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
3616e5dd7070Spatrick Flags |= FragileABI_Class_Hidden;
3617e5dd7070Spatrick
3618e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3619e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ClassTy);
3620e5dd7070Spatrick // The isa for the metaclass is the root of the hierarchy.
3621e5dd7070Spatrick const ObjCInterfaceDecl *Root = ID->getClassInterface();
3622e5dd7070Spatrick while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
3623e5dd7070Spatrick Root = Super;
3624e5dd7070Spatrick values.addBitCast(GetClassName(Root->getObjCRuntimeNameAsString()),
3625e5dd7070Spatrick ObjCTypes.ClassPtrTy);
3626e5dd7070Spatrick // The super class for the metaclass is emitted as the name of the
3627e5dd7070Spatrick // super class. The runtime fixes this up to point to the
3628e5dd7070Spatrick // *metaclass* for the super class.
3629e5dd7070Spatrick if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) {
3630e5dd7070Spatrick values.addBitCast(GetClassName(Super->getObjCRuntimeNameAsString()),
3631e5dd7070Spatrick ObjCTypes.ClassPtrTy);
3632e5dd7070Spatrick } else {
3633e5dd7070Spatrick values.addNullPointer(ObjCTypes.ClassPtrTy);
3634e5dd7070Spatrick }
3635e5dd7070Spatrick values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
3636e5dd7070Spatrick // Version is always 0.
3637e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, 0);
3638e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, Flags);
3639e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, Size);
3640e5dd7070Spatrick values.add(EmitIvarList(ID, true));
3641e5dd7070Spatrick values.add(emitMethodList(ID->getName(), MethodListType::ClassMethods,
3642e5dd7070Spatrick Methods));
3643e5dd7070Spatrick // cache is always NULL.
3644e5dd7070Spatrick values.addNullPointer(ObjCTypes.CachePtrTy);
3645e5dd7070Spatrick values.add(Protocols);
3646e5dd7070Spatrick // ivar_layout for metaclass is always NULL.
3647e5dd7070Spatrick values.addNullPointer(ObjCTypes.Int8PtrTy);
3648e5dd7070Spatrick // The class extension is used to store class properties for metaclasses.
3649e5dd7070Spatrick values.add(EmitClassExtension(ID, CharUnits::Zero(), false/*hasMRCWeak*/,
3650e5dd7070Spatrick /*isMetaclass*/true));
3651e5dd7070Spatrick
3652e5dd7070Spatrick std::string Name("OBJC_METACLASS_");
3653e5dd7070Spatrick Name += ID->getName();
3654e5dd7070Spatrick
3655e5dd7070Spatrick // Check for a forward reference.
3656e5dd7070Spatrick llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
3657e5dd7070Spatrick if (GV) {
3658ec727ea7Spatrick assert(GV->getValueType() == ObjCTypes.ClassTy &&
3659e5dd7070Spatrick "Forward metaclass reference has incorrect type.");
3660e5dd7070Spatrick values.finishAndSetAsInitializer(GV);
3661e5dd7070Spatrick } else {
3662e5dd7070Spatrick GV = values.finishAndCreateGlobal(Name, CGM.getPointerAlign(),
3663e5dd7070Spatrick /*constant*/ false,
3664e5dd7070Spatrick llvm::GlobalValue::PrivateLinkage);
3665e5dd7070Spatrick }
3666e5dd7070Spatrick GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
3667e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
3668e5dd7070Spatrick
3669e5dd7070Spatrick return GV;
3670e5dd7070Spatrick }
3671e5dd7070Spatrick
EmitMetaClassRef(const ObjCInterfaceDecl * ID)3672e5dd7070Spatrick llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
3673e5dd7070Spatrick std::string Name = "OBJC_METACLASS_" + ID->getNameAsString();
3674e5dd7070Spatrick
3675e5dd7070Spatrick // FIXME: Should we look these up somewhere other than the module. Its a bit
3676e5dd7070Spatrick // silly since we only generate these while processing an implementation, so
3677e5dd7070Spatrick // exactly one pointer would work if know when we entered/exitted an
3678e5dd7070Spatrick // implementation block.
3679e5dd7070Spatrick
3680e5dd7070Spatrick // Check for an existing forward reference.
3681e5dd7070Spatrick // Previously, metaclass with internal linkage may have been defined.
3682e5dd7070Spatrick // pass 'true' as 2nd argument so it is returned.
3683e5dd7070Spatrick llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
3684e5dd7070Spatrick if (!GV)
3685e5dd7070Spatrick GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
3686e5dd7070Spatrick llvm::GlobalValue::PrivateLinkage, nullptr,
3687e5dd7070Spatrick Name);
3688e5dd7070Spatrick
3689ec727ea7Spatrick assert(GV->getValueType() == ObjCTypes.ClassTy &&
3690e5dd7070Spatrick "Forward metaclass reference has incorrect type.");
3691e5dd7070Spatrick return GV;
3692e5dd7070Spatrick }
3693e5dd7070Spatrick
EmitSuperClassRef(const ObjCInterfaceDecl * ID)3694e5dd7070Spatrick llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
3695e5dd7070Spatrick std::string Name = "OBJC_CLASS_" + ID->getNameAsString();
3696e5dd7070Spatrick llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
3697e5dd7070Spatrick
3698e5dd7070Spatrick if (!GV)
3699e5dd7070Spatrick GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
3700e5dd7070Spatrick llvm::GlobalValue::PrivateLinkage, nullptr,
3701e5dd7070Spatrick Name);
3702e5dd7070Spatrick
3703ec727ea7Spatrick assert(GV->getValueType() == ObjCTypes.ClassTy &&
3704e5dd7070Spatrick "Forward class metadata reference has incorrect type.");
3705e5dd7070Spatrick return GV;
3706e5dd7070Spatrick }
3707e5dd7070Spatrick
3708e5dd7070Spatrick /*
3709e5dd7070Spatrick Emit a "class extension", which in this specific context means extra
3710e5dd7070Spatrick data that doesn't fit in the normal fragile-ABI class structure, and
3711e5dd7070Spatrick has nothing to do with the language concept of a class extension.
3712e5dd7070Spatrick
3713e5dd7070Spatrick struct objc_class_ext {
3714e5dd7070Spatrick uint32_t size;
3715e5dd7070Spatrick const char *weak_ivar_layout;
3716e5dd7070Spatrick struct _objc_property_list *properties;
3717e5dd7070Spatrick };
3718e5dd7070Spatrick */
3719e5dd7070Spatrick llvm::Constant *
EmitClassExtension(const ObjCImplementationDecl * ID,CharUnits InstanceSize,bool hasMRCWeakIvars,bool isMetaclass)3720e5dd7070Spatrick CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID,
3721e5dd7070Spatrick CharUnits InstanceSize, bool hasMRCWeakIvars,
3722e5dd7070Spatrick bool isMetaclass) {
3723e5dd7070Spatrick // Weak ivar layout.
3724e5dd7070Spatrick llvm::Constant *layout;
3725e5dd7070Spatrick if (isMetaclass) {
3726e5dd7070Spatrick layout = llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
3727e5dd7070Spatrick } else {
3728e5dd7070Spatrick layout = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize,
3729e5dd7070Spatrick hasMRCWeakIvars);
3730e5dd7070Spatrick }
3731e5dd7070Spatrick
3732e5dd7070Spatrick // Properties.
3733e5dd7070Spatrick llvm::Constant *propertyList =
3734e5dd7070Spatrick EmitPropertyList((isMetaclass ? Twine("_OBJC_$_CLASS_PROP_LIST_")
3735e5dd7070Spatrick : Twine("_OBJC_$_PROP_LIST_"))
3736e5dd7070Spatrick + ID->getName(),
3737e5dd7070Spatrick ID, ID->getClassInterface(), ObjCTypes, isMetaclass);
3738e5dd7070Spatrick
3739e5dd7070Spatrick // Return null if no extension bits are used.
3740e5dd7070Spatrick if (layout->isNullValue() && propertyList->isNullValue()) {
3741e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
3742e5dd7070Spatrick }
3743e5dd7070Spatrick
3744e5dd7070Spatrick uint64_t size =
3745e5dd7070Spatrick CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
3746e5dd7070Spatrick
3747e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3748e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ClassExtensionTy);
3749e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, size);
3750e5dd7070Spatrick values.add(layout);
3751e5dd7070Spatrick values.add(propertyList);
3752e5dd7070Spatrick
3753e5dd7070Spatrick return CreateMetadataVar("OBJC_CLASSEXT_" + ID->getName(), values,
3754e5dd7070Spatrick "__OBJC,__class_ext,regular,no_dead_strip",
3755e5dd7070Spatrick CGM.getPointerAlign(), true);
3756e5dd7070Spatrick }
3757e5dd7070Spatrick
3758e5dd7070Spatrick /*
3759e5dd7070Spatrick struct objc_ivar {
3760e5dd7070Spatrick char *ivar_name;
3761e5dd7070Spatrick char *ivar_type;
3762e5dd7070Spatrick int ivar_offset;
3763e5dd7070Spatrick };
3764e5dd7070Spatrick
3765e5dd7070Spatrick struct objc_ivar_list {
3766e5dd7070Spatrick int ivar_count;
3767e5dd7070Spatrick struct objc_ivar list[count];
3768e5dd7070Spatrick };
3769e5dd7070Spatrick */
EmitIvarList(const ObjCImplementationDecl * ID,bool ForClass)3770e5dd7070Spatrick llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
3771e5dd7070Spatrick bool ForClass) {
3772e5dd7070Spatrick // When emitting the root class GCC emits ivar entries for the
3773e5dd7070Spatrick // actual class structure. It is not clear if we need to follow this
3774e5dd7070Spatrick // behavior; for now lets try and get away with not doing it. If so,
3775e5dd7070Spatrick // the cleanest solution would be to make up an ObjCInterfaceDecl
3776e5dd7070Spatrick // for the class.
3777e5dd7070Spatrick if (ForClass)
3778e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
3779e5dd7070Spatrick
3780e5dd7070Spatrick const ObjCInterfaceDecl *OID = ID->getClassInterface();
3781e5dd7070Spatrick
3782e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3783e5dd7070Spatrick auto ivarList = builder.beginStruct();
3784e5dd7070Spatrick auto countSlot = ivarList.addPlaceholder();
3785e5dd7070Spatrick auto ivars = ivarList.beginArray(ObjCTypes.IvarTy);
3786e5dd7070Spatrick
3787e5dd7070Spatrick for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
3788e5dd7070Spatrick IVD; IVD = IVD->getNextIvar()) {
3789e5dd7070Spatrick // Ignore unnamed bit-fields.
3790e5dd7070Spatrick if (!IVD->getDeclName())
3791e5dd7070Spatrick continue;
3792e5dd7070Spatrick
3793e5dd7070Spatrick auto ivar = ivars.beginStruct(ObjCTypes.IvarTy);
3794e5dd7070Spatrick ivar.add(GetMethodVarName(IVD->getIdentifier()));
3795e5dd7070Spatrick ivar.add(GetMethodVarType(IVD));
3796e5dd7070Spatrick ivar.addInt(ObjCTypes.IntTy, ComputeIvarBaseOffset(CGM, OID, IVD));
3797e5dd7070Spatrick ivar.finishAndAddTo(ivars);
3798e5dd7070Spatrick }
3799e5dd7070Spatrick
3800e5dd7070Spatrick // Return null for empty list.
3801e5dd7070Spatrick auto count = ivars.size();
3802e5dd7070Spatrick if (count == 0) {
3803e5dd7070Spatrick ivars.abandon();
3804e5dd7070Spatrick ivarList.abandon();
3805e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
3806e5dd7070Spatrick }
3807e5dd7070Spatrick
3808e5dd7070Spatrick ivars.finishAndAddTo(ivarList);
3809e5dd7070Spatrick ivarList.fillPlaceholderWithInt(countSlot, ObjCTypes.IntTy, count);
3810e5dd7070Spatrick
3811e5dd7070Spatrick llvm::GlobalVariable *GV;
3812e5dd7070Spatrick if (ForClass)
3813e5dd7070Spatrick GV =
3814e5dd7070Spatrick CreateMetadataVar("OBJC_CLASS_VARIABLES_" + ID->getName(), ivarList,
3815e5dd7070Spatrick "__OBJC,__class_vars,regular,no_dead_strip",
3816e5dd7070Spatrick CGM.getPointerAlign(), true);
3817e5dd7070Spatrick else
3818e5dd7070Spatrick GV = CreateMetadataVar("OBJC_INSTANCE_VARIABLES_" + ID->getName(), ivarList,
3819e5dd7070Spatrick "__OBJC,__instance_vars,regular,no_dead_strip",
3820e5dd7070Spatrick CGM.getPointerAlign(), true);
3821e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy);
3822e5dd7070Spatrick }
3823e5dd7070Spatrick
3824e5dd7070Spatrick /// Build a struct objc_method_description constant for the given method.
3825e5dd7070Spatrick ///
3826e5dd7070Spatrick /// struct objc_method_description {
3827e5dd7070Spatrick /// SEL method_name;
3828e5dd7070Spatrick /// char *method_types;
3829e5dd7070Spatrick /// };
emitMethodDescriptionConstant(ConstantArrayBuilder & builder,const ObjCMethodDecl * MD)3830e5dd7070Spatrick void CGObjCMac::emitMethodDescriptionConstant(ConstantArrayBuilder &builder,
3831e5dd7070Spatrick const ObjCMethodDecl *MD) {
3832e5dd7070Spatrick auto description = builder.beginStruct(ObjCTypes.MethodDescriptionTy);
3833e5dd7070Spatrick description.addBitCast(GetMethodVarName(MD->getSelector()),
3834e5dd7070Spatrick ObjCTypes.SelectorPtrTy);
3835e5dd7070Spatrick description.add(GetMethodVarType(MD));
3836e5dd7070Spatrick description.finishAndAddTo(builder);
3837e5dd7070Spatrick }
3838e5dd7070Spatrick
3839e5dd7070Spatrick /// Build a struct objc_method constant for the given method.
3840e5dd7070Spatrick ///
3841e5dd7070Spatrick /// struct objc_method {
3842e5dd7070Spatrick /// SEL method_name;
3843e5dd7070Spatrick /// char *method_types;
3844e5dd7070Spatrick /// void *method;
3845e5dd7070Spatrick /// };
emitMethodConstant(ConstantArrayBuilder & builder,const ObjCMethodDecl * MD)3846e5dd7070Spatrick void CGObjCMac::emitMethodConstant(ConstantArrayBuilder &builder,
3847e5dd7070Spatrick const ObjCMethodDecl *MD) {
3848e5dd7070Spatrick llvm::Function *fn = GetMethodDefinition(MD);
3849e5dd7070Spatrick assert(fn && "no definition registered for method");
3850e5dd7070Spatrick
3851e5dd7070Spatrick auto method = builder.beginStruct(ObjCTypes.MethodTy);
3852e5dd7070Spatrick method.addBitCast(GetMethodVarName(MD->getSelector()),
3853e5dd7070Spatrick ObjCTypes.SelectorPtrTy);
3854e5dd7070Spatrick method.add(GetMethodVarType(MD));
3855e5dd7070Spatrick method.addBitCast(fn, ObjCTypes.Int8PtrTy);
3856e5dd7070Spatrick method.finishAndAddTo(builder);
3857e5dd7070Spatrick }
3858e5dd7070Spatrick
3859e5dd7070Spatrick /// Build a struct objc_method_list or struct objc_method_description_list,
3860e5dd7070Spatrick /// as appropriate.
3861e5dd7070Spatrick ///
3862e5dd7070Spatrick /// struct objc_method_list {
3863e5dd7070Spatrick /// struct objc_method_list *obsolete;
3864e5dd7070Spatrick /// int count;
3865e5dd7070Spatrick /// struct objc_method methods_list[count];
3866e5dd7070Spatrick /// };
3867e5dd7070Spatrick ///
3868e5dd7070Spatrick /// struct objc_method_description_list {
3869e5dd7070Spatrick /// int count;
3870e5dd7070Spatrick /// struct objc_method_description list[count];
3871e5dd7070Spatrick /// };
emitMethodList(Twine name,MethodListType MLT,ArrayRef<const ObjCMethodDecl * > methods)3872e5dd7070Spatrick llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT,
3873e5dd7070Spatrick ArrayRef<const ObjCMethodDecl *> methods) {
3874e5dd7070Spatrick StringRef prefix;
3875e5dd7070Spatrick StringRef section;
3876e5dd7070Spatrick bool forProtocol = false;
3877e5dd7070Spatrick switch (MLT) {
3878e5dd7070Spatrick case MethodListType::CategoryInstanceMethods:
3879e5dd7070Spatrick prefix = "OBJC_CATEGORY_INSTANCE_METHODS_";
3880e5dd7070Spatrick section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
3881e5dd7070Spatrick forProtocol = false;
3882e5dd7070Spatrick break;
3883e5dd7070Spatrick case MethodListType::CategoryClassMethods:
3884e5dd7070Spatrick prefix = "OBJC_CATEGORY_CLASS_METHODS_";
3885e5dd7070Spatrick section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
3886e5dd7070Spatrick forProtocol = false;
3887e5dd7070Spatrick break;
3888e5dd7070Spatrick case MethodListType::InstanceMethods:
3889e5dd7070Spatrick prefix = "OBJC_INSTANCE_METHODS_";
3890e5dd7070Spatrick section = "__OBJC,__inst_meth,regular,no_dead_strip";
3891e5dd7070Spatrick forProtocol = false;
3892e5dd7070Spatrick break;
3893e5dd7070Spatrick case MethodListType::ClassMethods:
3894e5dd7070Spatrick prefix = "OBJC_CLASS_METHODS_";
3895e5dd7070Spatrick section = "__OBJC,__cls_meth,regular,no_dead_strip";
3896e5dd7070Spatrick forProtocol = false;
3897e5dd7070Spatrick break;
3898e5dd7070Spatrick case MethodListType::ProtocolInstanceMethods:
3899e5dd7070Spatrick prefix = "OBJC_PROTOCOL_INSTANCE_METHODS_";
3900e5dd7070Spatrick section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
3901e5dd7070Spatrick forProtocol = true;
3902e5dd7070Spatrick break;
3903e5dd7070Spatrick case MethodListType::ProtocolClassMethods:
3904e5dd7070Spatrick prefix = "OBJC_PROTOCOL_CLASS_METHODS_";
3905e5dd7070Spatrick section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
3906e5dd7070Spatrick forProtocol = true;
3907e5dd7070Spatrick break;
3908e5dd7070Spatrick case MethodListType::OptionalProtocolInstanceMethods:
3909e5dd7070Spatrick prefix = "OBJC_PROTOCOL_INSTANCE_METHODS_OPT_";
3910e5dd7070Spatrick section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
3911e5dd7070Spatrick forProtocol = true;
3912e5dd7070Spatrick break;
3913e5dd7070Spatrick case MethodListType::OptionalProtocolClassMethods:
3914e5dd7070Spatrick prefix = "OBJC_PROTOCOL_CLASS_METHODS_OPT_";
3915e5dd7070Spatrick section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
3916e5dd7070Spatrick forProtocol = true;
3917e5dd7070Spatrick break;
3918e5dd7070Spatrick }
3919e5dd7070Spatrick
3920e5dd7070Spatrick // Return null for empty list.
3921e5dd7070Spatrick if (methods.empty())
3922e5dd7070Spatrick return llvm::Constant::getNullValue(forProtocol
3923e5dd7070Spatrick ? ObjCTypes.MethodDescriptionListPtrTy
3924e5dd7070Spatrick : ObjCTypes.MethodListPtrTy);
3925e5dd7070Spatrick
3926e5dd7070Spatrick // For protocols, this is an objc_method_description_list, which has
3927e5dd7070Spatrick // a slightly different structure.
3928e5dd7070Spatrick if (forProtocol) {
3929e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3930e5dd7070Spatrick auto values = builder.beginStruct();
3931e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, methods.size());
3932e5dd7070Spatrick auto methodArray = values.beginArray(ObjCTypes.MethodDescriptionTy);
3933e5dd7070Spatrick for (auto MD : methods) {
3934e5dd7070Spatrick emitMethodDescriptionConstant(methodArray, MD);
3935e5dd7070Spatrick }
3936e5dd7070Spatrick methodArray.finishAndAddTo(values);
3937e5dd7070Spatrick
3938e5dd7070Spatrick llvm::GlobalVariable *GV = CreateMetadataVar(prefix + name, values, section,
3939e5dd7070Spatrick CGM.getPointerAlign(), true);
3940e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV,
3941e5dd7070Spatrick ObjCTypes.MethodDescriptionListPtrTy);
3942e5dd7070Spatrick }
3943e5dd7070Spatrick
3944e5dd7070Spatrick // Otherwise, it's an objc_method_list.
3945e5dd7070Spatrick ConstantInitBuilder builder(CGM);
3946e5dd7070Spatrick auto values = builder.beginStruct();
3947e5dd7070Spatrick values.addNullPointer(ObjCTypes.Int8PtrTy);
3948e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, methods.size());
3949e5dd7070Spatrick auto methodArray = values.beginArray(ObjCTypes.MethodTy);
3950e5dd7070Spatrick for (auto MD : methods) {
3951e5dd7070Spatrick if (!MD->isDirectMethod())
3952e5dd7070Spatrick emitMethodConstant(methodArray, MD);
3953e5dd7070Spatrick }
3954e5dd7070Spatrick methodArray.finishAndAddTo(values);
3955e5dd7070Spatrick
3956e5dd7070Spatrick llvm::GlobalVariable *GV = CreateMetadataVar(prefix + name, values, section,
3957e5dd7070Spatrick CGM.getPointerAlign(), true);
3958e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListPtrTy);
3959e5dd7070Spatrick }
3960e5dd7070Spatrick
GenerateMethod(const ObjCMethodDecl * OMD,const ObjCContainerDecl * CD)3961e5dd7070Spatrick llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
3962e5dd7070Spatrick const ObjCContainerDecl *CD) {
3963e5dd7070Spatrick llvm::Function *Method;
3964e5dd7070Spatrick
3965e5dd7070Spatrick if (OMD->isDirectMethod()) {
3966e5dd7070Spatrick Method = GenerateDirectMethod(OMD, CD);
3967e5dd7070Spatrick } else {
3968a9ac8606Spatrick auto Name = getSymbolNameForMethod(OMD);
3969e5dd7070Spatrick
3970e5dd7070Spatrick CodeGenTypes &Types = CGM.getTypes();
3971e5dd7070Spatrick llvm::FunctionType *MethodTy =
3972e5dd7070Spatrick Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
3973e5dd7070Spatrick Method =
3974e5dd7070Spatrick llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage,
3975a9ac8606Spatrick Name, &CGM.getModule());
3976e5dd7070Spatrick }
3977e5dd7070Spatrick
3978e5dd7070Spatrick MethodDefinitions.insert(std::make_pair(OMD, Method));
3979e5dd7070Spatrick
3980e5dd7070Spatrick return Method;
3981e5dd7070Spatrick }
3982e5dd7070Spatrick
3983e5dd7070Spatrick llvm::Function *
GenerateDirectMethod(const ObjCMethodDecl * OMD,const ObjCContainerDecl * CD)3984e5dd7070Spatrick CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD,
3985e5dd7070Spatrick const ObjCContainerDecl *CD) {
3986ec727ea7Spatrick auto *COMD = OMD->getCanonicalDecl();
3987ec727ea7Spatrick auto I = DirectMethodDefinitions.find(COMD);
3988ec727ea7Spatrick llvm::Function *OldFn = nullptr, *Fn = nullptr;
3989e5dd7070Spatrick
3990ec727ea7Spatrick if (I != DirectMethodDefinitions.end()) {
3991ec727ea7Spatrick // Objective-C allows for the declaration and implementation types
3992ec727ea7Spatrick // to differ slightly.
3993ec727ea7Spatrick //
3994ec727ea7Spatrick // If we're being asked for the Function associated for a method
3995ec727ea7Spatrick // implementation, a previous value might have been cached
3996ec727ea7Spatrick // based on the type of the canonical declaration.
3997ec727ea7Spatrick //
3998ec727ea7Spatrick // If these do not match, then we'll replace this function with
3999ec727ea7Spatrick // a new one that has the proper type below.
4000ec727ea7Spatrick if (!OMD->getBody() || COMD->getReturnType() == OMD->getReturnType())
4001ec727ea7Spatrick return I->second;
4002ec727ea7Spatrick OldFn = I->second;
4003ec727ea7Spatrick }
4004e5dd7070Spatrick
4005e5dd7070Spatrick CodeGenTypes &Types = CGM.getTypes();
4006e5dd7070Spatrick llvm::FunctionType *MethodTy =
4007e5dd7070Spatrick Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
4008e5dd7070Spatrick
4009ec727ea7Spatrick if (OldFn) {
4010ec727ea7Spatrick Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
4011ec727ea7Spatrick "", &CGM.getModule());
4012ec727ea7Spatrick Fn->takeName(OldFn);
4013ec727ea7Spatrick OldFn->replaceAllUsesWith(
4014ec727ea7Spatrick llvm::ConstantExpr::getBitCast(Fn, OldFn->getType()));
4015ec727ea7Spatrick OldFn->eraseFromParent();
4016ec727ea7Spatrick
4017ec727ea7Spatrick // Replace the cached function in the map.
4018ec727ea7Spatrick I->second = Fn;
4019ec727ea7Spatrick } else {
4020a9ac8606Spatrick auto Name = getSymbolNameForMethod(OMD, /*include category*/ false);
4021ec727ea7Spatrick
4022ec727ea7Spatrick Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
4023a9ac8606Spatrick Name, &CGM.getModule());
4024ec727ea7Spatrick DirectMethodDefinitions.insert(std::make_pair(COMD, Fn));
4025ec727ea7Spatrick }
4026ec727ea7Spatrick
4027ec727ea7Spatrick return Fn;
4028e5dd7070Spatrick }
4029e5dd7070Spatrick
GenerateDirectMethodPrologue(CodeGenFunction & CGF,llvm::Function * Fn,const ObjCMethodDecl * OMD,const ObjCContainerDecl * CD)4030e5dd7070Spatrick void CGObjCCommonMac::GenerateDirectMethodPrologue(
4031e5dd7070Spatrick CodeGenFunction &CGF, llvm::Function *Fn, const ObjCMethodDecl *OMD,
4032e5dd7070Spatrick const ObjCContainerDecl *CD) {
4033e5dd7070Spatrick auto &Builder = CGF.Builder;
4034e5dd7070Spatrick bool ReceiverCanBeNull = true;
4035e5dd7070Spatrick auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
4036e5dd7070Spatrick auto selfValue = Builder.CreateLoad(selfAddr);
4037e5dd7070Spatrick
4038e5dd7070Spatrick // Generate:
4039e5dd7070Spatrick //
4040e5dd7070Spatrick // /* for class methods only to force class lazy initialization */
4041e5dd7070Spatrick // self = [self self];
4042e5dd7070Spatrick //
4043e5dd7070Spatrick // /* unless the receiver is never NULL */
4044e5dd7070Spatrick // if (self == nil) {
4045e5dd7070Spatrick // return (ReturnType){ };
4046e5dd7070Spatrick // }
4047e5dd7070Spatrick //
4048e5dd7070Spatrick // _cmd = @selector(...)
4049e5dd7070Spatrick // ...
4050e5dd7070Spatrick
4051e5dd7070Spatrick if (OMD->isClassMethod()) {
4052e5dd7070Spatrick const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
4053e5dd7070Spatrick assert(OID &&
4054e5dd7070Spatrick "GenerateDirectMethod() should be called with the Class Interface");
4055e5dd7070Spatrick Selector SelfSel = GetNullarySelector("self", CGM.getContext());
4056e5dd7070Spatrick auto ResultType = CGF.getContext().getObjCIdType();
4057e5dd7070Spatrick RValue result;
4058e5dd7070Spatrick CallArgList Args;
4059e5dd7070Spatrick
4060e5dd7070Spatrick // TODO: If this method is inlined, the caller might know that `self` is
4061e5dd7070Spatrick // already initialized; for example, it might be an ordinary Objective-C
4062e5dd7070Spatrick // method which always receives an initialized `self`, or it might have just
4063e5dd7070Spatrick // forced initialization on its own.
4064e5dd7070Spatrick //
4065e5dd7070Spatrick // We should find a way to eliminate this unnecessary initialization in such
4066e5dd7070Spatrick // cases in LLVM.
4067e5dd7070Spatrick result = GeneratePossiblySpecializedMessageSend(
4068e5dd7070Spatrick CGF, ReturnValueSlot(), ResultType, SelfSel, selfValue, Args, OID,
4069e5dd7070Spatrick nullptr, true);
4070e5dd7070Spatrick Builder.CreateStore(result.getScalarVal(), selfAddr);
4071e5dd7070Spatrick
4072e5dd7070Spatrick // Nullable `Class` expressions cannot be messaged with a direct method
4073e5dd7070Spatrick // so the only reason why the receive can be null would be because
4074e5dd7070Spatrick // of weak linking.
4075e5dd7070Spatrick ReceiverCanBeNull = isWeakLinkedClass(OID);
4076e5dd7070Spatrick }
4077e5dd7070Spatrick
4078e5dd7070Spatrick if (ReceiverCanBeNull) {
4079e5dd7070Spatrick llvm::BasicBlock *SelfIsNilBlock =
4080e5dd7070Spatrick CGF.createBasicBlock("objc_direct_method.self_is_nil");
4081e5dd7070Spatrick llvm::BasicBlock *ContBlock =
4082e5dd7070Spatrick CGF.createBasicBlock("objc_direct_method.cont");
4083e5dd7070Spatrick
4084e5dd7070Spatrick // if (self == nil) {
4085e5dd7070Spatrick auto selfTy = cast<llvm::PointerType>(selfValue->getType());
4086e5dd7070Spatrick auto Zero = llvm::ConstantPointerNull::get(selfTy);
4087e5dd7070Spatrick
4088e5dd7070Spatrick llvm::MDBuilder MDHelper(CGM.getLLVMContext());
4089e5dd7070Spatrick Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero), SelfIsNilBlock,
4090e5dd7070Spatrick ContBlock, MDHelper.createBranchWeights(1, 1 << 20));
4091e5dd7070Spatrick
4092e5dd7070Spatrick CGF.EmitBlock(SelfIsNilBlock);
4093e5dd7070Spatrick
4094e5dd7070Spatrick // return (ReturnType){ };
4095e5dd7070Spatrick auto retTy = OMD->getReturnType();
4096e5dd7070Spatrick Builder.SetInsertPoint(SelfIsNilBlock);
4097e5dd7070Spatrick if (!retTy->isVoidType()) {
4098e5dd7070Spatrick CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
4099e5dd7070Spatrick }
4100e5dd7070Spatrick CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
4101e5dd7070Spatrick // }
4102e5dd7070Spatrick
4103e5dd7070Spatrick // rest of the body
4104e5dd7070Spatrick CGF.EmitBlock(ContBlock);
4105e5dd7070Spatrick Builder.SetInsertPoint(ContBlock);
4106e5dd7070Spatrick }
4107e5dd7070Spatrick
4108e5dd7070Spatrick // only synthesize _cmd if it's referenced
4109e5dd7070Spatrick if (OMD->getCmdDecl()->isUsed()) {
4110*12c85518Srobert // `_cmd` is not a parameter to direct methods, so storage must be
4111*12c85518Srobert // explicitly declared for it.
4112*12c85518Srobert CGF.EmitVarDecl(*OMD->getCmdDecl());
4113e5dd7070Spatrick Builder.CreateStore(GetSelector(CGF, OMD),
4114e5dd7070Spatrick CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
4115e5dd7070Spatrick }
4116e5dd7070Spatrick }
4117e5dd7070Spatrick
CreateMetadataVar(Twine Name,ConstantStructBuilder & Init,StringRef Section,CharUnits Align,bool AddToUsed)4118e5dd7070Spatrick llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
4119e5dd7070Spatrick ConstantStructBuilder &Init,
4120e5dd7070Spatrick StringRef Section,
4121e5dd7070Spatrick CharUnits Align,
4122e5dd7070Spatrick bool AddToUsed) {
4123e5dd7070Spatrick llvm::GlobalValue::LinkageTypes LT =
4124e5dd7070Spatrick getLinkageTypeForObjCMetadata(CGM, Section);
4125e5dd7070Spatrick llvm::GlobalVariable *GV =
4126e5dd7070Spatrick Init.finishAndCreateGlobal(Name, Align, /*constant*/ false, LT);
4127e5dd7070Spatrick if (!Section.empty())
4128e5dd7070Spatrick GV->setSection(Section);
4129e5dd7070Spatrick if (AddToUsed)
4130e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
4131e5dd7070Spatrick return GV;
4132e5dd7070Spatrick }
4133e5dd7070Spatrick
CreateMetadataVar(Twine Name,llvm::Constant * Init,StringRef Section,CharUnits Align,bool AddToUsed)4134e5dd7070Spatrick llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
4135e5dd7070Spatrick llvm::Constant *Init,
4136e5dd7070Spatrick StringRef Section,
4137e5dd7070Spatrick CharUnits Align,
4138e5dd7070Spatrick bool AddToUsed) {
4139e5dd7070Spatrick llvm::Type *Ty = Init->getType();
4140e5dd7070Spatrick llvm::GlobalValue::LinkageTypes LT =
4141e5dd7070Spatrick getLinkageTypeForObjCMetadata(CGM, Section);
4142e5dd7070Spatrick llvm::GlobalVariable *GV =
4143e5dd7070Spatrick new llvm::GlobalVariable(CGM.getModule(), Ty, false, LT, Init, Name);
4144e5dd7070Spatrick if (!Section.empty())
4145e5dd7070Spatrick GV->setSection(Section);
4146e5dd7070Spatrick GV->setAlignment(Align.getAsAlign());
4147e5dd7070Spatrick if (AddToUsed)
4148e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
4149e5dd7070Spatrick return GV;
4150e5dd7070Spatrick }
4151e5dd7070Spatrick
4152e5dd7070Spatrick llvm::GlobalVariable *
CreateCStringLiteral(StringRef Name,ObjCLabelType Type,bool ForceNonFragileABI,bool NullTerminate)4153e5dd7070Spatrick CGObjCCommonMac::CreateCStringLiteral(StringRef Name, ObjCLabelType Type,
4154e5dd7070Spatrick bool ForceNonFragileABI,
4155e5dd7070Spatrick bool NullTerminate) {
4156e5dd7070Spatrick StringRef Label;
4157e5dd7070Spatrick switch (Type) {
4158e5dd7070Spatrick case ObjCLabelType::ClassName: Label = "OBJC_CLASS_NAME_"; break;
4159e5dd7070Spatrick case ObjCLabelType::MethodVarName: Label = "OBJC_METH_VAR_NAME_"; break;
4160e5dd7070Spatrick case ObjCLabelType::MethodVarType: Label = "OBJC_METH_VAR_TYPE_"; break;
4161e5dd7070Spatrick case ObjCLabelType::PropertyName: Label = "OBJC_PROP_NAME_ATTR_"; break;
4162e5dd7070Spatrick }
4163e5dd7070Spatrick
4164e5dd7070Spatrick bool NonFragile = ForceNonFragileABI || isNonFragileABI();
4165e5dd7070Spatrick
4166e5dd7070Spatrick StringRef Section;
4167e5dd7070Spatrick switch (Type) {
4168e5dd7070Spatrick case ObjCLabelType::ClassName:
4169e5dd7070Spatrick Section = NonFragile ? "__TEXT,__objc_classname,cstring_literals"
4170e5dd7070Spatrick : "__TEXT,__cstring,cstring_literals";
4171e5dd7070Spatrick break;
4172e5dd7070Spatrick case ObjCLabelType::MethodVarName:
4173e5dd7070Spatrick Section = NonFragile ? "__TEXT,__objc_methname,cstring_literals"
4174e5dd7070Spatrick : "__TEXT,__cstring,cstring_literals";
4175e5dd7070Spatrick break;
4176e5dd7070Spatrick case ObjCLabelType::MethodVarType:
4177e5dd7070Spatrick Section = NonFragile ? "__TEXT,__objc_methtype,cstring_literals"
4178e5dd7070Spatrick : "__TEXT,__cstring,cstring_literals";
4179e5dd7070Spatrick break;
4180e5dd7070Spatrick case ObjCLabelType::PropertyName:
4181ec727ea7Spatrick Section = NonFragile ? "__TEXT,__objc_methname,cstring_literals"
4182ec727ea7Spatrick : "__TEXT,__cstring,cstring_literals";
4183e5dd7070Spatrick break;
4184e5dd7070Spatrick }
4185e5dd7070Spatrick
4186e5dd7070Spatrick llvm::Constant *Value =
4187e5dd7070Spatrick llvm::ConstantDataArray::getString(VMContext, Name, NullTerminate);
4188e5dd7070Spatrick llvm::GlobalVariable *GV =
4189e5dd7070Spatrick new llvm::GlobalVariable(CGM.getModule(), Value->getType(),
4190e5dd7070Spatrick /*isConstant=*/true,
4191e5dd7070Spatrick llvm::GlobalValue::PrivateLinkage, Value, Label);
4192e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO())
4193e5dd7070Spatrick GV->setSection(Section);
4194e5dd7070Spatrick GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
4195e5dd7070Spatrick GV->setAlignment(CharUnits::One().getAsAlign());
4196e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
4197e5dd7070Spatrick
4198e5dd7070Spatrick return GV;
4199e5dd7070Spatrick }
4200e5dd7070Spatrick
ModuleInitFunction()4201e5dd7070Spatrick llvm::Function *CGObjCMac::ModuleInitFunction() {
4202e5dd7070Spatrick // Abuse this interface function as a place to finalize.
4203e5dd7070Spatrick FinishModule();
4204e5dd7070Spatrick return nullptr;
4205e5dd7070Spatrick }
4206e5dd7070Spatrick
GetPropertyGetFunction()4207e5dd7070Spatrick llvm::FunctionCallee CGObjCMac::GetPropertyGetFunction() {
4208e5dd7070Spatrick return ObjCTypes.getGetPropertyFn();
4209e5dd7070Spatrick }
4210e5dd7070Spatrick
GetPropertySetFunction()4211e5dd7070Spatrick llvm::FunctionCallee CGObjCMac::GetPropertySetFunction() {
4212e5dd7070Spatrick return ObjCTypes.getSetPropertyFn();
4213e5dd7070Spatrick }
4214e5dd7070Spatrick
GetOptimizedPropertySetFunction(bool atomic,bool copy)4215e5dd7070Spatrick llvm::FunctionCallee CGObjCMac::GetOptimizedPropertySetFunction(bool atomic,
4216e5dd7070Spatrick bool copy) {
4217e5dd7070Spatrick return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
4218e5dd7070Spatrick }
4219e5dd7070Spatrick
GetGetStructFunction()4220e5dd7070Spatrick llvm::FunctionCallee CGObjCMac::GetGetStructFunction() {
4221e5dd7070Spatrick return ObjCTypes.getCopyStructFn();
4222e5dd7070Spatrick }
4223e5dd7070Spatrick
GetSetStructFunction()4224e5dd7070Spatrick llvm::FunctionCallee CGObjCMac::GetSetStructFunction() {
4225e5dd7070Spatrick return ObjCTypes.getCopyStructFn();
4226e5dd7070Spatrick }
4227e5dd7070Spatrick
GetCppAtomicObjectGetFunction()4228e5dd7070Spatrick llvm::FunctionCallee CGObjCMac::GetCppAtomicObjectGetFunction() {
4229e5dd7070Spatrick return ObjCTypes.getCppAtomicObjectFunction();
4230e5dd7070Spatrick }
4231e5dd7070Spatrick
GetCppAtomicObjectSetFunction()4232e5dd7070Spatrick llvm::FunctionCallee CGObjCMac::GetCppAtomicObjectSetFunction() {
4233e5dd7070Spatrick return ObjCTypes.getCppAtomicObjectFunction();
4234e5dd7070Spatrick }
4235e5dd7070Spatrick
EnumerationMutationFunction()4236e5dd7070Spatrick llvm::FunctionCallee CGObjCMac::EnumerationMutationFunction() {
4237e5dd7070Spatrick return ObjCTypes.getEnumerationMutationFn();
4238e5dd7070Spatrick }
4239e5dd7070Spatrick
EmitTryStmt(CodeGenFunction & CGF,const ObjCAtTryStmt & S)4240e5dd7070Spatrick void CGObjCMac::EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S) {
4241e5dd7070Spatrick return EmitTryOrSynchronizedStmt(CGF, S);
4242e5dd7070Spatrick }
4243e5dd7070Spatrick
EmitSynchronizedStmt(CodeGenFunction & CGF,const ObjCAtSynchronizedStmt & S)4244e5dd7070Spatrick void CGObjCMac::EmitSynchronizedStmt(CodeGenFunction &CGF,
4245e5dd7070Spatrick const ObjCAtSynchronizedStmt &S) {
4246e5dd7070Spatrick return EmitTryOrSynchronizedStmt(CGF, S);
4247e5dd7070Spatrick }
4248e5dd7070Spatrick
4249e5dd7070Spatrick namespace {
4250e5dd7070Spatrick struct PerformFragileFinally final : EHScopeStack::Cleanup {
4251e5dd7070Spatrick const Stmt &S;
4252e5dd7070Spatrick Address SyncArgSlot;
4253e5dd7070Spatrick Address CallTryExitVar;
4254e5dd7070Spatrick Address ExceptionData;
4255e5dd7070Spatrick ObjCTypesHelper &ObjCTypes;
PerformFragileFinally__anon288f636e0811::PerformFragileFinally4256e5dd7070Spatrick PerformFragileFinally(const Stmt *S,
4257e5dd7070Spatrick Address SyncArgSlot,
4258e5dd7070Spatrick Address CallTryExitVar,
4259e5dd7070Spatrick Address ExceptionData,
4260e5dd7070Spatrick ObjCTypesHelper *ObjCTypes)
4261e5dd7070Spatrick : S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar),
4262e5dd7070Spatrick ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {}
4263e5dd7070Spatrick
Emit__anon288f636e0811::PerformFragileFinally4264e5dd7070Spatrick void Emit(CodeGenFunction &CGF, Flags flags) override {
4265e5dd7070Spatrick // Check whether we need to call objc_exception_try_exit.
4266e5dd7070Spatrick // In optimized code, this branch will always be folded.
4267e5dd7070Spatrick llvm::BasicBlock *FinallyCallExit =
4268e5dd7070Spatrick CGF.createBasicBlock("finally.call_exit");
4269e5dd7070Spatrick llvm::BasicBlock *FinallyNoCallExit =
4270e5dd7070Spatrick CGF.createBasicBlock("finally.no_call_exit");
4271e5dd7070Spatrick CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CallTryExitVar),
4272e5dd7070Spatrick FinallyCallExit, FinallyNoCallExit);
4273e5dd7070Spatrick
4274e5dd7070Spatrick CGF.EmitBlock(FinallyCallExit);
4275e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(),
4276e5dd7070Spatrick ExceptionData.getPointer());
4277e5dd7070Spatrick
4278e5dd7070Spatrick CGF.EmitBlock(FinallyNoCallExit);
4279e5dd7070Spatrick
4280e5dd7070Spatrick if (isa<ObjCAtTryStmt>(S)) {
4281e5dd7070Spatrick if (const ObjCAtFinallyStmt* FinallyStmt =
4282e5dd7070Spatrick cast<ObjCAtTryStmt>(S).getFinallyStmt()) {
4283e5dd7070Spatrick // Don't try to do the @finally if this is an EH cleanup.
4284e5dd7070Spatrick if (flags.isForEHCleanup()) return;
4285e5dd7070Spatrick
4286e5dd7070Spatrick // Save the current cleanup destination in case there's
4287e5dd7070Spatrick // control flow inside the finally statement.
4288e5dd7070Spatrick llvm::Value *CurCleanupDest =
4289e5dd7070Spatrick CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot());
4290e5dd7070Spatrick
4291e5dd7070Spatrick CGF.EmitStmt(FinallyStmt->getFinallyBody());
4292e5dd7070Spatrick
4293e5dd7070Spatrick if (CGF.HaveInsertPoint()) {
4294e5dd7070Spatrick CGF.Builder.CreateStore(CurCleanupDest,
4295e5dd7070Spatrick CGF.getNormalCleanupDestSlot());
4296e5dd7070Spatrick } else {
4297e5dd7070Spatrick // Currently, the end of the cleanup must always exist.
4298e5dd7070Spatrick CGF.EnsureInsertPoint();
4299e5dd7070Spatrick }
4300e5dd7070Spatrick }
4301e5dd7070Spatrick } else {
4302e5dd7070Spatrick // Emit objc_sync_exit(expr); as finally's sole statement for
4303e5dd7070Spatrick // @synchronized.
4304e5dd7070Spatrick llvm::Value *SyncArg = CGF.Builder.CreateLoad(SyncArgSlot);
4305e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncExitFn(), SyncArg);
4306e5dd7070Spatrick }
4307e5dd7070Spatrick }
4308e5dd7070Spatrick };
4309e5dd7070Spatrick
4310e5dd7070Spatrick class FragileHazards {
4311e5dd7070Spatrick CodeGenFunction &CGF;
4312e5dd7070Spatrick SmallVector<llvm::Value*, 20> Locals;
4313e5dd7070Spatrick llvm::DenseSet<llvm::BasicBlock*> BlocksBeforeTry;
4314e5dd7070Spatrick
4315e5dd7070Spatrick llvm::InlineAsm *ReadHazard;
4316e5dd7070Spatrick llvm::InlineAsm *WriteHazard;
4317e5dd7070Spatrick
4318e5dd7070Spatrick llvm::FunctionType *GetAsmFnType();
4319e5dd7070Spatrick
4320e5dd7070Spatrick void collectLocals();
4321e5dd7070Spatrick void emitReadHazard(CGBuilderTy &Builder);
4322e5dd7070Spatrick
4323e5dd7070Spatrick public:
4324e5dd7070Spatrick FragileHazards(CodeGenFunction &CGF);
4325e5dd7070Spatrick
4326e5dd7070Spatrick void emitWriteHazard();
4327e5dd7070Spatrick void emitHazardsInNewBlocks();
4328e5dd7070Spatrick };
4329e5dd7070Spatrick } // end anonymous namespace
4330e5dd7070Spatrick
4331e5dd7070Spatrick /// Create the fragile-ABI read and write hazards based on the current
4332e5dd7070Spatrick /// state of the function, which is presumed to be immediately prior
4333e5dd7070Spatrick /// to a @try block. These hazards are used to maintain correct
4334e5dd7070Spatrick /// semantics in the face of optimization and the fragile ABI's
4335e5dd7070Spatrick /// cavalier use of setjmp/longjmp.
FragileHazards(CodeGenFunction & CGF)4336e5dd7070Spatrick FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
4337e5dd7070Spatrick collectLocals();
4338e5dd7070Spatrick
4339e5dd7070Spatrick if (Locals.empty()) return;
4340e5dd7070Spatrick
4341e5dd7070Spatrick // Collect all the blocks in the function.
4342e5dd7070Spatrick for (llvm::Function::iterator
4343e5dd7070Spatrick I = CGF.CurFn->begin(), E = CGF.CurFn->end(); I != E; ++I)
4344e5dd7070Spatrick BlocksBeforeTry.insert(&*I);
4345e5dd7070Spatrick
4346e5dd7070Spatrick llvm::FunctionType *AsmFnTy = GetAsmFnType();
4347e5dd7070Spatrick
4348e5dd7070Spatrick // Create a read hazard for the allocas. This inhibits dead-store
4349e5dd7070Spatrick // optimizations and forces the values to memory. This hazard is
4350e5dd7070Spatrick // inserted before any 'throwing' calls in the protected scope to
4351e5dd7070Spatrick // reflect the possibility that the variables might be read from the
4352e5dd7070Spatrick // catch block if the call throws.
4353e5dd7070Spatrick {
4354e5dd7070Spatrick std::string Constraint;
4355e5dd7070Spatrick for (unsigned I = 0, E = Locals.size(); I != E; ++I) {
4356e5dd7070Spatrick if (I) Constraint += ',';
4357e5dd7070Spatrick Constraint += "*m";
4358e5dd7070Spatrick }
4359e5dd7070Spatrick
4360e5dd7070Spatrick ReadHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false);
4361e5dd7070Spatrick }
4362e5dd7070Spatrick
4363e5dd7070Spatrick // Create a write hazard for the allocas. This inhibits folding
4364e5dd7070Spatrick // loads across the hazard. This hazard is inserted at the
4365e5dd7070Spatrick // beginning of the catch path to reflect the possibility that the
4366e5dd7070Spatrick // variables might have been written within the protected scope.
4367e5dd7070Spatrick {
4368e5dd7070Spatrick std::string Constraint;
4369e5dd7070Spatrick for (unsigned I = 0, E = Locals.size(); I != E; ++I) {
4370e5dd7070Spatrick if (I) Constraint += ',';
4371e5dd7070Spatrick Constraint += "=*m";
4372e5dd7070Spatrick }
4373e5dd7070Spatrick
4374e5dd7070Spatrick WriteHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false);
4375e5dd7070Spatrick }
4376e5dd7070Spatrick }
4377e5dd7070Spatrick
4378e5dd7070Spatrick /// Emit a write hazard at the current location.
emitWriteHazard()4379e5dd7070Spatrick void FragileHazards::emitWriteHazard() {
4380e5dd7070Spatrick if (Locals.empty()) return;
4381e5dd7070Spatrick
4382*12c85518Srobert llvm::CallInst *Call = CGF.EmitNounwindRuntimeCall(WriteHazard, Locals);
4383*12c85518Srobert for (auto Pair : llvm::enumerate(Locals))
4384*12c85518Srobert Call->addParamAttr(Pair.index(), llvm::Attribute::get(
4385*12c85518Srobert CGF.getLLVMContext(), llvm::Attribute::ElementType,
4386*12c85518Srobert cast<llvm::AllocaInst>(Pair.value())->getAllocatedType()));
4387e5dd7070Spatrick }
4388e5dd7070Spatrick
emitReadHazard(CGBuilderTy & Builder)4389e5dd7070Spatrick void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
4390e5dd7070Spatrick assert(!Locals.empty());
4391e5dd7070Spatrick llvm::CallInst *call = Builder.CreateCall(ReadHazard, Locals);
4392e5dd7070Spatrick call->setDoesNotThrow();
4393e5dd7070Spatrick call->setCallingConv(CGF.getRuntimeCC());
4394*12c85518Srobert for (auto Pair : llvm::enumerate(Locals))
4395*12c85518Srobert call->addParamAttr(Pair.index(), llvm::Attribute::get(
4396*12c85518Srobert Builder.getContext(), llvm::Attribute::ElementType,
4397*12c85518Srobert cast<llvm::AllocaInst>(Pair.value())->getAllocatedType()));
4398e5dd7070Spatrick }
4399e5dd7070Spatrick
4400e5dd7070Spatrick /// Emit read hazards in all the protected blocks, i.e. all the blocks
4401e5dd7070Spatrick /// which have been inserted since the beginning of the try.
emitHazardsInNewBlocks()4402e5dd7070Spatrick void FragileHazards::emitHazardsInNewBlocks() {
4403e5dd7070Spatrick if (Locals.empty()) return;
4404e5dd7070Spatrick
4405e5dd7070Spatrick CGBuilderTy Builder(CGF, CGF.getLLVMContext());
4406e5dd7070Spatrick
4407e5dd7070Spatrick // Iterate through all blocks, skipping those prior to the try.
4408e5dd7070Spatrick for (llvm::Function::iterator
4409e5dd7070Spatrick FI = CGF.CurFn->begin(), FE = CGF.CurFn->end(); FI != FE; ++FI) {
4410e5dd7070Spatrick llvm::BasicBlock &BB = *FI;
4411e5dd7070Spatrick if (BlocksBeforeTry.count(&BB)) continue;
4412e5dd7070Spatrick
4413e5dd7070Spatrick // Walk through all the calls in the block.
4414e5dd7070Spatrick for (llvm::BasicBlock::iterator
4415e5dd7070Spatrick BI = BB.begin(), BE = BB.end(); BI != BE; ++BI) {
4416e5dd7070Spatrick llvm::Instruction &I = *BI;
4417e5dd7070Spatrick
4418e5dd7070Spatrick // Ignore instructions that aren't non-intrinsic calls.
4419e5dd7070Spatrick // These are the only calls that can possibly call longjmp.
4420e5dd7070Spatrick if (!isa<llvm::CallInst>(I) && !isa<llvm::InvokeInst>(I))
4421e5dd7070Spatrick continue;
4422e5dd7070Spatrick if (isa<llvm::IntrinsicInst>(I))
4423e5dd7070Spatrick continue;
4424e5dd7070Spatrick
4425e5dd7070Spatrick // Ignore call sites marked nounwind. This may be questionable,
4426e5dd7070Spatrick // since 'nounwind' doesn't necessarily mean 'does not call longjmp'.
4427e5dd7070Spatrick if (cast<llvm::CallBase>(I).doesNotThrow())
4428e5dd7070Spatrick continue;
4429e5dd7070Spatrick
4430e5dd7070Spatrick // Insert a read hazard before the call. This will ensure that
4431e5dd7070Spatrick // any writes to the locals are performed before making the
4432e5dd7070Spatrick // call. If the call throws, then this is sufficient to
4433e5dd7070Spatrick // guarantee correctness as long as it doesn't also write to any
4434e5dd7070Spatrick // locals.
4435e5dd7070Spatrick Builder.SetInsertPoint(&BB, BI);
4436e5dd7070Spatrick emitReadHazard(Builder);
4437e5dd7070Spatrick }
4438e5dd7070Spatrick }
4439e5dd7070Spatrick }
4440e5dd7070Spatrick
addIfPresent(llvm::DenseSet<llvm::Value * > & S,Address V)4441e5dd7070Spatrick static void addIfPresent(llvm::DenseSet<llvm::Value*> &S, Address V) {
4442e5dd7070Spatrick if (V.isValid()) S.insert(V.getPointer());
4443e5dd7070Spatrick }
4444e5dd7070Spatrick
collectLocals()4445e5dd7070Spatrick void FragileHazards::collectLocals() {
4446e5dd7070Spatrick // Compute a set of allocas to ignore.
4447e5dd7070Spatrick llvm::DenseSet<llvm::Value*> AllocasToIgnore;
4448e5dd7070Spatrick addIfPresent(AllocasToIgnore, CGF.ReturnValue);
4449e5dd7070Spatrick addIfPresent(AllocasToIgnore, CGF.NormalCleanupDest);
4450e5dd7070Spatrick
4451e5dd7070Spatrick // Collect all the allocas currently in the function. This is
4452e5dd7070Spatrick // probably way too aggressive.
4453e5dd7070Spatrick llvm::BasicBlock &Entry = CGF.CurFn->getEntryBlock();
4454e5dd7070Spatrick for (llvm::BasicBlock::iterator
4455e5dd7070Spatrick I = Entry.begin(), E = Entry.end(); I != E; ++I)
4456e5dd7070Spatrick if (isa<llvm::AllocaInst>(*I) && !AllocasToIgnore.count(&*I))
4457e5dd7070Spatrick Locals.push_back(&*I);
4458e5dd7070Spatrick }
4459e5dd7070Spatrick
GetAsmFnType()4460e5dd7070Spatrick llvm::FunctionType *FragileHazards::GetAsmFnType() {
4461e5dd7070Spatrick SmallVector<llvm::Type *, 16> tys(Locals.size());
4462e5dd7070Spatrick for (unsigned i = 0, e = Locals.size(); i != e; ++i)
4463e5dd7070Spatrick tys[i] = Locals[i]->getType();
4464e5dd7070Spatrick return llvm::FunctionType::get(CGF.VoidTy, tys, false);
4465e5dd7070Spatrick }
4466e5dd7070Spatrick
4467e5dd7070Spatrick /*
4468e5dd7070Spatrick
4469e5dd7070Spatrick Objective-C setjmp-longjmp (sjlj) Exception Handling
4470e5dd7070Spatrick --
4471e5dd7070Spatrick
4472e5dd7070Spatrick A catch buffer is a setjmp buffer plus:
4473e5dd7070Spatrick - a pointer to the exception that was caught
4474e5dd7070Spatrick - a pointer to the previous exception data buffer
4475e5dd7070Spatrick - two pointers of reserved storage
4476e5dd7070Spatrick Therefore catch buffers form a stack, with a pointer to the top
4477e5dd7070Spatrick of the stack kept in thread-local storage.
4478e5dd7070Spatrick
4479e5dd7070Spatrick objc_exception_try_enter pushes a catch buffer onto the EH stack.
4480e5dd7070Spatrick objc_exception_try_exit pops the given catch buffer, which is
4481e5dd7070Spatrick required to be the top of the EH stack.
4482e5dd7070Spatrick objc_exception_throw pops the top of the EH stack, writes the
4483e5dd7070Spatrick thrown exception into the appropriate field, and longjmps
4484e5dd7070Spatrick to the setjmp buffer. It crashes the process (with a printf
4485e5dd7070Spatrick and an abort()) if there are no catch buffers on the stack.
4486e5dd7070Spatrick objc_exception_extract just reads the exception pointer out of the
4487e5dd7070Spatrick catch buffer.
4488e5dd7070Spatrick
4489e5dd7070Spatrick There's no reason an implementation couldn't use a light-weight
4490e5dd7070Spatrick setjmp here --- something like __builtin_setjmp, but API-compatible
4491e5dd7070Spatrick with the heavyweight setjmp. This will be more important if we ever
4492e5dd7070Spatrick want to implement correct ObjC/C++ exception interactions for the
4493e5dd7070Spatrick fragile ABI.
4494e5dd7070Spatrick
4495e5dd7070Spatrick Note that for this use of setjmp/longjmp to be correct, we may need
4496e5dd7070Spatrick to mark some local variables volatile: if a non-volatile local
4497e5dd7070Spatrick variable is modified between the setjmp and the longjmp, it has
4498e5dd7070Spatrick indeterminate value. For the purposes of LLVM IR, it may be
4499e5dd7070Spatrick sufficient to make loads and stores within the @try (to variables
4500e5dd7070Spatrick declared outside the @try) volatile. This is necessary for
4501e5dd7070Spatrick optimized correctness, but is not currently being done; this is
4502e5dd7070Spatrick being tracked as rdar://problem/8160285
4503e5dd7070Spatrick
4504e5dd7070Spatrick The basic framework for a @try-catch-finally is as follows:
4505e5dd7070Spatrick {
4506e5dd7070Spatrick objc_exception_data d;
4507e5dd7070Spatrick id _rethrow = null;
4508e5dd7070Spatrick bool _call_try_exit = true;
4509e5dd7070Spatrick
4510e5dd7070Spatrick objc_exception_try_enter(&d);
4511e5dd7070Spatrick if (!setjmp(d.jmp_buf)) {
4512e5dd7070Spatrick ... try body ...
4513e5dd7070Spatrick } else {
4514e5dd7070Spatrick // exception path
4515e5dd7070Spatrick id _caught = objc_exception_extract(&d);
4516e5dd7070Spatrick
4517e5dd7070Spatrick // enter new try scope for handlers
4518e5dd7070Spatrick if (!setjmp(d.jmp_buf)) {
4519e5dd7070Spatrick ... match exception and execute catch blocks ...
4520e5dd7070Spatrick
4521e5dd7070Spatrick // fell off end, rethrow.
4522e5dd7070Spatrick _rethrow = _caught;
4523e5dd7070Spatrick ... jump-through-finally to finally_rethrow ...
4524e5dd7070Spatrick } else {
4525e5dd7070Spatrick // exception in catch block
4526e5dd7070Spatrick _rethrow = objc_exception_extract(&d);
4527e5dd7070Spatrick _call_try_exit = false;
4528e5dd7070Spatrick ... jump-through-finally to finally_rethrow ...
4529e5dd7070Spatrick }
4530e5dd7070Spatrick }
4531e5dd7070Spatrick ... jump-through-finally to finally_end ...
4532e5dd7070Spatrick
4533e5dd7070Spatrick finally:
4534e5dd7070Spatrick if (_call_try_exit)
4535e5dd7070Spatrick objc_exception_try_exit(&d);
4536e5dd7070Spatrick
4537e5dd7070Spatrick ... finally block ....
4538e5dd7070Spatrick ... dispatch to finally destination ...
4539e5dd7070Spatrick
4540e5dd7070Spatrick finally_rethrow:
4541e5dd7070Spatrick objc_exception_throw(_rethrow);
4542e5dd7070Spatrick
4543e5dd7070Spatrick finally_end:
4544e5dd7070Spatrick }
4545e5dd7070Spatrick
4546e5dd7070Spatrick This framework differs slightly from the one gcc uses, in that gcc
4547e5dd7070Spatrick uses _rethrow to determine if objc_exception_try_exit should be called
4548e5dd7070Spatrick and if the object should be rethrown. This breaks in the face of
4549e5dd7070Spatrick throwing nil and introduces unnecessary branches.
4550e5dd7070Spatrick
4551e5dd7070Spatrick We specialize this framework for a few particular circumstances:
4552e5dd7070Spatrick
4553e5dd7070Spatrick - If there are no catch blocks, then we avoid emitting the second
4554e5dd7070Spatrick exception handling context.
4555e5dd7070Spatrick
4556e5dd7070Spatrick - If there is a catch-all catch block (i.e. @catch(...) or @catch(id
4557e5dd7070Spatrick e)) we avoid emitting the code to rethrow an uncaught exception.
4558e5dd7070Spatrick
4559e5dd7070Spatrick - FIXME: If there is no @finally block we can do a few more
4560e5dd7070Spatrick simplifications.
4561e5dd7070Spatrick
4562e5dd7070Spatrick Rethrows and Jumps-Through-Finally
4563e5dd7070Spatrick --
4564e5dd7070Spatrick
4565e5dd7070Spatrick '@throw;' is supported by pushing the currently-caught exception
4566e5dd7070Spatrick onto ObjCEHStack while the @catch blocks are emitted.
4567e5dd7070Spatrick
4568e5dd7070Spatrick Branches through the @finally block are handled with an ordinary
4569e5dd7070Spatrick normal cleanup. We do not register an EH cleanup; fragile-ABI ObjC
4570e5dd7070Spatrick exceptions are not compatible with C++ exceptions, and this is
4571e5dd7070Spatrick hardly the only place where this will go wrong.
4572e5dd7070Spatrick
4573e5dd7070Spatrick @synchronized(expr) { stmt; } is emitted as if it were:
4574e5dd7070Spatrick id synch_value = expr;
4575e5dd7070Spatrick objc_sync_enter(synch_value);
4576e5dd7070Spatrick @try { stmt; } @finally { objc_sync_exit(synch_value); }
4577e5dd7070Spatrick */
4578e5dd7070Spatrick
EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction & CGF,const Stmt & S)4579e5dd7070Spatrick void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
4580e5dd7070Spatrick const Stmt &S) {
4581e5dd7070Spatrick bool isTry = isa<ObjCAtTryStmt>(S);
4582e5dd7070Spatrick
4583e5dd7070Spatrick // A destination for the fall-through edges of the catch handlers to
4584e5dd7070Spatrick // jump to.
4585e5dd7070Spatrick CodeGenFunction::JumpDest FinallyEnd =
4586e5dd7070Spatrick CGF.getJumpDestInCurrentScope("finally.end");
4587e5dd7070Spatrick
4588e5dd7070Spatrick // A destination for the rethrow edge of the catch handlers to jump
4589e5dd7070Spatrick // to.
4590e5dd7070Spatrick CodeGenFunction::JumpDest FinallyRethrow =
4591e5dd7070Spatrick CGF.getJumpDestInCurrentScope("finally.rethrow");
4592e5dd7070Spatrick
4593e5dd7070Spatrick // For @synchronized, call objc_sync_enter(sync.expr). The
4594e5dd7070Spatrick // evaluation of the expression must occur before we enter the
4595e5dd7070Spatrick // @synchronized. We can't avoid a temp here because we need the
4596e5dd7070Spatrick // value to be preserved. If the backend ever does liveness
4597e5dd7070Spatrick // correctly after setjmp, this will be unnecessary.
4598e5dd7070Spatrick Address SyncArgSlot = Address::invalid();
4599e5dd7070Spatrick if (!isTry) {
4600e5dd7070Spatrick llvm::Value *SyncArg =
4601e5dd7070Spatrick CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
4602e5dd7070Spatrick SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
4603e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncEnterFn(), SyncArg);
4604e5dd7070Spatrick
4605e5dd7070Spatrick SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(),
4606e5dd7070Spatrick CGF.getPointerAlign(), "sync.arg");
4607e5dd7070Spatrick CGF.Builder.CreateStore(SyncArg, SyncArgSlot);
4608e5dd7070Spatrick }
4609e5dd7070Spatrick
4610e5dd7070Spatrick // Allocate memory for the setjmp buffer. This needs to be kept
4611e5dd7070Spatrick // live throughout the try and catch blocks.
4612e5dd7070Spatrick Address ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
4613e5dd7070Spatrick CGF.getPointerAlign(),
4614e5dd7070Spatrick "exceptiondata.ptr");
4615e5dd7070Spatrick
4616e5dd7070Spatrick // Create the fragile hazards. Note that this will not capture any
4617e5dd7070Spatrick // of the allocas required for exception processing, but will
4618e5dd7070Spatrick // capture the current basic block (which extends all the way to the
4619e5dd7070Spatrick // setjmp call) as "before the @try".
4620e5dd7070Spatrick FragileHazards Hazards(CGF);
4621e5dd7070Spatrick
4622e5dd7070Spatrick // Create a flag indicating whether the cleanup needs to call
4623e5dd7070Spatrick // objc_exception_try_exit. This is true except when
4624e5dd7070Spatrick // - no catches match and we're branching through the cleanup
4625e5dd7070Spatrick // just to rethrow the exception, or
4626e5dd7070Spatrick // - a catch matched and we're falling out of the catch handler.
4627e5dd7070Spatrick // The setjmp-safety rule here is that we should always store to this
4628e5dd7070Spatrick // variable in a place that dominates the branch through the cleanup
4629e5dd7070Spatrick // without passing through any setjmps.
4630e5dd7070Spatrick Address CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(),
4631e5dd7070Spatrick CharUnits::One(),
4632e5dd7070Spatrick "_call_try_exit");
4633e5dd7070Spatrick
4634e5dd7070Spatrick // A slot containing the exception to rethrow. Only needed when we
4635e5dd7070Spatrick // have both a @catch and a @finally.
4636e5dd7070Spatrick Address PropagatingExnVar = Address::invalid();
4637e5dd7070Spatrick
4638e5dd7070Spatrick // Push a normal cleanup to leave the try scope.
4639e5dd7070Spatrick CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S,
4640e5dd7070Spatrick SyncArgSlot,
4641e5dd7070Spatrick CallTryExitVar,
4642e5dd7070Spatrick ExceptionData,
4643e5dd7070Spatrick &ObjCTypes);
4644e5dd7070Spatrick
4645e5dd7070Spatrick // Enter a try block:
4646e5dd7070Spatrick // - Call objc_exception_try_enter to push ExceptionData on top of
4647e5dd7070Spatrick // the EH stack.
4648e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
4649e5dd7070Spatrick ExceptionData.getPointer());
4650e5dd7070Spatrick
4651e5dd7070Spatrick // - Call setjmp on the exception data buffer.
4652e5dd7070Spatrick llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
4653e5dd7070Spatrick llvm::Value *GEPIndexes[] = { Zero, Zero, Zero };
4654e5dd7070Spatrick llvm::Value *SetJmpBuffer = CGF.Builder.CreateGEP(
4655e5dd7070Spatrick ObjCTypes.ExceptionDataTy, ExceptionData.getPointer(), GEPIndexes,
4656e5dd7070Spatrick "setjmp_buffer");
4657e5dd7070Spatrick llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall(
4658e5dd7070Spatrick ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
4659e5dd7070Spatrick SetJmpResult->setCanReturnTwice();
4660e5dd7070Spatrick
4661e5dd7070Spatrick // If setjmp returned 0, enter the protected block; otherwise,
4662e5dd7070Spatrick // branch to the handler.
4663e5dd7070Spatrick llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
4664e5dd7070Spatrick llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
4665e5dd7070Spatrick llvm::Value *DidCatch =
4666e5dd7070Spatrick CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
4667e5dd7070Spatrick CGF.Builder.CreateCondBr(DidCatch, TryHandler, TryBlock);
4668e5dd7070Spatrick
4669e5dd7070Spatrick // Emit the protected block.
4670e5dd7070Spatrick CGF.EmitBlock(TryBlock);
4671e5dd7070Spatrick CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar);
4672e5dd7070Spatrick CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
4673e5dd7070Spatrick : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
4674e5dd7070Spatrick
4675e5dd7070Spatrick CGBuilderTy::InsertPoint TryFallthroughIP = CGF.Builder.saveAndClearIP();
4676e5dd7070Spatrick
4677e5dd7070Spatrick // Emit the exception handler block.
4678e5dd7070Spatrick CGF.EmitBlock(TryHandler);
4679e5dd7070Spatrick
4680e5dd7070Spatrick // Don't optimize loads of the in-scope locals across this point.
4681e5dd7070Spatrick Hazards.emitWriteHazard();
4682e5dd7070Spatrick
4683e5dd7070Spatrick // For a @synchronized (or a @try with no catches), just branch
4684e5dd7070Spatrick // through the cleanup to the rethrow block.
4685e5dd7070Spatrick if (!isTry || !cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
4686e5dd7070Spatrick // Tell the cleanup not to re-pop the exit.
4687e5dd7070Spatrick CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
4688e5dd7070Spatrick CGF.EmitBranchThroughCleanup(FinallyRethrow);
4689e5dd7070Spatrick
4690e5dd7070Spatrick // Otherwise, we have to match against the caught exceptions.
4691e5dd7070Spatrick } else {
4692e5dd7070Spatrick // Retrieve the exception object. We may emit multiple blocks but
4693e5dd7070Spatrick // nothing can cross this so the value is already in SSA form.
4694e5dd7070Spatrick llvm::CallInst *Caught =
4695e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
4696e5dd7070Spatrick ExceptionData.getPointer(), "caught");
4697e5dd7070Spatrick
4698e5dd7070Spatrick // Push the exception to rethrow onto the EH value stack for the
4699e5dd7070Spatrick // benefit of any @throws in the handlers.
4700e5dd7070Spatrick CGF.ObjCEHValueStack.push_back(Caught);
4701e5dd7070Spatrick
4702e5dd7070Spatrick const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S);
4703e5dd7070Spatrick
4704e5dd7070Spatrick bool HasFinally = (AtTryStmt->getFinallyStmt() != nullptr);
4705e5dd7070Spatrick
4706e5dd7070Spatrick llvm::BasicBlock *CatchBlock = nullptr;
4707e5dd7070Spatrick llvm::BasicBlock *CatchHandler = nullptr;
4708e5dd7070Spatrick if (HasFinally) {
4709e5dd7070Spatrick // Save the currently-propagating exception before
4710e5dd7070Spatrick // objc_exception_try_enter clears the exception slot.
4711e5dd7070Spatrick PropagatingExnVar = CGF.CreateTempAlloca(Caught->getType(),
4712e5dd7070Spatrick CGF.getPointerAlign(),
4713e5dd7070Spatrick "propagating_exception");
4714e5dd7070Spatrick CGF.Builder.CreateStore(Caught, PropagatingExnVar);
4715e5dd7070Spatrick
4716e5dd7070Spatrick // Enter a new exception try block (in case a @catch block
4717e5dd7070Spatrick // throws an exception).
4718e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
4719e5dd7070Spatrick ExceptionData.getPointer());
4720e5dd7070Spatrick
4721e5dd7070Spatrick llvm::CallInst *SetJmpResult =
4722e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(),
4723e5dd7070Spatrick SetJmpBuffer, "setjmp.result");
4724e5dd7070Spatrick SetJmpResult->setCanReturnTwice();
4725e5dd7070Spatrick
4726e5dd7070Spatrick llvm::Value *Threw =
4727e5dd7070Spatrick CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
4728e5dd7070Spatrick
4729e5dd7070Spatrick CatchBlock = CGF.createBasicBlock("catch");
4730e5dd7070Spatrick CatchHandler = CGF.createBasicBlock("catch_for_catch");
4731e5dd7070Spatrick CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock);
4732e5dd7070Spatrick
4733e5dd7070Spatrick CGF.EmitBlock(CatchBlock);
4734e5dd7070Spatrick }
4735e5dd7070Spatrick
4736e5dd7070Spatrick CGF.Builder.CreateStore(CGF.Builder.getInt1(HasFinally), CallTryExitVar);
4737e5dd7070Spatrick
4738e5dd7070Spatrick // Handle catch list. As a special case we check if everything is
4739e5dd7070Spatrick // matched and avoid generating code for falling off the end if
4740e5dd7070Spatrick // so.
4741e5dd7070Spatrick bool AllMatched = false;
4742*12c85518Srobert for (const ObjCAtCatchStmt *CatchStmt : AtTryStmt->catch_stmts()) {
4743e5dd7070Spatrick const VarDecl *CatchParam = CatchStmt->getCatchParamDecl();
4744e5dd7070Spatrick const ObjCObjectPointerType *OPT = nullptr;
4745e5dd7070Spatrick
4746e5dd7070Spatrick // catch(...) always matches.
4747e5dd7070Spatrick if (!CatchParam) {
4748e5dd7070Spatrick AllMatched = true;
4749e5dd7070Spatrick } else {
4750e5dd7070Spatrick OPT = CatchParam->getType()->getAs<ObjCObjectPointerType>();
4751e5dd7070Spatrick
4752e5dd7070Spatrick // catch(id e) always matches under this ABI, since only
4753e5dd7070Spatrick // ObjC exceptions end up here in the first place.
4754e5dd7070Spatrick // FIXME: For the time being we also match id<X>; this should
4755e5dd7070Spatrick // be rejected by Sema instead.
4756e5dd7070Spatrick if (OPT && (OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()))
4757e5dd7070Spatrick AllMatched = true;
4758e5dd7070Spatrick }
4759e5dd7070Spatrick
4760e5dd7070Spatrick // If this is a catch-all, we don't need to test anything.
4761e5dd7070Spatrick if (AllMatched) {
4762e5dd7070Spatrick CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF);
4763e5dd7070Spatrick
4764e5dd7070Spatrick if (CatchParam) {
4765e5dd7070Spatrick CGF.EmitAutoVarDecl(*CatchParam);
4766e5dd7070Spatrick assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
4767e5dd7070Spatrick
4768e5dd7070Spatrick // These types work out because ConvertType(id) == i8*.
4769e5dd7070Spatrick EmitInitOfCatchParam(CGF, Caught, CatchParam);
4770e5dd7070Spatrick }
4771e5dd7070Spatrick
4772e5dd7070Spatrick CGF.EmitStmt(CatchStmt->getCatchBody());
4773e5dd7070Spatrick
4774e5dd7070Spatrick // The scope of the catch variable ends right here.
4775e5dd7070Spatrick CatchVarCleanups.ForceCleanup();
4776e5dd7070Spatrick
4777e5dd7070Spatrick CGF.EmitBranchThroughCleanup(FinallyEnd);
4778e5dd7070Spatrick break;
4779e5dd7070Spatrick }
4780e5dd7070Spatrick
4781e5dd7070Spatrick assert(OPT && "Unexpected non-object pointer type in @catch");
4782e5dd7070Spatrick const ObjCObjectType *ObjTy = OPT->getObjectType();
4783e5dd7070Spatrick
4784e5dd7070Spatrick // FIXME: @catch (Class c) ?
4785e5dd7070Spatrick ObjCInterfaceDecl *IDecl = ObjTy->getInterface();
4786e5dd7070Spatrick assert(IDecl && "Catch parameter must have Objective-C type!");
4787e5dd7070Spatrick
4788e5dd7070Spatrick // Check if the @catch block matches the exception object.
4789e5dd7070Spatrick llvm::Value *Class = EmitClassRef(CGF, IDecl);
4790e5dd7070Spatrick
4791e5dd7070Spatrick llvm::Value *matchArgs[] = { Class, Caught };
4792e5dd7070Spatrick llvm::CallInst *Match =
4793e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionMatchFn(),
4794e5dd7070Spatrick matchArgs, "match");
4795e5dd7070Spatrick
4796e5dd7070Spatrick llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("match");
4797e5dd7070Spatrick llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch.next");
4798e5dd7070Spatrick
4799e5dd7070Spatrick CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(Match, "matched"),
4800e5dd7070Spatrick MatchedBlock, NextCatchBlock);
4801e5dd7070Spatrick
4802e5dd7070Spatrick // Emit the @catch block.
4803e5dd7070Spatrick CGF.EmitBlock(MatchedBlock);
4804e5dd7070Spatrick
4805e5dd7070Spatrick // Collect any cleanups for the catch variable. The scope lasts until
4806e5dd7070Spatrick // the end of the catch body.
4807e5dd7070Spatrick CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF);
4808e5dd7070Spatrick
4809e5dd7070Spatrick CGF.EmitAutoVarDecl(*CatchParam);
4810e5dd7070Spatrick assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
4811e5dd7070Spatrick
4812e5dd7070Spatrick // Initialize the catch variable.
4813e5dd7070Spatrick llvm::Value *Tmp =
4814e5dd7070Spatrick CGF.Builder.CreateBitCast(Caught,
4815e5dd7070Spatrick CGF.ConvertType(CatchParam->getType()));
4816e5dd7070Spatrick EmitInitOfCatchParam(CGF, Tmp, CatchParam);
4817e5dd7070Spatrick
4818e5dd7070Spatrick CGF.EmitStmt(CatchStmt->getCatchBody());
4819e5dd7070Spatrick
4820e5dd7070Spatrick // We're done with the catch variable.
4821e5dd7070Spatrick CatchVarCleanups.ForceCleanup();
4822e5dd7070Spatrick
4823e5dd7070Spatrick CGF.EmitBranchThroughCleanup(FinallyEnd);
4824e5dd7070Spatrick
4825e5dd7070Spatrick CGF.EmitBlock(NextCatchBlock);
4826e5dd7070Spatrick }
4827e5dd7070Spatrick
4828e5dd7070Spatrick CGF.ObjCEHValueStack.pop_back();
4829e5dd7070Spatrick
4830e5dd7070Spatrick // If nothing wanted anything to do with the caught exception,
4831e5dd7070Spatrick // kill the extract call.
4832e5dd7070Spatrick if (Caught->use_empty())
4833e5dd7070Spatrick Caught->eraseFromParent();
4834e5dd7070Spatrick
4835e5dd7070Spatrick if (!AllMatched)
4836e5dd7070Spatrick CGF.EmitBranchThroughCleanup(FinallyRethrow);
4837e5dd7070Spatrick
4838e5dd7070Spatrick if (HasFinally) {
4839e5dd7070Spatrick // Emit the exception handler for the @catch blocks.
4840e5dd7070Spatrick CGF.EmitBlock(CatchHandler);
4841e5dd7070Spatrick
4842e5dd7070Spatrick // In theory we might now need a write hazard, but actually it's
4843e5dd7070Spatrick // unnecessary because there's no local-accessing code between
4844e5dd7070Spatrick // the try's write hazard and here.
4845e5dd7070Spatrick //Hazards.emitWriteHazard();
4846e5dd7070Spatrick
4847e5dd7070Spatrick // Extract the new exception and save it to the
4848e5dd7070Spatrick // propagating-exception slot.
4849e5dd7070Spatrick assert(PropagatingExnVar.isValid());
4850e5dd7070Spatrick llvm::CallInst *NewCaught =
4851e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
4852e5dd7070Spatrick ExceptionData.getPointer(), "caught");
4853e5dd7070Spatrick CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
4854e5dd7070Spatrick
4855e5dd7070Spatrick // Don't pop the catch handler; the throw already did.
4856e5dd7070Spatrick CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
4857e5dd7070Spatrick CGF.EmitBranchThroughCleanup(FinallyRethrow);
4858e5dd7070Spatrick }
4859e5dd7070Spatrick }
4860e5dd7070Spatrick
4861e5dd7070Spatrick // Insert read hazards as required in the new blocks.
4862e5dd7070Spatrick Hazards.emitHazardsInNewBlocks();
4863e5dd7070Spatrick
4864e5dd7070Spatrick // Pop the cleanup.
4865e5dd7070Spatrick CGF.Builder.restoreIP(TryFallthroughIP);
4866e5dd7070Spatrick if (CGF.HaveInsertPoint())
4867e5dd7070Spatrick CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar);
4868e5dd7070Spatrick CGF.PopCleanupBlock();
4869e5dd7070Spatrick CGF.EmitBlock(FinallyEnd.getBlock(), true);
4870e5dd7070Spatrick
4871e5dd7070Spatrick // Emit the rethrow block.
4872e5dd7070Spatrick CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
4873e5dd7070Spatrick CGF.EmitBlock(FinallyRethrow.getBlock(), true);
4874e5dd7070Spatrick if (CGF.HaveInsertPoint()) {
4875e5dd7070Spatrick // If we have a propagating-exception variable, check it.
4876e5dd7070Spatrick llvm::Value *PropagatingExn;
4877e5dd7070Spatrick if (PropagatingExnVar.isValid()) {
4878e5dd7070Spatrick PropagatingExn = CGF.Builder.CreateLoad(PropagatingExnVar);
4879e5dd7070Spatrick
4880e5dd7070Spatrick // Otherwise, just look in the buffer for the exception to throw.
4881e5dd7070Spatrick } else {
4882e5dd7070Spatrick llvm::CallInst *Caught =
4883e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
4884e5dd7070Spatrick ExceptionData.getPointer());
4885e5dd7070Spatrick PropagatingExn = Caught;
4886e5dd7070Spatrick }
4887e5dd7070Spatrick
4888e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionThrowFn(),
4889e5dd7070Spatrick PropagatingExn);
4890e5dd7070Spatrick CGF.Builder.CreateUnreachable();
4891e5dd7070Spatrick }
4892e5dd7070Spatrick
4893e5dd7070Spatrick CGF.Builder.restoreIP(SavedIP);
4894e5dd7070Spatrick }
4895e5dd7070Spatrick
EmitThrowStmt(CodeGen::CodeGenFunction & CGF,const ObjCAtThrowStmt & S,bool ClearInsertionPoint)4896e5dd7070Spatrick void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
4897e5dd7070Spatrick const ObjCAtThrowStmt &S,
4898e5dd7070Spatrick bool ClearInsertionPoint) {
4899e5dd7070Spatrick llvm::Value *ExceptionAsObject;
4900e5dd7070Spatrick
4901e5dd7070Spatrick if (const Expr *ThrowExpr = S.getThrowExpr()) {
4902e5dd7070Spatrick llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
4903e5dd7070Spatrick ExceptionAsObject =
4904e5dd7070Spatrick CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
4905e5dd7070Spatrick } else {
4906e5dd7070Spatrick assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
4907e5dd7070Spatrick "Unexpected rethrow outside @catch block.");
4908e5dd7070Spatrick ExceptionAsObject = CGF.ObjCEHValueStack.back();
4909e5dd7070Spatrick }
4910e5dd7070Spatrick
4911e5dd7070Spatrick CGF.EmitRuntimeCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
4912e5dd7070Spatrick ->setDoesNotReturn();
4913e5dd7070Spatrick CGF.Builder.CreateUnreachable();
4914e5dd7070Spatrick
4915e5dd7070Spatrick // Clear the insertion point to indicate we are in unreachable code.
4916e5dd7070Spatrick if (ClearInsertionPoint)
4917e5dd7070Spatrick CGF.Builder.ClearInsertionPoint();
4918e5dd7070Spatrick }
4919e5dd7070Spatrick
4920e5dd7070Spatrick /// EmitObjCWeakRead - Code gen for loading value of a __weak
4921e5dd7070Spatrick /// object: objc_read_weak (id *src)
4922e5dd7070Spatrick ///
EmitObjCWeakRead(CodeGen::CodeGenFunction & CGF,Address AddrWeakObj)4923e5dd7070Spatrick llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
4924e5dd7070Spatrick Address AddrWeakObj) {
4925e5dd7070Spatrick llvm::Type* DestTy = AddrWeakObj.getElementType();
4926*12c85518Srobert llvm::Value *AddrWeakObjVal = CGF.Builder.CreateBitCast(
4927*12c85518Srobert AddrWeakObj.getPointer(), ObjCTypes.PtrObjectPtrTy);
4928e5dd7070Spatrick llvm::Value *read_weak =
4929e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
4930*12c85518Srobert AddrWeakObjVal, "weakread");
4931e5dd7070Spatrick read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
4932e5dd7070Spatrick return read_weak;
4933e5dd7070Spatrick }
4934e5dd7070Spatrick
4935e5dd7070Spatrick /// EmitObjCWeakAssign - Code gen for assigning to a __weak object.
4936e5dd7070Spatrick /// objc_assign_weak (id src, id *dst)
4937e5dd7070Spatrick ///
EmitObjCWeakAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst)4938e5dd7070Spatrick void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
4939e5dd7070Spatrick llvm::Value *src, Address dst) {
4940e5dd7070Spatrick llvm::Type * SrcTy = src->getType();
4941e5dd7070Spatrick if (!isa<llvm::PointerType>(SrcTy)) {
4942e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
4943e5dd7070Spatrick assert(Size <= 8 && "does not support size > 8");
4944e5dd7070Spatrick src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
4945e5dd7070Spatrick : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
4946e5dd7070Spatrick src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
4947e5dd7070Spatrick }
4948e5dd7070Spatrick src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
4949*12c85518Srobert llvm::Value *dstVal =
4950*12c85518Srobert CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy);
4951*12c85518Srobert llvm::Value *args[] = { src, dstVal };
4952e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
4953e5dd7070Spatrick args, "weakassign");
4954e5dd7070Spatrick }
4955e5dd7070Spatrick
4956e5dd7070Spatrick /// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
4957e5dd7070Spatrick /// objc_assign_global (id src, id *dst)
4958e5dd7070Spatrick ///
EmitObjCGlobalAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst,bool threadlocal)4959e5dd7070Spatrick void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
4960e5dd7070Spatrick llvm::Value *src, Address dst,
4961e5dd7070Spatrick bool threadlocal) {
4962e5dd7070Spatrick llvm::Type * SrcTy = src->getType();
4963e5dd7070Spatrick if (!isa<llvm::PointerType>(SrcTy)) {
4964e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
4965e5dd7070Spatrick assert(Size <= 8 && "does not support size > 8");
4966e5dd7070Spatrick src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
4967e5dd7070Spatrick : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
4968e5dd7070Spatrick src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
4969e5dd7070Spatrick }
4970e5dd7070Spatrick src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
4971*12c85518Srobert llvm::Value *dstVal =
4972*12c85518Srobert CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy);
4973*12c85518Srobert llvm::Value *args[] = {src, dstVal};
4974e5dd7070Spatrick if (!threadlocal)
4975e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
4976e5dd7070Spatrick args, "globalassign");
4977e5dd7070Spatrick else
4978e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
4979e5dd7070Spatrick args, "threadlocalassign");
4980e5dd7070Spatrick }
4981e5dd7070Spatrick
4982e5dd7070Spatrick /// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
4983e5dd7070Spatrick /// objc_assign_ivar (id src, id *dst, ptrdiff_t ivaroffset)
4984e5dd7070Spatrick ///
EmitObjCIvarAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst,llvm::Value * ivarOffset)4985e5dd7070Spatrick void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
4986e5dd7070Spatrick llvm::Value *src, Address dst,
4987e5dd7070Spatrick llvm::Value *ivarOffset) {
4988e5dd7070Spatrick assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
4989e5dd7070Spatrick llvm::Type * SrcTy = src->getType();
4990e5dd7070Spatrick if (!isa<llvm::PointerType>(SrcTy)) {
4991e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
4992e5dd7070Spatrick assert(Size <= 8 && "does not support size > 8");
4993e5dd7070Spatrick src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
4994e5dd7070Spatrick : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
4995e5dd7070Spatrick src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
4996e5dd7070Spatrick }
4997e5dd7070Spatrick src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
4998*12c85518Srobert llvm::Value *dstVal =
4999*12c85518Srobert CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy);
5000*12c85518Srobert llvm::Value *args[] = {src, dstVal, ivarOffset};
5001e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
5002e5dd7070Spatrick }
5003e5dd7070Spatrick
5004e5dd7070Spatrick /// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
5005e5dd7070Spatrick /// objc_assign_strongCast (id src, id *dst)
5006e5dd7070Spatrick ///
EmitObjCStrongCastAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst)5007e5dd7070Spatrick void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
5008e5dd7070Spatrick llvm::Value *src, Address dst) {
5009e5dd7070Spatrick llvm::Type * SrcTy = src->getType();
5010e5dd7070Spatrick if (!isa<llvm::PointerType>(SrcTy)) {
5011e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
5012e5dd7070Spatrick assert(Size <= 8 && "does not support size > 8");
5013e5dd7070Spatrick src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
5014e5dd7070Spatrick : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
5015e5dd7070Spatrick src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
5016e5dd7070Spatrick }
5017e5dd7070Spatrick src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
5018*12c85518Srobert llvm::Value *dstVal =
5019*12c85518Srobert CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy);
5020*12c85518Srobert llvm::Value *args[] = {src, dstVal};
5021e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
5022e5dd7070Spatrick args, "strongassign");
5023e5dd7070Spatrick }
5024e5dd7070Spatrick
EmitGCMemmoveCollectable(CodeGen::CodeGenFunction & CGF,Address DestPtr,Address SrcPtr,llvm::Value * size)5025e5dd7070Spatrick void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
5026e5dd7070Spatrick Address DestPtr,
5027e5dd7070Spatrick Address SrcPtr,
5028e5dd7070Spatrick llvm::Value *size) {
5029*12c85518Srobert SrcPtr = CGF.Builder.CreateElementBitCast(SrcPtr, CGF.Int8Ty);
5030*12c85518Srobert DestPtr = CGF.Builder.CreateElementBitCast(DestPtr, CGF.Int8Ty);
5031e5dd7070Spatrick llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), size };
5032e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
5033e5dd7070Spatrick }
5034e5dd7070Spatrick
5035e5dd7070Spatrick /// EmitObjCValueForIvar - Code Gen for ivar reference.
5036e5dd7070Spatrick ///
EmitObjCValueForIvar(CodeGen::CodeGenFunction & CGF,QualType ObjectTy,llvm::Value * BaseValue,const ObjCIvarDecl * Ivar,unsigned CVRQualifiers)5037e5dd7070Spatrick LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
5038e5dd7070Spatrick QualType ObjectTy,
5039e5dd7070Spatrick llvm::Value *BaseValue,
5040e5dd7070Spatrick const ObjCIvarDecl *Ivar,
5041e5dd7070Spatrick unsigned CVRQualifiers) {
5042e5dd7070Spatrick const ObjCInterfaceDecl *ID =
5043e5dd7070Spatrick ObjectTy->castAs<ObjCObjectType>()->getInterface();
5044e5dd7070Spatrick return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
5045e5dd7070Spatrick EmitIvarOffset(CGF, ID, Ivar));
5046e5dd7070Spatrick }
5047e5dd7070Spatrick
EmitIvarOffset(CodeGen::CodeGenFunction & CGF,const ObjCInterfaceDecl * Interface,const ObjCIvarDecl * Ivar)5048e5dd7070Spatrick llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
5049e5dd7070Spatrick const ObjCInterfaceDecl *Interface,
5050e5dd7070Spatrick const ObjCIvarDecl *Ivar) {
5051e5dd7070Spatrick uint64_t Offset = ComputeIvarBaseOffset(CGM, Interface, Ivar);
5052e5dd7070Spatrick return llvm::ConstantInt::get(
5053e5dd7070Spatrick CGM.getTypes().ConvertType(CGM.getContext().LongTy),
5054e5dd7070Spatrick Offset);
5055e5dd7070Spatrick }
5056e5dd7070Spatrick
5057e5dd7070Spatrick /* *** Private Interface *** */
5058e5dd7070Spatrick
GetSectionName(StringRef Section,StringRef MachOAttributes)5059e5dd7070Spatrick std::string CGObjCCommonMac::GetSectionName(StringRef Section,
5060e5dd7070Spatrick StringRef MachOAttributes) {
5061e5dd7070Spatrick switch (CGM.getTriple().getObjectFormat()) {
5062e5dd7070Spatrick case llvm::Triple::UnknownObjectFormat:
5063e5dd7070Spatrick llvm_unreachable("unexpected object file format");
5064e5dd7070Spatrick case llvm::Triple::MachO: {
5065e5dd7070Spatrick if (MachOAttributes.empty())
5066e5dd7070Spatrick return ("__DATA," + Section).str();
5067e5dd7070Spatrick return ("__DATA," + Section + "," + MachOAttributes).str();
5068e5dd7070Spatrick }
5069e5dd7070Spatrick case llvm::Triple::ELF:
5070e5dd7070Spatrick assert(Section.substr(0, 2) == "__" &&
5071e5dd7070Spatrick "expected the name to begin with __");
5072e5dd7070Spatrick return Section.substr(2).str();
5073e5dd7070Spatrick case llvm::Triple::COFF:
5074e5dd7070Spatrick assert(Section.substr(0, 2) == "__" &&
5075e5dd7070Spatrick "expected the name to begin with __");
5076e5dd7070Spatrick return ("." + Section.substr(2) + "$B").str();
5077e5dd7070Spatrick case llvm::Triple::Wasm:
5078a9ac8606Spatrick case llvm::Triple::GOFF:
5079*12c85518Srobert case llvm::Triple::SPIRV:
5080e5dd7070Spatrick case llvm::Triple::XCOFF:
5081*12c85518Srobert case llvm::Triple::DXContainer:
5082e5dd7070Spatrick llvm::report_fatal_error(
5083a9ac8606Spatrick "Objective-C support is unimplemented for object file format");
5084e5dd7070Spatrick }
5085e5dd7070Spatrick
5086e5dd7070Spatrick llvm_unreachable("Unhandled llvm::Triple::ObjectFormatType enum");
5087e5dd7070Spatrick }
5088e5dd7070Spatrick
5089e5dd7070Spatrick /// EmitImageInfo - Emit the image info marker used to encode some module
5090e5dd7070Spatrick /// level information.
5091e5dd7070Spatrick ///
5092e5dd7070Spatrick /// See: <rdr://4810609&4810587&4810587>
5093e5dd7070Spatrick /// struct IMAGE_INFO {
5094e5dd7070Spatrick /// unsigned version;
5095e5dd7070Spatrick /// unsigned flags;
5096e5dd7070Spatrick /// };
5097e5dd7070Spatrick enum ImageInfoFlags {
5098e5dd7070Spatrick eImageInfo_FixAndContinue = (1 << 0), // This flag is no longer set by clang.
5099e5dd7070Spatrick eImageInfo_GarbageCollected = (1 << 1),
5100e5dd7070Spatrick eImageInfo_GCOnly = (1 << 2),
5101e5dd7070Spatrick eImageInfo_OptimizedByDyld = (1 << 3), // This flag is set by the dyld shared cache.
5102e5dd7070Spatrick
5103e5dd7070Spatrick // A flag indicating that the module has no instances of a @synthesize of a
5104e5dd7070Spatrick // superclass variable. <rdar://problem/6803242>
5105e5dd7070Spatrick eImageInfo_CorrectedSynthesize = (1 << 4), // This flag is no longer set by clang.
5106e5dd7070Spatrick eImageInfo_ImageIsSimulated = (1 << 5),
5107e5dd7070Spatrick eImageInfo_ClassProperties = (1 << 6)
5108e5dd7070Spatrick };
5109e5dd7070Spatrick
EmitImageInfo()5110e5dd7070Spatrick void CGObjCCommonMac::EmitImageInfo() {
5111e5dd7070Spatrick unsigned version = 0; // Version is unused?
5112e5dd7070Spatrick std::string Section =
5113e5dd7070Spatrick (ObjCABI == 1)
5114e5dd7070Spatrick ? "__OBJC,__image_info,regular"
5115e5dd7070Spatrick : GetSectionName("__objc_imageinfo", "regular,no_dead_strip");
5116e5dd7070Spatrick
5117e5dd7070Spatrick // Generate module-level named metadata to convey this information to the
5118e5dd7070Spatrick // linker and code-gen.
5119e5dd7070Spatrick llvm::Module &Mod = CGM.getModule();
5120e5dd7070Spatrick
5121e5dd7070Spatrick // Add the ObjC ABI version to the module flags.
5122e5dd7070Spatrick Mod.addModuleFlag(llvm::Module::Error, "Objective-C Version", ObjCABI);
5123e5dd7070Spatrick Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
5124e5dd7070Spatrick version);
5125e5dd7070Spatrick Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
5126e5dd7070Spatrick llvm::MDString::get(VMContext, Section));
5127e5dd7070Spatrick
5128ec727ea7Spatrick auto Int8Ty = llvm::Type::getInt8Ty(VMContext);
5129e5dd7070Spatrick if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
5130e5dd7070Spatrick // Non-GC overrides those files which specify GC.
5131ec727ea7Spatrick Mod.addModuleFlag(llvm::Module::Error,
5132ec727ea7Spatrick "Objective-C Garbage Collection",
5133ec727ea7Spatrick llvm::ConstantInt::get(Int8Ty,0));
5134e5dd7070Spatrick } else {
5135e5dd7070Spatrick // Add the ObjC garbage collection value.
5136e5dd7070Spatrick Mod.addModuleFlag(llvm::Module::Error,
5137e5dd7070Spatrick "Objective-C Garbage Collection",
5138ec727ea7Spatrick llvm::ConstantInt::get(Int8Ty,
5139ec727ea7Spatrick (uint8_t)eImageInfo_GarbageCollected));
5140e5dd7070Spatrick
5141e5dd7070Spatrick if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
5142e5dd7070Spatrick // Add the ObjC GC Only value.
5143e5dd7070Spatrick Mod.addModuleFlag(llvm::Module::Error, "Objective-C GC Only",
5144e5dd7070Spatrick eImageInfo_GCOnly);
5145e5dd7070Spatrick
5146e5dd7070Spatrick // Require that GC be specified and set to eImageInfo_GarbageCollected.
5147e5dd7070Spatrick llvm::Metadata *Ops[2] = {
5148e5dd7070Spatrick llvm::MDString::get(VMContext, "Objective-C Garbage Collection"),
5149e5dd7070Spatrick llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
5150ec727ea7Spatrick Int8Ty, eImageInfo_GarbageCollected))};
5151e5dd7070Spatrick Mod.addModuleFlag(llvm::Module::Require, "Objective-C GC Only",
5152e5dd7070Spatrick llvm::MDNode::get(VMContext, Ops));
5153e5dd7070Spatrick }
5154e5dd7070Spatrick }
5155e5dd7070Spatrick
5156e5dd7070Spatrick // Indicate whether we're compiling this to run on a simulator.
5157e5dd7070Spatrick if (CGM.getTarget().getTriple().isSimulatorEnvironment())
5158e5dd7070Spatrick Mod.addModuleFlag(llvm::Module::Error, "Objective-C Is Simulated",
5159e5dd7070Spatrick eImageInfo_ImageIsSimulated);
5160e5dd7070Spatrick
5161e5dd7070Spatrick // Indicate whether we are generating class properties.
5162e5dd7070Spatrick Mod.addModuleFlag(llvm::Module::Error, "Objective-C Class Properties",
5163e5dd7070Spatrick eImageInfo_ClassProperties);
5164e5dd7070Spatrick }
5165e5dd7070Spatrick
5166e5dd7070Spatrick // struct objc_module {
5167e5dd7070Spatrick // unsigned long version;
5168e5dd7070Spatrick // unsigned long size;
5169e5dd7070Spatrick // const char *name;
5170e5dd7070Spatrick // Symtab symtab;
5171e5dd7070Spatrick // };
5172e5dd7070Spatrick
5173e5dd7070Spatrick // FIXME: Get from somewhere
5174e5dd7070Spatrick static const int ModuleVersion = 7;
5175e5dd7070Spatrick
EmitModuleInfo()5176e5dd7070Spatrick void CGObjCMac::EmitModuleInfo() {
5177e5dd7070Spatrick uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ModuleTy);
5178e5dd7070Spatrick
5179e5dd7070Spatrick ConstantInitBuilder builder(CGM);
5180e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ModuleTy);
5181e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, ModuleVersion);
5182e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, Size);
5183e5dd7070Spatrick // This used to be the filename, now it is unused. <rdr://4327263>
5184e5dd7070Spatrick values.add(GetClassName(StringRef("")));
5185e5dd7070Spatrick values.add(EmitModuleSymbols());
5186e5dd7070Spatrick CreateMetadataVar("OBJC_MODULES", values,
5187e5dd7070Spatrick "__OBJC,__module_info,regular,no_dead_strip",
5188e5dd7070Spatrick CGM.getPointerAlign(), true);
5189e5dd7070Spatrick }
5190e5dd7070Spatrick
EmitModuleSymbols()5191e5dd7070Spatrick llvm::Constant *CGObjCMac::EmitModuleSymbols() {
5192e5dd7070Spatrick unsigned NumClasses = DefinedClasses.size();
5193e5dd7070Spatrick unsigned NumCategories = DefinedCategories.size();
5194e5dd7070Spatrick
5195e5dd7070Spatrick // Return null if no symbols were defined.
5196e5dd7070Spatrick if (!NumClasses && !NumCategories)
5197e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.SymtabPtrTy);
5198e5dd7070Spatrick
5199e5dd7070Spatrick ConstantInitBuilder builder(CGM);
5200e5dd7070Spatrick auto values = builder.beginStruct();
5201e5dd7070Spatrick values.addInt(ObjCTypes.LongTy, 0);
5202e5dd7070Spatrick values.addNullPointer(ObjCTypes.SelectorPtrTy);
5203e5dd7070Spatrick values.addInt(ObjCTypes.ShortTy, NumClasses);
5204e5dd7070Spatrick values.addInt(ObjCTypes.ShortTy, NumCategories);
5205e5dd7070Spatrick
5206e5dd7070Spatrick // The runtime expects exactly the list of defined classes followed
5207e5dd7070Spatrick // by the list of defined categories, in a single array.
5208e5dd7070Spatrick auto array = values.beginArray(ObjCTypes.Int8PtrTy);
5209e5dd7070Spatrick for (unsigned i=0; i<NumClasses; i++) {
5210e5dd7070Spatrick const ObjCInterfaceDecl *ID = ImplementedClasses[i];
5211e5dd7070Spatrick assert(ID);
5212e5dd7070Spatrick if (ObjCImplementationDecl *IMP = ID->getImplementation())
5213e5dd7070Spatrick // We are implementing a weak imported interface. Give it external linkage
5214e5dd7070Spatrick if (ID->isWeakImported() && !IMP->isWeakImported())
5215e5dd7070Spatrick DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
5216e5dd7070Spatrick
5217e5dd7070Spatrick array.addBitCast(DefinedClasses[i], ObjCTypes.Int8PtrTy);
5218e5dd7070Spatrick }
5219e5dd7070Spatrick for (unsigned i=0; i<NumCategories; i++)
5220e5dd7070Spatrick array.addBitCast(DefinedCategories[i], ObjCTypes.Int8PtrTy);
5221e5dd7070Spatrick
5222e5dd7070Spatrick array.finishAndAddTo(values);
5223e5dd7070Spatrick
5224e5dd7070Spatrick llvm::GlobalVariable *GV = CreateMetadataVar(
5225e5dd7070Spatrick "OBJC_SYMBOLS", values, "__OBJC,__symbols,regular,no_dead_strip",
5226e5dd7070Spatrick CGM.getPointerAlign(), true);
5227e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
5228e5dd7070Spatrick }
5229e5dd7070Spatrick
EmitClassRefFromId(CodeGenFunction & CGF,IdentifierInfo * II)5230e5dd7070Spatrick llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
5231e5dd7070Spatrick IdentifierInfo *II) {
5232e5dd7070Spatrick LazySymbols.insert(II);
5233e5dd7070Spatrick
5234e5dd7070Spatrick llvm::GlobalVariable *&Entry = ClassReferences[II];
5235e5dd7070Spatrick
5236e5dd7070Spatrick if (!Entry) {
5237e5dd7070Spatrick llvm::Constant *Casted =
5238e5dd7070Spatrick llvm::ConstantExpr::getBitCast(GetClassName(II->getName()),
5239e5dd7070Spatrick ObjCTypes.ClassPtrTy);
5240e5dd7070Spatrick Entry = CreateMetadataVar(
5241e5dd7070Spatrick "OBJC_CLASS_REFERENCES_", Casted,
5242e5dd7070Spatrick "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
5243e5dd7070Spatrick CGM.getPointerAlign(), true);
5244e5dd7070Spatrick }
5245e5dd7070Spatrick
5246a9ac8606Spatrick return CGF.Builder.CreateAlignedLoad(Entry->getValueType(), Entry,
5247a9ac8606Spatrick CGF.getPointerAlign());
5248e5dd7070Spatrick }
5249e5dd7070Spatrick
EmitClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)5250e5dd7070Spatrick llvm::Value *CGObjCMac::EmitClassRef(CodeGenFunction &CGF,
5251e5dd7070Spatrick const ObjCInterfaceDecl *ID) {
5252e5dd7070Spatrick // If the class has the objc_runtime_visible attribute, we need to
5253e5dd7070Spatrick // use the Objective-C runtime to get the class.
5254e5dd7070Spatrick if (ID->hasAttr<ObjCRuntimeVisibleAttr>())
5255e5dd7070Spatrick return EmitClassRefViaRuntime(CGF, ID, ObjCTypes);
5256e5dd7070Spatrick
5257e5dd7070Spatrick IdentifierInfo *RuntimeName =
5258e5dd7070Spatrick &CGM.getContext().Idents.get(ID->getObjCRuntimeNameAsString());
5259e5dd7070Spatrick return EmitClassRefFromId(CGF, RuntimeName);
5260e5dd7070Spatrick }
5261e5dd7070Spatrick
EmitNSAutoreleasePoolClassRef(CodeGenFunction & CGF)5262e5dd7070Spatrick llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
5263e5dd7070Spatrick IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
5264e5dd7070Spatrick return EmitClassRefFromId(CGF, II);
5265e5dd7070Spatrick }
5266e5dd7070Spatrick
EmitSelector(CodeGenFunction & CGF,Selector Sel)5267e5dd7070Spatrick llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) {
5268e5dd7070Spatrick return CGF.Builder.CreateLoad(EmitSelectorAddr(Sel));
5269e5dd7070Spatrick }
5270e5dd7070Spatrick
EmitSelectorAddr(Selector Sel)5271e5dd7070Spatrick Address CGObjCMac::EmitSelectorAddr(Selector Sel) {
5272e5dd7070Spatrick CharUnits Align = CGM.getPointerAlign();
5273e5dd7070Spatrick
5274e5dd7070Spatrick llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
5275e5dd7070Spatrick if (!Entry) {
5276e5dd7070Spatrick llvm::Constant *Casted =
5277e5dd7070Spatrick llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
5278e5dd7070Spatrick ObjCTypes.SelectorPtrTy);
5279e5dd7070Spatrick Entry = CreateMetadataVar(
5280e5dd7070Spatrick "OBJC_SELECTOR_REFERENCES_", Casted,
5281e5dd7070Spatrick "__OBJC,__message_refs,literal_pointers,no_dead_strip", Align, true);
5282e5dd7070Spatrick Entry->setExternallyInitialized(true);
5283e5dd7070Spatrick }
5284e5dd7070Spatrick
5285*12c85518Srobert return Address(Entry, ObjCTypes.SelectorPtrTy, Align);
5286e5dd7070Spatrick }
5287e5dd7070Spatrick
GetClassName(StringRef RuntimeName)5288e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) {
5289e5dd7070Spatrick llvm::GlobalVariable *&Entry = ClassNames[RuntimeName];
5290e5dd7070Spatrick if (!Entry)
5291e5dd7070Spatrick Entry = CreateCStringLiteral(RuntimeName, ObjCLabelType::ClassName);
5292e5dd7070Spatrick return getConstantGEP(VMContext, Entry, 0, 0);
5293e5dd7070Spatrick }
5294e5dd7070Spatrick
GetMethodDefinition(const ObjCMethodDecl * MD)5295e5dd7070Spatrick llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) {
5296e5dd7070Spatrick llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*>::iterator
5297e5dd7070Spatrick I = MethodDefinitions.find(MD);
5298e5dd7070Spatrick if (I != MethodDefinitions.end())
5299e5dd7070Spatrick return I->second;
5300e5dd7070Spatrick
5301e5dd7070Spatrick return nullptr;
5302e5dd7070Spatrick }
5303e5dd7070Spatrick
5304e5dd7070Spatrick /// GetIvarLayoutName - Returns a unique constant for the given
5305e5dd7070Spatrick /// ivar layout bitmap.
GetIvarLayoutName(IdentifierInfo * Ident,const ObjCCommonTypesHelper & ObjCTypes)5306e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident,
5307e5dd7070Spatrick const ObjCCommonTypesHelper &ObjCTypes) {
5308e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
5309e5dd7070Spatrick }
5310e5dd7070Spatrick
visitRecord(const RecordType * RT,CharUnits offset)5311e5dd7070Spatrick void IvarLayoutBuilder::visitRecord(const RecordType *RT,
5312e5dd7070Spatrick CharUnits offset) {
5313e5dd7070Spatrick const RecordDecl *RD = RT->getDecl();
5314e5dd7070Spatrick
5315e5dd7070Spatrick // If this is a union, remember that we had one, because it might mess
5316e5dd7070Spatrick // up the ordering of layout entries.
5317e5dd7070Spatrick if (RD->isUnion())
5318e5dd7070Spatrick IsDisordered = true;
5319e5dd7070Spatrick
5320e5dd7070Spatrick const ASTRecordLayout *recLayout = nullptr;
5321e5dd7070Spatrick visitAggregate(RD->field_begin(), RD->field_end(), offset,
5322e5dd7070Spatrick [&](const FieldDecl *field) -> CharUnits {
5323e5dd7070Spatrick if (!recLayout)
5324e5dd7070Spatrick recLayout = &CGM.getContext().getASTRecordLayout(RD);
5325e5dd7070Spatrick auto offsetInBits = recLayout->getFieldOffset(field->getFieldIndex());
5326e5dd7070Spatrick return CGM.getContext().toCharUnitsFromBits(offsetInBits);
5327e5dd7070Spatrick });
5328e5dd7070Spatrick }
5329e5dd7070Spatrick
5330e5dd7070Spatrick template <class Iterator, class GetOffsetFn>
visitAggregate(Iterator begin,Iterator end,CharUnits aggregateOffset,const GetOffsetFn & getOffset)5331e5dd7070Spatrick void IvarLayoutBuilder::visitAggregate(Iterator begin, Iterator end,
5332e5dd7070Spatrick CharUnits aggregateOffset,
5333e5dd7070Spatrick const GetOffsetFn &getOffset) {
5334e5dd7070Spatrick for (; begin != end; ++begin) {
5335e5dd7070Spatrick auto field = *begin;
5336e5dd7070Spatrick
5337e5dd7070Spatrick // Skip over bitfields.
5338e5dd7070Spatrick if (field->isBitField()) {
5339e5dd7070Spatrick continue;
5340e5dd7070Spatrick }
5341e5dd7070Spatrick
5342e5dd7070Spatrick // Compute the offset of the field within the aggregate.
5343e5dd7070Spatrick CharUnits fieldOffset = aggregateOffset + getOffset(field);
5344e5dd7070Spatrick
5345e5dd7070Spatrick visitField(field, fieldOffset);
5346e5dd7070Spatrick }
5347e5dd7070Spatrick }
5348e5dd7070Spatrick
5349e5dd7070Spatrick /// Collect layout information for the given fields into IvarsInfo.
visitField(const FieldDecl * field,CharUnits fieldOffset)5350e5dd7070Spatrick void IvarLayoutBuilder::visitField(const FieldDecl *field,
5351e5dd7070Spatrick CharUnits fieldOffset) {
5352e5dd7070Spatrick QualType fieldType = field->getType();
5353e5dd7070Spatrick
5354e5dd7070Spatrick // Drill down into arrays.
5355e5dd7070Spatrick uint64_t numElts = 1;
5356e5dd7070Spatrick if (auto arrayType = CGM.getContext().getAsIncompleteArrayType(fieldType)) {
5357e5dd7070Spatrick numElts = 0;
5358e5dd7070Spatrick fieldType = arrayType->getElementType();
5359e5dd7070Spatrick }
5360e5dd7070Spatrick // Unlike incomplete arrays, constant arrays can be nested.
5361e5dd7070Spatrick while (auto arrayType = CGM.getContext().getAsConstantArrayType(fieldType)) {
5362e5dd7070Spatrick numElts *= arrayType->getSize().getZExtValue();
5363e5dd7070Spatrick fieldType = arrayType->getElementType();
5364e5dd7070Spatrick }
5365e5dd7070Spatrick
5366e5dd7070Spatrick assert(!fieldType->isArrayType() && "ivar of non-constant array type?");
5367e5dd7070Spatrick
5368e5dd7070Spatrick // If we ended up with a zero-sized array, we've done what we can do within
5369e5dd7070Spatrick // the limits of this layout encoding.
5370e5dd7070Spatrick if (numElts == 0) return;
5371e5dd7070Spatrick
5372e5dd7070Spatrick // Recurse if the base element type is a record type.
5373e5dd7070Spatrick if (auto recType = fieldType->getAs<RecordType>()) {
5374e5dd7070Spatrick size_t oldEnd = IvarsInfo.size();
5375e5dd7070Spatrick
5376e5dd7070Spatrick visitRecord(recType, fieldOffset);
5377e5dd7070Spatrick
5378e5dd7070Spatrick // If we have an array, replicate the first entry's layout information.
5379e5dd7070Spatrick auto numEltEntries = IvarsInfo.size() - oldEnd;
5380e5dd7070Spatrick if (numElts != 1 && numEltEntries != 0) {
5381e5dd7070Spatrick CharUnits eltSize = CGM.getContext().getTypeSizeInChars(recType);
5382e5dd7070Spatrick for (uint64_t eltIndex = 1; eltIndex != numElts; ++eltIndex) {
5383e5dd7070Spatrick // Copy the last numEltEntries onto the end of the array, adjusting
5384e5dd7070Spatrick // each for the element size.
5385e5dd7070Spatrick for (size_t i = 0; i != numEltEntries; ++i) {
5386e5dd7070Spatrick auto firstEntry = IvarsInfo[oldEnd + i];
5387e5dd7070Spatrick IvarsInfo.push_back(IvarInfo(firstEntry.Offset + eltIndex * eltSize,
5388e5dd7070Spatrick firstEntry.SizeInWords));
5389e5dd7070Spatrick }
5390e5dd7070Spatrick }
5391e5dd7070Spatrick }
5392e5dd7070Spatrick
5393e5dd7070Spatrick return;
5394e5dd7070Spatrick }
5395e5dd7070Spatrick
5396e5dd7070Spatrick // Classify the element type.
5397e5dd7070Spatrick Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), fieldType);
5398e5dd7070Spatrick
5399e5dd7070Spatrick // If it matches what we're looking for, add an entry.
5400e5dd7070Spatrick if ((ForStrongLayout && GCAttr == Qualifiers::Strong)
5401e5dd7070Spatrick || (!ForStrongLayout && GCAttr == Qualifiers::Weak)) {
5402e5dd7070Spatrick assert(CGM.getContext().getTypeSizeInChars(fieldType)
5403e5dd7070Spatrick == CGM.getPointerSize());
5404e5dd7070Spatrick IvarsInfo.push_back(IvarInfo(fieldOffset, numElts));
5405e5dd7070Spatrick }
5406e5dd7070Spatrick }
5407e5dd7070Spatrick
5408e5dd7070Spatrick /// buildBitmap - This routine does the horsework of taking the offsets of
5409e5dd7070Spatrick /// strong/weak references and creating a bitmap. The bitmap is also
5410e5dd7070Spatrick /// returned in the given buffer, suitable for being passed to \c dump().
buildBitmap(CGObjCCommonMac & CGObjC,llvm::SmallVectorImpl<unsigned char> & buffer)5411e5dd7070Spatrick llvm::Constant *IvarLayoutBuilder::buildBitmap(CGObjCCommonMac &CGObjC,
5412e5dd7070Spatrick llvm::SmallVectorImpl<unsigned char> &buffer) {
5413e5dd7070Spatrick // The bitmap is a series of skip/scan instructions, aligned to word
5414e5dd7070Spatrick // boundaries. The skip is performed first.
5415e5dd7070Spatrick const unsigned char MaxNibble = 0xF;
5416e5dd7070Spatrick const unsigned char SkipMask = 0xF0, SkipShift = 4;
5417e5dd7070Spatrick const unsigned char ScanMask = 0x0F, ScanShift = 0;
5418e5dd7070Spatrick
5419e5dd7070Spatrick assert(!IvarsInfo.empty() && "generating bitmap for no data");
5420e5dd7070Spatrick
5421e5dd7070Spatrick // Sort the ivar info on byte position in case we encounterred a
5422e5dd7070Spatrick // union nested in the ivar list.
5423e5dd7070Spatrick if (IsDisordered) {
5424e5dd7070Spatrick // This isn't a stable sort, but our algorithm should handle it fine.
5425e5dd7070Spatrick llvm::array_pod_sort(IvarsInfo.begin(), IvarsInfo.end());
5426e5dd7070Spatrick } else {
5427ec727ea7Spatrick assert(llvm::is_sorted(IvarsInfo));
5428e5dd7070Spatrick }
5429e5dd7070Spatrick assert(IvarsInfo.back().Offset < InstanceEnd);
5430e5dd7070Spatrick
5431e5dd7070Spatrick assert(buffer.empty());
5432e5dd7070Spatrick
5433e5dd7070Spatrick // Skip the next N words.
5434e5dd7070Spatrick auto skip = [&](unsigned numWords) {
5435e5dd7070Spatrick assert(numWords > 0);
5436e5dd7070Spatrick
5437e5dd7070Spatrick // Try to merge into the previous byte. Since scans happen second, we
5438e5dd7070Spatrick // can't do this if it includes a scan.
5439e5dd7070Spatrick if (!buffer.empty() && !(buffer.back() & ScanMask)) {
5440e5dd7070Spatrick unsigned lastSkip = buffer.back() >> SkipShift;
5441e5dd7070Spatrick if (lastSkip < MaxNibble) {
5442e5dd7070Spatrick unsigned claimed = std::min(MaxNibble - lastSkip, numWords);
5443e5dd7070Spatrick numWords -= claimed;
5444e5dd7070Spatrick lastSkip += claimed;
5445e5dd7070Spatrick buffer.back() = (lastSkip << SkipShift);
5446e5dd7070Spatrick }
5447e5dd7070Spatrick }
5448e5dd7070Spatrick
5449e5dd7070Spatrick while (numWords >= MaxNibble) {
5450e5dd7070Spatrick buffer.push_back(MaxNibble << SkipShift);
5451e5dd7070Spatrick numWords -= MaxNibble;
5452e5dd7070Spatrick }
5453e5dd7070Spatrick if (numWords) {
5454e5dd7070Spatrick buffer.push_back(numWords << SkipShift);
5455e5dd7070Spatrick }
5456e5dd7070Spatrick };
5457e5dd7070Spatrick
5458e5dd7070Spatrick // Scan the next N words.
5459e5dd7070Spatrick auto scan = [&](unsigned numWords) {
5460e5dd7070Spatrick assert(numWords > 0);
5461e5dd7070Spatrick
5462e5dd7070Spatrick // Try to merge into the previous byte. Since scans happen second, we can
5463e5dd7070Spatrick // do this even if it includes a skip.
5464e5dd7070Spatrick if (!buffer.empty()) {
5465e5dd7070Spatrick unsigned lastScan = (buffer.back() & ScanMask) >> ScanShift;
5466e5dd7070Spatrick if (lastScan < MaxNibble) {
5467e5dd7070Spatrick unsigned claimed = std::min(MaxNibble - lastScan, numWords);
5468e5dd7070Spatrick numWords -= claimed;
5469e5dd7070Spatrick lastScan += claimed;
5470e5dd7070Spatrick buffer.back() = (buffer.back() & SkipMask) | (lastScan << ScanShift);
5471e5dd7070Spatrick }
5472e5dd7070Spatrick }
5473e5dd7070Spatrick
5474e5dd7070Spatrick while (numWords >= MaxNibble) {
5475e5dd7070Spatrick buffer.push_back(MaxNibble << ScanShift);
5476e5dd7070Spatrick numWords -= MaxNibble;
5477e5dd7070Spatrick }
5478e5dd7070Spatrick if (numWords) {
5479e5dd7070Spatrick buffer.push_back(numWords << ScanShift);
5480e5dd7070Spatrick }
5481e5dd7070Spatrick };
5482e5dd7070Spatrick
5483e5dd7070Spatrick // One past the end of the last scan.
5484e5dd7070Spatrick unsigned endOfLastScanInWords = 0;
5485e5dd7070Spatrick const CharUnits WordSize = CGM.getPointerSize();
5486e5dd7070Spatrick
5487e5dd7070Spatrick // Consider all the scan requests.
5488e5dd7070Spatrick for (auto &request : IvarsInfo) {
5489e5dd7070Spatrick CharUnits beginOfScan = request.Offset - InstanceBegin;
5490e5dd7070Spatrick
5491e5dd7070Spatrick // Ignore scan requests that don't start at an even multiple of the
5492e5dd7070Spatrick // word size. We can't encode them.
5493e5dd7070Spatrick if ((beginOfScan % WordSize) != 0) continue;
5494e5dd7070Spatrick
5495e5dd7070Spatrick // Ignore scan requests that start before the instance start.
5496e5dd7070Spatrick // This assumes that scans never span that boundary. The boundary
5497e5dd7070Spatrick // isn't the true start of the ivars, because in the fragile-ARC case
5498e5dd7070Spatrick // it's rounded up to word alignment, but the test above should leave
5499e5dd7070Spatrick // us ignoring that possibility.
5500e5dd7070Spatrick if (beginOfScan.isNegative()) {
5501e5dd7070Spatrick assert(request.Offset + request.SizeInWords * WordSize <= InstanceBegin);
5502e5dd7070Spatrick continue;
5503e5dd7070Spatrick }
5504e5dd7070Spatrick
5505e5dd7070Spatrick unsigned beginOfScanInWords = beginOfScan / WordSize;
5506e5dd7070Spatrick unsigned endOfScanInWords = beginOfScanInWords + request.SizeInWords;
5507e5dd7070Spatrick
5508e5dd7070Spatrick // If the scan starts some number of words after the last one ended,
5509e5dd7070Spatrick // skip forward.
5510e5dd7070Spatrick if (beginOfScanInWords > endOfLastScanInWords) {
5511e5dd7070Spatrick skip(beginOfScanInWords - endOfLastScanInWords);
5512e5dd7070Spatrick
5513e5dd7070Spatrick // Otherwise, start scanning where the last left off.
5514e5dd7070Spatrick } else {
5515e5dd7070Spatrick beginOfScanInWords = endOfLastScanInWords;
5516e5dd7070Spatrick
5517e5dd7070Spatrick // If that leaves us with nothing to scan, ignore this request.
5518e5dd7070Spatrick if (beginOfScanInWords >= endOfScanInWords) continue;
5519e5dd7070Spatrick }
5520e5dd7070Spatrick
5521e5dd7070Spatrick // Scan to the end of the request.
5522e5dd7070Spatrick assert(beginOfScanInWords < endOfScanInWords);
5523e5dd7070Spatrick scan(endOfScanInWords - beginOfScanInWords);
5524e5dd7070Spatrick endOfLastScanInWords = endOfScanInWords;
5525e5dd7070Spatrick }
5526e5dd7070Spatrick
5527e5dd7070Spatrick if (buffer.empty())
5528e5dd7070Spatrick return llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
5529e5dd7070Spatrick
5530e5dd7070Spatrick // For GC layouts, emit a skip to the end of the allocation so that we
5531e5dd7070Spatrick // have precise information about the entire thing. This isn't useful
5532e5dd7070Spatrick // or necessary for the ARC-style layout strings.
5533e5dd7070Spatrick if (CGM.getLangOpts().getGC() != LangOptions::NonGC) {
5534e5dd7070Spatrick unsigned lastOffsetInWords =
5535e5dd7070Spatrick (InstanceEnd - InstanceBegin + WordSize - CharUnits::One()) / WordSize;
5536e5dd7070Spatrick if (lastOffsetInWords > endOfLastScanInWords) {
5537e5dd7070Spatrick skip(lastOffsetInWords - endOfLastScanInWords);
5538e5dd7070Spatrick }
5539e5dd7070Spatrick }
5540e5dd7070Spatrick
5541e5dd7070Spatrick // Null terminate the string.
5542e5dd7070Spatrick buffer.push_back(0);
5543e5dd7070Spatrick
5544e5dd7070Spatrick auto *Entry = CGObjC.CreateCStringLiteral(
5545e5dd7070Spatrick reinterpret_cast<char *>(buffer.data()), ObjCLabelType::ClassName);
5546e5dd7070Spatrick return getConstantGEP(CGM.getLLVMContext(), Entry, 0, 0);
5547e5dd7070Spatrick }
5548e5dd7070Spatrick
5549e5dd7070Spatrick /// BuildIvarLayout - Builds ivar layout bitmap for the class
5550e5dd7070Spatrick /// implementation for the __strong or __weak case.
5551e5dd7070Spatrick /// The layout map displays which words in ivar list must be skipped
5552e5dd7070Spatrick /// and which must be scanned by GC (see below). String is built of bytes.
5553e5dd7070Spatrick /// Each byte is divided up in two nibbles (4-bit each). Left nibble is count
5554e5dd7070Spatrick /// of words to skip and right nibble is count of words to scan. So, each
5555e5dd7070Spatrick /// nibble represents up to 15 workds to skip or scan. Skipping the rest is
5556e5dd7070Spatrick /// represented by a 0x00 byte which also ends the string.
5557e5dd7070Spatrick /// 1. when ForStrongLayout is true, following ivars are scanned:
5558e5dd7070Spatrick /// - id, Class
5559e5dd7070Spatrick /// - object *
5560e5dd7070Spatrick /// - __strong anything
5561e5dd7070Spatrick ///
5562e5dd7070Spatrick /// 2. When ForStrongLayout is false, following ivars are scanned:
5563e5dd7070Spatrick /// - __weak anything
5564e5dd7070Spatrick ///
5565e5dd7070Spatrick llvm::Constant *
BuildIvarLayout(const ObjCImplementationDecl * OMD,CharUnits beginOffset,CharUnits endOffset,bool ForStrongLayout,bool HasMRCWeakIvars)5566e5dd7070Spatrick CGObjCCommonMac::BuildIvarLayout(const ObjCImplementationDecl *OMD,
5567e5dd7070Spatrick CharUnits beginOffset, CharUnits endOffset,
5568e5dd7070Spatrick bool ForStrongLayout, bool HasMRCWeakIvars) {
5569e5dd7070Spatrick // If this is MRC, and we're either building a strong layout or there
5570e5dd7070Spatrick // are no weak ivars, bail out early.
5571e5dd7070Spatrick llvm::Type *PtrTy = CGM.Int8PtrTy;
5572e5dd7070Spatrick if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
5573e5dd7070Spatrick !CGM.getLangOpts().ObjCAutoRefCount &&
5574e5dd7070Spatrick (ForStrongLayout || !HasMRCWeakIvars))
5575e5dd7070Spatrick return llvm::Constant::getNullValue(PtrTy);
5576e5dd7070Spatrick
5577e5dd7070Spatrick const ObjCInterfaceDecl *OI = OMD->getClassInterface();
5578e5dd7070Spatrick SmallVector<const ObjCIvarDecl*, 32> ivars;
5579e5dd7070Spatrick
5580e5dd7070Spatrick // GC layout strings include the complete object layout, possibly
5581e5dd7070Spatrick // inaccurately in the non-fragile ABI; the runtime knows how to fix this
5582e5dd7070Spatrick // up.
5583e5dd7070Spatrick //
5584e5dd7070Spatrick // ARC layout strings only include the class's ivars. In non-fragile
5585e5dd7070Spatrick // runtimes, that means starting at InstanceStart, rounded up to word
5586e5dd7070Spatrick // alignment. In fragile runtimes, there's no InstanceStart, so it means
5587e5dd7070Spatrick // starting at the offset of the first ivar, rounded up to word alignment.
5588e5dd7070Spatrick //
5589e5dd7070Spatrick // MRC weak layout strings follow the ARC style.
5590e5dd7070Spatrick CharUnits baseOffset;
5591e5dd7070Spatrick if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
5592e5dd7070Spatrick for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
5593e5dd7070Spatrick IVD; IVD = IVD->getNextIvar())
5594e5dd7070Spatrick ivars.push_back(IVD);
5595e5dd7070Spatrick
5596e5dd7070Spatrick if (isNonFragileABI()) {
5597e5dd7070Spatrick baseOffset = beginOffset; // InstanceStart
5598e5dd7070Spatrick } else if (!ivars.empty()) {
5599e5dd7070Spatrick baseOffset =
5600e5dd7070Spatrick CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivars[0]));
5601e5dd7070Spatrick } else {
5602e5dd7070Spatrick baseOffset = CharUnits::Zero();
5603e5dd7070Spatrick }
5604e5dd7070Spatrick
5605e5dd7070Spatrick baseOffset = baseOffset.alignTo(CGM.getPointerAlign());
5606e5dd7070Spatrick }
5607e5dd7070Spatrick else {
5608e5dd7070Spatrick CGM.getContext().DeepCollectObjCIvars(OI, true, ivars);
5609e5dd7070Spatrick
5610e5dd7070Spatrick baseOffset = CharUnits::Zero();
5611e5dd7070Spatrick }
5612e5dd7070Spatrick
5613e5dd7070Spatrick if (ivars.empty())
5614e5dd7070Spatrick return llvm::Constant::getNullValue(PtrTy);
5615e5dd7070Spatrick
5616e5dd7070Spatrick IvarLayoutBuilder builder(CGM, baseOffset, endOffset, ForStrongLayout);
5617e5dd7070Spatrick
5618e5dd7070Spatrick builder.visitAggregate(ivars.begin(), ivars.end(), CharUnits::Zero(),
5619e5dd7070Spatrick [&](const ObjCIvarDecl *ivar) -> CharUnits {
5620e5dd7070Spatrick return CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivar));
5621e5dd7070Spatrick });
5622e5dd7070Spatrick
5623e5dd7070Spatrick if (!builder.hasBitmapData())
5624e5dd7070Spatrick return llvm::Constant::getNullValue(PtrTy);
5625e5dd7070Spatrick
5626e5dd7070Spatrick llvm::SmallVector<unsigned char, 4> buffer;
5627e5dd7070Spatrick llvm::Constant *C = builder.buildBitmap(*this, buffer);
5628e5dd7070Spatrick
5629e5dd7070Spatrick if (CGM.getLangOpts().ObjCGCBitmapPrint && !buffer.empty()) {
5630e5dd7070Spatrick printf("\n%s ivar layout for class '%s': ",
5631e5dd7070Spatrick ForStrongLayout ? "strong" : "weak",
5632e5dd7070Spatrick OMD->getClassInterface()->getName().str().c_str());
5633e5dd7070Spatrick builder.dump(buffer);
5634e5dd7070Spatrick }
5635e5dd7070Spatrick return C;
5636e5dd7070Spatrick }
5637e5dd7070Spatrick
GetMethodVarName(Selector Sel)5638e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
5639e5dd7070Spatrick llvm::GlobalVariable *&Entry = MethodVarNames[Sel];
5640e5dd7070Spatrick // FIXME: Avoid std::string in "Sel.getAsString()"
5641e5dd7070Spatrick if (!Entry)
5642e5dd7070Spatrick Entry = CreateCStringLiteral(Sel.getAsString(), ObjCLabelType::MethodVarName);
5643e5dd7070Spatrick return getConstantGEP(VMContext, Entry, 0, 0);
5644e5dd7070Spatrick }
5645e5dd7070Spatrick
5646e5dd7070Spatrick // FIXME: Merge into a single cstring creation function.
GetMethodVarName(IdentifierInfo * ID)5647e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::GetMethodVarName(IdentifierInfo *ID) {
5648e5dd7070Spatrick return GetMethodVarName(CGM.getContext().Selectors.getNullarySelector(ID));
5649e5dd7070Spatrick }
5650e5dd7070Spatrick
GetMethodVarType(const FieldDecl * Field)5651e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
5652e5dd7070Spatrick std::string TypeStr;
5653e5dd7070Spatrick CGM.getContext().getObjCEncodingForType(Field->getType(), TypeStr, Field);
5654e5dd7070Spatrick
5655e5dd7070Spatrick llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
5656e5dd7070Spatrick if (!Entry)
5657e5dd7070Spatrick Entry = CreateCStringLiteral(TypeStr, ObjCLabelType::MethodVarType);
5658e5dd7070Spatrick return getConstantGEP(VMContext, Entry, 0, 0);
5659e5dd7070Spatrick }
5660e5dd7070Spatrick
GetMethodVarType(const ObjCMethodDecl * D,bool Extended)5661e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D,
5662e5dd7070Spatrick bool Extended) {
5663e5dd7070Spatrick std::string TypeStr =
5664e5dd7070Spatrick CGM.getContext().getObjCEncodingForMethodDecl(D, Extended);
5665e5dd7070Spatrick
5666e5dd7070Spatrick llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
5667e5dd7070Spatrick if (!Entry)
5668e5dd7070Spatrick Entry = CreateCStringLiteral(TypeStr, ObjCLabelType::MethodVarType);
5669e5dd7070Spatrick return getConstantGEP(VMContext, Entry, 0, 0);
5670e5dd7070Spatrick }
5671e5dd7070Spatrick
5672e5dd7070Spatrick // FIXME: Merge into a single cstring creation function.
GetPropertyName(IdentifierInfo * Ident)5673e5dd7070Spatrick llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
5674e5dd7070Spatrick llvm::GlobalVariable *&Entry = PropertyNames[Ident];
5675e5dd7070Spatrick if (!Entry)
5676e5dd7070Spatrick Entry = CreateCStringLiteral(Ident->getName(), ObjCLabelType::PropertyName);
5677e5dd7070Spatrick return getConstantGEP(VMContext, Entry, 0, 0);
5678e5dd7070Spatrick }
5679e5dd7070Spatrick
5680e5dd7070Spatrick // FIXME: Merge into a single cstring creation function.
5681e5dd7070Spatrick // FIXME: This Decl should be more precise.
5682e5dd7070Spatrick llvm::Constant *
GetPropertyTypeString(const ObjCPropertyDecl * PD,const Decl * Container)5683e5dd7070Spatrick CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
5684e5dd7070Spatrick const Decl *Container) {
5685e5dd7070Spatrick std::string TypeStr =
5686e5dd7070Spatrick CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container);
5687e5dd7070Spatrick return GetPropertyName(&CGM.getContext().Idents.get(TypeStr));
5688e5dd7070Spatrick }
5689e5dd7070Spatrick
FinishModule()5690e5dd7070Spatrick void CGObjCMac::FinishModule() {
5691e5dd7070Spatrick EmitModuleInfo();
5692e5dd7070Spatrick
5693e5dd7070Spatrick // Emit the dummy bodies for any protocols which were referenced but
5694e5dd7070Spatrick // never defined.
5695e5dd7070Spatrick for (auto &entry : Protocols) {
5696e5dd7070Spatrick llvm::GlobalVariable *global = entry.second;
5697e5dd7070Spatrick if (global->hasInitializer())
5698e5dd7070Spatrick continue;
5699e5dd7070Spatrick
5700e5dd7070Spatrick ConstantInitBuilder builder(CGM);
5701e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ProtocolTy);
5702e5dd7070Spatrick values.addNullPointer(ObjCTypes.ProtocolExtensionPtrTy);
5703e5dd7070Spatrick values.add(GetClassName(entry.first->getName()));
5704e5dd7070Spatrick values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
5705e5dd7070Spatrick values.addNullPointer(ObjCTypes.MethodDescriptionListPtrTy);
5706e5dd7070Spatrick values.addNullPointer(ObjCTypes.MethodDescriptionListPtrTy);
5707e5dd7070Spatrick values.finishAndSetAsInitializer(global);
5708e5dd7070Spatrick CGM.addCompilerUsedGlobal(global);
5709e5dd7070Spatrick }
5710e5dd7070Spatrick
5711e5dd7070Spatrick // Add assembler directives to add lazy undefined symbol references
5712e5dd7070Spatrick // for classes which are referenced but not defined. This is
5713e5dd7070Spatrick // important for correct linker interaction.
5714e5dd7070Spatrick //
5715e5dd7070Spatrick // FIXME: It would be nice if we had an LLVM construct for this.
5716e5dd7070Spatrick if ((!LazySymbols.empty() || !DefinedSymbols.empty()) &&
5717e5dd7070Spatrick CGM.getTriple().isOSBinFormatMachO()) {
5718e5dd7070Spatrick SmallString<256> Asm;
5719e5dd7070Spatrick Asm += CGM.getModule().getModuleInlineAsm();
5720e5dd7070Spatrick if (!Asm.empty() && Asm.back() != '\n')
5721e5dd7070Spatrick Asm += '\n';
5722e5dd7070Spatrick
5723e5dd7070Spatrick llvm::raw_svector_ostream OS(Asm);
5724e5dd7070Spatrick for (const auto *Sym : DefinedSymbols)
5725e5dd7070Spatrick OS << "\t.objc_class_name_" << Sym->getName() << "=0\n"
5726e5dd7070Spatrick << "\t.globl .objc_class_name_" << Sym->getName() << "\n";
5727e5dd7070Spatrick for (const auto *Sym : LazySymbols)
5728e5dd7070Spatrick OS << "\t.lazy_reference .objc_class_name_" << Sym->getName() << "\n";
5729e5dd7070Spatrick for (const auto &Category : DefinedCategoryNames)
5730e5dd7070Spatrick OS << "\t.objc_category_name_" << Category << "=0\n"
5731e5dd7070Spatrick << "\t.globl .objc_category_name_" << Category << "\n";
5732e5dd7070Spatrick
5733e5dd7070Spatrick CGM.getModule().setModuleInlineAsm(OS.str());
5734e5dd7070Spatrick }
5735e5dd7070Spatrick }
5736e5dd7070Spatrick
CGObjCNonFragileABIMac(CodeGen::CodeGenModule & cgm)5737e5dd7070Spatrick CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
5738e5dd7070Spatrick : CGObjCCommonMac(cgm), ObjCTypes(cgm), ObjCEmptyCacheVar(nullptr),
5739e5dd7070Spatrick ObjCEmptyVtableVar(nullptr) {
5740e5dd7070Spatrick ObjCABI = 2;
5741e5dd7070Spatrick }
5742e5dd7070Spatrick
5743e5dd7070Spatrick /* *** */
5744e5dd7070Spatrick
ObjCCommonTypesHelper(CodeGen::CodeGenModule & cgm)5745e5dd7070Spatrick ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
5746e5dd7070Spatrick : VMContext(cgm.getLLVMContext()), CGM(cgm), ExternalProtocolPtrTy(nullptr)
5747e5dd7070Spatrick {
5748e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
5749e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
5750*12c85518Srobert unsigned ProgramAS = CGM.getDataLayout().getProgramAddressSpace();
5751e5dd7070Spatrick
5752e5dd7070Spatrick ShortTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.ShortTy));
5753e5dd7070Spatrick IntTy = CGM.IntTy;
5754e5dd7070Spatrick LongTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.LongTy));
5755e5dd7070Spatrick Int8PtrTy = CGM.Int8PtrTy;
5756*12c85518Srobert Int8PtrProgramASTy = llvm::PointerType::get(CGM.Int8Ty, ProgramAS);
5757e5dd7070Spatrick Int8PtrPtrTy = CGM.Int8PtrPtrTy;
5758e5dd7070Spatrick
5759e5dd7070Spatrick // arm64 targets use "int" ivar offset variables. All others,
5760e5dd7070Spatrick // including OS X x86_64 and Windows x86_64, use "long" ivar offsets.
5761e5dd7070Spatrick if (CGM.getTarget().getTriple().getArch() == llvm::Triple::aarch64)
5762e5dd7070Spatrick IvarOffsetVarTy = IntTy;
5763e5dd7070Spatrick else
5764e5dd7070Spatrick IvarOffsetVarTy = LongTy;
5765e5dd7070Spatrick
5766e5dd7070Spatrick ObjectPtrTy =
5767e5dd7070Spatrick cast<llvm::PointerType>(Types.ConvertType(Ctx.getObjCIdType()));
5768e5dd7070Spatrick PtrObjectPtrTy =
5769e5dd7070Spatrick llvm::PointerType::getUnqual(ObjectPtrTy);
5770e5dd7070Spatrick SelectorPtrTy =
5771e5dd7070Spatrick cast<llvm::PointerType>(Types.ConvertType(Ctx.getObjCSelType()));
5772e5dd7070Spatrick
5773e5dd7070Spatrick // I'm not sure I like this. The implicit coordination is a bit
5774e5dd7070Spatrick // gross. We should solve this in a reasonable fashion because this
5775e5dd7070Spatrick // is a pretty common task (match some runtime data structure with
5776e5dd7070Spatrick // an LLVM data structure).
5777e5dd7070Spatrick
5778e5dd7070Spatrick // FIXME: This is leaked.
5779e5dd7070Spatrick // FIXME: Merge with rewriter code?
5780e5dd7070Spatrick
5781e5dd7070Spatrick // struct _objc_super {
5782e5dd7070Spatrick // id self;
5783e5dd7070Spatrick // Class cls;
5784e5dd7070Spatrick // }
5785e5dd7070Spatrick RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
5786e5dd7070Spatrick Ctx.getTranslationUnitDecl(),
5787e5dd7070Spatrick SourceLocation(), SourceLocation(),
5788e5dd7070Spatrick &Ctx.Idents.get("_objc_super"));
5789e5dd7070Spatrick RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
5790e5dd7070Spatrick nullptr, Ctx.getObjCIdType(), nullptr, nullptr,
5791e5dd7070Spatrick false, ICIS_NoInit));
5792e5dd7070Spatrick RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
5793e5dd7070Spatrick nullptr, Ctx.getObjCClassType(), nullptr,
5794e5dd7070Spatrick nullptr, false, ICIS_NoInit));
5795e5dd7070Spatrick RD->completeDefinition();
5796e5dd7070Spatrick
5797e5dd7070Spatrick SuperCTy = Ctx.getTagDeclType(RD);
5798e5dd7070Spatrick SuperPtrCTy = Ctx.getPointerType(SuperCTy);
5799e5dd7070Spatrick
5800e5dd7070Spatrick SuperTy = cast<llvm::StructType>(Types.ConvertType(SuperCTy));
5801e5dd7070Spatrick SuperPtrTy = llvm::PointerType::getUnqual(SuperTy);
5802e5dd7070Spatrick
5803e5dd7070Spatrick // struct _prop_t {
5804e5dd7070Spatrick // char *name;
5805e5dd7070Spatrick // char *attributes;
5806e5dd7070Spatrick // }
5807e5dd7070Spatrick PropertyTy = llvm::StructType::create("struct._prop_t", Int8PtrTy, Int8PtrTy);
5808e5dd7070Spatrick
5809e5dd7070Spatrick // struct _prop_list_t {
5810e5dd7070Spatrick // uint32_t entsize; // sizeof(struct _prop_t)
5811e5dd7070Spatrick // uint32_t count_of_properties;
5812e5dd7070Spatrick // struct _prop_t prop_list[count_of_properties];
5813e5dd7070Spatrick // }
5814e5dd7070Spatrick PropertyListTy = llvm::StructType::create(
5815e5dd7070Spatrick "struct._prop_list_t", IntTy, IntTy, llvm::ArrayType::get(PropertyTy, 0));
5816e5dd7070Spatrick // struct _prop_list_t *
5817e5dd7070Spatrick PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
5818e5dd7070Spatrick
5819e5dd7070Spatrick // struct _objc_method {
5820e5dd7070Spatrick // SEL _cmd;
5821e5dd7070Spatrick // char *method_type;
5822e5dd7070Spatrick // char *_imp;
5823e5dd7070Spatrick // }
5824e5dd7070Spatrick MethodTy = llvm::StructType::create("struct._objc_method", SelectorPtrTy,
5825*12c85518Srobert Int8PtrTy, Int8PtrProgramASTy);
5826e5dd7070Spatrick
5827e5dd7070Spatrick // struct _objc_cache *
5828e5dd7070Spatrick CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
5829e5dd7070Spatrick CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
5830e5dd7070Spatrick }
5831e5dd7070Spatrick
ObjCTypesHelper(CodeGen::CodeGenModule & cgm)5832e5dd7070Spatrick ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
5833e5dd7070Spatrick : ObjCCommonTypesHelper(cgm) {
5834e5dd7070Spatrick // struct _objc_method_description {
5835e5dd7070Spatrick // SEL name;
5836e5dd7070Spatrick // char *types;
5837e5dd7070Spatrick // }
5838e5dd7070Spatrick MethodDescriptionTy = llvm::StructType::create(
5839e5dd7070Spatrick "struct._objc_method_description", SelectorPtrTy, Int8PtrTy);
5840e5dd7070Spatrick
5841e5dd7070Spatrick // struct _objc_method_description_list {
5842e5dd7070Spatrick // int count;
5843e5dd7070Spatrick // struct _objc_method_description[1];
5844e5dd7070Spatrick // }
5845e5dd7070Spatrick MethodDescriptionListTy =
5846e5dd7070Spatrick llvm::StructType::create("struct._objc_method_description_list", IntTy,
5847e5dd7070Spatrick llvm::ArrayType::get(MethodDescriptionTy, 0));
5848e5dd7070Spatrick
5849e5dd7070Spatrick // struct _objc_method_description_list *
5850e5dd7070Spatrick MethodDescriptionListPtrTy =
5851e5dd7070Spatrick llvm::PointerType::getUnqual(MethodDescriptionListTy);
5852e5dd7070Spatrick
5853e5dd7070Spatrick // Protocol description structures
5854e5dd7070Spatrick
5855e5dd7070Spatrick // struct _objc_protocol_extension {
5856e5dd7070Spatrick // uint32_t size; // sizeof(struct _objc_protocol_extension)
5857e5dd7070Spatrick // struct _objc_method_description_list *optional_instance_methods;
5858e5dd7070Spatrick // struct _objc_method_description_list *optional_class_methods;
5859e5dd7070Spatrick // struct _objc_property_list *instance_properties;
5860e5dd7070Spatrick // const char ** extendedMethodTypes;
5861e5dd7070Spatrick // struct _objc_property_list *class_properties;
5862e5dd7070Spatrick // }
5863e5dd7070Spatrick ProtocolExtensionTy = llvm::StructType::create(
5864e5dd7070Spatrick "struct._objc_protocol_extension", IntTy, MethodDescriptionListPtrTy,
5865e5dd7070Spatrick MethodDescriptionListPtrTy, PropertyListPtrTy, Int8PtrPtrTy,
5866e5dd7070Spatrick PropertyListPtrTy);
5867e5dd7070Spatrick
5868e5dd7070Spatrick // struct _objc_protocol_extension *
5869e5dd7070Spatrick ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
5870e5dd7070Spatrick
5871e5dd7070Spatrick // Handle recursive construction of Protocol and ProtocolList types
5872e5dd7070Spatrick
5873e5dd7070Spatrick ProtocolTy =
5874e5dd7070Spatrick llvm::StructType::create(VMContext, "struct._objc_protocol");
5875e5dd7070Spatrick
5876e5dd7070Spatrick ProtocolListTy =
5877e5dd7070Spatrick llvm::StructType::create(VMContext, "struct._objc_protocol_list");
5878e5dd7070Spatrick ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy), LongTy,
5879e5dd7070Spatrick llvm::ArrayType::get(ProtocolTy, 0));
5880e5dd7070Spatrick
5881e5dd7070Spatrick // struct _objc_protocol {
5882e5dd7070Spatrick // struct _objc_protocol_extension *isa;
5883e5dd7070Spatrick // char *protocol_name;
5884e5dd7070Spatrick // struct _objc_protocol **_objc_protocol_list;
5885e5dd7070Spatrick // struct _objc_method_description_list *instance_methods;
5886e5dd7070Spatrick // struct _objc_method_description_list *class_methods;
5887e5dd7070Spatrick // }
5888e5dd7070Spatrick ProtocolTy->setBody(ProtocolExtensionPtrTy, Int8PtrTy,
5889e5dd7070Spatrick llvm::PointerType::getUnqual(ProtocolListTy),
5890e5dd7070Spatrick MethodDescriptionListPtrTy, MethodDescriptionListPtrTy);
5891e5dd7070Spatrick
5892e5dd7070Spatrick // struct _objc_protocol_list *
5893e5dd7070Spatrick ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
5894e5dd7070Spatrick
5895e5dd7070Spatrick ProtocolPtrTy = llvm::PointerType::getUnqual(ProtocolTy);
5896e5dd7070Spatrick
5897e5dd7070Spatrick // Class description structures
5898e5dd7070Spatrick
5899e5dd7070Spatrick // struct _objc_ivar {
5900e5dd7070Spatrick // char *ivar_name;
5901e5dd7070Spatrick // char *ivar_type;
5902e5dd7070Spatrick // int ivar_offset;
5903e5dd7070Spatrick // }
5904e5dd7070Spatrick IvarTy = llvm::StructType::create("struct._objc_ivar", Int8PtrTy, Int8PtrTy,
5905e5dd7070Spatrick IntTy);
5906e5dd7070Spatrick
5907e5dd7070Spatrick // struct _objc_ivar_list *
5908e5dd7070Spatrick IvarListTy =
5909e5dd7070Spatrick llvm::StructType::create(VMContext, "struct._objc_ivar_list");
5910e5dd7070Spatrick IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
5911e5dd7070Spatrick
5912e5dd7070Spatrick // struct _objc_method_list *
5913e5dd7070Spatrick MethodListTy =
5914e5dd7070Spatrick llvm::StructType::create(VMContext, "struct._objc_method_list");
5915e5dd7070Spatrick MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
5916e5dd7070Spatrick
5917e5dd7070Spatrick // struct _objc_class_extension *
5918e5dd7070Spatrick ClassExtensionTy = llvm::StructType::create(
5919e5dd7070Spatrick "struct._objc_class_extension", IntTy, Int8PtrTy, PropertyListPtrTy);
5920e5dd7070Spatrick ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
5921e5dd7070Spatrick
5922e5dd7070Spatrick ClassTy = llvm::StructType::create(VMContext, "struct._objc_class");
5923e5dd7070Spatrick
5924e5dd7070Spatrick // struct _objc_class {
5925e5dd7070Spatrick // Class isa;
5926e5dd7070Spatrick // Class super_class;
5927e5dd7070Spatrick // char *name;
5928e5dd7070Spatrick // long version;
5929e5dd7070Spatrick // long info;
5930e5dd7070Spatrick // long instance_size;
5931e5dd7070Spatrick // struct _objc_ivar_list *ivars;
5932e5dd7070Spatrick // struct _objc_method_list *methods;
5933e5dd7070Spatrick // struct _objc_cache *cache;
5934e5dd7070Spatrick // struct _objc_protocol_list *protocols;
5935e5dd7070Spatrick // char *ivar_layout;
5936e5dd7070Spatrick // struct _objc_class_ext *ext;
5937e5dd7070Spatrick // };
5938e5dd7070Spatrick ClassTy->setBody(llvm::PointerType::getUnqual(ClassTy),
5939e5dd7070Spatrick llvm::PointerType::getUnqual(ClassTy), Int8PtrTy, LongTy,
5940e5dd7070Spatrick LongTy, LongTy, IvarListPtrTy, MethodListPtrTy, CachePtrTy,
5941e5dd7070Spatrick ProtocolListPtrTy, Int8PtrTy, ClassExtensionPtrTy);
5942e5dd7070Spatrick
5943e5dd7070Spatrick ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
5944e5dd7070Spatrick
5945e5dd7070Spatrick // struct _objc_category {
5946e5dd7070Spatrick // char *category_name;
5947e5dd7070Spatrick // char *class_name;
5948e5dd7070Spatrick // struct _objc_method_list *instance_method;
5949e5dd7070Spatrick // struct _objc_method_list *class_method;
5950e5dd7070Spatrick // struct _objc_protocol_list *protocols;
5951e5dd7070Spatrick // uint32_t size; // sizeof(struct _objc_category)
5952e5dd7070Spatrick // struct _objc_property_list *instance_properties;// category's @property
5953e5dd7070Spatrick // struct _objc_property_list *class_properties;
5954e5dd7070Spatrick // }
5955e5dd7070Spatrick CategoryTy = llvm::StructType::create(
5956e5dd7070Spatrick "struct._objc_category", Int8PtrTy, Int8PtrTy, MethodListPtrTy,
5957e5dd7070Spatrick MethodListPtrTy, ProtocolListPtrTy, IntTy, PropertyListPtrTy,
5958e5dd7070Spatrick PropertyListPtrTy);
5959e5dd7070Spatrick
5960e5dd7070Spatrick // Global metadata structures
5961e5dd7070Spatrick
5962e5dd7070Spatrick // struct _objc_symtab {
5963e5dd7070Spatrick // long sel_ref_cnt;
5964e5dd7070Spatrick // SEL *refs;
5965e5dd7070Spatrick // short cls_def_cnt;
5966e5dd7070Spatrick // short cat_def_cnt;
5967e5dd7070Spatrick // char *defs[cls_def_cnt + cat_def_cnt];
5968e5dd7070Spatrick // }
5969e5dd7070Spatrick SymtabTy = llvm::StructType::create("struct._objc_symtab", LongTy,
5970e5dd7070Spatrick SelectorPtrTy, ShortTy, ShortTy,
5971e5dd7070Spatrick llvm::ArrayType::get(Int8PtrTy, 0));
5972e5dd7070Spatrick SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
5973e5dd7070Spatrick
5974e5dd7070Spatrick // struct _objc_module {
5975e5dd7070Spatrick // long version;
5976e5dd7070Spatrick // long size; // sizeof(struct _objc_module)
5977e5dd7070Spatrick // char *name;
5978e5dd7070Spatrick // struct _objc_symtab* symtab;
5979e5dd7070Spatrick // }
5980e5dd7070Spatrick ModuleTy = llvm::StructType::create("struct._objc_module", LongTy, LongTy,
5981e5dd7070Spatrick Int8PtrTy, SymtabPtrTy);
5982e5dd7070Spatrick
5983e5dd7070Spatrick // FIXME: This is the size of the setjmp buffer and should be target
5984e5dd7070Spatrick // specific. 18 is what's used on 32-bit X86.
5985e5dd7070Spatrick uint64_t SetJmpBufferSize = 18;
5986e5dd7070Spatrick
5987e5dd7070Spatrick // Exceptions
5988e5dd7070Spatrick llvm::Type *StackPtrTy = llvm::ArrayType::get(CGM.Int8PtrTy, 4);
5989e5dd7070Spatrick
5990e5dd7070Spatrick ExceptionDataTy = llvm::StructType::create(
5991e5dd7070Spatrick "struct._objc_exception_data",
5992e5dd7070Spatrick llvm::ArrayType::get(CGM.Int32Ty, SetJmpBufferSize), StackPtrTy);
5993e5dd7070Spatrick }
5994e5dd7070Spatrick
ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule & cgm)5995e5dd7070Spatrick ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm)
5996e5dd7070Spatrick : ObjCCommonTypesHelper(cgm) {
5997e5dd7070Spatrick // struct _method_list_t {
5998e5dd7070Spatrick // uint32_t entsize; // sizeof(struct _objc_method)
5999e5dd7070Spatrick // uint32_t method_count;
6000e5dd7070Spatrick // struct _objc_method method_list[method_count];
6001e5dd7070Spatrick // }
6002e5dd7070Spatrick MethodListnfABITy =
6003e5dd7070Spatrick llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
6004e5dd7070Spatrick llvm::ArrayType::get(MethodTy, 0));
6005e5dd7070Spatrick // struct method_list_t *
6006e5dd7070Spatrick MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
6007e5dd7070Spatrick
6008e5dd7070Spatrick // struct _protocol_t {
6009e5dd7070Spatrick // id isa; // NULL
6010e5dd7070Spatrick // const char * const protocol_name;
6011e5dd7070Spatrick // const struct _protocol_list_t * protocol_list; // super protocols
6012e5dd7070Spatrick // const struct method_list_t * const instance_methods;
6013e5dd7070Spatrick // const struct method_list_t * const class_methods;
6014e5dd7070Spatrick // const struct method_list_t *optionalInstanceMethods;
6015e5dd7070Spatrick // const struct method_list_t *optionalClassMethods;
6016e5dd7070Spatrick // const struct _prop_list_t * properties;
6017e5dd7070Spatrick // const uint32_t size; // sizeof(struct _protocol_t)
6018e5dd7070Spatrick // const uint32_t flags; // = 0
6019e5dd7070Spatrick // const char ** extendedMethodTypes;
6020e5dd7070Spatrick // const char *demangledName;
6021e5dd7070Spatrick // const struct _prop_list_t * class_properties;
6022e5dd7070Spatrick // }
6023e5dd7070Spatrick
6024e5dd7070Spatrick // Holder for struct _protocol_list_t *
6025e5dd7070Spatrick ProtocolListnfABITy =
6026e5dd7070Spatrick llvm::StructType::create(VMContext, "struct._objc_protocol_list");
6027e5dd7070Spatrick
6028e5dd7070Spatrick ProtocolnfABITy = llvm::StructType::create(
6029e5dd7070Spatrick "struct._protocol_t", ObjectPtrTy, Int8PtrTy,
6030e5dd7070Spatrick llvm::PointerType::getUnqual(ProtocolListnfABITy), MethodListnfABIPtrTy,
6031e5dd7070Spatrick MethodListnfABIPtrTy, MethodListnfABIPtrTy, MethodListnfABIPtrTy,
6032e5dd7070Spatrick PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy, Int8PtrTy,
6033e5dd7070Spatrick PropertyListPtrTy);
6034e5dd7070Spatrick
6035e5dd7070Spatrick // struct _protocol_t*
6036e5dd7070Spatrick ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
6037e5dd7070Spatrick
6038e5dd7070Spatrick // struct _protocol_list_t {
6039e5dd7070Spatrick // long protocol_count; // Note, this is 32/64 bit
6040e5dd7070Spatrick // struct _protocol_t *[protocol_count];
6041e5dd7070Spatrick // }
6042e5dd7070Spatrick ProtocolListnfABITy->setBody(LongTy,
6043e5dd7070Spatrick llvm::ArrayType::get(ProtocolnfABIPtrTy, 0));
6044e5dd7070Spatrick
6045e5dd7070Spatrick // struct _objc_protocol_list*
6046e5dd7070Spatrick ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
6047e5dd7070Spatrick
6048e5dd7070Spatrick // struct _ivar_t {
6049e5dd7070Spatrick // unsigned [long] int *offset; // pointer to ivar offset location
6050e5dd7070Spatrick // char *name;
6051e5dd7070Spatrick // char *type;
6052e5dd7070Spatrick // uint32_t alignment;
6053e5dd7070Spatrick // uint32_t size;
6054e5dd7070Spatrick // }
6055e5dd7070Spatrick IvarnfABITy = llvm::StructType::create(
6056e5dd7070Spatrick "struct._ivar_t", llvm::PointerType::getUnqual(IvarOffsetVarTy),
6057e5dd7070Spatrick Int8PtrTy, Int8PtrTy, IntTy, IntTy);
6058e5dd7070Spatrick
6059e5dd7070Spatrick // struct _ivar_list_t {
6060e5dd7070Spatrick // uint32 entsize; // sizeof(struct _ivar_t)
6061e5dd7070Spatrick // uint32 count;
6062e5dd7070Spatrick // struct _iver_t list[count];
6063e5dd7070Spatrick // }
6064e5dd7070Spatrick IvarListnfABITy =
6065e5dd7070Spatrick llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
6066e5dd7070Spatrick llvm::ArrayType::get(IvarnfABITy, 0));
6067e5dd7070Spatrick
6068e5dd7070Spatrick IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
6069e5dd7070Spatrick
6070e5dd7070Spatrick // struct _class_ro_t {
6071e5dd7070Spatrick // uint32_t const flags;
6072e5dd7070Spatrick // uint32_t const instanceStart;
6073e5dd7070Spatrick // uint32_t const instanceSize;
6074e5dd7070Spatrick // uint32_t const reserved; // only when building for 64bit targets
6075e5dd7070Spatrick // const uint8_t * const ivarLayout;
6076e5dd7070Spatrick // const char *const name;
6077e5dd7070Spatrick // const struct _method_list_t * const baseMethods;
6078e5dd7070Spatrick // const struct _objc_protocol_list *const baseProtocols;
6079e5dd7070Spatrick // const struct _ivar_list_t *const ivars;
6080e5dd7070Spatrick // const uint8_t * const weakIvarLayout;
6081e5dd7070Spatrick // const struct _prop_list_t * const properties;
6082e5dd7070Spatrick // }
6083e5dd7070Spatrick
6084e5dd7070Spatrick // FIXME. Add 'reserved' field in 64bit abi mode!
6085e5dd7070Spatrick ClassRonfABITy = llvm::StructType::create(
6086e5dd7070Spatrick "struct._class_ro_t", IntTy, IntTy, IntTy, Int8PtrTy, Int8PtrTy,
6087e5dd7070Spatrick MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, IvarListnfABIPtrTy,
6088e5dd7070Spatrick Int8PtrTy, PropertyListPtrTy);
6089e5dd7070Spatrick
6090e5dd7070Spatrick // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
6091e5dd7070Spatrick llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
6092e5dd7070Spatrick ImpnfABITy = llvm::FunctionType::get(ObjectPtrTy, params, false)
6093e5dd7070Spatrick ->getPointerTo();
6094e5dd7070Spatrick
6095e5dd7070Spatrick // struct _class_t {
6096e5dd7070Spatrick // struct _class_t *isa;
6097e5dd7070Spatrick // struct _class_t * const superclass;
6098e5dd7070Spatrick // void *cache;
6099e5dd7070Spatrick // IMP *vtable;
6100e5dd7070Spatrick // struct class_ro_t *ro;
6101e5dd7070Spatrick // }
6102e5dd7070Spatrick
6103e5dd7070Spatrick ClassnfABITy = llvm::StructType::create(VMContext, "struct._class_t");
6104e5dd7070Spatrick ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy),
6105e5dd7070Spatrick llvm::PointerType::getUnqual(ClassnfABITy), CachePtrTy,
6106e5dd7070Spatrick llvm::PointerType::getUnqual(ImpnfABITy),
6107e5dd7070Spatrick llvm::PointerType::getUnqual(ClassRonfABITy));
6108e5dd7070Spatrick
6109e5dd7070Spatrick // LLVM for struct _class_t *
6110e5dd7070Spatrick ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
6111e5dd7070Spatrick
6112e5dd7070Spatrick // struct _category_t {
6113e5dd7070Spatrick // const char * const name;
6114e5dd7070Spatrick // struct _class_t *const cls;
6115e5dd7070Spatrick // const struct _method_list_t * const instance_methods;
6116e5dd7070Spatrick // const struct _method_list_t * const class_methods;
6117e5dd7070Spatrick // const struct _protocol_list_t * const protocols;
6118e5dd7070Spatrick // const struct _prop_list_t * const properties;
6119e5dd7070Spatrick // const struct _prop_list_t * const class_properties;
6120e5dd7070Spatrick // const uint32_t size;
6121e5dd7070Spatrick // }
6122e5dd7070Spatrick CategorynfABITy = llvm::StructType::create(
6123e5dd7070Spatrick "struct._category_t", Int8PtrTy, ClassnfABIPtrTy, MethodListnfABIPtrTy,
6124e5dd7070Spatrick MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, PropertyListPtrTy,
6125e5dd7070Spatrick PropertyListPtrTy, IntTy);
6126e5dd7070Spatrick
6127e5dd7070Spatrick // New types for nonfragile abi messaging.
6128e5dd7070Spatrick CodeGen::CodeGenTypes &Types = CGM.getTypes();
6129e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
6130e5dd7070Spatrick
6131e5dd7070Spatrick // MessageRefTy - LLVM for:
6132e5dd7070Spatrick // struct _message_ref_t {
6133e5dd7070Spatrick // IMP messenger;
6134e5dd7070Spatrick // SEL name;
6135e5dd7070Spatrick // };
6136e5dd7070Spatrick
6137e5dd7070Spatrick // First the clang type for struct _message_ref_t
6138e5dd7070Spatrick RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
6139e5dd7070Spatrick Ctx.getTranslationUnitDecl(),
6140e5dd7070Spatrick SourceLocation(), SourceLocation(),
6141e5dd7070Spatrick &Ctx.Idents.get("_message_ref_t"));
6142e5dd7070Spatrick RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
6143e5dd7070Spatrick nullptr, Ctx.VoidPtrTy, nullptr, nullptr, false,
6144e5dd7070Spatrick ICIS_NoInit));
6145e5dd7070Spatrick RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
6146e5dd7070Spatrick nullptr, Ctx.getObjCSelType(), nullptr, nullptr,
6147e5dd7070Spatrick false, ICIS_NoInit));
6148e5dd7070Spatrick RD->completeDefinition();
6149e5dd7070Spatrick
6150e5dd7070Spatrick MessageRefCTy = Ctx.getTagDeclType(RD);
6151e5dd7070Spatrick MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy);
6152e5dd7070Spatrick MessageRefTy = cast<llvm::StructType>(Types.ConvertType(MessageRefCTy));
6153e5dd7070Spatrick
6154e5dd7070Spatrick // MessageRefPtrTy - LLVM for struct _message_ref_t*
6155e5dd7070Spatrick MessageRefPtrTy = llvm::PointerType::getUnqual(MessageRefTy);
6156e5dd7070Spatrick
6157e5dd7070Spatrick // SuperMessageRefTy - LLVM for:
6158e5dd7070Spatrick // struct _super_message_ref_t {
6159e5dd7070Spatrick // SUPER_IMP messenger;
6160e5dd7070Spatrick // SEL name;
6161e5dd7070Spatrick // };
6162e5dd7070Spatrick SuperMessageRefTy = llvm::StructType::create("struct._super_message_ref_t",
6163e5dd7070Spatrick ImpnfABITy, SelectorPtrTy);
6164e5dd7070Spatrick
6165e5dd7070Spatrick // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
6166e5dd7070Spatrick SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
6167e5dd7070Spatrick
6168e5dd7070Spatrick
6169e5dd7070Spatrick // struct objc_typeinfo {
6170e5dd7070Spatrick // const void** vtable; // objc_ehtype_vtable + 2
6171e5dd7070Spatrick // const char* name; // c++ typeinfo string
6172e5dd7070Spatrick // Class cls;
6173e5dd7070Spatrick // };
6174e5dd7070Spatrick EHTypeTy = llvm::StructType::create("struct._objc_typeinfo",
6175e5dd7070Spatrick llvm::PointerType::getUnqual(Int8PtrTy),
6176e5dd7070Spatrick Int8PtrTy, ClassnfABIPtrTy);
6177e5dd7070Spatrick EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
6178e5dd7070Spatrick }
6179e5dd7070Spatrick
ModuleInitFunction()6180e5dd7070Spatrick llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
6181e5dd7070Spatrick FinishNonFragileABIModule();
6182e5dd7070Spatrick
6183e5dd7070Spatrick return nullptr;
6184e5dd7070Spatrick }
6185e5dd7070Spatrick
AddModuleClassList(ArrayRef<llvm::GlobalValue * > Container,StringRef SymbolName,StringRef SectionName)6186e5dd7070Spatrick void CGObjCNonFragileABIMac::AddModuleClassList(
6187e5dd7070Spatrick ArrayRef<llvm::GlobalValue *> Container, StringRef SymbolName,
6188e5dd7070Spatrick StringRef SectionName) {
6189e5dd7070Spatrick unsigned NumClasses = Container.size();
6190e5dd7070Spatrick
6191e5dd7070Spatrick if (!NumClasses)
6192e5dd7070Spatrick return;
6193e5dd7070Spatrick
6194e5dd7070Spatrick SmallVector<llvm::Constant*, 8> Symbols(NumClasses);
6195e5dd7070Spatrick for (unsigned i=0; i<NumClasses; i++)
6196e5dd7070Spatrick Symbols[i] = llvm::ConstantExpr::getBitCast(Container[i],
6197e5dd7070Spatrick ObjCTypes.Int8PtrTy);
6198e5dd7070Spatrick llvm::Constant *Init =
6199e5dd7070Spatrick llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
6200e5dd7070Spatrick Symbols.size()),
6201e5dd7070Spatrick Symbols);
6202e5dd7070Spatrick
6203e5dd7070Spatrick // Section name is obtained by calling GetSectionName, which returns
6204e5dd7070Spatrick // sections in the __DATA segment on MachO.
6205e5dd7070Spatrick assert((!CGM.getTriple().isOSBinFormatMachO() ||
6206e5dd7070Spatrick SectionName.startswith("__DATA")) &&
6207e5dd7070Spatrick "SectionName expected to start with __DATA on MachO");
6208ec727ea7Spatrick llvm::GlobalVariable *GV = new llvm::GlobalVariable(
6209ec727ea7Spatrick CGM.getModule(), Init->getType(), false,
6210ec727ea7Spatrick llvm::GlobalValue::PrivateLinkage, Init, SymbolName);
6211*12c85518Srobert GV->setAlignment(CGM.getDataLayout().getABITypeAlign(Init->getType()));
6212e5dd7070Spatrick GV->setSection(SectionName);
6213e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
6214e5dd7070Spatrick }
6215e5dd7070Spatrick
FinishNonFragileABIModule()6216e5dd7070Spatrick void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
6217e5dd7070Spatrick // nonfragile abi has no module definition.
6218e5dd7070Spatrick
6219e5dd7070Spatrick // Build list of all implemented class addresses in array
6220e5dd7070Spatrick // L_OBJC_LABEL_CLASS_$.
6221e5dd7070Spatrick
6222e5dd7070Spatrick for (unsigned i=0, NumClasses=ImplementedClasses.size(); i<NumClasses; i++) {
6223e5dd7070Spatrick const ObjCInterfaceDecl *ID = ImplementedClasses[i];
6224e5dd7070Spatrick assert(ID);
6225e5dd7070Spatrick if (ObjCImplementationDecl *IMP = ID->getImplementation())
6226e5dd7070Spatrick // We are implementing a weak imported interface. Give it external linkage
6227e5dd7070Spatrick if (ID->isWeakImported() && !IMP->isWeakImported()) {
6228e5dd7070Spatrick DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
6229e5dd7070Spatrick DefinedMetaClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
6230e5dd7070Spatrick }
6231e5dd7070Spatrick }
6232e5dd7070Spatrick
6233e5dd7070Spatrick AddModuleClassList(DefinedClasses, "OBJC_LABEL_CLASS_$",
6234e5dd7070Spatrick GetSectionName("__objc_classlist",
6235e5dd7070Spatrick "regular,no_dead_strip"));
6236e5dd7070Spatrick
6237e5dd7070Spatrick AddModuleClassList(DefinedNonLazyClasses, "OBJC_LABEL_NONLAZY_CLASS_$",
6238e5dd7070Spatrick GetSectionName("__objc_nlclslist",
6239e5dd7070Spatrick "regular,no_dead_strip"));
6240e5dd7070Spatrick
6241e5dd7070Spatrick // Build list of all implemented category addresses in array
6242e5dd7070Spatrick // L_OBJC_LABEL_CATEGORY_$.
6243e5dd7070Spatrick AddModuleClassList(DefinedCategories, "OBJC_LABEL_CATEGORY_$",
6244e5dd7070Spatrick GetSectionName("__objc_catlist",
6245e5dd7070Spatrick "regular,no_dead_strip"));
6246e5dd7070Spatrick AddModuleClassList(DefinedStubCategories, "OBJC_LABEL_STUB_CATEGORY_$",
6247e5dd7070Spatrick GetSectionName("__objc_catlist2",
6248e5dd7070Spatrick "regular,no_dead_strip"));
6249e5dd7070Spatrick AddModuleClassList(DefinedNonLazyCategories, "OBJC_LABEL_NONLAZY_CATEGORY_$",
6250e5dd7070Spatrick GetSectionName("__objc_nlcatlist",
6251e5dd7070Spatrick "regular,no_dead_strip"));
6252e5dd7070Spatrick
6253e5dd7070Spatrick EmitImageInfo();
6254e5dd7070Spatrick }
6255e5dd7070Spatrick
6256e5dd7070Spatrick /// isVTableDispatchedSelector - Returns true if SEL is not in the list of
6257e5dd7070Spatrick /// VTableDispatchMethods; false otherwise. What this means is that
6258e5dd7070Spatrick /// except for the 19 selectors in the list, we generate 32bit-style
6259e5dd7070Spatrick /// message dispatch call for all the rest.
isVTableDispatchedSelector(Selector Sel)6260e5dd7070Spatrick bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
6261e5dd7070Spatrick // At various points we've experimented with using vtable-based
6262e5dd7070Spatrick // dispatch for all methods.
6263e5dd7070Spatrick switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
6264e5dd7070Spatrick case CodeGenOptions::Legacy:
6265e5dd7070Spatrick return false;
6266e5dd7070Spatrick case CodeGenOptions::NonLegacy:
6267e5dd7070Spatrick return true;
6268e5dd7070Spatrick case CodeGenOptions::Mixed:
6269e5dd7070Spatrick break;
6270e5dd7070Spatrick }
6271e5dd7070Spatrick
6272e5dd7070Spatrick // If so, see whether this selector is in the white-list of things which must
6273e5dd7070Spatrick // use the new dispatch convention. We lazily build a dense set for this.
6274e5dd7070Spatrick if (VTableDispatchMethods.empty()) {
6275e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("alloc"));
6276e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("class"));
6277e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("self"));
6278e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("isFlipped"));
6279e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("length"));
6280e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("count"));
6281e5dd7070Spatrick
6282e5dd7070Spatrick // These are vtable-based if GC is disabled.
6283e5dd7070Spatrick // Optimistically use vtable dispatch for hybrid compiles.
6284e5dd7070Spatrick if (CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
6285e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("retain"));
6286e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("release"));
6287e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
6288e5dd7070Spatrick }
6289e5dd7070Spatrick
6290e5dd7070Spatrick VTableDispatchMethods.insert(GetUnarySelector("allocWithZone"));
6291e5dd7070Spatrick VTableDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
6292e5dd7070Spatrick VTableDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
6293e5dd7070Spatrick VTableDispatchMethods.insert(GetUnarySelector("objectForKey"));
6294e5dd7070Spatrick VTableDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
6295e5dd7070Spatrick VTableDispatchMethods.insert(GetUnarySelector("isEqualToString"));
6296e5dd7070Spatrick VTableDispatchMethods.insert(GetUnarySelector("isEqual"));
6297e5dd7070Spatrick
6298e5dd7070Spatrick // These are vtable-based if GC is enabled.
6299e5dd7070Spatrick // Optimistically use vtable dispatch for hybrid compiles.
6300e5dd7070Spatrick if (CGM.getLangOpts().getGC() != LangOptions::NonGC) {
6301e5dd7070Spatrick VTableDispatchMethods.insert(GetNullarySelector("hash"));
6302e5dd7070Spatrick VTableDispatchMethods.insert(GetUnarySelector("addObject"));
6303e5dd7070Spatrick
6304e5dd7070Spatrick // "countByEnumeratingWithState:objects:count"
6305e5dd7070Spatrick IdentifierInfo *KeyIdents[] = {
6306e5dd7070Spatrick &CGM.getContext().Idents.get("countByEnumeratingWithState"),
6307e5dd7070Spatrick &CGM.getContext().Idents.get("objects"),
6308e5dd7070Spatrick &CGM.getContext().Idents.get("count")
6309e5dd7070Spatrick };
6310e5dd7070Spatrick VTableDispatchMethods.insert(
6311e5dd7070Spatrick CGM.getContext().Selectors.getSelector(3, KeyIdents));
6312e5dd7070Spatrick }
6313e5dd7070Spatrick }
6314e5dd7070Spatrick
6315e5dd7070Spatrick return VTableDispatchMethods.count(Sel);
6316e5dd7070Spatrick }
6317e5dd7070Spatrick
6318e5dd7070Spatrick /// BuildClassRoTInitializer - generate meta-data for:
6319e5dd7070Spatrick /// struct _class_ro_t {
6320e5dd7070Spatrick /// uint32_t const flags;
6321e5dd7070Spatrick /// uint32_t const instanceStart;
6322e5dd7070Spatrick /// uint32_t const instanceSize;
6323e5dd7070Spatrick /// uint32_t const reserved; // only when building for 64bit targets
6324e5dd7070Spatrick /// const uint8_t * const ivarLayout;
6325e5dd7070Spatrick /// const char *const name;
6326e5dd7070Spatrick /// const struct _method_list_t * const baseMethods;
6327e5dd7070Spatrick /// const struct _protocol_list_t *const baseProtocols;
6328e5dd7070Spatrick /// const struct _ivar_list_t *const ivars;
6329e5dd7070Spatrick /// const uint8_t * const weakIvarLayout;
6330e5dd7070Spatrick /// const struct _prop_list_t * const properties;
6331e5dd7070Spatrick /// }
6332e5dd7070Spatrick ///
BuildClassRoTInitializer(unsigned flags,unsigned InstanceStart,unsigned InstanceSize,const ObjCImplementationDecl * ID)6333e5dd7070Spatrick llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
6334e5dd7070Spatrick unsigned flags,
6335e5dd7070Spatrick unsigned InstanceStart,
6336e5dd7070Spatrick unsigned InstanceSize,
6337e5dd7070Spatrick const ObjCImplementationDecl *ID) {
6338ec727ea7Spatrick std::string ClassName = std::string(ID->getObjCRuntimeNameAsString());
6339e5dd7070Spatrick
6340e5dd7070Spatrick CharUnits beginInstance = CharUnits::fromQuantity(InstanceStart);
6341e5dd7070Spatrick CharUnits endInstance = CharUnits::fromQuantity(InstanceSize);
6342e5dd7070Spatrick
6343e5dd7070Spatrick bool hasMRCWeak = false;
6344e5dd7070Spatrick if (CGM.getLangOpts().ObjCAutoRefCount)
6345e5dd7070Spatrick flags |= NonFragileABI_Class_CompiledByARC;
6346e5dd7070Spatrick else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID)))
6347e5dd7070Spatrick flags |= NonFragileABI_Class_HasMRCWeakIvars;
6348e5dd7070Spatrick
6349e5dd7070Spatrick ConstantInitBuilder builder(CGM);
6350e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ClassRonfABITy);
6351e5dd7070Spatrick
6352e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, flags);
6353e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, InstanceStart);
6354e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, InstanceSize);
6355e5dd7070Spatrick values.add((flags & NonFragileABI_Class_Meta)
6356e5dd7070Spatrick ? GetIvarLayoutName(nullptr, ObjCTypes)
6357e5dd7070Spatrick : BuildStrongIvarLayout(ID, beginInstance, endInstance));
6358e5dd7070Spatrick values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
6359e5dd7070Spatrick
6360e5dd7070Spatrick // const struct _method_list_t * const baseMethods;
6361e5dd7070Spatrick SmallVector<const ObjCMethodDecl*, 16> methods;
6362e5dd7070Spatrick if (flags & NonFragileABI_Class_Meta) {
6363e5dd7070Spatrick for (const auto *MD : ID->class_methods())
6364e5dd7070Spatrick if (!MD->isDirectMethod())
6365e5dd7070Spatrick methods.push_back(MD);
6366e5dd7070Spatrick } else {
6367e5dd7070Spatrick for (const auto *MD : ID->instance_methods())
6368e5dd7070Spatrick if (!MD->isDirectMethod())
6369e5dd7070Spatrick methods.push_back(MD);
6370e5dd7070Spatrick }
6371e5dd7070Spatrick
6372e5dd7070Spatrick values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
6373e5dd7070Spatrick (flags & NonFragileABI_Class_Meta)
6374e5dd7070Spatrick ? MethodListType::ClassMethods
6375e5dd7070Spatrick : MethodListType::InstanceMethods,
6376e5dd7070Spatrick methods));
6377e5dd7070Spatrick
6378e5dd7070Spatrick const ObjCInterfaceDecl *OID = ID->getClassInterface();
6379e5dd7070Spatrick assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
6380e5dd7070Spatrick values.add(EmitProtocolList("_OBJC_CLASS_PROTOCOLS_$_"
6381e5dd7070Spatrick + OID->getObjCRuntimeNameAsString(),
6382e5dd7070Spatrick OID->all_referenced_protocol_begin(),
6383e5dd7070Spatrick OID->all_referenced_protocol_end()));
6384e5dd7070Spatrick
6385e5dd7070Spatrick if (flags & NonFragileABI_Class_Meta) {
6386e5dd7070Spatrick values.addNullPointer(ObjCTypes.IvarListnfABIPtrTy);
6387e5dd7070Spatrick values.add(GetIvarLayoutName(nullptr, ObjCTypes));
6388e5dd7070Spatrick values.add(EmitPropertyList(
6389e5dd7070Spatrick "_OBJC_$_CLASS_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
6390e5dd7070Spatrick ID, ID->getClassInterface(), ObjCTypes, true));
6391e5dd7070Spatrick } else {
6392e5dd7070Spatrick values.add(EmitIvarList(ID));
6393e5dd7070Spatrick values.add(BuildWeakIvarLayout(ID, beginInstance, endInstance, hasMRCWeak));
6394e5dd7070Spatrick values.add(EmitPropertyList(
6395e5dd7070Spatrick "_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
6396e5dd7070Spatrick ID, ID->getClassInterface(), ObjCTypes, false));
6397e5dd7070Spatrick }
6398e5dd7070Spatrick
6399e5dd7070Spatrick llvm::SmallString<64> roLabel;
6400e5dd7070Spatrick llvm::raw_svector_ostream(roLabel)
6401e5dd7070Spatrick << ((flags & NonFragileABI_Class_Meta) ? "_OBJC_METACLASS_RO_$_"
6402e5dd7070Spatrick : "_OBJC_CLASS_RO_$_")
6403e5dd7070Spatrick << ClassName;
6404e5dd7070Spatrick
6405e5dd7070Spatrick return finishAndCreateGlobal(values, roLabel, CGM);
6406e5dd7070Spatrick }
6407e5dd7070Spatrick
6408e5dd7070Spatrick /// Build the metaclass object for a class.
6409e5dd7070Spatrick ///
6410e5dd7070Spatrick /// struct _class_t {
6411e5dd7070Spatrick /// struct _class_t *isa;
6412e5dd7070Spatrick /// struct _class_t * const superclass;
6413e5dd7070Spatrick /// void *cache;
6414e5dd7070Spatrick /// IMP *vtable;
6415e5dd7070Spatrick /// struct class_ro_t *ro;
6416e5dd7070Spatrick /// }
6417e5dd7070Spatrick ///
6418e5dd7070Spatrick llvm::GlobalVariable *
BuildClassObject(const ObjCInterfaceDecl * CI,bool isMetaclass,llvm::Constant * IsAGV,llvm::Constant * SuperClassGV,llvm::Constant * ClassRoGV,bool HiddenVisibility)6419e5dd7070Spatrick CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI,
6420e5dd7070Spatrick bool isMetaclass,
6421e5dd7070Spatrick llvm::Constant *IsAGV,
6422e5dd7070Spatrick llvm::Constant *SuperClassGV,
6423e5dd7070Spatrick llvm::Constant *ClassRoGV,
6424e5dd7070Spatrick bool HiddenVisibility) {
6425e5dd7070Spatrick ConstantInitBuilder builder(CGM);
6426e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ClassnfABITy);
6427e5dd7070Spatrick values.add(IsAGV);
6428e5dd7070Spatrick if (SuperClassGV) {
6429e5dd7070Spatrick values.add(SuperClassGV);
6430e5dd7070Spatrick } else {
6431e5dd7070Spatrick values.addNullPointer(ObjCTypes.ClassnfABIPtrTy);
6432e5dd7070Spatrick }
6433e5dd7070Spatrick values.add(ObjCEmptyCacheVar);
6434e5dd7070Spatrick values.add(ObjCEmptyVtableVar);
6435e5dd7070Spatrick values.add(ClassRoGV);
6436e5dd7070Spatrick
6437e5dd7070Spatrick llvm::GlobalVariable *GV =
6438e5dd7070Spatrick cast<llvm::GlobalVariable>(GetClassGlobal(CI, isMetaclass, ForDefinition));
6439e5dd7070Spatrick values.finishAndSetAsInitializer(GV);
6440e5dd7070Spatrick
6441e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO())
6442e5dd7070Spatrick GV->setSection("__DATA, __objc_data");
6443*12c85518Srobert GV->setAlignment(CGM.getDataLayout().getABITypeAlign(ObjCTypes.ClassnfABITy));
6444e5dd7070Spatrick if (!CGM.getTriple().isOSBinFormatCOFF())
6445e5dd7070Spatrick if (HiddenVisibility)
6446e5dd7070Spatrick GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
6447e5dd7070Spatrick return GV;
6448e5dd7070Spatrick }
6449e5dd7070Spatrick
ImplementationIsNonLazy(const ObjCImplDecl * OD) const6450e5dd7070Spatrick bool CGObjCNonFragileABIMac::ImplementationIsNonLazy(
6451e5dd7070Spatrick const ObjCImplDecl *OD) const {
6452e5dd7070Spatrick return OD->getClassMethod(GetNullarySelector("load")) != nullptr ||
6453e5dd7070Spatrick OD->getClassInterface()->hasAttr<ObjCNonLazyClassAttr>() ||
6454e5dd7070Spatrick OD->hasAttr<ObjCNonLazyClassAttr>();
6455e5dd7070Spatrick }
6456e5dd7070Spatrick
GetClassSizeInfo(const ObjCImplementationDecl * OID,uint32_t & InstanceStart,uint32_t & InstanceSize)6457e5dd7070Spatrick void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
6458e5dd7070Spatrick uint32_t &InstanceStart,
6459e5dd7070Spatrick uint32_t &InstanceSize) {
6460e5dd7070Spatrick const ASTRecordLayout &RL =
6461e5dd7070Spatrick CGM.getContext().getASTObjCImplementationLayout(OID);
6462e5dd7070Spatrick
6463e5dd7070Spatrick // InstanceSize is really instance end.
6464e5dd7070Spatrick InstanceSize = RL.getDataSize().getQuantity();
6465e5dd7070Spatrick
6466e5dd7070Spatrick // If there are no fields, the start is the same as the end.
6467e5dd7070Spatrick if (!RL.getFieldCount())
6468e5dd7070Spatrick InstanceStart = InstanceSize;
6469e5dd7070Spatrick else
6470e5dd7070Spatrick InstanceStart = RL.getFieldOffset(0) / CGM.getContext().getCharWidth();
6471e5dd7070Spatrick }
6472e5dd7070Spatrick
getStorage(CodeGenModule & CGM,StringRef Name)6473e5dd7070Spatrick static llvm::GlobalValue::DLLStorageClassTypes getStorage(CodeGenModule &CGM,
6474e5dd7070Spatrick StringRef Name) {
6475e5dd7070Spatrick IdentifierInfo &II = CGM.getContext().Idents.get(Name);
6476e5dd7070Spatrick TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl();
6477e5dd7070Spatrick DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
6478e5dd7070Spatrick
6479e5dd7070Spatrick const VarDecl *VD = nullptr;
6480a9ac8606Spatrick for (const auto *Result : DC->lookup(&II))
6481e5dd7070Spatrick if ((VD = dyn_cast<VarDecl>(Result)))
6482e5dd7070Spatrick break;
6483e5dd7070Spatrick
6484e5dd7070Spatrick if (!VD)
6485e5dd7070Spatrick return llvm::GlobalValue::DLLImportStorageClass;
6486e5dd7070Spatrick if (VD->hasAttr<DLLExportAttr>())
6487e5dd7070Spatrick return llvm::GlobalValue::DLLExportStorageClass;
6488e5dd7070Spatrick if (VD->hasAttr<DLLImportAttr>())
6489e5dd7070Spatrick return llvm::GlobalValue::DLLImportStorageClass;
6490e5dd7070Spatrick return llvm::GlobalValue::DefaultStorageClass;
6491e5dd7070Spatrick }
6492e5dd7070Spatrick
GenerateClass(const ObjCImplementationDecl * ID)6493e5dd7070Spatrick void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
6494e5dd7070Spatrick if (!ObjCEmptyCacheVar) {
6495e5dd7070Spatrick ObjCEmptyCacheVar =
6496e5dd7070Spatrick new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.CacheTy, false,
6497e5dd7070Spatrick llvm::GlobalValue::ExternalLinkage, nullptr,
6498e5dd7070Spatrick "_objc_empty_cache");
6499e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatCOFF())
6500e5dd7070Spatrick ObjCEmptyCacheVar->setDLLStorageClass(getStorage(CGM, "_objc_empty_cache"));
6501e5dd7070Spatrick
6502e5dd7070Spatrick // Only OS X with deployment version <10.9 use the empty vtable symbol
6503e5dd7070Spatrick const llvm::Triple &Triple = CGM.getTarget().getTriple();
6504e5dd7070Spatrick if (Triple.isMacOSX() && Triple.isMacOSXVersionLT(10, 9))
6505e5dd7070Spatrick ObjCEmptyVtableVar =
6506e5dd7070Spatrick new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ImpnfABITy, false,
6507e5dd7070Spatrick llvm::GlobalValue::ExternalLinkage, nullptr,
6508e5dd7070Spatrick "_objc_empty_vtable");
6509e5dd7070Spatrick else
6510e5dd7070Spatrick ObjCEmptyVtableVar =
6511e5dd7070Spatrick llvm::ConstantPointerNull::get(ObjCTypes.ImpnfABITy->getPointerTo());
6512e5dd7070Spatrick }
6513e5dd7070Spatrick
6514e5dd7070Spatrick // FIXME: Is this correct (that meta class size is never computed)?
6515e5dd7070Spatrick uint32_t InstanceStart =
6516e5dd7070Spatrick CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassnfABITy);
6517e5dd7070Spatrick uint32_t InstanceSize = InstanceStart;
6518e5dd7070Spatrick uint32_t flags = NonFragileABI_Class_Meta;
6519e5dd7070Spatrick
6520e5dd7070Spatrick llvm::Constant *SuperClassGV, *IsAGV;
6521e5dd7070Spatrick
6522e5dd7070Spatrick const auto *CI = ID->getClassInterface();
6523e5dd7070Spatrick assert(CI && "CGObjCNonFragileABIMac::GenerateClass - class is 0");
6524e5dd7070Spatrick
6525e5dd7070Spatrick // Build the flags for the metaclass.
6526e5dd7070Spatrick bool classIsHidden = (CGM.getTriple().isOSBinFormatCOFF())
6527e5dd7070Spatrick ? !CI->hasAttr<DLLExportAttr>()
6528e5dd7070Spatrick : CI->getVisibility() == HiddenVisibility;
6529e5dd7070Spatrick if (classIsHidden)
6530e5dd7070Spatrick flags |= NonFragileABI_Class_Hidden;
6531e5dd7070Spatrick
6532e5dd7070Spatrick // FIXME: why is this flag set on the metaclass?
6533e5dd7070Spatrick // ObjC metaclasses have no fields and don't really get constructed.
6534e5dd7070Spatrick if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
6535e5dd7070Spatrick flags |= NonFragileABI_Class_HasCXXStructors;
6536e5dd7070Spatrick if (!ID->hasNonZeroConstructors())
6537e5dd7070Spatrick flags |= NonFragileABI_Class_HasCXXDestructorOnly;
6538e5dd7070Spatrick }
6539e5dd7070Spatrick
6540e5dd7070Spatrick if (!CI->getSuperClass()) {
6541e5dd7070Spatrick // class is root
6542e5dd7070Spatrick flags |= NonFragileABI_Class_Root;
6543e5dd7070Spatrick
6544e5dd7070Spatrick SuperClassGV = GetClassGlobal(CI, /*metaclass*/ false, NotForDefinition);
6545e5dd7070Spatrick IsAGV = GetClassGlobal(CI, /*metaclass*/ true, NotForDefinition);
6546e5dd7070Spatrick } else {
6547e5dd7070Spatrick // Has a root. Current class is not a root.
6548e5dd7070Spatrick const ObjCInterfaceDecl *Root = ID->getClassInterface();
6549e5dd7070Spatrick while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
6550e5dd7070Spatrick Root = Super;
6551e5dd7070Spatrick
6552e5dd7070Spatrick const auto *Super = CI->getSuperClass();
6553e5dd7070Spatrick IsAGV = GetClassGlobal(Root, /*metaclass*/ true, NotForDefinition);
6554e5dd7070Spatrick SuperClassGV = GetClassGlobal(Super, /*metaclass*/ true, NotForDefinition);
6555e5dd7070Spatrick }
6556e5dd7070Spatrick
6557e5dd7070Spatrick llvm::GlobalVariable *CLASS_RO_GV =
6558e5dd7070Spatrick BuildClassRoTInitializer(flags, InstanceStart, InstanceSize, ID);
6559e5dd7070Spatrick
6560e5dd7070Spatrick llvm::GlobalVariable *MetaTClass =
6561e5dd7070Spatrick BuildClassObject(CI, /*metaclass*/ true,
6562e5dd7070Spatrick IsAGV, SuperClassGV, CLASS_RO_GV, classIsHidden);
6563e5dd7070Spatrick CGM.setGVProperties(MetaTClass, CI);
6564e5dd7070Spatrick DefinedMetaClasses.push_back(MetaTClass);
6565e5dd7070Spatrick
6566e5dd7070Spatrick // Metadata for the class
6567e5dd7070Spatrick flags = 0;
6568e5dd7070Spatrick if (classIsHidden)
6569e5dd7070Spatrick flags |= NonFragileABI_Class_Hidden;
6570e5dd7070Spatrick
6571e5dd7070Spatrick if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
6572e5dd7070Spatrick flags |= NonFragileABI_Class_HasCXXStructors;
6573e5dd7070Spatrick
6574e5dd7070Spatrick // Set a flag to enable a runtime optimization when a class has
6575e5dd7070Spatrick // fields that require destruction but which don't require
6576e5dd7070Spatrick // anything except zero-initialization during construction. This
6577e5dd7070Spatrick // is most notably true of __strong and __weak types, but you can
6578e5dd7070Spatrick // also imagine there being C++ types with non-trivial default
6579e5dd7070Spatrick // constructors that merely set all fields to null.
6580e5dd7070Spatrick if (!ID->hasNonZeroConstructors())
6581e5dd7070Spatrick flags |= NonFragileABI_Class_HasCXXDestructorOnly;
6582e5dd7070Spatrick }
6583e5dd7070Spatrick
6584e5dd7070Spatrick if (hasObjCExceptionAttribute(CGM.getContext(), CI))
6585e5dd7070Spatrick flags |= NonFragileABI_Class_Exception;
6586e5dd7070Spatrick
6587e5dd7070Spatrick if (!CI->getSuperClass()) {
6588e5dd7070Spatrick flags |= NonFragileABI_Class_Root;
6589e5dd7070Spatrick SuperClassGV = nullptr;
6590e5dd7070Spatrick } else {
6591e5dd7070Spatrick // Has a root. Current class is not a root.
6592e5dd7070Spatrick const auto *Super = CI->getSuperClass();
6593e5dd7070Spatrick SuperClassGV = GetClassGlobal(Super, /*metaclass*/ false, NotForDefinition);
6594e5dd7070Spatrick }
6595e5dd7070Spatrick
6596e5dd7070Spatrick GetClassSizeInfo(ID, InstanceStart, InstanceSize);
6597e5dd7070Spatrick CLASS_RO_GV =
6598e5dd7070Spatrick BuildClassRoTInitializer(flags, InstanceStart, InstanceSize, ID);
6599e5dd7070Spatrick
6600e5dd7070Spatrick llvm::GlobalVariable *ClassMD =
6601e5dd7070Spatrick BuildClassObject(CI, /*metaclass*/ false,
6602e5dd7070Spatrick MetaTClass, SuperClassGV, CLASS_RO_GV, classIsHidden);
6603e5dd7070Spatrick CGM.setGVProperties(ClassMD, CI);
6604e5dd7070Spatrick DefinedClasses.push_back(ClassMD);
6605e5dd7070Spatrick ImplementedClasses.push_back(CI);
6606e5dd7070Spatrick
6607e5dd7070Spatrick // Determine if this class is also "non-lazy".
6608e5dd7070Spatrick if (ImplementationIsNonLazy(ID))
6609e5dd7070Spatrick DefinedNonLazyClasses.push_back(ClassMD);
6610e5dd7070Spatrick
6611e5dd7070Spatrick // Force the definition of the EHType if necessary.
6612e5dd7070Spatrick if (flags & NonFragileABI_Class_Exception)
6613e5dd7070Spatrick (void) GetInterfaceEHType(CI, ForDefinition);
6614e5dd7070Spatrick // Make sure method definition entries are all clear for next implementation.
6615e5dd7070Spatrick MethodDefinitions.clear();
6616e5dd7070Spatrick }
6617e5dd7070Spatrick
6618e5dd7070Spatrick /// GenerateProtocolRef - This routine is called to generate code for
6619e5dd7070Spatrick /// a protocol reference expression; as in:
6620e5dd7070Spatrick /// @code
6621e5dd7070Spatrick /// @protocol(Proto1);
6622e5dd7070Spatrick /// @endcode
6623e5dd7070Spatrick /// It generates a weak reference to l_OBJC_PROTOCOL_REFERENCE_$_Proto1
6624e5dd7070Spatrick /// which will hold address of the protocol meta-data.
6625e5dd7070Spatrick ///
GenerateProtocolRef(CodeGenFunction & CGF,const ObjCProtocolDecl * PD)6626e5dd7070Spatrick llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
6627e5dd7070Spatrick const ObjCProtocolDecl *PD) {
6628e5dd7070Spatrick
6629e5dd7070Spatrick // This routine is called for @protocol only. So, we must build definition
6630e5dd7070Spatrick // of protocol's meta-data (not a reference to it!)
6631a9ac8606Spatrick assert(!PD->isNonRuntimeProtocol() &&
6632a9ac8606Spatrick "attempting to get a protocol ref to a static protocol.");
6633e5dd7070Spatrick llvm::Constant *Init =
6634e5dd7070Spatrick llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD),
6635e5dd7070Spatrick ObjCTypes.getExternalProtocolPtrTy());
6636e5dd7070Spatrick
6637e5dd7070Spatrick std::string ProtocolName("_OBJC_PROTOCOL_REFERENCE_$_");
6638e5dd7070Spatrick ProtocolName += PD->getObjCRuntimeNameAsString();
6639e5dd7070Spatrick
6640e5dd7070Spatrick CharUnits Align = CGF.getPointerAlign();
6641e5dd7070Spatrick
6642e5dd7070Spatrick llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
6643e5dd7070Spatrick if (PTGV)
6644a9ac8606Spatrick return CGF.Builder.CreateAlignedLoad(PTGV->getValueType(), PTGV, Align);
6645e5dd7070Spatrick PTGV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
6646e5dd7070Spatrick llvm::GlobalValue::WeakAnyLinkage, Init,
6647e5dd7070Spatrick ProtocolName);
6648e5dd7070Spatrick PTGV->setSection(GetSectionName("__objc_protorefs",
6649e5dd7070Spatrick "coalesced,no_dead_strip"));
6650e5dd7070Spatrick PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
6651e5dd7070Spatrick PTGV->setAlignment(Align.getAsAlign());
6652e5dd7070Spatrick if (!CGM.getTriple().isOSBinFormatMachO())
6653e5dd7070Spatrick PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolName));
6654e5dd7070Spatrick CGM.addUsedGlobal(PTGV);
6655a9ac8606Spatrick return CGF.Builder.CreateAlignedLoad(PTGV->getValueType(), PTGV, Align);
6656e5dd7070Spatrick }
6657e5dd7070Spatrick
6658e5dd7070Spatrick /// GenerateCategory - Build metadata for a category implementation.
6659e5dd7070Spatrick /// struct _category_t {
6660e5dd7070Spatrick /// const char * const name;
6661e5dd7070Spatrick /// struct _class_t *const cls;
6662e5dd7070Spatrick /// const struct _method_list_t * const instance_methods;
6663e5dd7070Spatrick /// const struct _method_list_t * const class_methods;
6664e5dd7070Spatrick /// const struct _protocol_list_t * const protocols;
6665e5dd7070Spatrick /// const struct _prop_list_t * const properties;
6666e5dd7070Spatrick /// const struct _prop_list_t * const class_properties;
6667e5dd7070Spatrick /// const uint32_t size;
6668e5dd7070Spatrick /// }
6669e5dd7070Spatrick ///
GenerateCategory(const ObjCCategoryImplDecl * OCD)6670e5dd7070Spatrick void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
6671e5dd7070Spatrick const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
6672e5dd7070Spatrick const char *Prefix = "_OBJC_$_CATEGORY_";
6673e5dd7070Spatrick
6674e5dd7070Spatrick llvm::SmallString<64> ExtCatName(Prefix);
6675e5dd7070Spatrick ExtCatName += Interface->getObjCRuntimeNameAsString();
6676e5dd7070Spatrick ExtCatName += "_$_";
6677e5dd7070Spatrick ExtCatName += OCD->getNameAsString();
6678e5dd7070Spatrick
6679e5dd7070Spatrick ConstantInitBuilder builder(CGM);
6680e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.CategorynfABITy);
6681e5dd7070Spatrick values.add(GetClassName(OCD->getIdentifier()->getName()));
6682e5dd7070Spatrick // meta-class entry symbol
6683e5dd7070Spatrick values.add(GetClassGlobal(Interface, /*metaclass*/ false, NotForDefinition));
6684e5dd7070Spatrick std::string listName =
6685e5dd7070Spatrick (Interface->getObjCRuntimeNameAsString() + "_$_" + OCD->getName()).str();
6686e5dd7070Spatrick
6687e5dd7070Spatrick SmallVector<const ObjCMethodDecl *, 16> instanceMethods;
6688e5dd7070Spatrick SmallVector<const ObjCMethodDecl *, 8> classMethods;
6689e5dd7070Spatrick for (const auto *MD : OCD->methods()) {
6690e5dd7070Spatrick if (MD->isDirectMethod())
6691e5dd7070Spatrick continue;
6692e5dd7070Spatrick if (MD->isInstanceMethod()) {
6693e5dd7070Spatrick instanceMethods.push_back(MD);
6694e5dd7070Spatrick } else {
6695e5dd7070Spatrick classMethods.push_back(MD);
6696e5dd7070Spatrick }
6697e5dd7070Spatrick }
6698e5dd7070Spatrick
6699*12c85518Srobert auto instanceMethodList = emitMethodList(
6700*12c85518Srobert listName, MethodListType::CategoryInstanceMethods, instanceMethods);
6701*12c85518Srobert auto classMethodList = emitMethodList(
6702*12c85518Srobert listName, MethodListType::CategoryClassMethods, classMethods);
6703*12c85518Srobert values.add(instanceMethodList);
6704*12c85518Srobert values.add(classMethodList);
6705*12c85518Srobert // Keep track of whether we have actual metadata to emit.
6706*12c85518Srobert bool isEmptyCategory =
6707*12c85518Srobert instanceMethodList->isNullValue() && classMethodList->isNullValue();
6708e5dd7070Spatrick
6709e5dd7070Spatrick const ObjCCategoryDecl *Category =
6710e5dd7070Spatrick Interface->FindCategoryDeclaration(OCD->getIdentifier());
6711e5dd7070Spatrick if (Category) {
6712e5dd7070Spatrick SmallString<256> ExtName;
6713*12c85518Srobert llvm::raw_svector_ostream(ExtName)
6714*12c85518Srobert << Interface->getObjCRuntimeNameAsString() << "_$_" << OCD->getName();
6715*12c85518Srobert auto protocolList =
6716*12c85518Srobert EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_" +
6717*12c85518Srobert Interface->getObjCRuntimeNameAsString() + "_$_" +
6718*12c85518Srobert Category->getName(),
6719*12c85518Srobert Category->protocol_begin(), Category->protocol_end());
6720*12c85518Srobert auto propertyList = EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(),
6721*12c85518Srobert OCD, Category, ObjCTypes, false);
6722*12c85518Srobert auto classPropertyList =
6723*12c85518Srobert EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), OCD,
6724*12c85518Srobert Category, ObjCTypes, true);
6725*12c85518Srobert values.add(protocolList);
6726*12c85518Srobert values.add(propertyList);
6727*12c85518Srobert values.add(classPropertyList);
6728*12c85518Srobert isEmptyCategory &= protocolList->isNullValue() &&
6729*12c85518Srobert propertyList->isNullValue() &&
6730*12c85518Srobert classPropertyList->isNullValue();
6731e5dd7070Spatrick } else {
6732e5dd7070Spatrick values.addNullPointer(ObjCTypes.ProtocolListnfABIPtrTy);
6733e5dd7070Spatrick values.addNullPointer(ObjCTypes.PropertyListPtrTy);
6734e5dd7070Spatrick values.addNullPointer(ObjCTypes.PropertyListPtrTy);
6735e5dd7070Spatrick }
6736e5dd7070Spatrick
6737*12c85518Srobert if (isEmptyCategory) {
6738*12c85518Srobert // Empty category, don't emit any metadata.
6739*12c85518Srobert values.abandon();
6740*12c85518Srobert MethodDefinitions.clear();
6741*12c85518Srobert return;
6742*12c85518Srobert }
6743*12c85518Srobert
6744*12c85518Srobert unsigned Size =
6745*12c85518Srobert CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy);
6746e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, Size);
6747e5dd7070Spatrick
6748e5dd7070Spatrick llvm::GlobalVariable *GCATV =
6749e5dd7070Spatrick finishAndCreateGlobal(values, ExtCatName.str(), CGM);
6750e5dd7070Spatrick CGM.addCompilerUsedGlobal(GCATV);
6751e5dd7070Spatrick if (Interface->hasAttr<ObjCClassStubAttr>())
6752e5dd7070Spatrick DefinedStubCategories.push_back(GCATV);
6753e5dd7070Spatrick else
6754e5dd7070Spatrick DefinedCategories.push_back(GCATV);
6755e5dd7070Spatrick
6756e5dd7070Spatrick // Determine if this category is also "non-lazy".
6757e5dd7070Spatrick if (ImplementationIsNonLazy(OCD))
6758e5dd7070Spatrick DefinedNonLazyCategories.push_back(GCATV);
6759e5dd7070Spatrick // method definition entries must be clear for next implementation.
6760e5dd7070Spatrick MethodDefinitions.clear();
6761e5dd7070Spatrick }
6762e5dd7070Spatrick
6763e5dd7070Spatrick /// emitMethodConstant - Return a struct objc_method constant. If
6764e5dd7070Spatrick /// forProtocol is true, the implementation will be null; otherwise,
6765e5dd7070Spatrick /// the method must have a definition registered with the runtime.
6766e5dd7070Spatrick ///
6767e5dd7070Spatrick /// struct _objc_method {
6768e5dd7070Spatrick /// SEL _cmd;
6769e5dd7070Spatrick /// char *method_type;
6770e5dd7070Spatrick /// char *_imp;
6771e5dd7070Spatrick /// }
emitMethodConstant(ConstantArrayBuilder & builder,const ObjCMethodDecl * MD,bool forProtocol)6772e5dd7070Spatrick void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
6773e5dd7070Spatrick const ObjCMethodDecl *MD,
6774e5dd7070Spatrick bool forProtocol) {
6775e5dd7070Spatrick auto method = builder.beginStruct(ObjCTypes.MethodTy);
6776e5dd7070Spatrick method.addBitCast(GetMethodVarName(MD->getSelector()),
6777e5dd7070Spatrick ObjCTypes.SelectorPtrTy);
6778e5dd7070Spatrick method.add(GetMethodVarType(MD));
6779e5dd7070Spatrick
6780e5dd7070Spatrick if (forProtocol) {
6781e5dd7070Spatrick // Protocol methods have no implementation. So, this entry is always NULL.
6782*12c85518Srobert method.addNullPointer(ObjCTypes.Int8PtrProgramASTy);
6783e5dd7070Spatrick } else {
6784e5dd7070Spatrick llvm::Function *fn = GetMethodDefinition(MD);
6785e5dd7070Spatrick assert(fn && "no definition for method?");
6786*12c85518Srobert method.addBitCast(fn, ObjCTypes.Int8PtrProgramASTy);
6787e5dd7070Spatrick }
6788e5dd7070Spatrick
6789e5dd7070Spatrick method.finishAndAddTo(builder);
6790e5dd7070Spatrick }
6791e5dd7070Spatrick
6792e5dd7070Spatrick /// Build meta-data for method declarations.
6793e5dd7070Spatrick ///
6794e5dd7070Spatrick /// struct _method_list_t {
6795e5dd7070Spatrick /// uint32_t entsize; // sizeof(struct _objc_method)
6796e5dd7070Spatrick /// uint32_t method_count;
6797e5dd7070Spatrick /// struct _objc_method method_list[method_count];
6798e5dd7070Spatrick /// }
6799e5dd7070Spatrick ///
6800e5dd7070Spatrick llvm::Constant *
emitMethodList(Twine name,MethodListType kind,ArrayRef<const ObjCMethodDecl * > methods)6801e5dd7070Spatrick CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind,
6802e5dd7070Spatrick ArrayRef<const ObjCMethodDecl *> methods) {
6803e5dd7070Spatrick // Return null for empty list.
6804e5dd7070Spatrick if (methods.empty())
6805e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy);
6806e5dd7070Spatrick
6807e5dd7070Spatrick StringRef prefix;
6808e5dd7070Spatrick bool forProtocol;
6809e5dd7070Spatrick switch (kind) {
6810e5dd7070Spatrick case MethodListType::CategoryInstanceMethods:
6811e5dd7070Spatrick prefix = "_OBJC_$_CATEGORY_INSTANCE_METHODS_";
6812e5dd7070Spatrick forProtocol = false;
6813e5dd7070Spatrick break;
6814e5dd7070Spatrick case MethodListType::CategoryClassMethods:
6815e5dd7070Spatrick prefix = "_OBJC_$_CATEGORY_CLASS_METHODS_";
6816e5dd7070Spatrick forProtocol = false;
6817e5dd7070Spatrick break;
6818e5dd7070Spatrick case MethodListType::InstanceMethods:
6819e5dd7070Spatrick prefix = "_OBJC_$_INSTANCE_METHODS_";
6820e5dd7070Spatrick forProtocol = false;
6821e5dd7070Spatrick break;
6822e5dd7070Spatrick case MethodListType::ClassMethods:
6823e5dd7070Spatrick prefix = "_OBJC_$_CLASS_METHODS_";
6824e5dd7070Spatrick forProtocol = false;
6825e5dd7070Spatrick break;
6826e5dd7070Spatrick
6827e5dd7070Spatrick case MethodListType::ProtocolInstanceMethods:
6828e5dd7070Spatrick prefix = "_OBJC_$_PROTOCOL_INSTANCE_METHODS_";
6829e5dd7070Spatrick forProtocol = true;
6830e5dd7070Spatrick break;
6831e5dd7070Spatrick case MethodListType::ProtocolClassMethods:
6832e5dd7070Spatrick prefix = "_OBJC_$_PROTOCOL_CLASS_METHODS_";
6833e5dd7070Spatrick forProtocol = true;
6834e5dd7070Spatrick break;
6835e5dd7070Spatrick case MethodListType::OptionalProtocolInstanceMethods:
6836e5dd7070Spatrick prefix = "_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_";
6837e5dd7070Spatrick forProtocol = true;
6838e5dd7070Spatrick break;
6839e5dd7070Spatrick case MethodListType::OptionalProtocolClassMethods:
6840e5dd7070Spatrick prefix = "_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_";
6841e5dd7070Spatrick forProtocol = true;
6842e5dd7070Spatrick break;
6843e5dd7070Spatrick }
6844e5dd7070Spatrick
6845e5dd7070Spatrick ConstantInitBuilder builder(CGM);
6846e5dd7070Spatrick auto values = builder.beginStruct();
6847e5dd7070Spatrick
6848e5dd7070Spatrick // sizeof(struct _objc_method)
6849e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.MethodTy);
6850e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, Size);
6851e5dd7070Spatrick // method_count
6852e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, methods.size());
6853e5dd7070Spatrick auto methodArray = values.beginArray(ObjCTypes.MethodTy);
6854e5dd7070Spatrick for (auto MD : methods)
6855e5dd7070Spatrick emitMethodConstant(methodArray, MD, forProtocol);
6856e5dd7070Spatrick methodArray.finishAndAddTo(values);
6857e5dd7070Spatrick
6858e5dd7070Spatrick llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM);
6859e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
6860e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
6861e5dd7070Spatrick }
6862e5dd7070Spatrick
6863e5dd7070Spatrick /// ObjCIvarOffsetVariable - Returns the ivar offset variable for
6864e5dd7070Spatrick /// the given ivar.
6865e5dd7070Spatrick llvm::GlobalVariable *
ObjCIvarOffsetVariable(const ObjCInterfaceDecl * ID,const ObjCIvarDecl * Ivar)6866e5dd7070Spatrick CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
6867e5dd7070Spatrick const ObjCIvarDecl *Ivar) {
6868e5dd7070Spatrick const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
6869e5dd7070Spatrick llvm::SmallString<64> Name("OBJC_IVAR_$_");
6870e5dd7070Spatrick Name += Container->getObjCRuntimeNameAsString();
6871e5dd7070Spatrick Name += ".";
6872e5dd7070Spatrick Name += Ivar->getName();
6873e5dd7070Spatrick llvm::GlobalVariable *IvarOffsetGV = CGM.getModule().getGlobalVariable(Name);
6874e5dd7070Spatrick if (!IvarOffsetGV) {
6875e5dd7070Spatrick IvarOffsetGV =
6876e5dd7070Spatrick new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.IvarOffsetVarTy,
6877e5dd7070Spatrick false, llvm::GlobalValue::ExternalLinkage,
6878e5dd7070Spatrick nullptr, Name.str());
6879e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatCOFF()) {
6880e5dd7070Spatrick bool IsPrivateOrPackage =
6881e5dd7070Spatrick Ivar->getAccessControl() == ObjCIvarDecl::Private ||
6882e5dd7070Spatrick Ivar->getAccessControl() == ObjCIvarDecl::Package;
6883e5dd7070Spatrick
6884e5dd7070Spatrick const ObjCInterfaceDecl *ContainingID = Ivar->getContainingInterface();
6885e5dd7070Spatrick
6886e5dd7070Spatrick if (ContainingID->hasAttr<DLLImportAttr>())
6887e5dd7070Spatrick IvarOffsetGV
6888e5dd7070Spatrick ->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
6889e5dd7070Spatrick else if (ContainingID->hasAttr<DLLExportAttr>() && !IsPrivateOrPackage)
6890e5dd7070Spatrick IvarOffsetGV
6891e5dd7070Spatrick ->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
6892e5dd7070Spatrick }
6893e5dd7070Spatrick }
6894e5dd7070Spatrick return IvarOffsetGV;
6895e5dd7070Spatrick }
6896e5dd7070Spatrick
6897e5dd7070Spatrick llvm::Constant *
EmitIvarOffsetVar(const ObjCInterfaceDecl * ID,const ObjCIvarDecl * Ivar,unsigned long int Offset)6898e5dd7070Spatrick CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
6899e5dd7070Spatrick const ObjCIvarDecl *Ivar,
6900e5dd7070Spatrick unsigned long int Offset) {
6901e5dd7070Spatrick llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
6902e5dd7070Spatrick IvarOffsetGV->setInitializer(
6903e5dd7070Spatrick llvm::ConstantInt::get(ObjCTypes.IvarOffsetVarTy, Offset));
6904*12c85518Srobert IvarOffsetGV->setAlignment(
6905*12c85518Srobert CGM.getDataLayout().getABITypeAlign(ObjCTypes.IvarOffsetVarTy));
6906e5dd7070Spatrick
6907e5dd7070Spatrick if (!CGM.getTriple().isOSBinFormatCOFF()) {
6908e5dd7070Spatrick // FIXME: This matches gcc, but shouldn't the visibility be set on the use
6909e5dd7070Spatrick // as well (i.e., in ObjCIvarOffsetVariable).
6910e5dd7070Spatrick if (Ivar->getAccessControl() == ObjCIvarDecl::Private ||
6911e5dd7070Spatrick Ivar->getAccessControl() == ObjCIvarDecl::Package ||
6912e5dd7070Spatrick ID->getVisibility() == HiddenVisibility)
6913e5dd7070Spatrick IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
6914e5dd7070Spatrick else
6915e5dd7070Spatrick IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
6916e5dd7070Spatrick }
6917e5dd7070Spatrick
6918e5dd7070Spatrick // If ID's layout is known, then make the global constant. This serves as a
6919e5dd7070Spatrick // useful assertion: we'll never use this variable to calculate ivar offsets,
6920e5dd7070Spatrick // so if the runtime tries to patch it then we should crash.
6921e5dd7070Spatrick if (isClassLayoutKnownStatically(ID))
6922e5dd7070Spatrick IvarOffsetGV->setConstant(true);
6923e5dd7070Spatrick
6924e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO())
6925e5dd7070Spatrick IvarOffsetGV->setSection("__DATA, __objc_ivar");
6926e5dd7070Spatrick return IvarOffsetGV;
6927e5dd7070Spatrick }
6928e5dd7070Spatrick
6929e5dd7070Spatrick /// EmitIvarList - Emit the ivar list for the given
6930e5dd7070Spatrick /// implementation. The return value has type
6931e5dd7070Spatrick /// IvarListnfABIPtrTy.
6932e5dd7070Spatrick /// struct _ivar_t {
6933e5dd7070Spatrick /// unsigned [long] int *offset; // pointer to ivar offset location
6934e5dd7070Spatrick /// char *name;
6935e5dd7070Spatrick /// char *type;
6936e5dd7070Spatrick /// uint32_t alignment;
6937e5dd7070Spatrick /// uint32_t size;
6938e5dd7070Spatrick /// }
6939e5dd7070Spatrick /// struct _ivar_list_t {
6940e5dd7070Spatrick /// uint32 entsize; // sizeof(struct _ivar_t)
6941e5dd7070Spatrick /// uint32 count;
6942e5dd7070Spatrick /// struct _iver_t list[count];
6943e5dd7070Spatrick /// }
6944e5dd7070Spatrick ///
6945e5dd7070Spatrick
EmitIvarList(const ObjCImplementationDecl * ID)6946e5dd7070Spatrick llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
6947e5dd7070Spatrick const ObjCImplementationDecl *ID) {
6948e5dd7070Spatrick
6949e5dd7070Spatrick ConstantInitBuilder builder(CGM);
6950e5dd7070Spatrick auto ivarList = builder.beginStruct();
6951e5dd7070Spatrick ivarList.addInt(ObjCTypes.IntTy,
6952e5dd7070Spatrick CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy));
6953e5dd7070Spatrick auto ivarCountSlot = ivarList.addPlaceholder();
6954e5dd7070Spatrick auto ivars = ivarList.beginArray(ObjCTypes.IvarnfABITy);
6955e5dd7070Spatrick
6956e5dd7070Spatrick const ObjCInterfaceDecl *OID = ID->getClassInterface();
6957e5dd7070Spatrick assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface");
6958e5dd7070Spatrick
6959e5dd7070Spatrick // FIXME. Consolidate this with similar code in GenerateClass.
6960e5dd7070Spatrick
6961e5dd7070Spatrick for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
6962e5dd7070Spatrick IVD; IVD = IVD->getNextIvar()) {
6963e5dd7070Spatrick // Ignore unnamed bit-fields.
6964e5dd7070Spatrick if (!IVD->getDeclName())
6965e5dd7070Spatrick continue;
6966e5dd7070Spatrick
6967e5dd7070Spatrick auto ivar = ivars.beginStruct(ObjCTypes.IvarnfABITy);
6968e5dd7070Spatrick ivar.add(EmitIvarOffsetVar(ID->getClassInterface(), IVD,
6969e5dd7070Spatrick ComputeIvarBaseOffset(CGM, ID, IVD)));
6970e5dd7070Spatrick ivar.add(GetMethodVarName(IVD->getIdentifier()));
6971e5dd7070Spatrick ivar.add(GetMethodVarType(IVD));
6972e5dd7070Spatrick llvm::Type *FieldTy =
6973e5dd7070Spatrick CGM.getTypes().ConvertTypeForMem(IVD->getType());
6974e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(FieldTy);
6975e5dd7070Spatrick unsigned Align = CGM.getContext().getPreferredTypeAlign(
6976e5dd7070Spatrick IVD->getType().getTypePtr()) >> 3;
6977e5dd7070Spatrick Align = llvm::Log2_32(Align);
6978e5dd7070Spatrick ivar.addInt(ObjCTypes.IntTy, Align);
6979e5dd7070Spatrick // NOTE. Size of a bitfield does not match gcc's, because of the
6980e5dd7070Spatrick // way bitfields are treated special in each. But I am told that
6981e5dd7070Spatrick // 'size' for bitfield ivars is ignored by the runtime so it does
6982e5dd7070Spatrick // not matter. If it matters, there is enough info to get the
6983e5dd7070Spatrick // bitfield right!
6984e5dd7070Spatrick ivar.addInt(ObjCTypes.IntTy, Size);
6985e5dd7070Spatrick ivar.finishAndAddTo(ivars);
6986e5dd7070Spatrick }
6987e5dd7070Spatrick // Return null for empty list.
6988e5dd7070Spatrick if (ivars.empty()) {
6989e5dd7070Spatrick ivars.abandon();
6990e5dd7070Spatrick ivarList.abandon();
6991e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
6992e5dd7070Spatrick }
6993e5dd7070Spatrick
6994e5dd7070Spatrick auto ivarCount = ivars.size();
6995e5dd7070Spatrick ivars.finishAndAddTo(ivarList);
6996e5dd7070Spatrick ivarList.fillPlaceholderWithInt(ivarCountSlot, ObjCTypes.IntTy, ivarCount);
6997e5dd7070Spatrick
6998e5dd7070Spatrick const char *Prefix = "_OBJC_$_INSTANCE_VARIABLES_";
6999e5dd7070Spatrick llvm::GlobalVariable *GV = finishAndCreateGlobal(
7000e5dd7070Spatrick ivarList, Prefix + OID->getObjCRuntimeNameAsString(), CGM);
7001e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
7002e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListnfABIPtrTy);
7003e5dd7070Spatrick }
7004e5dd7070Spatrick
GetOrEmitProtocolRef(const ObjCProtocolDecl * PD)7005e5dd7070Spatrick llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
7006e5dd7070Spatrick const ObjCProtocolDecl *PD) {
7007e5dd7070Spatrick llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
7008e5dd7070Spatrick
7009a9ac8606Spatrick assert(!PD->isNonRuntimeProtocol() &&
7010a9ac8606Spatrick "attempting to GetOrEmit a non-runtime protocol");
7011e5dd7070Spatrick if (!Entry) {
7012e5dd7070Spatrick // We use the initializer as a marker of whether this is a forward
7013e5dd7070Spatrick // reference or not. At module finalization we add the empty
7014e5dd7070Spatrick // contents for protocols which were referenced but never defined.
7015e5dd7070Spatrick llvm::SmallString<64> Protocol;
7016e5dd7070Spatrick llvm::raw_svector_ostream(Protocol) << "_OBJC_PROTOCOL_$_"
7017e5dd7070Spatrick << PD->getObjCRuntimeNameAsString();
7018e5dd7070Spatrick
7019e5dd7070Spatrick Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy,
7020e5dd7070Spatrick false, llvm::GlobalValue::ExternalLinkage,
7021e5dd7070Spatrick nullptr, Protocol);
7022e5dd7070Spatrick if (!CGM.getTriple().isOSBinFormatMachO())
7023e5dd7070Spatrick Entry->setComdat(CGM.getModule().getOrInsertComdat(Protocol));
7024e5dd7070Spatrick }
7025e5dd7070Spatrick
7026e5dd7070Spatrick return Entry;
7027e5dd7070Spatrick }
7028e5dd7070Spatrick
7029e5dd7070Spatrick /// GetOrEmitProtocol - Generate the protocol meta-data:
7030e5dd7070Spatrick /// @code
7031e5dd7070Spatrick /// struct _protocol_t {
7032e5dd7070Spatrick /// id isa; // NULL
7033e5dd7070Spatrick /// const char * const protocol_name;
7034e5dd7070Spatrick /// const struct _protocol_list_t * protocol_list; // super protocols
7035e5dd7070Spatrick /// const struct method_list_t * const instance_methods;
7036e5dd7070Spatrick /// const struct method_list_t * const class_methods;
7037e5dd7070Spatrick /// const struct method_list_t *optionalInstanceMethods;
7038e5dd7070Spatrick /// const struct method_list_t *optionalClassMethods;
7039e5dd7070Spatrick /// const struct _prop_list_t * properties;
7040e5dd7070Spatrick /// const uint32_t size; // sizeof(struct _protocol_t)
7041e5dd7070Spatrick /// const uint32_t flags; // = 0
7042e5dd7070Spatrick /// const char ** extendedMethodTypes;
7043e5dd7070Spatrick /// const char *demangledName;
7044e5dd7070Spatrick /// const struct _prop_list_t * class_properties;
7045e5dd7070Spatrick /// }
7046e5dd7070Spatrick /// @endcode
7047e5dd7070Spatrick ///
7048e5dd7070Spatrick
GetOrEmitProtocol(const ObjCProtocolDecl * PD)7049e5dd7070Spatrick llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
7050e5dd7070Spatrick const ObjCProtocolDecl *PD) {
7051e5dd7070Spatrick llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()];
7052e5dd7070Spatrick
7053e5dd7070Spatrick // Early exit if a defining object has already been generated.
7054e5dd7070Spatrick if (Entry && Entry->hasInitializer())
7055e5dd7070Spatrick return Entry;
7056e5dd7070Spatrick
7057e5dd7070Spatrick // Use the protocol definition, if there is one.
7058e5dd7070Spatrick assert(PD->hasDefinition() &&
7059e5dd7070Spatrick "emitting protocol metadata without definition");
7060e5dd7070Spatrick PD = PD->getDefinition();
7061e5dd7070Spatrick
7062e5dd7070Spatrick auto methodLists = ProtocolMethodLists::get(PD);
7063e5dd7070Spatrick
7064e5dd7070Spatrick ConstantInitBuilder builder(CGM);
7065e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.ProtocolnfABITy);
7066e5dd7070Spatrick
7067e5dd7070Spatrick // isa is NULL
7068e5dd7070Spatrick values.addNullPointer(ObjCTypes.ObjectPtrTy);
7069e5dd7070Spatrick values.add(GetClassName(PD->getObjCRuntimeNameAsString()));
7070e5dd7070Spatrick values.add(EmitProtocolList("_OBJC_$_PROTOCOL_REFS_"
7071e5dd7070Spatrick + PD->getObjCRuntimeNameAsString(),
7072e5dd7070Spatrick PD->protocol_begin(),
7073e5dd7070Spatrick PD->protocol_end()));
7074e5dd7070Spatrick values.add(methodLists.emitMethodList(this, PD,
7075e5dd7070Spatrick ProtocolMethodLists::RequiredInstanceMethods));
7076e5dd7070Spatrick values.add(methodLists.emitMethodList(this, PD,
7077e5dd7070Spatrick ProtocolMethodLists::RequiredClassMethods));
7078e5dd7070Spatrick values.add(methodLists.emitMethodList(this, PD,
7079e5dd7070Spatrick ProtocolMethodLists::OptionalInstanceMethods));
7080e5dd7070Spatrick values.add(methodLists.emitMethodList(this, PD,
7081e5dd7070Spatrick ProtocolMethodLists::OptionalClassMethods));
7082e5dd7070Spatrick values.add(EmitPropertyList(
7083e5dd7070Spatrick "_OBJC_$_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
7084e5dd7070Spatrick nullptr, PD, ObjCTypes, false));
7085e5dd7070Spatrick uint32_t Size =
7086e5dd7070Spatrick CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
7087e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, Size);
7088e5dd7070Spatrick values.addInt(ObjCTypes.IntTy, 0);
7089e5dd7070Spatrick values.add(EmitProtocolMethodTypes("_OBJC_$_PROTOCOL_METHOD_TYPES_"
7090e5dd7070Spatrick + PD->getObjCRuntimeNameAsString(),
7091e5dd7070Spatrick methodLists.emitExtendedTypesArray(this),
7092e5dd7070Spatrick ObjCTypes));
7093e5dd7070Spatrick
7094e5dd7070Spatrick // const char *demangledName;
7095e5dd7070Spatrick values.addNullPointer(ObjCTypes.Int8PtrTy);
7096e5dd7070Spatrick
7097e5dd7070Spatrick values.add(EmitPropertyList(
7098e5dd7070Spatrick "_OBJC_$_CLASS_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
7099e5dd7070Spatrick nullptr, PD, ObjCTypes, true));
7100e5dd7070Spatrick
7101e5dd7070Spatrick if (Entry) {
7102e5dd7070Spatrick // Already created, fix the linkage and update the initializer.
7103e5dd7070Spatrick Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
7104e5dd7070Spatrick values.finishAndSetAsInitializer(Entry);
7105e5dd7070Spatrick } else {
7106e5dd7070Spatrick llvm::SmallString<64> symbolName;
7107e5dd7070Spatrick llvm::raw_svector_ostream(symbolName)
7108e5dd7070Spatrick << "_OBJC_PROTOCOL_$_" << PD->getObjCRuntimeNameAsString();
7109e5dd7070Spatrick
7110e5dd7070Spatrick Entry = values.finishAndCreateGlobal(symbolName, CGM.getPointerAlign(),
7111e5dd7070Spatrick /*constant*/ false,
7112e5dd7070Spatrick llvm::GlobalValue::WeakAnyLinkage);
7113e5dd7070Spatrick if (!CGM.getTriple().isOSBinFormatMachO())
7114e5dd7070Spatrick Entry->setComdat(CGM.getModule().getOrInsertComdat(symbolName));
7115e5dd7070Spatrick
7116e5dd7070Spatrick Protocols[PD->getIdentifier()] = Entry;
7117e5dd7070Spatrick }
7118e5dd7070Spatrick Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
7119e5dd7070Spatrick CGM.addUsedGlobal(Entry);
7120e5dd7070Spatrick
7121e5dd7070Spatrick // Use this protocol meta-data to build protocol list table in section
7122e5dd7070Spatrick // __DATA, __objc_protolist
7123e5dd7070Spatrick llvm::SmallString<64> ProtocolRef;
7124e5dd7070Spatrick llvm::raw_svector_ostream(ProtocolRef) << "_OBJC_LABEL_PROTOCOL_$_"
7125e5dd7070Spatrick << PD->getObjCRuntimeNameAsString();
7126e5dd7070Spatrick
7127e5dd7070Spatrick llvm::GlobalVariable *PTGV =
7128e5dd7070Spatrick new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABIPtrTy,
7129e5dd7070Spatrick false, llvm::GlobalValue::WeakAnyLinkage, Entry,
7130e5dd7070Spatrick ProtocolRef);
7131e5dd7070Spatrick if (!CGM.getTriple().isOSBinFormatMachO())
7132e5dd7070Spatrick PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef));
7133*12c85518Srobert PTGV->setAlignment(
7134*12c85518Srobert CGM.getDataLayout().getABITypeAlign(ObjCTypes.ProtocolnfABIPtrTy));
7135e5dd7070Spatrick PTGV->setSection(GetSectionName("__objc_protolist",
7136e5dd7070Spatrick "coalesced,no_dead_strip"));
7137e5dd7070Spatrick PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
7138e5dd7070Spatrick CGM.addUsedGlobal(PTGV);
7139e5dd7070Spatrick return Entry;
7140e5dd7070Spatrick }
7141e5dd7070Spatrick
7142e5dd7070Spatrick /// EmitProtocolList - Generate protocol list meta-data:
7143e5dd7070Spatrick /// @code
7144e5dd7070Spatrick /// struct _protocol_list_t {
7145e5dd7070Spatrick /// long protocol_count; // Note, this is 32/64 bit
7146e5dd7070Spatrick /// struct _protocol_t[protocol_count];
7147e5dd7070Spatrick /// }
7148e5dd7070Spatrick /// @endcode
7149e5dd7070Spatrick ///
7150e5dd7070Spatrick llvm::Constant *
EmitProtocolList(Twine Name,ObjCProtocolDecl::protocol_iterator begin,ObjCProtocolDecl::protocol_iterator end)7151e5dd7070Spatrick CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
7152e5dd7070Spatrick ObjCProtocolDecl::protocol_iterator begin,
7153e5dd7070Spatrick ObjCProtocolDecl::protocol_iterator end) {
7154e5dd7070Spatrick // Just return null for empty protocol lists
7155a9ac8606Spatrick auto Protocols = GetRuntimeProtocolList(begin, end);
7156a9ac8606Spatrick if (Protocols.empty())
7157a9ac8606Spatrick return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
7158a9ac8606Spatrick
7159a9ac8606Spatrick SmallVector<llvm::Constant *, 16> ProtocolRefs;
7160a9ac8606Spatrick ProtocolRefs.reserve(Protocols.size());
7161a9ac8606Spatrick
7162a9ac8606Spatrick for (const auto *PD : Protocols)
7163a9ac8606Spatrick ProtocolRefs.push_back(GetProtocolRef(PD));
7164a9ac8606Spatrick
7165a9ac8606Spatrick // If all of the protocols in the protocol list are objc_non_runtime_protocol
7166a9ac8606Spatrick // just return null
7167a9ac8606Spatrick if (ProtocolRefs.size() == 0)
7168e5dd7070Spatrick return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
7169e5dd7070Spatrick
7170e5dd7070Spatrick // FIXME: We shouldn't need to do this lookup here, should we?
7171e5dd7070Spatrick SmallString<256> TmpName;
7172e5dd7070Spatrick Name.toVector(TmpName);
7173e5dd7070Spatrick llvm::GlobalVariable *GV =
7174e5dd7070Spatrick CGM.getModule().getGlobalVariable(TmpName.str(), true);
7175e5dd7070Spatrick if (GV)
7176e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy);
7177e5dd7070Spatrick
7178e5dd7070Spatrick ConstantInitBuilder builder(CGM);
7179e5dd7070Spatrick auto values = builder.beginStruct();
7180e5dd7070Spatrick auto countSlot = values.addPlaceholder();
7181e5dd7070Spatrick
7182e5dd7070Spatrick // A null-terminated array of protocols.
7183e5dd7070Spatrick auto array = values.beginArray(ObjCTypes.ProtocolnfABIPtrTy);
7184a9ac8606Spatrick for (auto const &proto : ProtocolRefs)
7185a9ac8606Spatrick array.add(proto);
7186e5dd7070Spatrick auto count = array.size();
7187e5dd7070Spatrick array.addNullPointer(ObjCTypes.ProtocolnfABIPtrTy);
7188e5dd7070Spatrick
7189e5dd7070Spatrick array.finishAndAddTo(values);
7190e5dd7070Spatrick values.fillPlaceholderWithInt(countSlot, ObjCTypes.LongTy, count);
7191e5dd7070Spatrick
7192e5dd7070Spatrick GV = finishAndCreateGlobal(values, Name, CGM);
7193e5dd7070Spatrick CGM.addCompilerUsedGlobal(GV);
7194e5dd7070Spatrick return llvm::ConstantExpr::getBitCast(GV,
7195e5dd7070Spatrick ObjCTypes.ProtocolListnfABIPtrTy);
7196e5dd7070Spatrick }
7197e5dd7070Spatrick
7198e5dd7070Spatrick /// EmitObjCValueForIvar - Code Gen for nonfragile ivar reference.
7199e5dd7070Spatrick /// This code gen. amounts to generating code for:
7200e5dd7070Spatrick /// @code
7201e5dd7070Spatrick /// (type *)((char *)base + _OBJC_IVAR_$_.ivar;
7202e5dd7070Spatrick /// @encode
7203e5dd7070Spatrick ///
EmitObjCValueForIvar(CodeGen::CodeGenFunction & CGF,QualType ObjectTy,llvm::Value * BaseValue,const ObjCIvarDecl * Ivar,unsigned CVRQualifiers)7204e5dd7070Spatrick LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
7205e5dd7070Spatrick CodeGen::CodeGenFunction &CGF,
7206e5dd7070Spatrick QualType ObjectTy,
7207e5dd7070Spatrick llvm::Value *BaseValue,
7208e5dd7070Spatrick const ObjCIvarDecl *Ivar,
7209e5dd7070Spatrick unsigned CVRQualifiers) {
7210e5dd7070Spatrick ObjCInterfaceDecl *ID = ObjectTy->castAs<ObjCObjectType>()->getInterface();
7211e5dd7070Spatrick llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
7212e5dd7070Spatrick return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
7213e5dd7070Spatrick Offset);
7214e5dd7070Spatrick }
7215e5dd7070Spatrick
7216e5dd7070Spatrick llvm::Value *
EmitIvarOffset(CodeGen::CodeGenFunction & CGF,const ObjCInterfaceDecl * Interface,const ObjCIvarDecl * Ivar)7217e5dd7070Spatrick CGObjCNonFragileABIMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
7218e5dd7070Spatrick const ObjCInterfaceDecl *Interface,
7219e5dd7070Spatrick const ObjCIvarDecl *Ivar) {
7220e5dd7070Spatrick llvm::Value *IvarOffsetValue;
7221e5dd7070Spatrick if (isClassLayoutKnownStatically(Interface)) {
7222e5dd7070Spatrick IvarOffsetValue = llvm::ConstantInt::get(
7223e5dd7070Spatrick ObjCTypes.IvarOffsetVarTy,
7224e5dd7070Spatrick ComputeIvarBaseOffset(CGM, Interface->getImplementation(), Ivar));
7225e5dd7070Spatrick } else {
7226e5dd7070Spatrick llvm::GlobalVariable *GV = ObjCIvarOffsetVariable(Interface, Ivar);
7227e5dd7070Spatrick IvarOffsetValue =
7228a9ac8606Spatrick CGF.Builder.CreateAlignedLoad(GV->getValueType(), GV,
7229a9ac8606Spatrick CGF.getSizeAlign(), "ivar");
7230e5dd7070Spatrick if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
7231e5dd7070Spatrick cast<llvm::LoadInst>(IvarOffsetValue)
7232e5dd7070Spatrick ->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
7233*12c85518Srobert llvm::MDNode::get(VMContext, std::nullopt));
7234e5dd7070Spatrick }
7235e5dd7070Spatrick
7236e5dd7070Spatrick // This could be 32bit int or 64bit integer depending on the architecture.
7237e5dd7070Spatrick // Cast it to 64bit integer value, if it is a 32bit integer ivar offset value
7238e5dd7070Spatrick // as this is what caller always expects.
7239e5dd7070Spatrick if (ObjCTypes.IvarOffsetVarTy == ObjCTypes.IntTy)
7240e5dd7070Spatrick IvarOffsetValue = CGF.Builder.CreateIntCast(
7241e5dd7070Spatrick IvarOffsetValue, ObjCTypes.LongTy, true, "ivar.conv");
7242e5dd7070Spatrick return IvarOffsetValue;
7243e5dd7070Spatrick }
7244e5dd7070Spatrick
appendSelectorForMessageRefTable(std::string & buffer,Selector selector)7245e5dd7070Spatrick static void appendSelectorForMessageRefTable(std::string &buffer,
7246e5dd7070Spatrick Selector selector) {
7247e5dd7070Spatrick if (selector.isUnarySelector()) {
7248e5dd7070Spatrick buffer += selector.getNameForSlot(0);
7249e5dd7070Spatrick return;
7250e5dd7070Spatrick }
7251e5dd7070Spatrick
7252e5dd7070Spatrick for (unsigned i = 0, e = selector.getNumArgs(); i != e; ++i) {
7253e5dd7070Spatrick buffer += selector.getNameForSlot(i);
7254e5dd7070Spatrick buffer += '_';
7255e5dd7070Spatrick }
7256e5dd7070Spatrick }
7257e5dd7070Spatrick
7258e5dd7070Spatrick /// Emit a "vtable" message send. We emit a weak hidden-visibility
7259e5dd7070Spatrick /// struct, initially containing the selector pointer and a pointer to
7260e5dd7070Spatrick /// a "fixup" variant of the appropriate objc_msgSend. To call, we
7261e5dd7070Spatrick /// load and call the function pointer, passing the address of the
7262e5dd7070Spatrick /// struct as the second parameter. The runtime determines whether
7263e5dd7070Spatrick /// the selector is currently emitted using vtable dispatch; if so, it
7264e5dd7070Spatrick /// substitutes a stub function which simply tail-calls through the
7265e5dd7070Spatrick /// appropriate vtable slot, and if not, it substitues a stub function
7266e5dd7070Spatrick /// which tail-calls objc_msgSend. Both stubs adjust the selector
7267e5dd7070Spatrick /// argument to correctly point to the selector.
7268e5dd7070Spatrick RValue
EmitVTableMessageSend(CodeGenFunction & CGF,ReturnValueSlot returnSlot,QualType resultType,Selector selector,llvm::Value * arg0,QualType arg0Type,bool isSuper,const CallArgList & formalArgs,const ObjCMethodDecl * method)7269e5dd7070Spatrick CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
7270e5dd7070Spatrick ReturnValueSlot returnSlot,
7271e5dd7070Spatrick QualType resultType,
7272e5dd7070Spatrick Selector selector,
7273e5dd7070Spatrick llvm::Value *arg0,
7274e5dd7070Spatrick QualType arg0Type,
7275e5dd7070Spatrick bool isSuper,
7276e5dd7070Spatrick const CallArgList &formalArgs,
7277e5dd7070Spatrick const ObjCMethodDecl *method) {
7278e5dd7070Spatrick // Compute the actual arguments.
7279e5dd7070Spatrick CallArgList args;
7280e5dd7070Spatrick
7281e5dd7070Spatrick // First argument: the receiver / super-call structure.
7282e5dd7070Spatrick if (!isSuper)
7283e5dd7070Spatrick arg0 = CGF.Builder.CreateBitCast(arg0, ObjCTypes.ObjectPtrTy);
7284e5dd7070Spatrick args.add(RValue::get(arg0), arg0Type);
7285e5dd7070Spatrick
7286e5dd7070Spatrick // Second argument: a pointer to the message ref structure. Leave
7287e5dd7070Spatrick // the actual argument value blank for now.
7288e5dd7070Spatrick args.add(RValue::get(nullptr), ObjCTypes.MessageRefCPtrTy);
7289e5dd7070Spatrick
7290e5dd7070Spatrick args.insert(args.end(), formalArgs.begin(), formalArgs.end());
7291e5dd7070Spatrick
7292e5dd7070Spatrick MessageSendInfo MSI = getMessageSendInfo(method, resultType, args);
7293e5dd7070Spatrick
7294e5dd7070Spatrick NullReturnState nullReturn;
7295e5dd7070Spatrick
7296e5dd7070Spatrick // Find the function to call and the mangled name for the message
7297e5dd7070Spatrick // ref structure. Using a different mangled name wouldn't actually
7298e5dd7070Spatrick // be a problem; it would just be a waste.
7299e5dd7070Spatrick //
7300e5dd7070Spatrick // The runtime currently never uses vtable dispatch for anything
7301e5dd7070Spatrick // except normal, non-super message-sends.
7302e5dd7070Spatrick // FIXME: don't use this for that.
7303e5dd7070Spatrick llvm::FunctionCallee fn = nullptr;
7304e5dd7070Spatrick std::string messageRefName("_");
7305e5dd7070Spatrick if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
7306e5dd7070Spatrick if (isSuper) {
7307e5dd7070Spatrick fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
7308e5dd7070Spatrick messageRefName += "objc_msgSendSuper2_stret_fixup";
7309e5dd7070Spatrick } else {
7310e5dd7070Spatrick nullReturn.init(CGF, arg0);
7311e5dd7070Spatrick fn = ObjCTypes.getMessageSendStretFixupFn();
7312e5dd7070Spatrick messageRefName += "objc_msgSend_stret_fixup";
7313e5dd7070Spatrick }
7314e5dd7070Spatrick } else if (!isSuper && CGM.ReturnTypeUsesFPRet(resultType)) {
7315e5dd7070Spatrick fn = ObjCTypes.getMessageSendFpretFixupFn();
7316e5dd7070Spatrick messageRefName += "objc_msgSend_fpret_fixup";
7317e5dd7070Spatrick } else {
7318e5dd7070Spatrick if (isSuper) {
7319e5dd7070Spatrick fn = ObjCTypes.getMessageSendSuper2FixupFn();
7320e5dd7070Spatrick messageRefName += "objc_msgSendSuper2_fixup";
7321e5dd7070Spatrick } else {
7322e5dd7070Spatrick fn = ObjCTypes.getMessageSendFixupFn();
7323e5dd7070Spatrick messageRefName += "objc_msgSend_fixup";
7324e5dd7070Spatrick }
7325e5dd7070Spatrick }
7326e5dd7070Spatrick assert(fn && "CGObjCNonFragileABIMac::EmitMessageSend");
7327e5dd7070Spatrick messageRefName += '_';
7328e5dd7070Spatrick
7329e5dd7070Spatrick // Append the selector name, except use underscores anywhere we
7330e5dd7070Spatrick // would have used colons.
7331e5dd7070Spatrick appendSelectorForMessageRefTable(messageRefName, selector);
7332e5dd7070Spatrick
7333e5dd7070Spatrick llvm::GlobalVariable *messageRef
7334e5dd7070Spatrick = CGM.getModule().getGlobalVariable(messageRefName);
7335e5dd7070Spatrick if (!messageRef) {
7336e5dd7070Spatrick // Build the message ref structure.
7337e5dd7070Spatrick ConstantInitBuilder builder(CGM);
7338e5dd7070Spatrick auto values = builder.beginStruct();
7339e5dd7070Spatrick values.add(cast<llvm::Constant>(fn.getCallee()));
7340e5dd7070Spatrick values.add(GetMethodVarName(selector));
7341e5dd7070Spatrick messageRef = values.finishAndCreateGlobal(messageRefName,
7342e5dd7070Spatrick CharUnits::fromQuantity(16),
7343e5dd7070Spatrick /*constant*/ false,
7344e5dd7070Spatrick llvm::GlobalValue::WeakAnyLinkage);
7345e5dd7070Spatrick messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
7346e5dd7070Spatrick messageRef->setSection(GetSectionName("__objc_msgrefs", "coalesced"));
7347e5dd7070Spatrick }
7348e5dd7070Spatrick
7349e5dd7070Spatrick bool requiresnullCheck = false;
7350e5dd7070Spatrick if (CGM.getLangOpts().ObjCAutoRefCount && method)
7351e5dd7070Spatrick for (const auto *ParamDecl : method->parameters()) {
7352a9ac8606Spatrick if (ParamDecl->isDestroyedInCallee()) {
7353e5dd7070Spatrick if (!nullReturn.NullBB)
7354e5dd7070Spatrick nullReturn.init(CGF, arg0);
7355e5dd7070Spatrick requiresnullCheck = true;
7356e5dd7070Spatrick break;
7357e5dd7070Spatrick }
7358e5dd7070Spatrick }
7359e5dd7070Spatrick
7360e5dd7070Spatrick Address mref =
7361e5dd7070Spatrick Address(CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy),
7362*12c85518Srobert ObjCTypes.MessageRefTy, CGF.getPointerAlign());
7363e5dd7070Spatrick
7364e5dd7070Spatrick // Update the message ref argument.
7365e5dd7070Spatrick args[1].setRValue(RValue::get(mref.getPointer()));
7366e5dd7070Spatrick
7367e5dd7070Spatrick // Load the function to call from the message ref table.
7368e5dd7070Spatrick Address calleeAddr = CGF.Builder.CreateStructGEP(mref, 0);
7369e5dd7070Spatrick llvm::Value *calleePtr = CGF.Builder.CreateLoad(calleeAddr, "msgSend_fn");
7370e5dd7070Spatrick
7371e5dd7070Spatrick calleePtr = CGF.Builder.CreateBitCast(calleePtr, MSI.MessengerType);
7372e5dd7070Spatrick CGCallee callee(CGCalleeInfo(), calleePtr);
7373e5dd7070Spatrick
7374e5dd7070Spatrick RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
7375e5dd7070Spatrick return nullReturn.complete(CGF, returnSlot, result, resultType, formalArgs,
7376e5dd7070Spatrick requiresnullCheck ? method : nullptr);
7377e5dd7070Spatrick }
7378e5dd7070Spatrick
7379e5dd7070Spatrick /// Generate code for a message send expression in the nonfragile abi.
7380e5dd7070Spatrick CodeGen::RValue
GenerateMessageSend(CodeGen::CodeGenFunction & CGF,ReturnValueSlot Return,QualType ResultType,Selector Sel,llvm::Value * Receiver,const CallArgList & CallArgs,const ObjCInterfaceDecl * Class,const ObjCMethodDecl * Method)7381e5dd7070Spatrick CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
7382e5dd7070Spatrick ReturnValueSlot Return,
7383e5dd7070Spatrick QualType ResultType,
7384e5dd7070Spatrick Selector Sel,
7385e5dd7070Spatrick llvm::Value *Receiver,
7386e5dd7070Spatrick const CallArgList &CallArgs,
7387e5dd7070Spatrick const ObjCInterfaceDecl *Class,
7388e5dd7070Spatrick const ObjCMethodDecl *Method) {
7389e5dd7070Spatrick return isVTableDispatchedSelector(Sel)
7390e5dd7070Spatrick ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
7391e5dd7070Spatrick Receiver, CGF.getContext().getObjCIdType(),
7392e5dd7070Spatrick false, CallArgs, Method)
7393e5dd7070Spatrick : EmitMessageSend(CGF, Return, ResultType, Sel,
7394e5dd7070Spatrick Receiver, CGF.getContext().getObjCIdType(),
7395e5dd7070Spatrick false, CallArgs, Method, Class, ObjCTypes);
7396e5dd7070Spatrick }
7397e5dd7070Spatrick
7398e5dd7070Spatrick llvm::Constant *
GetClassGlobal(const ObjCInterfaceDecl * ID,bool metaclass,ForDefinition_t isForDefinition)7399e5dd7070Spatrick CGObjCNonFragileABIMac::GetClassGlobal(const ObjCInterfaceDecl *ID,
7400e5dd7070Spatrick bool metaclass,
7401e5dd7070Spatrick ForDefinition_t isForDefinition) {
7402e5dd7070Spatrick auto prefix =
7403e5dd7070Spatrick (metaclass ? getMetaclassSymbolPrefix() : getClassSymbolPrefix());
7404e5dd7070Spatrick return GetClassGlobal((prefix + ID->getObjCRuntimeNameAsString()).str(),
7405e5dd7070Spatrick isForDefinition,
7406e5dd7070Spatrick ID->isWeakImported(),
7407e5dd7070Spatrick !isForDefinition
7408e5dd7070Spatrick && CGM.getTriple().isOSBinFormatCOFF()
7409e5dd7070Spatrick && ID->hasAttr<DLLImportAttr>());
7410e5dd7070Spatrick }
7411e5dd7070Spatrick
7412e5dd7070Spatrick llvm::Constant *
GetClassGlobal(StringRef Name,ForDefinition_t IsForDefinition,bool Weak,bool DLLImport)7413e5dd7070Spatrick CGObjCNonFragileABIMac::GetClassGlobal(StringRef Name,
7414e5dd7070Spatrick ForDefinition_t IsForDefinition,
7415e5dd7070Spatrick bool Weak, bool DLLImport) {
7416e5dd7070Spatrick llvm::GlobalValue::LinkageTypes L =
7417e5dd7070Spatrick Weak ? llvm::GlobalValue::ExternalWeakLinkage
7418e5dd7070Spatrick : llvm::GlobalValue::ExternalLinkage;
7419e5dd7070Spatrick
7420e5dd7070Spatrick llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
7421*12c85518Srobert if (!GV || GV->getValueType() != ObjCTypes.ClassnfABITy) {
7422e5dd7070Spatrick auto *NewGV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false, L,
7423e5dd7070Spatrick nullptr, Name);
7424e5dd7070Spatrick
7425e5dd7070Spatrick if (DLLImport)
7426e5dd7070Spatrick NewGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
7427e5dd7070Spatrick
7428e5dd7070Spatrick if (GV) {
7429e5dd7070Spatrick GV->replaceAllUsesWith(
7430e5dd7070Spatrick llvm::ConstantExpr::getBitCast(NewGV, GV->getType()));
7431e5dd7070Spatrick GV->eraseFromParent();
7432e5dd7070Spatrick }
7433e5dd7070Spatrick GV = NewGV;
7434e5dd7070Spatrick CGM.getModule().getGlobalList().push_back(GV);
7435e5dd7070Spatrick }
7436e5dd7070Spatrick
7437e5dd7070Spatrick assert(GV->getLinkage() == L);
7438e5dd7070Spatrick return GV;
7439e5dd7070Spatrick }
7440e5dd7070Spatrick
7441e5dd7070Spatrick llvm::Constant *
GetClassGlobalForClassRef(const ObjCInterfaceDecl * ID)7442e5dd7070Spatrick CGObjCNonFragileABIMac::GetClassGlobalForClassRef(const ObjCInterfaceDecl *ID) {
7443e5dd7070Spatrick llvm::Constant *ClassGV = GetClassGlobal(ID, /*metaclass*/ false,
7444e5dd7070Spatrick NotForDefinition);
7445e5dd7070Spatrick
7446e5dd7070Spatrick if (!ID->hasAttr<ObjCClassStubAttr>())
7447e5dd7070Spatrick return ClassGV;
7448e5dd7070Spatrick
7449e5dd7070Spatrick ClassGV = llvm::ConstantExpr::getPointerCast(ClassGV, ObjCTypes.Int8PtrTy);
7450e5dd7070Spatrick
7451e5dd7070Spatrick // Stub classes are pointer-aligned. Classrefs pointing at stub classes
7452e5dd7070Spatrick // must set the least significant bit set to 1.
7453e5dd7070Spatrick auto *Idx = llvm::ConstantInt::get(CGM.Int32Ty, 1);
7454e5dd7070Spatrick return llvm::ConstantExpr::getGetElementPtr(CGM.Int8Ty, ClassGV, Idx);
7455e5dd7070Spatrick }
7456e5dd7070Spatrick
7457e5dd7070Spatrick llvm::Value *
EmitLoadOfClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID,llvm::GlobalVariable * Entry)7458e5dd7070Spatrick CGObjCNonFragileABIMac::EmitLoadOfClassRef(CodeGenFunction &CGF,
7459e5dd7070Spatrick const ObjCInterfaceDecl *ID,
7460e5dd7070Spatrick llvm::GlobalVariable *Entry) {
7461e5dd7070Spatrick if (ID && ID->hasAttr<ObjCClassStubAttr>()) {
7462e5dd7070Spatrick // Classrefs pointing at Objective-C stub classes must be loaded by calling
7463e5dd7070Spatrick // a special runtime function.
7464e5dd7070Spatrick return CGF.EmitRuntimeCall(
7465e5dd7070Spatrick ObjCTypes.getLoadClassrefFn(), Entry, "load_classref_result");
7466e5dd7070Spatrick }
7467e5dd7070Spatrick
7468e5dd7070Spatrick CharUnits Align = CGF.getPointerAlign();
7469a9ac8606Spatrick return CGF.Builder.CreateAlignedLoad(Entry->getValueType(), Entry, Align);
7470e5dd7070Spatrick }
7471e5dd7070Spatrick
7472e5dd7070Spatrick llvm::Value *
EmitClassRefFromId(CodeGenFunction & CGF,IdentifierInfo * II,const ObjCInterfaceDecl * ID)7473e5dd7070Spatrick CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
7474e5dd7070Spatrick IdentifierInfo *II,
7475e5dd7070Spatrick const ObjCInterfaceDecl *ID) {
7476e5dd7070Spatrick llvm::GlobalVariable *&Entry = ClassReferences[II];
7477e5dd7070Spatrick
7478e5dd7070Spatrick if (!Entry) {
7479e5dd7070Spatrick llvm::Constant *ClassGV;
7480e5dd7070Spatrick if (ID) {
7481e5dd7070Spatrick ClassGV = GetClassGlobalForClassRef(ID);
7482e5dd7070Spatrick } else {
7483e5dd7070Spatrick ClassGV = GetClassGlobal((getClassSymbolPrefix() + II->getName()).str(),
7484e5dd7070Spatrick NotForDefinition);
7485e5dd7070Spatrick assert(ClassGV->getType() == ObjCTypes.ClassnfABIPtrTy &&
7486e5dd7070Spatrick "classref was emitted with the wrong type?");
7487e5dd7070Spatrick }
7488e5dd7070Spatrick
7489e5dd7070Spatrick std::string SectionName =
7490e5dd7070Spatrick GetSectionName("__objc_classrefs", "regular,no_dead_strip");
7491e5dd7070Spatrick Entry = new llvm::GlobalVariable(
7492e5dd7070Spatrick CGM.getModule(), ClassGV->getType(), false,
7493e5dd7070Spatrick getLinkageTypeForObjCMetadata(CGM, SectionName), ClassGV,
7494e5dd7070Spatrick "OBJC_CLASSLIST_REFERENCES_$_");
7495e5dd7070Spatrick Entry->setAlignment(CGF.getPointerAlign().getAsAlign());
7496e5dd7070Spatrick if (!ID || !ID->hasAttr<ObjCClassStubAttr>())
7497e5dd7070Spatrick Entry->setSection(SectionName);
7498e5dd7070Spatrick
7499e5dd7070Spatrick CGM.addCompilerUsedGlobal(Entry);
7500e5dd7070Spatrick }
7501e5dd7070Spatrick
7502e5dd7070Spatrick return EmitLoadOfClassRef(CGF, ID, Entry);
7503e5dd7070Spatrick }
7504e5dd7070Spatrick
EmitClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)7505e5dd7070Spatrick llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
7506e5dd7070Spatrick const ObjCInterfaceDecl *ID) {
7507e5dd7070Spatrick // If the class has the objc_runtime_visible attribute, we need to
7508e5dd7070Spatrick // use the Objective-C runtime to get the class.
7509e5dd7070Spatrick if (ID->hasAttr<ObjCRuntimeVisibleAttr>())
7510e5dd7070Spatrick return EmitClassRefViaRuntime(CGF, ID, ObjCTypes);
7511e5dd7070Spatrick
7512e5dd7070Spatrick return EmitClassRefFromId(CGF, ID->getIdentifier(), ID);
7513e5dd7070Spatrick }
7514e5dd7070Spatrick
EmitNSAutoreleasePoolClassRef(CodeGenFunction & CGF)7515e5dd7070Spatrick llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
7516e5dd7070Spatrick CodeGenFunction &CGF) {
7517e5dd7070Spatrick IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
7518e5dd7070Spatrick return EmitClassRefFromId(CGF, II, nullptr);
7519e5dd7070Spatrick }
7520e5dd7070Spatrick
7521e5dd7070Spatrick llvm::Value *
EmitSuperClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)7522e5dd7070Spatrick CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
7523e5dd7070Spatrick const ObjCInterfaceDecl *ID) {
7524e5dd7070Spatrick llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
7525e5dd7070Spatrick
7526e5dd7070Spatrick if (!Entry) {
7527e5dd7070Spatrick llvm::Constant *ClassGV = GetClassGlobalForClassRef(ID);
7528e5dd7070Spatrick std::string SectionName =
7529e5dd7070Spatrick GetSectionName("__objc_superrefs", "regular,no_dead_strip");
7530ec727ea7Spatrick Entry = new llvm::GlobalVariable(CGM.getModule(), ClassGV->getType(), false,
7531ec727ea7Spatrick llvm::GlobalValue::PrivateLinkage, ClassGV,
7532e5dd7070Spatrick "OBJC_CLASSLIST_SUP_REFS_$_");
7533e5dd7070Spatrick Entry->setAlignment(CGF.getPointerAlign().getAsAlign());
7534e5dd7070Spatrick Entry->setSection(SectionName);
7535e5dd7070Spatrick CGM.addCompilerUsedGlobal(Entry);
7536e5dd7070Spatrick }
7537e5dd7070Spatrick
7538e5dd7070Spatrick return EmitLoadOfClassRef(CGF, ID, Entry);
7539e5dd7070Spatrick }
7540e5dd7070Spatrick
7541e5dd7070Spatrick /// EmitMetaClassRef - Return a Value * of the address of _class_t
7542e5dd7070Spatrick /// meta-data
7543e5dd7070Spatrick ///
EmitMetaClassRef(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID,bool Weak)7544e5dd7070Spatrick llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
7545e5dd7070Spatrick const ObjCInterfaceDecl *ID,
7546e5dd7070Spatrick bool Weak) {
7547e5dd7070Spatrick CharUnits Align = CGF.getPointerAlign();
7548e5dd7070Spatrick llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
7549e5dd7070Spatrick if (!Entry) {
7550e5dd7070Spatrick auto MetaClassGV = GetClassGlobal(ID, /*metaclass*/ true, NotForDefinition);
7551e5dd7070Spatrick std::string SectionName =
7552e5dd7070Spatrick GetSectionName("__objc_superrefs", "regular,no_dead_strip");
7553ec727ea7Spatrick Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
7554ec727ea7Spatrick false, llvm::GlobalValue::PrivateLinkage,
7555ec727ea7Spatrick MetaClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
7556e5dd7070Spatrick Entry->setAlignment(Align.getAsAlign());
7557e5dd7070Spatrick Entry->setSection(SectionName);
7558e5dd7070Spatrick CGM.addCompilerUsedGlobal(Entry);
7559e5dd7070Spatrick }
7560e5dd7070Spatrick
7561a9ac8606Spatrick return CGF.Builder.CreateAlignedLoad(ObjCTypes.ClassnfABIPtrTy, Entry, Align);
7562e5dd7070Spatrick }
7563e5dd7070Spatrick
7564e5dd7070Spatrick /// GetClass - Return a reference to the class for the given interface
7565e5dd7070Spatrick /// decl.
GetClass(CodeGenFunction & CGF,const ObjCInterfaceDecl * ID)7566e5dd7070Spatrick llvm::Value *CGObjCNonFragileABIMac::GetClass(CodeGenFunction &CGF,
7567e5dd7070Spatrick const ObjCInterfaceDecl *ID) {
7568e5dd7070Spatrick if (ID->isWeakImported()) {
7569e5dd7070Spatrick auto ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition);
7570e5dd7070Spatrick (void)ClassGV;
7571e5dd7070Spatrick assert(!isa<llvm::GlobalVariable>(ClassGV) ||
7572e5dd7070Spatrick cast<llvm::GlobalVariable>(ClassGV)->hasExternalWeakLinkage());
7573e5dd7070Spatrick }
7574e5dd7070Spatrick
7575e5dd7070Spatrick return EmitClassRef(CGF, ID);
7576e5dd7070Spatrick }
7577e5dd7070Spatrick
7578e5dd7070Spatrick /// Generates a message send where the super is the receiver. This is
7579e5dd7070Spatrick /// a message send to self with special delivery semantics indicating
7580e5dd7070Spatrick /// which class's method should be called.
7581e5dd7070Spatrick 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)7582e5dd7070Spatrick CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
7583e5dd7070Spatrick ReturnValueSlot Return,
7584e5dd7070Spatrick QualType ResultType,
7585e5dd7070Spatrick Selector Sel,
7586e5dd7070Spatrick const ObjCInterfaceDecl *Class,
7587e5dd7070Spatrick bool isCategoryImpl,
7588e5dd7070Spatrick llvm::Value *Receiver,
7589e5dd7070Spatrick bool IsClassMessage,
7590e5dd7070Spatrick const CodeGen::CallArgList &CallArgs,
7591e5dd7070Spatrick const ObjCMethodDecl *Method) {
7592e5dd7070Spatrick // ...
7593e5dd7070Spatrick // Create and init a super structure; this is a (receiver, class)
7594e5dd7070Spatrick // pair we will pass to objc_msgSendSuper.
7595e5dd7070Spatrick Address ObjCSuper =
7596e5dd7070Spatrick CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(),
7597e5dd7070Spatrick "objc_super");
7598e5dd7070Spatrick
7599e5dd7070Spatrick llvm::Value *ReceiverAsObject =
7600e5dd7070Spatrick CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
7601e5dd7070Spatrick CGF.Builder.CreateStore(ReceiverAsObject,
7602e5dd7070Spatrick CGF.Builder.CreateStructGEP(ObjCSuper, 0));
7603e5dd7070Spatrick
7604e5dd7070Spatrick // If this is a class message the metaclass is passed as the target.
7605e5dd7070Spatrick llvm::Value *Target;
7606e5dd7070Spatrick if (IsClassMessage)
7607e5dd7070Spatrick Target = EmitMetaClassRef(CGF, Class, Class->isWeakImported());
7608e5dd7070Spatrick else
7609e5dd7070Spatrick Target = EmitSuperClassRef(CGF, Class);
7610e5dd7070Spatrick
7611e5dd7070Spatrick // FIXME: We shouldn't need to do this cast, rectify the ASTContext and
7612e5dd7070Spatrick // ObjCTypes types.
7613e5dd7070Spatrick llvm::Type *ClassTy =
7614e5dd7070Spatrick CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
7615e5dd7070Spatrick Target = CGF.Builder.CreateBitCast(Target, ClassTy);
7616e5dd7070Spatrick CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1));
7617e5dd7070Spatrick
7618e5dd7070Spatrick return (isVTableDispatchedSelector(Sel))
7619e5dd7070Spatrick ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
7620e5dd7070Spatrick ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
7621e5dd7070Spatrick true, CallArgs, Method)
7622e5dd7070Spatrick : EmitMessageSend(CGF, Return, ResultType, Sel,
7623e5dd7070Spatrick ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
7624e5dd7070Spatrick true, CallArgs, Method, Class, ObjCTypes);
7625e5dd7070Spatrick }
7626e5dd7070Spatrick
EmitSelector(CodeGenFunction & CGF,Selector Sel)7627e5dd7070Spatrick llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
7628e5dd7070Spatrick Selector Sel) {
7629e5dd7070Spatrick Address Addr = EmitSelectorAddr(Sel);
7630e5dd7070Spatrick
7631e5dd7070Spatrick llvm::LoadInst* LI = CGF.Builder.CreateLoad(Addr);
7632e5dd7070Spatrick LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
7633*12c85518Srobert llvm::MDNode::get(VMContext, std::nullopt));
7634e5dd7070Spatrick return LI;
7635e5dd7070Spatrick }
7636e5dd7070Spatrick
EmitSelectorAddr(Selector Sel)7637e5dd7070Spatrick Address CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) {
7638e5dd7070Spatrick llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
7639e5dd7070Spatrick CharUnits Align = CGM.getPointerAlign();
7640e5dd7070Spatrick if (!Entry) {
7641e5dd7070Spatrick llvm::Constant *Casted =
7642e5dd7070Spatrick llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
7643e5dd7070Spatrick ObjCTypes.SelectorPtrTy);
7644e5dd7070Spatrick std::string SectionName =
7645e5dd7070Spatrick GetSectionName("__objc_selrefs", "literal_pointers,no_dead_strip");
7646e5dd7070Spatrick Entry = new llvm::GlobalVariable(
7647e5dd7070Spatrick CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
7648e5dd7070Spatrick getLinkageTypeForObjCMetadata(CGM, SectionName), Casted,
7649e5dd7070Spatrick "OBJC_SELECTOR_REFERENCES_");
7650e5dd7070Spatrick Entry->setExternallyInitialized(true);
7651e5dd7070Spatrick Entry->setSection(SectionName);
7652e5dd7070Spatrick Entry->setAlignment(Align.getAsAlign());
7653e5dd7070Spatrick CGM.addCompilerUsedGlobal(Entry);
7654e5dd7070Spatrick }
7655e5dd7070Spatrick
7656*12c85518Srobert return Address(Entry, ObjCTypes.SelectorPtrTy, Align);
7657e5dd7070Spatrick }
7658e5dd7070Spatrick
7659e5dd7070Spatrick /// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
7660e5dd7070Spatrick /// objc_assign_ivar (id src, id *dst, ptrdiff_t)
7661e5dd7070Spatrick ///
EmitObjCIvarAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst,llvm::Value * ivarOffset)7662e5dd7070Spatrick void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
7663e5dd7070Spatrick llvm::Value *src,
7664e5dd7070Spatrick Address dst,
7665e5dd7070Spatrick llvm::Value *ivarOffset) {
7666e5dd7070Spatrick llvm::Type * SrcTy = src->getType();
7667e5dd7070Spatrick if (!isa<llvm::PointerType>(SrcTy)) {
7668e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
7669e5dd7070Spatrick assert(Size <= 8 && "does not support size > 8");
7670e5dd7070Spatrick src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
7671e5dd7070Spatrick : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
7672e5dd7070Spatrick src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
7673e5dd7070Spatrick }
7674e5dd7070Spatrick src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
7675*12c85518Srobert llvm::Value *dstVal =
7676*12c85518Srobert CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy);
7677*12c85518Srobert llvm::Value *args[] = {src, dstVal, ivarOffset};
7678e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
7679e5dd7070Spatrick }
7680e5dd7070Spatrick
7681e5dd7070Spatrick /// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
7682e5dd7070Spatrick /// objc_assign_strongCast (id src, id *dst)
7683e5dd7070Spatrick ///
EmitObjCStrongCastAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst)7684e5dd7070Spatrick void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
7685e5dd7070Spatrick CodeGen::CodeGenFunction &CGF,
7686e5dd7070Spatrick llvm::Value *src, Address dst) {
7687e5dd7070Spatrick llvm::Type * SrcTy = src->getType();
7688e5dd7070Spatrick if (!isa<llvm::PointerType>(SrcTy)) {
7689e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
7690e5dd7070Spatrick assert(Size <= 8 && "does not support size > 8");
7691e5dd7070Spatrick src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
7692e5dd7070Spatrick : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
7693e5dd7070Spatrick src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
7694e5dd7070Spatrick }
7695e5dd7070Spatrick src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
7696*12c85518Srobert llvm::Value *dstVal =
7697*12c85518Srobert CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy);
7698*12c85518Srobert llvm::Value *args[] = {src, dstVal};
7699e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
7700e5dd7070Spatrick args, "weakassign");
7701e5dd7070Spatrick }
7702e5dd7070Spatrick
EmitGCMemmoveCollectable(CodeGen::CodeGenFunction & CGF,Address DestPtr,Address SrcPtr,llvm::Value * Size)7703e5dd7070Spatrick void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
7704e5dd7070Spatrick CodeGen::CodeGenFunction &CGF,
7705e5dd7070Spatrick Address DestPtr,
7706e5dd7070Spatrick Address SrcPtr,
7707e5dd7070Spatrick llvm::Value *Size) {
7708*12c85518Srobert SrcPtr = CGF.Builder.CreateElementBitCast(SrcPtr, CGF.Int8Ty);
7709*12c85518Srobert DestPtr = CGF.Builder.CreateElementBitCast(DestPtr, CGF.Int8Ty);
7710e5dd7070Spatrick llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), Size };
7711e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
7712e5dd7070Spatrick }
7713e5dd7070Spatrick
7714e5dd7070Spatrick /// EmitObjCWeakRead - Code gen for loading value of a __weak
7715e5dd7070Spatrick /// object: objc_read_weak (id *src)
7716e5dd7070Spatrick ///
EmitObjCWeakRead(CodeGen::CodeGenFunction & CGF,Address AddrWeakObj)7717e5dd7070Spatrick llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
7718e5dd7070Spatrick CodeGen::CodeGenFunction &CGF,
7719e5dd7070Spatrick Address AddrWeakObj) {
7720e5dd7070Spatrick llvm::Type *DestTy = AddrWeakObj.getElementType();
7721*12c85518Srobert llvm::Value *AddrWeakObjVal = CGF.Builder.CreateBitCast(
7722*12c85518Srobert AddrWeakObj.getPointer(), ObjCTypes.PtrObjectPtrTy);
7723e5dd7070Spatrick llvm::Value *read_weak =
7724e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
7725*12c85518Srobert AddrWeakObjVal, "weakread");
7726e5dd7070Spatrick read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
7727e5dd7070Spatrick return read_weak;
7728e5dd7070Spatrick }
7729e5dd7070Spatrick
7730e5dd7070Spatrick /// EmitObjCWeakAssign - Code gen for assigning to a __weak object.
7731e5dd7070Spatrick /// objc_assign_weak (id src, id *dst)
7732e5dd7070Spatrick ///
EmitObjCWeakAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst)7733e5dd7070Spatrick void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
7734e5dd7070Spatrick llvm::Value *src, Address dst) {
7735e5dd7070Spatrick llvm::Type * SrcTy = src->getType();
7736e5dd7070Spatrick if (!isa<llvm::PointerType>(SrcTy)) {
7737e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
7738e5dd7070Spatrick assert(Size <= 8 && "does not support size > 8");
7739e5dd7070Spatrick src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
7740e5dd7070Spatrick : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
7741e5dd7070Spatrick src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
7742e5dd7070Spatrick }
7743e5dd7070Spatrick src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
7744*12c85518Srobert llvm::Value *dstVal =
7745*12c85518Srobert CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy);
7746*12c85518Srobert llvm::Value *args[] = {src, dstVal};
7747e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
7748e5dd7070Spatrick args, "weakassign");
7749e5dd7070Spatrick }
7750e5dd7070Spatrick
7751e5dd7070Spatrick /// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
7752e5dd7070Spatrick /// objc_assign_global (id src, id *dst)
7753e5dd7070Spatrick ///
EmitObjCGlobalAssign(CodeGen::CodeGenFunction & CGF,llvm::Value * src,Address dst,bool threadlocal)7754e5dd7070Spatrick void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
7755e5dd7070Spatrick llvm::Value *src, Address dst,
7756e5dd7070Spatrick bool threadlocal) {
7757e5dd7070Spatrick llvm::Type * SrcTy = src->getType();
7758e5dd7070Spatrick if (!isa<llvm::PointerType>(SrcTy)) {
7759e5dd7070Spatrick unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
7760e5dd7070Spatrick assert(Size <= 8 && "does not support size > 8");
7761e5dd7070Spatrick src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
7762e5dd7070Spatrick : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
7763e5dd7070Spatrick src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
7764e5dd7070Spatrick }
7765e5dd7070Spatrick src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
7766*12c85518Srobert llvm::Value *dstVal =
7767*12c85518Srobert CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy);
7768*12c85518Srobert llvm::Value *args[] = {src, dstVal};
7769e5dd7070Spatrick if (!threadlocal)
7770e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
7771e5dd7070Spatrick args, "globalassign");
7772e5dd7070Spatrick else
7773e5dd7070Spatrick CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
7774e5dd7070Spatrick args, "threadlocalassign");
7775e5dd7070Spatrick }
7776e5dd7070Spatrick
7777e5dd7070Spatrick void
EmitSynchronizedStmt(CodeGen::CodeGenFunction & CGF,const ObjCAtSynchronizedStmt & S)7778e5dd7070Spatrick CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
7779e5dd7070Spatrick const ObjCAtSynchronizedStmt &S) {
7780e5dd7070Spatrick EmitAtSynchronizedStmt(CGF, S, ObjCTypes.getSyncEnterFn(),
7781e5dd7070Spatrick ObjCTypes.getSyncExitFn());
7782e5dd7070Spatrick }
7783e5dd7070Spatrick
7784e5dd7070Spatrick llvm::Constant *
GetEHType(QualType T)7785e5dd7070Spatrick CGObjCNonFragileABIMac::GetEHType(QualType T) {
7786e5dd7070Spatrick // There's a particular fixed type info for 'id'.
7787e5dd7070Spatrick if (T->isObjCIdType() || T->isObjCQualifiedIdType()) {
7788e5dd7070Spatrick auto *IDEHType = CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
7789e5dd7070Spatrick if (!IDEHType) {
7790e5dd7070Spatrick IDEHType =
7791e5dd7070Spatrick new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
7792e5dd7070Spatrick llvm::GlobalValue::ExternalLinkage, nullptr,
7793e5dd7070Spatrick "OBJC_EHTYPE_id");
7794e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatCOFF())
7795e5dd7070Spatrick IDEHType->setDLLStorageClass(getStorage(CGM, "OBJC_EHTYPE_id"));
7796e5dd7070Spatrick }
7797e5dd7070Spatrick return IDEHType;
7798e5dd7070Spatrick }
7799e5dd7070Spatrick
7800e5dd7070Spatrick // All other types should be Objective-C interface pointer types.
7801e5dd7070Spatrick const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
7802e5dd7070Spatrick assert(PT && "Invalid @catch type.");
7803e5dd7070Spatrick
7804e5dd7070Spatrick const ObjCInterfaceType *IT = PT->getInterfaceType();
7805e5dd7070Spatrick assert(IT && "Invalid @catch type.");
7806e5dd7070Spatrick
7807e5dd7070Spatrick return GetInterfaceEHType(IT->getDecl(), NotForDefinition);
7808e5dd7070Spatrick }
7809e5dd7070Spatrick
EmitTryStmt(CodeGen::CodeGenFunction & CGF,const ObjCAtTryStmt & S)7810e5dd7070Spatrick void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
7811e5dd7070Spatrick const ObjCAtTryStmt &S) {
7812e5dd7070Spatrick EmitTryCatchStmt(CGF, S, ObjCTypes.getObjCBeginCatchFn(),
7813e5dd7070Spatrick ObjCTypes.getObjCEndCatchFn(),
7814e5dd7070Spatrick ObjCTypes.getExceptionRethrowFn());
7815e5dd7070Spatrick }
7816e5dd7070Spatrick
7817e5dd7070Spatrick /// EmitThrowStmt - Generate code for a throw statement.
EmitThrowStmt(CodeGen::CodeGenFunction & CGF,const ObjCAtThrowStmt & S,bool ClearInsertionPoint)7818e5dd7070Spatrick void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
7819e5dd7070Spatrick const ObjCAtThrowStmt &S,
7820e5dd7070Spatrick bool ClearInsertionPoint) {
7821e5dd7070Spatrick if (const Expr *ThrowExpr = S.getThrowExpr()) {
7822e5dd7070Spatrick llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
7823e5dd7070Spatrick Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
7824e5dd7070Spatrick llvm::CallBase *Call =
7825e5dd7070Spatrick CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception);
7826e5dd7070Spatrick Call->setDoesNotReturn();
7827e5dd7070Spatrick } else {
7828e5dd7070Spatrick llvm::CallBase *Call =
7829e5dd7070Spatrick CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionRethrowFn());
7830e5dd7070Spatrick Call->setDoesNotReturn();
7831e5dd7070Spatrick }
7832e5dd7070Spatrick
7833e5dd7070Spatrick CGF.Builder.CreateUnreachable();
7834e5dd7070Spatrick if (ClearInsertionPoint)
7835e5dd7070Spatrick CGF.Builder.ClearInsertionPoint();
7836e5dd7070Spatrick }
7837e5dd7070Spatrick
7838e5dd7070Spatrick llvm::Constant *
GetInterfaceEHType(const ObjCInterfaceDecl * ID,ForDefinition_t IsForDefinition)7839e5dd7070Spatrick CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
7840e5dd7070Spatrick ForDefinition_t IsForDefinition) {
7841e5dd7070Spatrick llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()];
7842e5dd7070Spatrick StringRef ClassName = ID->getObjCRuntimeNameAsString();
7843e5dd7070Spatrick
7844e5dd7070Spatrick // If we don't need a definition, return the entry if found or check
7845e5dd7070Spatrick // if we use an external reference.
7846e5dd7070Spatrick if (!IsForDefinition) {
7847e5dd7070Spatrick if (Entry)
7848e5dd7070Spatrick return Entry;
7849e5dd7070Spatrick
7850e5dd7070Spatrick // If this type (or a super class) has the __objc_exception__
7851e5dd7070Spatrick // attribute, emit an external reference.
7852e5dd7070Spatrick if (hasObjCExceptionAttribute(CGM.getContext(), ID)) {
7853e5dd7070Spatrick std::string EHTypeName = ("OBJC_EHTYPE_$_" + ClassName).str();
7854e5dd7070Spatrick Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
7855e5dd7070Spatrick false, llvm::GlobalValue::ExternalLinkage,
7856e5dd7070Spatrick nullptr, EHTypeName);
7857e5dd7070Spatrick CGM.setGVProperties(Entry, ID);
7858e5dd7070Spatrick return Entry;
7859e5dd7070Spatrick }
7860e5dd7070Spatrick }
7861e5dd7070Spatrick
7862e5dd7070Spatrick // Otherwise we need to either make a new entry or fill in the initializer.
7863e5dd7070Spatrick assert((!Entry || !Entry->hasInitializer()) && "Duplicate EHType definition");
7864e5dd7070Spatrick
7865e5dd7070Spatrick std::string VTableName = "objc_ehtype_vtable";
7866e5dd7070Spatrick auto *VTableGV = CGM.getModule().getGlobalVariable(VTableName);
7867e5dd7070Spatrick if (!VTableGV) {
7868e5dd7070Spatrick VTableGV =
7869e5dd7070Spatrick new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.Int8PtrTy, false,
7870e5dd7070Spatrick llvm::GlobalValue::ExternalLinkage, nullptr,
7871e5dd7070Spatrick VTableName);
7872e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatCOFF())
7873e5dd7070Spatrick VTableGV->setDLLStorageClass(getStorage(CGM, VTableName));
7874e5dd7070Spatrick }
7875e5dd7070Spatrick
7876e5dd7070Spatrick llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
7877e5dd7070Spatrick ConstantInitBuilder builder(CGM);
7878e5dd7070Spatrick auto values = builder.beginStruct(ObjCTypes.EHTypeTy);
7879e5dd7070Spatrick values.add(
7880e5dd7070Spatrick llvm::ConstantExpr::getInBoundsGetElementPtr(VTableGV->getValueType(),
7881e5dd7070Spatrick VTableGV, VTableIdx));
7882e5dd7070Spatrick values.add(GetClassName(ClassName));
7883e5dd7070Spatrick values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition));
7884e5dd7070Spatrick
7885e5dd7070Spatrick llvm::GlobalValue::LinkageTypes L = IsForDefinition
7886e5dd7070Spatrick ? llvm::GlobalValue::ExternalLinkage
7887e5dd7070Spatrick : llvm::GlobalValue::WeakAnyLinkage;
7888e5dd7070Spatrick if (Entry) {
7889e5dd7070Spatrick values.finishAndSetAsInitializer(Entry);
7890e5dd7070Spatrick Entry->setAlignment(CGM.getPointerAlign().getAsAlign());
7891e5dd7070Spatrick } else {
7892e5dd7070Spatrick Entry = values.finishAndCreateGlobal("OBJC_EHTYPE_$_" + ClassName,
7893e5dd7070Spatrick CGM.getPointerAlign(),
7894e5dd7070Spatrick /*constant*/ false,
7895e5dd7070Spatrick L);
7896e5dd7070Spatrick if (hasObjCExceptionAttribute(CGM.getContext(), ID))
7897e5dd7070Spatrick CGM.setGVProperties(Entry, ID);
7898e5dd7070Spatrick }
7899e5dd7070Spatrick assert(Entry->getLinkage() == L);
7900e5dd7070Spatrick
7901e5dd7070Spatrick if (!CGM.getTriple().isOSBinFormatCOFF())
7902e5dd7070Spatrick if (ID->getVisibility() == HiddenVisibility)
7903e5dd7070Spatrick Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
7904e5dd7070Spatrick
7905e5dd7070Spatrick if (IsForDefinition)
7906e5dd7070Spatrick if (CGM.getTriple().isOSBinFormatMachO())
7907e5dd7070Spatrick Entry->setSection("__DATA,__objc_const");
7908e5dd7070Spatrick
7909e5dd7070Spatrick return Entry;
7910e5dd7070Spatrick }
7911e5dd7070Spatrick
7912e5dd7070Spatrick /* *** */
7913e5dd7070Spatrick
7914e5dd7070Spatrick CodeGen::CGObjCRuntime *
CreateMacObjCRuntime(CodeGen::CodeGenModule & CGM)7915e5dd7070Spatrick CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
7916e5dd7070Spatrick switch (CGM.getLangOpts().ObjCRuntime.getKind()) {
7917e5dd7070Spatrick case ObjCRuntime::FragileMacOSX:
7918e5dd7070Spatrick return new CGObjCMac(CGM);
7919e5dd7070Spatrick
7920e5dd7070Spatrick case ObjCRuntime::MacOSX:
7921e5dd7070Spatrick case ObjCRuntime::iOS:
7922e5dd7070Spatrick case ObjCRuntime::WatchOS:
7923e5dd7070Spatrick return new CGObjCNonFragileABIMac(CGM);
7924e5dd7070Spatrick
7925e5dd7070Spatrick case ObjCRuntime::GNUstep:
7926e5dd7070Spatrick case ObjCRuntime::GCC:
7927e5dd7070Spatrick case ObjCRuntime::ObjFW:
7928e5dd7070Spatrick llvm_unreachable("these runtimes are not Mac runtimes");
7929e5dd7070Spatrick }
7930e5dd7070Spatrick llvm_unreachable("bad runtime");
7931e5dd7070Spatrick }
7932