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