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