/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/CodeGen/CGObjCRuntime.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //==- CGObjCRuntime.cpp - Interface to Shared Objective-C Runtime Features ==// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This abstract class defines the interface for Objective-C runtime-specific |
10 | | // code generation. It provides some concrete helper methods for functionality |
11 | | // shared between all (or most) of the Objective-C runtimes supported by clang. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "CGObjCRuntime.h" |
16 | | #include "CGCXXABI.h" |
17 | | #include "CGCleanup.h" |
18 | | #include "CGRecordLayout.h" |
19 | | #include "CodeGenFunction.h" |
20 | | #include "CodeGenModule.h" |
21 | | #include "clang/AST/RecordLayout.h" |
22 | | #include "clang/AST/StmtObjC.h" |
23 | | #include "clang/CodeGen/CGFunctionInfo.h" |
24 | | #include "clang/CodeGen/CodeGenABITypes.h" |
25 | | #include "llvm/Support/SaveAndRestore.h" |
26 | | |
27 | | using namespace clang; |
28 | | using namespace CodeGen; |
29 | | |
30 | | uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
31 | | const ObjCInterfaceDecl *OID, |
32 | 463 | const ObjCIvarDecl *Ivar) { |
33 | 463 | return CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar) / |
34 | 463 | CGM.getContext().getCharWidth(); |
35 | 463 | } |
36 | | |
37 | | uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
38 | | const ObjCImplementationDecl *OID, |
39 | 2.49k | const ObjCIvarDecl *Ivar) { |
40 | 2.49k | return CGM.getContext().lookupFieldBitOffset(OID->getClassInterface(), OID, |
41 | 2.49k | Ivar) / |
42 | 2.49k | CGM.getContext().getCharWidth(); |
43 | 2.49k | } |
44 | | |
45 | | unsigned CGObjCRuntime::ComputeBitfieldBitOffset( |
46 | | CodeGen::CodeGenModule &CGM, |
47 | | const ObjCInterfaceDecl *ID, |
48 | 307 | const ObjCIvarDecl *Ivar) { |
49 | 307 | return CGM.getContext().lookupFieldBitOffset(ID, ID->getImplementation(), |
50 | 307 | Ivar); |
51 | 307 | } |
52 | | |
53 | | LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, |
54 | | const ObjCInterfaceDecl *OID, |
55 | | llvm::Value *BaseValue, |
56 | | const ObjCIvarDecl *Ivar, |
57 | | unsigned CVRQualifiers, |
58 | 2.22k | llvm::Value *Offset) { |
59 | | // Compute (type*) ( (char *) BaseValue + Offset) |
60 | 2.22k | QualType InterfaceTy{OID->getTypeForDecl(), 0}; |
61 | 2.22k | QualType ObjectPtrTy = |
62 | 2.22k | CGF.CGM.getContext().getObjCObjectPointerType(InterfaceTy); |
63 | 2.22k | QualType IvarTy = |
64 | 2.22k | Ivar->getUsageType(ObjectPtrTy).withCVRQualifiers(CVRQualifiers); |
65 | 2.22k | llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); |
66 | 2.22k | llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy); |
67 | 2.22k | V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr"); |
68 | | |
69 | 2.22k | if (!Ivar->isBitField()) { |
70 | 2.09k | V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); |
71 | 2.09k | LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy); |
72 | 2.09k | return LV; |
73 | 2.09k | } |
74 | | |
75 | | // We need to compute an access strategy for this bit-field. We are given the |
76 | | // offset to the first byte in the bit-field, the sub-byte offset is taken |
77 | | // from the original layout. We reuse the normal bit-field access strategy by |
78 | | // treating this as an access to a struct where the bit-field is in byte 0, |
79 | | // and adjust the containing type size as appropriate. |
80 | | // |
81 | | // FIXME: Note that currently we make a very conservative estimate of the |
82 | | // alignment of the bit-field, because (a) it is not clear what guarantees the |
83 | | // runtime makes us, and (b) we don't have a way to specify that the struct is |
84 | | // at an alignment plus offset. |
85 | | // |
86 | | // Note, there is a subtle invariant here: we can only call this routine on |
87 | | // non-synthesized ivars but we may be called for synthesized ivars. However, |
88 | | // a synthesized ivar can never be a bit-field, so this is safe. |
89 | 130 | uint64_t FieldBitOffset = |
90 | 130 | CGF.CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar); |
91 | 130 | uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); |
92 | 130 | uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign(); |
93 | 130 | uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); |
94 | 130 | CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits( |
95 | 130 | llvm::alignTo(BitOffset + BitFieldSize, AlignmentBits)); |
96 | 130 | CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits); |
97 | | |
98 | | // Allocate a new CGBitFieldInfo object to describe this access. |
99 | | // |
100 | | // FIXME: This is incredibly wasteful, these should be uniqued or part of some |
101 | | // layout object. However, this is blocked on other cleanups to the |
102 | | // Objective-C code, so for now we just live with allocating a bunch of these |
103 | | // objects. |
104 | 130 | CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( |
105 | 130 | CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, |
106 | 130 | CGF.CGM.getContext().toBits(StorageSize), |
107 | 130 | CharUnits::fromQuantity(0))); |
108 | | |
109 | 130 | Address Addr(V, Alignment); |
110 | 130 | Addr = CGF.Builder.CreateElementBitCast(Addr, |
111 | 130 | llvm::Type::getIntNTy(CGF.getLLVMContext(), |
112 | 130 | Info->StorageSize)); |
113 | 130 | return LValue::MakeBitfield(Addr, *Info, IvarTy, |
114 | 130 | LValueBaseInfo(AlignmentSource::Decl), |
115 | 130 | TBAAAccessInfo()); |
116 | 130 | } |
117 | | |
118 | | namespace { |
119 | | struct CatchHandler { |
120 | | const VarDecl *Variable; |
121 | | const Stmt *Body; |
122 | | llvm::BasicBlock *Block; |
123 | | llvm::Constant *TypeInfo; |
124 | | /// Flags used to differentiate cleanups and catchalls in Windows SEH |
125 | | unsigned Flags; |
126 | | }; |
127 | | |
128 | | struct CallObjCEndCatch final : EHScopeStack::Cleanup { |
129 | | CallObjCEndCatch(bool MightThrow, llvm::FunctionCallee Fn) |
130 | 175 | : MightThrow(MightThrow), Fn(Fn) {} |
131 | | bool MightThrow; |
132 | | llvm::FunctionCallee Fn; |
133 | | |
134 | 207 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
135 | 207 | if (MightThrow) |
136 | 24 | CGF.EmitRuntimeCallOrInvoke(Fn); |
137 | 183 | else |
138 | 183 | CGF.EmitNounwindRuntimeCall(Fn); |
139 | 207 | } |
140 | | }; |
141 | | } |
142 | | |
143 | | void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, |
144 | | const ObjCAtTryStmt &S, |
145 | | llvm::FunctionCallee beginCatchFn, |
146 | | llvm::FunctionCallee endCatchFn, |
147 | 184 | llvm::FunctionCallee exceptionRethrowFn) { |
148 | | // Jump destination for falling out of catch bodies. |
149 | 184 | CodeGenFunction::JumpDest Cont; |
150 | 184 | if (S.getNumCatchStmts()) |
151 | 180 | Cont = CGF.getJumpDestInCurrentScope("eh.cont"); |
152 | | |
153 | 184 | bool useFunclets = EHPersonality::get(CGF).usesFuncletPads(); |
154 | | |
155 | 184 | CodeGenFunction::FinallyInfo FinallyInfo; |
156 | 184 | if (!useFunclets) |
157 | 169 | if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) |
158 | 10 | FinallyInfo.enter(CGF, Finally->getFinallyBody(), |
159 | 10 | beginCatchFn, endCatchFn, exceptionRethrowFn); |
160 | | |
161 | 184 | SmallVector<CatchHandler, 8> Handlers; |
162 | | |
163 | | |
164 | | // Enter the catch, if there is one. |
165 | 184 | if (S.getNumCatchStmts()) { |
166 | 363 | for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I183 ) { |
167 | 225 | const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I); |
168 | 225 | const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); |
169 | | |
170 | 225 | Handlers.push_back(CatchHandler()); |
171 | 225 | CatchHandler &Handler = Handlers.back(); |
172 | 225 | Handler.Variable = CatchDecl; |
173 | 225 | Handler.Body = CatchStmt->getCatchBody(); |
174 | 225 | Handler.Block = CGF.createBasicBlock("catch"); |
175 | 225 | Handler.Flags = 0; |
176 | | |
177 | | // @catch(...) always matches. |
178 | 225 | if (!CatchDecl) { |
179 | 42 | auto catchAll = getCatchAllTypeInfo(); |
180 | 42 | Handler.TypeInfo = catchAll.RTTI; |
181 | 42 | Handler.Flags = catchAll.Flags; |
182 | | // Don't consider any other catches. |
183 | 42 | break; |
184 | 42 | } |
185 | | |
186 | 183 | Handler.TypeInfo = GetEHType(CatchDecl->getType()); |
187 | 183 | } |
188 | | |
189 | 180 | EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size()); |
190 | 405 | for (unsigned I = 0, E = Handlers.size(); I != E; ++I225 ) |
191 | 225 | Catch->setHandler(I, { Handlers[I].TypeInfo, Handlers[I].Flags }, Handlers[I].Block); |
192 | 180 | } |
193 | | |
194 | 184 | if (useFunclets) |
195 | 15 | if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) { |
196 | 0 | CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); |
197 | 0 | if (!CGF.CurSEHParent) |
198 | 0 | CGF.CurSEHParent = cast<NamedDecl>(CGF.CurFuncDecl); |
199 | | // Outline the finally block. |
200 | 0 | const Stmt *FinallyBlock = Finally->getFinallyBody(); |
201 | 0 | HelperCGF.startOutlinedSEHHelper(CGF, /*isFilter*/false, FinallyBlock); |
202 | | |
203 | | // Emit the original filter expression, convert to i32, and return. |
204 | 0 | HelperCGF.EmitStmt(FinallyBlock); |
205 | |
|
206 | 0 | HelperCGF.FinishFunction(FinallyBlock->getEndLoc()); |
207 | |
|
208 | 0 | llvm::Function *FinallyFunc = HelperCGF.CurFn; |
209 | | |
210 | | |
211 | | // Push a cleanup for __finally blocks. |
212 | 0 | CGF.pushSEHCleanup(NormalAndEHCleanup, FinallyFunc); |
213 | 0 | } |
214 | | |
215 | | |
216 | | // Emit the try body. |
217 | 184 | CGF.EmitStmt(S.getTryBody()); |
218 | | |
219 | | // Leave the try. |
220 | 184 | if (S.getNumCatchStmts()) |
221 | 180 | CGF.popCatchScope(); |
222 | | |
223 | | // Remember where we were. |
224 | 184 | CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); |
225 | | |
226 | | // Emit the handlers. |
227 | 409 | for (unsigned I = 0, E = Handlers.size(); I != E; ++I225 ) { |
228 | 225 | CatchHandler &Handler = Handlers[I]; |
229 | | |
230 | 225 | CGF.EmitBlock(Handler.Block); |
231 | 225 | llvm::CatchPadInst *CPI = nullptr; |
232 | 225 | SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(CGF.CurrentFuncletPad); |
233 | 225 | if (useFunclets) |
234 | 23 | if ((CPI = dyn_cast_or_null<llvm::CatchPadInst>(Handler.Block->getFirstNonPHI()))) { |
235 | 14 | CGF.CurrentFuncletPad = CPI; |
236 | 14 | CPI->setOperand(2, CGF.getExceptionSlot().getPointer()); |
237 | 14 | } |
238 | 225 | llvm::Value *RawExn = CGF.getExceptionFromSlot(); |
239 | | |
240 | | // Enter the catch. |
241 | 225 | llvm::Value *Exn = RawExn; |
242 | 225 | if (beginCatchFn) |
243 | 175 | Exn = CGF.EmitNounwindRuntimeCall(beginCatchFn, RawExn, "exn.adjusted"); |
244 | | |
245 | 225 | CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange()); |
246 | | |
247 | 225 | if (endCatchFn) { |
248 | | // Add a cleanup to leave the catch. |
249 | 175 | bool EndCatchMightThrow = (Handler.Variable == nullptr); |
250 | | |
251 | 175 | CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup, |
252 | 175 | EndCatchMightThrow, |
253 | 175 | endCatchFn); |
254 | 175 | } |
255 | | |
256 | | // Bind the catch parameter if it exists. |
257 | 225 | if (const VarDecl *CatchParam = Handler.Variable) { |
258 | 183 | llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); |
259 | 183 | llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType); |
260 | | |
261 | 183 | CGF.EmitAutoVarDecl(*CatchParam); |
262 | 183 | EmitInitOfCatchParam(CGF, CastExn, CatchParam); |
263 | 183 | } |
264 | 225 | if (CPI) |
265 | 14 | CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI); |
266 | | |
267 | 225 | CGF.ObjCEHValueStack.push_back(Exn); |
268 | 225 | CGF.EmitStmt(Handler.Body); |
269 | 225 | CGF.ObjCEHValueStack.pop_back(); |
270 | | |
271 | | // Leave any cleanups associated with the catch. |
272 | 225 | cleanups.ForceCleanup(); |
273 | | |
274 | 225 | CGF.EmitBranchThroughCleanup(Cont); |
275 | 225 | } |
276 | | |
277 | | // Go back to the try-statement fallthrough. |
278 | 184 | CGF.Builder.restoreIP(SavedIP); |
279 | | |
280 | | // Pop out of the finally. |
281 | 184 | if (!useFunclets && S.getFinallyStmt()169 ) |
282 | 10 | FinallyInfo.exit(CGF); |
283 | | |
284 | 184 | if (Cont.isValid()) |
285 | 180 | CGF.EmitBlock(Cont.getBlock()); |
286 | 184 | } |
287 | | |
288 | | void CGObjCRuntime::EmitInitOfCatchParam(CodeGenFunction &CGF, |
289 | | llvm::Value *exn, |
290 | 208 | const VarDecl *paramDecl) { |
291 | | |
292 | 208 | Address paramAddr = CGF.GetAddrOfLocalVar(paramDecl); |
293 | | |
294 | 208 | switch (paramDecl->getType().getQualifiers().getObjCLifetime()) { |
295 | 7 | case Qualifiers::OCL_Strong: |
296 | 7 | exn = CGF.EmitARCRetainNonBlock(exn); |
297 | 7 | LLVM_FALLTHROUGH; |
298 | | |
299 | 206 | case Qualifiers::OCL_None: |
300 | 206 | case Qualifiers::OCL_ExplicitNone: |
301 | 206 | case Qualifiers::OCL_Autoreleasing: |
302 | 206 | CGF.Builder.CreateStore(exn, paramAddr); |
303 | 206 | return; |
304 | | |
305 | 2 | case Qualifiers::OCL_Weak: |
306 | 2 | CGF.EmitARCInitWeak(paramAddr, exn); |
307 | 2 | return; |
308 | 0 | } |
309 | 0 | llvm_unreachable("invalid ownership qualifier"); |
310 | 0 | } |
311 | | |
312 | | namespace { |
313 | | struct CallSyncExit final : EHScopeStack::Cleanup { |
314 | | llvm::FunctionCallee SyncExitFn; |
315 | | llvm::Value *SyncArg; |
316 | | CallSyncExit(llvm::FunctionCallee SyncExitFn, llvm::Value *SyncArg) |
317 | 7 | : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} |
318 | | |
319 | 7 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
320 | 7 | CGF.EmitNounwindRuntimeCall(SyncExitFn, SyncArg); |
321 | 7 | } |
322 | | }; |
323 | | } |
324 | | |
325 | | void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF, |
326 | | const ObjCAtSynchronizedStmt &S, |
327 | | llvm::FunctionCallee syncEnterFn, |
328 | 7 | llvm::FunctionCallee syncExitFn) { |
329 | 7 | CodeGenFunction::RunCleanupsScope cleanups(CGF); |
330 | | |
331 | | // Evaluate the lock operand. This is guaranteed to dominate the |
332 | | // ARC release and lock-release cleanups. |
333 | 7 | const Expr *lockExpr = S.getSynchExpr(); |
334 | 7 | llvm::Value *lock; |
335 | 7 | if (CGF.getLangOpts().ObjCAutoRefCount) { |
336 | 4 | lock = CGF.EmitARCRetainScalarExpr(lockExpr); |
337 | 4 | lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock); |
338 | 3 | } else { |
339 | 3 | lock = CGF.EmitScalarExpr(lockExpr); |
340 | 3 | } |
341 | 7 | lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy); |
342 | | |
343 | | // Acquire the lock. |
344 | 7 | CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow(); |
345 | | |
346 | | // Register an all-paths cleanup to release the lock. |
347 | 7 | CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock); |
348 | | |
349 | | // Emit the body of the statement. |
350 | 7 | CGF.EmitStmt(S.getSynchBody()); |
351 | 7 | } |
352 | | |
353 | | /// Compute the pointer-to-function type to which a message send |
354 | | /// should be casted in order to correctly call the given method |
355 | | /// with the given arguments. |
356 | | /// |
357 | | /// \param method - may be null |
358 | | /// \param resultType - the result type to use if there's no method |
359 | | /// \param callArgs - the actual arguments, including implicit ones |
360 | | CGObjCRuntime::MessageSendInfo |
361 | | CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method, |
362 | | QualType resultType, |
363 | 12.3k | CallArgList &callArgs) { |
364 | | // If there's a method, use information from that. |
365 | 12.3k | if (method) { |
366 | 11.5k | const CGFunctionInfo &signature = |
367 | 11.5k | CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty); |
368 | | |
369 | 11.5k | llvm::PointerType *signatureType = |
370 | 11.5k | CGM.getTypes().GetFunctionType(signature)->getPointerTo(); |
371 | | |
372 | 11.5k | const CGFunctionInfo &signatureForCall = |
373 | 11.5k | CGM.getTypes().arrangeCall(signature, callArgs); |
374 | | |
375 | 11.5k | return MessageSendInfo(signatureForCall, signatureType); |
376 | 11.5k | } |
377 | | |
378 | | // There's no method; just use a default CC. |
379 | 793 | const CGFunctionInfo &argsInfo = |
380 | 793 | CGM.getTypes().arrangeUnprototypedObjCMessageSend(resultType, callArgs); |
381 | | |
382 | | // Derive the signature to call from that. |
383 | 793 | llvm::PointerType *signatureType = |
384 | 793 | CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo(); |
385 | 793 | return MessageSendInfo(argsInfo, signatureType); |
386 | 793 | } |
387 | | |
388 | | llvm::Constant * |
389 | | clang::CodeGen::emitObjCProtocolObject(CodeGenModule &CGM, |
390 | 0 | const ObjCProtocolDecl *protocol) { |
391 | 0 | return CGM.getObjCRuntime().GetOrEmitProtocol(protocol); |
392 | 0 | } |
393 | | |
394 | | std::string CGObjCRuntime::getSymbolNameForMethod(const ObjCMethodDecl *OMD, |
395 | 2.64k | bool includeCategoryName) { |
396 | 2.64k | std::string buffer; |
397 | 2.64k | llvm::raw_string_ostream out(buffer); |
398 | 2.64k | CGM.getCXXABI().getMangleContext().mangleObjCMethodName(OMD, out, |
399 | 2.64k | /*includePrefixByte=*/true, |
400 | 2.64k | includeCategoryName); |
401 | 2.64k | return buffer; |
402 | 2.64k | } |