1f4a2713aSLionel Sambuc //==- CGObjCRuntime.cpp - Interface to Shared Objective-C Runtime Features ==//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This abstract class defines the interface for Objective-C runtime-specific
11f4a2713aSLionel Sambuc // code generation. It provides some concrete helper methods for functionality
12f4a2713aSLionel Sambuc // shared between all (or most) of the Objective-C runtimes supported by clang.
13f4a2713aSLionel Sambuc //
14f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
15f4a2713aSLionel Sambuc
16f4a2713aSLionel Sambuc #include "CGObjCRuntime.h"
17f4a2713aSLionel Sambuc #include "CGCleanup.h"
18f4a2713aSLionel Sambuc #include "CGRecordLayout.h"
19f4a2713aSLionel Sambuc #include "CodeGenFunction.h"
20f4a2713aSLionel Sambuc #include "CodeGenModule.h"
21f4a2713aSLionel Sambuc #include "clang/AST/RecordLayout.h"
22f4a2713aSLionel Sambuc #include "clang/AST/StmtObjC.h"
23f4a2713aSLionel Sambuc #include "clang/CodeGen/CGFunctionInfo.h"
24*0a6a1f1dSLionel Sambuc #include "llvm/IR/CallSite.h"
25f4a2713aSLionel Sambuc
26f4a2713aSLionel Sambuc using namespace clang;
27f4a2713aSLionel Sambuc using namespace CodeGen;
28f4a2713aSLionel Sambuc
LookupFieldBitOffset(CodeGen::CodeGenModule & CGM,const ObjCInterfaceDecl * OID,const ObjCImplementationDecl * ID,const ObjCIvarDecl * Ivar)29f4a2713aSLionel Sambuc static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
30f4a2713aSLionel Sambuc const ObjCInterfaceDecl *OID,
31f4a2713aSLionel Sambuc const ObjCImplementationDecl *ID,
32f4a2713aSLionel Sambuc const ObjCIvarDecl *Ivar) {
33f4a2713aSLionel Sambuc const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
34f4a2713aSLionel Sambuc
35f4a2713aSLionel Sambuc // FIXME: We should eliminate the need to have ObjCImplementationDecl passed
36f4a2713aSLionel Sambuc // in here; it should never be necessary because that should be the lexical
37f4a2713aSLionel Sambuc // decl context for the ivar.
38f4a2713aSLionel Sambuc
39f4a2713aSLionel Sambuc // If we know have an implementation (and the ivar is in it) then
40f4a2713aSLionel Sambuc // look up in the implementation layout.
41f4a2713aSLionel Sambuc const ASTRecordLayout *RL;
42f4a2713aSLionel Sambuc if (ID && declaresSameEntity(ID->getClassInterface(), Container))
43f4a2713aSLionel Sambuc RL = &CGM.getContext().getASTObjCImplementationLayout(ID);
44f4a2713aSLionel Sambuc else
45f4a2713aSLionel Sambuc RL = &CGM.getContext().getASTObjCInterfaceLayout(Container);
46f4a2713aSLionel Sambuc
47f4a2713aSLionel Sambuc // Compute field index.
48f4a2713aSLionel Sambuc //
49f4a2713aSLionel Sambuc // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is
50f4a2713aSLionel Sambuc // implemented. This should be fixed to get the information from the layout
51f4a2713aSLionel Sambuc // directly.
52f4a2713aSLionel Sambuc unsigned Index = 0;
53f4a2713aSLionel Sambuc
54f4a2713aSLionel Sambuc for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin();
55f4a2713aSLionel Sambuc IVD; IVD = IVD->getNextIvar()) {
56f4a2713aSLionel Sambuc if (Ivar == IVD)
57f4a2713aSLionel Sambuc break;
58f4a2713aSLionel Sambuc ++Index;
59f4a2713aSLionel Sambuc }
60f4a2713aSLionel Sambuc assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!");
61f4a2713aSLionel Sambuc
62f4a2713aSLionel Sambuc return RL->getFieldOffset(Index);
63f4a2713aSLionel Sambuc }
64f4a2713aSLionel Sambuc
ComputeIvarBaseOffset(CodeGen::CodeGenModule & CGM,const ObjCInterfaceDecl * OID,const ObjCIvarDecl * Ivar)65f4a2713aSLionel Sambuc uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
66f4a2713aSLionel Sambuc const ObjCInterfaceDecl *OID,
67f4a2713aSLionel Sambuc const ObjCIvarDecl *Ivar) {
68*0a6a1f1dSLionel Sambuc return LookupFieldBitOffset(CGM, OID, nullptr, Ivar) /
69f4a2713aSLionel Sambuc CGM.getContext().getCharWidth();
70f4a2713aSLionel Sambuc }
71f4a2713aSLionel Sambuc
ComputeIvarBaseOffset(CodeGen::CodeGenModule & CGM,const ObjCImplementationDecl * OID,const ObjCIvarDecl * Ivar)72f4a2713aSLionel Sambuc uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
73f4a2713aSLionel Sambuc const ObjCImplementationDecl *OID,
74f4a2713aSLionel Sambuc const ObjCIvarDecl *Ivar) {
75f4a2713aSLionel Sambuc return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) /
76f4a2713aSLionel Sambuc CGM.getContext().getCharWidth();
77f4a2713aSLionel Sambuc }
78f4a2713aSLionel Sambuc
ComputeBitfieldBitOffset(CodeGen::CodeGenModule & CGM,const ObjCInterfaceDecl * ID,const ObjCIvarDecl * Ivar)79f4a2713aSLionel Sambuc unsigned CGObjCRuntime::ComputeBitfieldBitOffset(
80f4a2713aSLionel Sambuc CodeGen::CodeGenModule &CGM,
81f4a2713aSLionel Sambuc const ObjCInterfaceDecl *ID,
82f4a2713aSLionel Sambuc const ObjCIvarDecl *Ivar) {
83f4a2713aSLionel Sambuc return LookupFieldBitOffset(CGM, ID, ID->getImplementation(), Ivar);
84f4a2713aSLionel Sambuc }
85f4a2713aSLionel Sambuc
EmitValueForIvarAtOffset(CodeGen::CodeGenFunction & CGF,const ObjCInterfaceDecl * OID,llvm::Value * BaseValue,const ObjCIvarDecl * Ivar,unsigned CVRQualifiers,llvm::Value * Offset)86f4a2713aSLionel Sambuc LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
87f4a2713aSLionel Sambuc const ObjCInterfaceDecl *OID,
88f4a2713aSLionel Sambuc llvm::Value *BaseValue,
89f4a2713aSLionel Sambuc const ObjCIvarDecl *Ivar,
90f4a2713aSLionel Sambuc unsigned CVRQualifiers,
91f4a2713aSLionel Sambuc llvm::Value *Offset) {
92f4a2713aSLionel Sambuc // Compute (type*) ( (char *) BaseValue + Offset)
93f4a2713aSLionel Sambuc QualType IvarTy = Ivar->getType();
94f4a2713aSLionel Sambuc llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
95f4a2713aSLionel Sambuc llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy);
96f4a2713aSLionel Sambuc V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr");
97f4a2713aSLionel Sambuc
98f4a2713aSLionel Sambuc if (!Ivar->isBitField()) {
99f4a2713aSLionel Sambuc V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
100f4a2713aSLionel Sambuc LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy);
101f4a2713aSLionel Sambuc LV.getQuals().addCVRQualifiers(CVRQualifiers);
102f4a2713aSLionel Sambuc return LV;
103f4a2713aSLionel Sambuc }
104f4a2713aSLionel Sambuc
105f4a2713aSLionel Sambuc // We need to compute an access strategy for this bit-field. We are given the
106f4a2713aSLionel Sambuc // offset to the first byte in the bit-field, the sub-byte offset is taken
107f4a2713aSLionel Sambuc // from the original layout. We reuse the normal bit-field access strategy by
108f4a2713aSLionel Sambuc // treating this as an access to a struct where the bit-field is in byte 0,
109f4a2713aSLionel Sambuc // and adjust the containing type size as appropriate.
110f4a2713aSLionel Sambuc //
111f4a2713aSLionel Sambuc // FIXME: Note that currently we make a very conservative estimate of the
112f4a2713aSLionel Sambuc // alignment of the bit-field, because (a) it is not clear what guarantees the
113f4a2713aSLionel Sambuc // runtime makes us, and (b) we don't have a way to specify that the struct is
114f4a2713aSLionel Sambuc // at an alignment plus offset.
115f4a2713aSLionel Sambuc //
116f4a2713aSLionel Sambuc // Note, there is a subtle invariant here: we can only call this routine on
117f4a2713aSLionel Sambuc // non-synthesized ivars but we may be called for synthesized ivars. However,
118f4a2713aSLionel Sambuc // a synthesized ivar can never be a bit-field, so this is safe.
119*0a6a1f1dSLionel Sambuc uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, nullptr, Ivar);
120f4a2713aSLionel Sambuc uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
121f4a2713aSLionel Sambuc uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign();
122f4a2713aSLionel Sambuc uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
123f4a2713aSLionel Sambuc CharUnits StorageSize =
124f4a2713aSLionel Sambuc CGF.CGM.getContext().toCharUnitsFromBits(
125f4a2713aSLionel Sambuc llvm::RoundUpToAlignment(BitOffset + BitFieldSize, AlignmentBits));
126f4a2713aSLionel Sambuc CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits);
127f4a2713aSLionel Sambuc
128f4a2713aSLionel Sambuc // Allocate a new CGBitFieldInfo object to describe this access.
129f4a2713aSLionel Sambuc //
130f4a2713aSLionel Sambuc // FIXME: This is incredibly wasteful, these should be uniqued or part of some
131f4a2713aSLionel Sambuc // layout object. However, this is blocked on other cleanups to the
132f4a2713aSLionel Sambuc // Objective-C code, so for now we just live with allocating a bunch of these
133f4a2713aSLionel Sambuc // objects.
134f4a2713aSLionel Sambuc CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo(
135f4a2713aSLionel Sambuc CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize,
136f4a2713aSLionel Sambuc CGF.CGM.getContext().toBits(StorageSize),
137f4a2713aSLionel Sambuc Alignment.getQuantity()));
138f4a2713aSLionel Sambuc
139f4a2713aSLionel Sambuc V = CGF.Builder.CreateBitCast(V,
140f4a2713aSLionel Sambuc llvm::Type::getIntNPtrTy(CGF.getLLVMContext(),
141f4a2713aSLionel Sambuc Info->StorageSize));
142f4a2713aSLionel Sambuc return LValue::MakeBitfield(V, *Info,
143f4a2713aSLionel Sambuc IvarTy.withCVRQualifiers(CVRQualifiers),
144f4a2713aSLionel Sambuc Alignment);
145f4a2713aSLionel Sambuc }
146f4a2713aSLionel Sambuc
147f4a2713aSLionel Sambuc namespace {
148f4a2713aSLionel Sambuc struct CatchHandler {
149f4a2713aSLionel Sambuc const VarDecl *Variable;
150f4a2713aSLionel Sambuc const Stmt *Body;
151f4a2713aSLionel Sambuc llvm::BasicBlock *Block;
152*0a6a1f1dSLionel Sambuc llvm::Constant *TypeInfo;
153f4a2713aSLionel Sambuc };
154f4a2713aSLionel Sambuc
155f4a2713aSLionel Sambuc struct CallObjCEndCatch : EHScopeStack::Cleanup {
CallObjCEndCatch__anoncd3284fd0111::CallObjCEndCatch156f4a2713aSLionel Sambuc CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) :
157f4a2713aSLionel Sambuc MightThrow(MightThrow), Fn(Fn) {}
158f4a2713aSLionel Sambuc bool MightThrow;
159f4a2713aSLionel Sambuc llvm::Value *Fn;
160f4a2713aSLionel Sambuc
Emit__anoncd3284fd0111::CallObjCEndCatch161*0a6a1f1dSLionel Sambuc void Emit(CodeGenFunction &CGF, Flags flags) override {
162f4a2713aSLionel Sambuc if (!MightThrow) {
163f4a2713aSLionel Sambuc CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
164f4a2713aSLionel Sambuc return;
165f4a2713aSLionel Sambuc }
166f4a2713aSLionel Sambuc
167f4a2713aSLionel Sambuc CGF.EmitRuntimeCallOrInvoke(Fn);
168f4a2713aSLionel Sambuc }
169f4a2713aSLionel Sambuc };
170f4a2713aSLionel Sambuc }
171f4a2713aSLionel Sambuc
172f4a2713aSLionel Sambuc
EmitTryCatchStmt(CodeGenFunction & CGF,const ObjCAtTryStmt & S,llvm::Constant * beginCatchFn,llvm::Constant * endCatchFn,llvm::Constant * exceptionRethrowFn)173f4a2713aSLionel Sambuc void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
174f4a2713aSLionel Sambuc const ObjCAtTryStmt &S,
175f4a2713aSLionel Sambuc llvm::Constant *beginCatchFn,
176f4a2713aSLionel Sambuc llvm::Constant *endCatchFn,
177f4a2713aSLionel Sambuc llvm::Constant *exceptionRethrowFn) {
178f4a2713aSLionel Sambuc // Jump destination for falling out of catch bodies.
179f4a2713aSLionel Sambuc CodeGenFunction::JumpDest Cont;
180f4a2713aSLionel Sambuc if (S.getNumCatchStmts())
181f4a2713aSLionel Sambuc Cont = CGF.getJumpDestInCurrentScope("eh.cont");
182f4a2713aSLionel Sambuc
183f4a2713aSLionel Sambuc CodeGenFunction::FinallyInfo FinallyInfo;
184f4a2713aSLionel Sambuc if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
185f4a2713aSLionel Sambuc FinallyInfo.enter(CGF, Finally->getFinallyBody(),
186f4a2713aSLionel Sambuc beginCatchFn, endCatchFn, exceptionRethrowFn);
187f4a2713aSLionel Sambuc
188f4a2713aSLionel Sambuc SmallVector<CatchHandler, 8> Handlers;
189f4a2713aSLionel Sambuc
190f4a2713aSLionel Sambuc // Enter the catch, if there is one.
191f4a2713aSLionel Sambuc if (S.getNumCatchStmts()) {
192f4a2713aSLionel Sambuc for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) {
193f4a2713aSLionel Sambuc const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I);
194f4a2713aSLionel Sambuc const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
195f4a2713aSLionel Sambuc
196f4a2713aSLionel Sambuc Handlers.push_back(CatchHandler());
197f4a2713aSLionel Sambuc CatchHandler &Handler = Handlers.back();
198f4a2713aSLionel Sambuc Handler.Variable = CatchDecl;
199f4a2713aSLionel Sambuc Handler.Body = CatchStmt->getCatchBody();
200f4a2713aSLionel Sambuc Handler.Block = CGF.createBasicBlock("catch");
201f4a2713aSLionel Sambuc
202f4a2713aSLionel Sambuc // @catch(...) always matches.
203f4a2713aSLionel Sambuc if (!CatchDecl) {
204*0a6a1f1dSLionel Sambuc Handler.TypeInfo = nullptr; // catch-all
205f4a2713aSLionel Sambuc // Don't consider any other catches.
206f4a2713aSLionel Sambuc break;
207f4a2713aSLionel Sambuc }
208f4a2713aSLionel Sambuc
209f4a2713aSLionel Sambuc Handler.TypeInfo = GetEHType(CatchDecl->getType());
210f4a2713aSLionel Sambuc }
211f4a2713aSLionel Sambuc
212f4a2713aSLionel Sambuc EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size());
213f4a2713aSLionel Sambuc for (unsigned I = 0, E = Handlers.size(); I != E; ++I)
214f4a2713aSLionel Sambuc Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block);
215f4a2713aSLionel Sambuc }
216f4a2713aSLionel Sambuc
217f4a2713aSLionel Sambuc // Emit the try body.
218f4a2713aSLionel Sambuc CGF.EmitStmt(S.getTryBody());
219f4a2713aSLionel Sambuc
220f4a2713aSLionel Sambuc // Leave the try.
221f4a2713aSLionel Sambuc if (S.getNumCatchStmts())
222f4a2713aSLionel Sambuc CGF.popCatchScope();
223f4a2713aSLionel Sambuc
224f4a2713aSLionel Sambuc // Remember where we were.
225f4a2713aSLionel Sambuc CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
226f4a2713aSLionel Sambuc
227f4a2713aSLionel Sambuc // Emit the handlers.
228f4a2713aSLionel Sambuc for (unsigned I = 0, E = Handlers.size(); I != E; ++I) {
229f4a2713aSLionel Sambuc CatchHandler &Handler = Handlers[I];
230f4a2713aSLionel Sambuc
231f4a2713aSLionel Sambuc CGF.EmitBlock(Handler.Block);
232f4a2713aSLionel Sambuc llvm::Value *RawExn = CGF.getExceptionFromSlot();
233f4a2713aSLionel Sambuc
234f4a2713aSLionel Sambuc // Enter the catch.
235f4a2713aSLionel Sambuc llvm::Value *Exn = RawExn;
236f4a2713aSLionel Sambuc if (beginCatchFn) {
237f4a2713aSLionel Sambuc Exn = CGF.Builder.CreateCall(beginCatchFn, RawExn, "exn.adjusted");
238f4a2713aSLionel Sambuc cast<llvm::CallInst>(Exn)->setDoesNotThrow();
239f4a2713aSLionel Sambuc }
240f4a2713aSLionel Sambuc
241f4a2713aSLionel Sambuc CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange());
242f4a2713aSLionel Sambuc
243f4a2713aSLionel Sambuc if (endCatchFn) {
244f4a2713aSLionel Sambuc // Add a cleanup to leave the catch.
245*0a6a1f1dSLionel Sambuc bool EndCatchMightThrow = (Handler.Variable == nullptr);
246f4a2713aSLionel Sambuc
247f4a2713aSLionel Sambuc CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup,
248f4a2713aSLionel Sambuc EndCatchMightThrow,
249f4a2713aSLionel Sambuc endCatchFn);
250f4a2713aSLionel Sambuc }
251f4a2713aSLionel Sambuc
252f4a2713aSLionel Sambuc // Bind the catch parameter if it exists.
253f4a2713aSLionel Sambuc if (const VarDecl *CatchParam = Handler.Variable) {
254f4a2713aSLionel Sambuc llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType());
255f4a2713aSLionel Sambuc llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType);
256f4a2713aSLionel Sambuc
257f4a2713aSLionel Sambuc CGF.EmitAutoVarDecl(*CatchParam);
258f4a2713aSLionel Sambuc
259f4a2713aSLionel Sambuc llvm::Value *CatchParamAddr = CGF.GetAddrOfLocalVar(CatchParam);
260f4a2713aSLionel Sambuc
261f4a2713aSLionel Sambuc switch (CatchParam->getType().getQualifiers().getObjCLifetime()) {
262f4a2713aSLionel Sambuc case Qualifiers::OCL_Strong:
263f4a2713aSLionel Sambuc CastExn = CGF.EmitARCRetainNonBlock(CastExn);
264f4a2713aSLionel Sambuc // fallthrough
265f4a2713aSLionel Sambuc
266f4a2713aSLionel Sambuc case Qualifiers::OCL_None:
267f4a2713aSLionel Sambuc case Qualifiers::OCL_ExplicitNone:
268f4a2713aSLionel Sambuc case Qualifiers::OCL_Autoreleasing:
269f4a2713aSLionel Sambuc CGF.Builder.CreateStore(CastExn, CatchParamAddr);
270f4a2713aSLionel Sambuc break;
271f4a2713aSLionel Sambuc
272f4a2713aSLionel Sambuc case Qualifiers::OCL_Weak:
273f4a2713aSLionel Sambuc CGF.EmitARCInitWeak(CatchParamAddr, CastExn);
274f4a2713aSLionel Sambuc break;
275f4a2713aSLionel Sambuc }
276f4a2713aSLionel Sambuc }
277f4a2713aSLionel Sambuc
278f4a2713aSLionel Sambuc CGF.ObjCEHValueStack.push_back(Exn);
279f4a2713aSLionel Sambuc CGF.EmitStmt(Handler.Body);
280f4a2713aSLionel Sambuc CGF.ObjCEHValueStack.pop_back();
281f4a2713aSLionel Sambuc
282f4a2713aSLionel Sambuc // Leave any cleanups associated with the catch.
283f4a2713aSLionel Sambuc cleanups.ForceCleanup();
284f4a2713aSLionel Sambuc
285f4a2713aSLionel Sambuc CGF.EmitBranchThroughCleanup(Cont);
286f4a2713aSLionel Sambuc }
287f4a2713aSLionel Sambuc
288f4a2713aSLionel Sambuc // Go back to the try-statement fallthrough.
289f4a2713aSLionel Sambuc CGF.Builder.restoreIP(SavedIP);
290f4a2713aSLionel Sambuc
291f4a2713aSLionel Sambuc // Pop out of the finally.
292f4a2713aSLionel Sambuc if (S.getFinallyStmt())
293f4a2713aSLionel Sambuc FinallyInfo.exit(CGF);
294f4a2713aSLionel Sambuc
295f4a2713aSLionel Sambuc if (Cont.isValid())
296f4a2713aSLionel Sambuc CGF.EmitBlock(Cont.getBlock());
297f4a2713aSLionel Sambuc }
298f4a2713aSLionel Sambuc
299f4a2713aSLionel Sambuc namespace {
300f4a2713aSLionel Sambuc struct CallSyncExit : EHScopeStack::Cleanup {
301f4a2713aSLionel Sambuc llvm::Value *SyncExitFn;
302f4a2713aSLionel Sambuc llvm::Value *SyncArg;
CallSyncExit__anoncd3284fd0211::CallSyncExit303f4a2713aSLionel Sambuc CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg)
304f4a2713aSLionel Sambuc : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
305f4a2713aSLionel Sambuc
Emit__anoncd3284fd0211::CallSyncExit306*0a6a1f1dSLionel Sambuc void Emit(CodeGenFunction &CGF, Flags flags) override {
307f4a2713aSLionel Sambuc CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow();
308f4a2713aSLionel Sambuc }
309f4a2713aSLionel Sambuc };
310f4a2713aSLionel Sambuc }
311f4a2713aSLionel Sambuc
EmitAtSynchronizedStmt(CodeGenFunction & CGF,const ObjCAtSynchronizedStmt & S,llvm::Function * syncEnterFn,llvm::Function * syncExitFn)312f4a2713aSLionel Sambuc void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF,
313f4a2713aSLionel Sambuc const ObjCAtSynchronizedStmt &S,
314f4a2713aSLionel Sambuc llvm::Function *syncEnterFn,
315f4a2713aSLionel Sambuc llvm::Function *syncExitFn) {
316f4a2713aSLionel Sambuc CodeGenFunction::RunCleanupsScope cleanups(CGF);
317f4a2713aSLionel Sambuc
318f4a2713aSLionel Sambuc // Evaluate the lock operand. This is guaranteed to dominate the
319f4a2713aSLionel Sambuc // ARC release and lock-release cleanups.
320f4a2713aSLionel Sambuc const Expr *lockExpr = S.getSynchExpr();
321f4a2713aSLionel Sambuc llvm::Value *lock;
322f4a2713aSLionel Sambuc if (CGF.getLangOpts().ObjCAutoRefCount) {
323f4a2713aSLionel Sambuc lock = CGF.EmitARCRetainScalarExpr(lockExpr);
324f4a2713aSLionel Sambuc lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock);
325f4a2713aSLionel Sambuc } else {
326f4a2713aSLionel Sambuc lock = CGF.EmitScalarExpr(lockExpr);
327f4a2713aSLionel Sambuc }
328f4a2713aSLionel Sambuc lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy);
329f4a2713aSLionel Sambuc
330f4a2713aSLionel Sambuc // Acquire the lock.
331f4a2713aSLionel Sambuc CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow();
332f4a2713aSLionel Sambuc
333f4a2713aSLionel Sambuc // Register an all-paths cleanup to release the lock.
334f4a2713aSLionel Sambuc CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock);
335f4a2713aSLionel Sambuc
336f4a2713aSLionel Sambuc // Emit the body of the statement.
337f4a2713aSLionel Sambuc CGF.EmitStmt(S.getSynchBody());
338f4a2713aSLionel Sambuc }
339f4a2713aSLionel Sambuc
340f4a2713aSLionel Sambuc /// Compute the pointer-to-function type to which a message send
341f4a2713aSLionel Sambuc /// should be casted in order to correctly call the given method
342f4a2713aSLionel Sambuc /// with the given arguments.
343f4a2713aSLionel Sambuc ///
344f4a2713aSLionel Sambuc /// \param method - may be null
345f4a2713aSLionel Sambuc /// \param resultType - the result type to use if there's no method
346f4a2713aSLionel Sambuc /// \param callArgs - the actual arguments, including implicit ones
347f4a2713aSLionel Sambuc CGObjCRuntime::MessageSendInfo
getMessageSendInfo(const ObjCMethodDecl * method,QualType resultType,CallArgList & callArgs)348f4a2713aSLionel Sambuc CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
349f4a2713aSLionel Sambuc QualType resultType,
350f4a2713aSLionel Sambuc CallArgList &callArgs) {
351f4a2713aSLionel Sambuc // If there's a method, use information from that.
352f4a2713aSLionel Sambuc if (method) {
353f4a2713aSLionel Sambuc const CGFunctionInfo &signature =
354f4a2713aSLionel Sambuc CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty);
355f4a2713aSLionel Sambuc
356f4a2713aSLionel Sambuc llvm::PointerType *signatureType =
357f4a2713aSLionel Sambuc CGM.getTypes().GetFunctionType(signature)->getPointerTo();
358f4a2713aSLionel Sambuc
359f4a2713aSLionel Sambuc // If that's not variadic, there's no need to recompute the ABI
360f4a2713aSLionel Sambuc // arrangement.
361f4a2713aSLionel Sambuc if (!signature.isVariadic())
362f4a2713aSLionel Sambuc return MessageSendInfo(signature, signatureType);
363f4a2713aSLionel Sambuc
364f4a2713aSLionel Sambuc // Otherwise, there is.
365f4a2713aSLionel Sambuc FunctionType::ExtInfo einfo = signature.getExtInfo();
366f4a2713aSLionel Sambuc const CGFunctionInfo &argsInfo =
367f4a2713aSLionel Sambuc CGM.getTypes().arrangeFreeFunctionCall(resultType, callArgs, einfo,
368f4a2713aSLionel Sambuc signature.getRequiredArgs());
369f4a2713aSLionel Sambuc
370f4a2713aSLionel Sambuc return MessageSendInfo(argsInfo, signatureType);
371f4a2713aSLionel Sambuc }
372f4a2713aSLionel Sambuc
373f4a2713aSLionel Sambuc // There's no method; just use a default CC.
374f4a2713aSLionel Sambuc const CGFunctionInfo &argsInfo =
375f4a2713aSLionel Sambuc CGM.getTypes().arrangeFreeFunctionCall(resultType, callArgs,
376f4a2713aSLionel Sambuc FunctionType::ExtInfo(),
377f4a2713aSLionel Sambuc RequiredArgs::All);
378f4a2713aSLionel Sambuc
379f4a2713aSLionel Sambuc // Derive the signature to call from that.
380f4a2713aSLionel Sambuc llvm::PointerType *signatureType =
381f4a2713aSLionel Sambuc CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo();
382f4a2713aSLionel Sambuc return MessageSendInfo(argsInfo, signatureType);
383f4a2713aSLionel Sambuc }
384