David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 1 | //==- CGObjCRuntime.cpp - Interface to Shared Objective-C Runtime Features ==// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This abstract class defines the interface for Objective-C runtime-specific |
| 11 | // code generation. It provides some concrete helper methods for functionality |
| 12 | // shared between all (or most) of the Objective-C runtimes supported by clang. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #include "CGObjCRuntime.h" |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 17 | #include "CGCleanup.h" |
Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 18 | #include "CGRecordLayout.h" |
| 19 | #include "CodeGenFunction.h" |
| 20 | #include "CodeGenModule.h" |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 21 | #include "clang/AST/RecordLayout.h" |
| 22 | #include "clang/AST/StmtObjC.h" |
Mark Lacey | a8e7df3 | 2013-10-30 21:53:58 +0000 | [diff] [blame] | 23 | #include "clang/CodeGen/CGFunctionInfo.h" |
Chandler Carruth | c80ceea | 2014-03-04 11:02:08 +0000 | [diff] [blame] | 24 | #include "llvm/IR/CallSite.h" |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 25 | |
| 26 | using namespace clang; |
| 27 | using namespace CodeGen; |
| 28 | |
Eli Friedman | 8cbca20 | 2012-11-06 22:15:52 +0000 | [diff] [blame] | 29 | uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
| 30 | const ObjCInterfaceDecl *OID, |
| 31 | const ObjCIvarDecl *Ivar) { |
Akira Hatanaka | 4b1c484 | 2017-06-27 04:34:04 +0000 | [diff] [blame] | 32 | return CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar) / |
| 33 | CGM.getContext().getCharWidth(); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 34 | } |
| 35 | |
Eli Friedman | 8cbca20 | 2012-11-06 22:15:52 +0000 | [diff] [blame] | 36 | uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
| 37 | const ObjCImplementationDecl *OID, |
| 38 | const ObjCIvarDecl *Ivar) { |
Akira Hatanaka | 4b1c484 | 2017-06-27 04:34:04 +0000 | [diff] [blame] | 39 | return CGM.getContext().lookupFieldBitOffset(OID->getClassInterface(), OID, |
| 40 | Ivar) / |
| 41 | CGM.getContext().getCharWidth(); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 42 | } |
| 43 | |
Eli Friedman | 8593748 | 2012-11-06 23:40:48 +0000 | [diff] [blame] | 44 | unsigned CGObjCRuntime::ComputeBitfieldBitOffset( |
| 45 | CodeGen::CodeGenModule &CGM, |
| 46 | const ObjCInterfaceDecl *ID, |
| 47 | const ObjCIvarDecl *Ivar) { |
Akira Hatanaka | 4b1c484 | 2017-06-27 04:34:04 +0000 | [diff] [blame] | 48 | return CGM.getContext().lookupFieldBitOffset(ID, ID->getImplementation(), |
| 49 | Ivar); |
Eli Friedman | 8593748 | 2012-11-06 23:40:48 +0000 | [diff] [blame] | 50 | } |
| 51 | |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 52 | LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, |
| 53 | const ObjCInterfaceDecl *OID, |
| 54 | llvm::Value *BaseValue, |
| 55 | const ObjCIvarDecl *Ivar, |
| 56 | unsigned CVRQualifiers, |
| 57 | llvm::Value *Offset) { |
| 58 | // Compute (type*) ( (char *) BaseValue + Offset) |
Akira Hatanaka | 14149bf | 2017-06-01 18:41:25 +0000 | [diff] [blame] | 59 | QualType InterfaceTy{OID->getTypeForDecl(), 0}; |
| 60 | QualType ObjectPtrTy = |
| 61 | CGF.CGM.getContext().getObjCObjectPointerType(InterfaceTy); |
| 62 | QualType IvarTy = |
| 63 | Ivar->getUsageType(ObjectPtrTy).withCVRQualifiers(CVRQualifiers); |
Chris Lattner | 2192fe5 | 2011-07-18 04:24:23 +0000 | [diff] [blame] | 64 | llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); |
Chandler Carruth | ff0e3a1 | 2012-12-06 11:14:44 +0000 | [diff] [blame] | 65 | llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 66 | V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr"); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 67 | |
| 68 | if (!Ivar->isBitField()) { |
Chandler Carruth | ff0e3a1 | 2012-12-06 11:14:44 +0000 | [diff] [blame] | 69 | V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); |
Eli Friedman | 3184a5e | 2011-12-19 23:03:09 +0000 | [diff] [blame] | 70 | LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 71 | return LV; |
| 72 | } |
| 73 | |
| 74 | // We need to compute an access strategy for this bit-field. We are given the |
| 75 | // offset to the first byte in the bit-field, the sub-byte offset is taken |
| 76 | // from the original layout. We reuse the normal bit-field access strategy by |
| 77 | // treating this as an access to a struct where the bit-field is in byte 0, |
| 78 | // and adjust the containing type size as appropriate. |
| 79 | // |
| 80 | // FIXME: Note that currently we make a very conservative estimate of the |
| 81 | // alignment of the bit-field, because (a) it is not clear what guarantees the |
| 82 | // runtime makes us, and (b) we don't have a way to specify that the struct is |
| 83 | // at an alignment plus offset. |
| 84 | // |
| 85 | // Note, there is a subtle invariant here: we can only call this routine on |
| 86 | // non-synthesized ivars but we may be called for synthesized ivars. However, |
| 87 | // a synthesized ivar can never be a bit-field, so this is safe. |
Akira Hatanaka | 4b1c484 | 2017-06-27 04:34:04 +0000 | [diff] [blame] | 88 | uint64_t FieldBitOffset = |
| 89 | CGF.CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar); |
Ken Dyck | abae3be | 2011-04-22 17:23:43 +0000 | [diff] [blame] | 90 | uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); |
John McCall | c8e0170 | 2013-04-16 22:48:15 +0000 | [diff] [blame] | 91 | uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign(); |
Richard Smith | caf3390 | 2011-10-10 18:28:20 +0000 | [diff] [blame] | 92 | uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); |
Rui Ueyama | 83aa979 | 2016-01-14 21:00:27 +0000 | [diff] [blame] | 93 | CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits( |
| 94 | llvm::alignTo(BitOffset + BitFieldSize, AlignmentBits)); |
Chandler Carruth | ff0e3a1 | 2012-12-06 11:14:44 +0000 | [diff] [blame] | 95 | CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 96 | |
| 97 | // Allocate a new CGBitFieldInfo object to describe this access. |
| 98 | // |
| 99 | // FIXME: This is incredibly wasteful, these should be uniqued or part of some |
| 100 | // layout object. However, this is blocked on other cleanups to the |
| 101 | // Objective-C code, so for now we just live with allocating a bunch of these |
| 102 | // objects. |
| 103 | CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( |
| 104 | CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, |
Chandler Carruth | ff0e3a1 | 2012-12-06 11:14:44 +0000 | [diff] [blame] | 105 | CGF.CGM.getContext().toBits(StorageSize), |
Ulrich Weigand | 03ce2a1 | 2015-07-10 17:30:00 +0000 | [diff] [blame] | 106 | CharUnits::fromQuantity(0))); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 107 | |
John McCall | 7f416cc | 2015-09-08 08:05:57 +0000 | [diff] [blame] | 108 | Address Addr(V, Alignment); |
| 109 | Addr = CGF.Builder.CreateElementBitCast(Addr, |
| 110 | llvm::Type::getIntNTy(CGF.getLLVMContext(), |
Chandler Carruth | ff0e3a1 | 2012-12-06 11:14:44 +0000 | [diff] [blame] | 111 | Info->StorageSize)); |
Krzysztof Parzyszek | 8f24823 | 2017-05-18 17:07:11 +0000 | [diff] [blame] | 112 | return LValue::MakeBitfield(Addr, *Info, IvarTy, |
Ivan A. Kosarev | b9c59f3 | 2017-10-31 11:05:34 +0000 | [diff] [blame] | 113 | LValueBaseInfo(AlignmentSource::Decl), |
Ivan A. Kosarev | d17f12a | 2017-10-17 10:17:43 +0000 | [diff] [blame] | 114 | TBAAAccessInfo()); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | namespace { |
| 118 | struct CatchHandler { |
| 119 | const VarDecl *Variable; |
| 120 | const Stmt *Body; |
| 121 | llvm::BasicBlock *Block; |
Rafael Espindola | bb9e7a3 | 2014-06-04 18:51:46 +0000 | [diff] [blame] | 122 | llvm::Constant *TypeInfo; |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 123 | }; |
| 124 | |
David Blaikie | 7e70d68 | 2015-08-18 22:40:54 +0000 | [diff] [blame] | 125 | struct CallObjCEndCatch final : EHScopeStack::Cleanup { |
Saleem Abdulrasool | 887a82c | 2016-10-13 19:45:08 +0000 | [diff] [blame] | 126 | CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) |
| 127 | : MightThrow(MightThrow), Fn(Fn) {} |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 128 | bool MightThrow; |
| 129 | llvm::Value *Fn; |
| 130 | |
Craig Topper | 4f12f10 | 2014-03-12 06:41:41 +0000 | [diff] [blame] | 131 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
Saleem Abdulrasool | 887a82c | 2016-10-13 19:45:08 +0000 | [diff] [blame] | 132 | if (MightThrow) |
| 133 | CGF.EmitRuntimeCallOrInvoke(Fn); |
| 134 | else |
| 135 | CGF.EmitNounwindRuntimeCall(Fn); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 136 | } |
| 137 | }; |
Alexander Kornienko | ab9db51 | 2015-06-22 23:07:51 +0000 | [diff] [blame] | 138 | } |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 139 | |
| 140 | |
| 141 | void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, |
| 142 | const ObjCAtTryStmt &S, |
David Chisnall | 3fe8956 | 2011-05-23 22:33:28 +0000 | [diff] [blame] | 143 | llvm::Constant *beginCatchFn, |
| 144 | llvm::Constant *endCatchFn, |
| 145 | llvm::Constant *exceptionRethrowFn) { |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 146 | // Jump destination for falling out of catch bodies. |
| 147 | CodeGenFunction::JumpDest Cont; |
| 148 | if (S.getNumCatchStmts()) |
| 149 | Cont = CGF.getJumpDestInCurrentScope("eh.cont"); |
| 150 | |
| 151 | CodeGenFunction::FinallyInfo FinallyInfo; |
| 152 | if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) |
John McCall | 6b0feb7 | 2011-06-22 02:32:12 +0000 | [diff] [blame] | 153 | FinallyInfo.enter(CGF, Finally->getFinallyBody(), |
| 154 | beginCatchFn, endCatchFn, exceptionRethrowFn); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 155 | |
Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 156 | SmallVector<CatchHandler, 8> Handlers; |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 157 | |
| 158 | // Enter the catch, if there is one. |
| 159 | if (S.getNumCatchStmts()) { |
| 160 | for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) { |
| 161 | const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I); |
| 162 | const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); |
| 163 | |
| 164 | Handlers.push_back(CatchHandler()); |
| 165 | CatchHandler &Handler = Handlers.back(); |
| 166 | Handler.Variable = CatchDecl; |
| 167 | Handler.Body = CatchStmt->getCatchBody(); |
| 168 | Handler.Block = CGF.createBasicBlock("catch"); |
| 169 | |
| 170 | // @catch(...) always matches. |
| 171 | if (!CatchDecl) { |
Craig Topper | 8a13c41 | 2014-05-21 05:09:00 +0000 | [diff] [blame] | 172 | Handler.TypeInfo = nullptr; // catch-all |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 173 | // Don't consider any other catches. |
| 174 | break; |
| 175 | } |
| 176 | |
| 177 | Handler.TypeInfo = GetEHType(CatchDecl->getType()); |
| 178 | } |
| 179 | |
| 180 | EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size()); |
| 181 | for (unsigned I = 0, E = Handlers.size(); I != E; ++I) |
| 182 | Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block); |
| 183 | } |
| 184 | |
| 185 | // Emit the try body. |
| 186 | CGF.EmitStmt(S.getTryBody()); |
| 187 | |
| 188 | // Leave the try. |
| 189 | if (S.getNumCatchStmts()) |
John McCall | 8e4c74b | 2011-08-11 02:22:43 +0000 | [diff] [blame] | 190 | CGF.popCatchScope(); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 191 | |
| 192 | // Remember where we were. |
| 193 | CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); |
| 194 | |
| 195 | // Emit the handlers. |
| 196 | for (unsigned I = 0, E = Handlers.size(); I != E; ++I) { |
| 197 | CatchHandler &Handler = Handlers[I]; |
| 198 | |
| 199 | CGF.EmitBlock(Handler.Block); |
Bill Wendling | 79a70e4 | 2011-09-15 18:57:19 +0000 | [diff] [blame] | 200 | llvm::Value *RawExn = CGF.getExceptionFromSlot(); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 201 | |
| 202 | // Enter the catch. |
| 203 | llvm::Value *Exn = RawExn; |
Saleem Abdulrasool | 887a82c | 2016-10-13 19:45:08 +0000 | [diff] [blame] | 204 | if (beginCatchFn) |
| 205 | Exn = CGF.EmitNounwindRuntimeCall(beginCatchFn, RawExn, "exn.adjusted"); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 206 | |
Eric Christopher | 7ec8ec8 | 2011-10-19 00:44:01 +0000 | [diff] [blame] | 207 | CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange()); |
John McCall | 3f6e745 | 2011-05-12 01:00:15 +0000 | [diff] [blame] | 208 | |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 209 | if (endCatchFn) { |
| 210 | // Add a cleanup to leave the catch. |
Craig Topper | 8a13c41 | 2014-05-21 05:09:00 +0000 | [diff] [blame] | 211 | bool EndCatchMightThrow = (Handler.Variable == nullptr); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 212 | |
| 213 | CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup, |
| 214 | EndCatchMightThrow, |
| 215 | endCatchFn); |
| 216 | } |
| 217 | |
| 218 | // Bind the catch parameter if it exists. |
| 219 | if (const VarDecl *CatchParam = Handler.Variable) { |
Chris Lattner | 2192fe5 | 2011-07-18 04:24:23 +0000 | [diff] [blame] | 220 | llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 221 | llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType); |
| 222 | |
| 223 | CGF.EmitAutoVarDecl(*CatchParam); |
John McCall | 17f0275 | 2015-10-30 00:56:02 +0000 | [diff] [blame] | 224 | EmitInitOfCatchParam(CGF, CastExn, CatchParam); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 225 | } |
| 226 | |
| 227 | CGF.ObjCEHValueStack.push_back(Exn); |
| 228 | CGF.EmitStmt(Handler.Body); |
| 229 | CGF.ObjCEHValueStack.pop_back(); |
| 230 | |
John McCall | 3f6e745 | 2011-05-12 01:00:15 +0000 | [diff] [blame] | 231 | // Leave any cleanups associated with the catch. |
| 232 | cleanups.ForceCleanup(); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 233 | |
| 234 | CGF.EmitBranchThroughCleanup(Cont); |
| 235 | } |
| 236 | |
| 237 | // Go back to the try-statement fallthrough. |
| 238 | CGF.Builder.restoreIP(SavedIP); |
| 239 | |
John McCall | 6b0feb7 | 2011-06-22 02:32:12 +0000 | [diff] [blame] | 240 | // Pop out of the finally. |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 241 | if (S.getFinallyStmt()) |
John McCall | 6b0feb7 | 2011-06-22 02:32:12 +0000 | [diff] [blame] | 242 | FinallyInfo.exit(CGF); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 243 | |
| 244 | if (Cont.isValid()) |
| 245 | CGF.EmitBlock(Cont.getBlock()); |
| 246 | } |
| 247 | |
John McCall | 17f0275 | 2015-10-30 00:56:02 +0000 | [diff] [blame] | 248 | void CGObjCRuntime::EmitInitOfCatchParam(CodeGenFunction &CGF, |
| 249 | llvm::Value *exn, |
| 250 | const VarDecl *paramDecl) { |
| 251 | |
| 252 | Address paramAddr = CGF.GetAddrOfLocalVar(paramDecl); |
| 253 | |
| 254 | switch (paramDecl->getType().getQualifiers().getObjCLifetime()) { |
| 255 | case Qualifiers::OCL_Strong: |
| 256 | exn = CGF.EmitARCRetainNonBlock(exn); |
| 257 | // fallthrough |
| 258 | |
| 259 | case Qualifiers::OCL_None: |
| 260 | case Qualifiers::OCL_ExplicitNone: |
| 261 | case Qualifiers::OCL_Autoreleasing: |
| 262 | CGF.Builder.CreateStore(exn, paramAddr); |
| 263 | return; |
| 264 | |
| 265 | case Qualifiers::OCL_Weak: |
| 266 | CGF.EmitARCInitWeak(paramAddr, exn); |
| 267 | return; |
| 268 | } |
| 269 | llvm_unreachable("invalid ownership qualifier"); |
| 270 | } |
| 271 | |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 272 | namespace { |
David Blaikie | 7e70d68 | 2015-08-18 22:40:54 +0000 | [diff] [blame] | 273 | struct CallSyncExit final : EHScopeStack::Cleanup { |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 274 | llvm::Value *SyncExitFn; |
| 275 | llvm::Value *SyncArg; |
| 276 | CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg) |
| 277 | : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} |
| 278 | |
Craig Topper | 4f12f10 | 2014-03-12 06:41:41 +0000 | [diff] [blame] | 279 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 280 | CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow(); |
| 281 | } |
| 282 | }; |
Alexander Kornienko | ab9db51 | 2015-06-22 23:07:51 +0000 | [diff] [blame] | 283 | } |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 284 | |
| 285 | void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF, |
| 286 | const ObjCAtSynchronizedStmt &S, |
| 287 | llvm::Function *syncEnterFn, |
| 288 | llvm::Function *syncExitFn) { |
John McCall | d9bb743 | 2011-07-27 21:50:02 +0000 | [diff] [blame] | 289 | CodeGenFunction::RunCleanupsScope cleanups(CGF); |
| 290 | |
| 291 | // Evaluate the lock operand. This is guaranteed to dominate the |
| 292 | // ARC release and lock-release cleanups. |
| 293 | const Expr *lockExpr = S.getSynchExpr(); |
| 294 | llvm::Value *lock; |
David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 295 | if (CGF.getLangOpts().ObjCAutoRefCount) { |
John McCall | d9bb743 | 2011-07-27 21:50:02 +0000 | [diff] [blame] | 296 | lock = CGF.EmitARCRetainScalarExpr(lockExpr); |
| 297 | lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock); |
| 298 | } else { |
| 299 | lock = CGF.EmitScalarExpr(lockExpr); |
| 300 | } |
| 301 | lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 302 | |
| 303 | // Acquire the lock. |
John McCall | d9bb743 | 2011-07-27 21:50:02 +0000 | [diff] [blame] | 304 | CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow(); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 305 | |
| 306 | // Register an all-paths cleanup to release the lock. |
John McCall | d9bb743 | 2011-07-27 21:50:02 +0000 | [diff] [blame] | 307 | CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 308 | |
| 309 | // Emit the body of the statement. |
| 310 | CGF.EmitStmt(S.getSynchBody()); |
David Chisnall | d3858d6 | 2011-03-25 11:57:33 +0000 | [diff] [blame] | 311 | } |
John McCall | a729c62 | 2012-02-17 03:33:10 +0000 | [diff] [blame] | 312 | |
| 313 | /// Compute the pointer-to-function type to which a message send |
| 314 | /// should be casted in order to correctly call the given method |
| 315 | /// with the given arguments. |
| 316 | /// |
| 317 | /// \param method - may be null |
| 318 | /// \param resultType - the result type to use if there's no method |
James Dennett | 9426c6c | 2012-06-15 09:02:08 +0000 | [diff] [blame] | 319 | /// \param callArgs - the actual arguments, including implicit ones |
John McCall | a729c62 | 2012-02-17 03:33:10 +0000 | [diff] [blame] | 320 | CGObjCRuntime::MessageSendInfo |
| 321 | CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method, |
| 322 | QualType resultType, |
| 323 | CallArgList &callArgs) { |
| 324 | // If there's a method, use information from that. |
| 325 | if (method) { |
| 326 | const CGFunctionInfo &signature = |
| 327 | CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty); |
| 328 | |
| 329 | llvm::PointerType *signatureType = |
| 330 | CGM.getTypes().GetFunctionType(signature)->getPointerTo(); |
| 331 | |
John McCall | c56a8b3 | 2016-03-11 04:30:31 +0000 | [diff] [blame] | 332 | const CGFunctionInfo &signatureForCall = |
| 333 | CGM.getTypes().arrangeCall(signature, callArgs); |
John McCall | a729c62 | 2012-02-17 03:33:10 +0000 | [diff] [blame] | 334 | |
John McCall | c56a8b3 | 2016-03-11 04:30:31 +0000 | [diff] [blame] | 335 | return MessageSendInfo(signatureForCall, signatureType); |
John McCall | a729c62 | 2012-02-17 03:33:10 +0000 | [diff] [blame] | 336 | } |
| 337 | |
| 338 | // There's no method; just use a default CC. |
| 339 | const CGFunctionInfo &argsInfo = |
John McCall | c56a8b3 | 2016-03-11 04:30:31 +0000 | [diff] [blame] | 340 | CGM.getTypes().arrangeUnprototypedObjCMessageSend(resultType, callArgs); |
John McCall | a729c62 | 2012-02-17 03:33:10 +0000 | [diff] [blame] | 341 | |
| 342 | // Derive the signature to call from that. |
| 343 | llvm::PointerType *signatureType = |
| 344 | CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo(); |
| 345 | return MessageSendInfo(argsInfo, signatureType); |
| 346 | } |