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 | const ObjCIvarDecl *Ivar) { |
33 | return CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar) / |
34 | CGM.getContext().getCharWidth(); |
35 | } |
36 | |
37 | uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
38 | const ObjCImplementationDecl *OID, |
39 | const ObjCIvarDecl *Ivar) { |
40 | return CGM.getContext().lookupFieldBitOffset(OID->getClassInterface(), OID, |
41 | Ivar) / |
42 | CGM.getContext().getCharWidth(); |
43 | } |
44 | |
45 | unsigned CGObjCRuntime::ComputeBitfieldBitOffset( |
46 | CodeGen::CodeGenModule &CGM, |
47 | const ObjCInterfaceDecl *ID, |
48 | const ObjCIvarDecl *Ivar) { |
49 | return CGM.getContext().lookupFieldBitOffset(ID, ID->getImplementation(), |
50 | Ivar); |
51 | } |
52 | |
53 | LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, |
54 | const ObjCInterfaceDecl *OID, |
55 | llvm::Value *BaseValue, |
56 | const ObjCIvarDecl *Ivar, |
57 | unsigned CVRQualifiers, |
58 | llvm::Value *Offset) { |
59 | // Compute (type*) ( (char *) BaseValue + Offset) |
60 | QualType InterfaceTy{OID->getTypeForDecl(), 0}; |
61 | QualType ObjectPtrTy = |
62 | CGF.CGM.getContext().getObjCObjectPointerType(InterfaceTy); |
63 | QualType IvarTy = |
64 | Ivar->getUsageType(ObjectPtrTy).withCVRQualifiers(CVRQualifiers); |
65 | llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); |
66 | llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy); |
67 | V = CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, V, Offset, "add.ptr" ); |
68 | |
69 | if (!Ivar->isBitField()) { |
70 | V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); |
71 | LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy); |
72 | return LV; |
73 | } |
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 | uint64_t FieldBitOffset = |
90 | CGF.CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar); |
91 | uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); |
92 | uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign(); |
93 | uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); |
94 | CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits( |
95 | llvm::alignTo(BitOffset + BitFieldSize, AlignmentBits)); |
96 | 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 | CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( |
105 | CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, |
106 | CGF.CGM.getContext().toBits(StorageSize), |
107 | CharUnits::fromQuantity(0))); |
108 | |
109 | Address Addr(V, Alignment); |
110 | Addr = CGF.Builder.CreateElementBitCast(Addr, |
111 | llvm::Type::getIntNTy(CGF.getLLVMContext(), |
112 | Info->StorageSize)); |
113 | return LValue::MakeBitfield(Addr, *Info, IvarTy, |
114 | LValueBaseInfo(AlignmentSource::Decl), |
115 | TBAAAccessInfo()); |
116 | } |
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 | : MightThrow(MightThrow), Fn(Fn) {} |
131 | bool MightThrow; |
132 | llvm::FunctionCallee Fn; |
133 | |
134 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
135 | if (MightThrow) |
136 | CGF.EmitRuntimeCallOrInvoke(Fn); |
137 | else |
138 | CGF.EmitNounwindRuntimeCall(Fn); |
139 | } |
140 | }; |
141 | } |
142 | |
143 | void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, |
144 | const ObjCAtTryStmt &S, |
145 | llvm::FunctionCallee beginCatchFn, |
146 | llvm::FunctionCallee endCatchFn, |
147 | llvm::FunctionCallee exceptionRethrowFn) { |
148 | // Jump destination for falling out of catch bodies. |
149 | CodeGenFunction::JumpDest Cont; |
150 | if (S.getNumCatchStmts()) |
151 | Cont = CGF.getJumpDestInCurrentScope("eh.cont" ); |
152 | |
153 | bool useFunclets = EHPersonality::get(CGF).usesFuncletPads(); |
154 | |
155 | CodeGenFunction::FinallyInfo FinallyInfo; |
156 | if (!useFunclets) |
157 | if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) |
158 | FinallyInfo.enter(CGF, Finally->getFinallyBody(), |
159 | beginCatchFn, endCatchFn, exceptionRethrowFn); |
160 | |
161 | SmallVector<CatchHandler, 8> Handlers; |
162 | |
163 | |
164 | // Enter the catch, if there is one. |
165 | if (S.getNumCatchStmts()) { |
166 | for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) { |
167 | const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I); |
168 | const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); |
169 | |
170 | Handlers.push_back(CatchHandler()); |
171 | CatchHandler &Handler = Handlers.back(); |
172 | Handler.Variable = CatchDecl; |
173 | Handler.Body = CatchStmt->getCatchBody(); |
174 | Handler.Block = CGF.createBasicBlock("catch" ); |
175 | Handler.Flags = 0; |
176 | |
177 | // @catch(...) always matches. |
178 | if (!CatchDecl) { |
179 | auto catchAll = getCatchAllTypeInfo(); |
180 | Handler.TypeInfo = catchAll.RTTI; |
181 | Handler.Flags = catchAll.Flags; |
182 | // Don't consider any other catches. |
183 | break; |
184 | } |
185 | |
186 | Handler.TypeInfo = GetEHType(CatchDecl->getType()); |
187 | } |
188 | |
189 | EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size()); |
190 | for (unsigned I = 0, E = Handlers.size(); I != E; ++I) |
191 | Catch->setHandler(I, { Handlers[I].TypeInfo, Handlers[I].Flags }, Handlers[I].Block); |
192 | } |
193 | |
194 | if (useFunclets) |
195 | if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) { |
196 | CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); |
197 | if (!CGF.CurSEHParent) |
198 | CGF.CurSEHParent = cast<NamedDecl>(CGF.CurFuncDecl); |
199 | // Outline the finally block. |
200 | const Stmt *FinallyBlock = Finally->getFinallyBody(); |
201 | HelperCGF.startOutlinedSEHHelper(CGF, /*isFilter*/false, FinallyBlock); |
202 | |
203 | // Emit the original filter expression, convert to i32, and return. |
204 | HelperCGF.EmitStmt(FinallyBlock); |
205 | |
206 | HelperCGF.FinishFunction(FinallyBlock->getEndLoc()); |
207 | |
208 | llvm::Function *FinallyFunc = HelperCGF.CurFn; |
209 | |
210 | |
211 | // Push a cleanup for __finally blocks. |
212 | CGF.pushSEHCleanup(NormalAndEHCleanup, FinallyFunc); |
213 | } |
214 | |
215 | |
216 | // Emit the try body. |
217 | CGF.EmitStmt(S.getTryBody()); |
218 | |
219 | // Leave the try. |
220 | if (S.getNumCatchStmts()) |
221 | CGF.popCatchScope(); |
222 | |
223 | // Remember where we were. |
224 | CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); |
225 | |
226 | // Emit the handlers. |
227 | for (unsigned I = 0, E = Handlers.size(); I != E; ++I) { |
228 | CatchHandler &Handler = Handlers[I]; |
229 | |
230 | CGF.EmitBlock(Handler.Block); |
231 | llvm::CatchPadInst *CPI = nullptr; |
232 | SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(CGF.CurrentFuncletPad); |
233 | if (useFunclets) |
234 | if ((CPI = dyn_cast_or_null<llvm::CatchPadInst>(Handler.Block->getFirstNonPHI()))) { |
235 | CGF.CurrentFuncletPad = CPI; |
236 | CPI->setOperand(2, CGF.getExceptionSlot().getPointer()); |
237 | } |
238 | llvm::Value *RawExn = CGF.getExceptionFromSlot(); |
239 | |
240 | // Enter the catch. |
241 | llvm::Value *Exn = RawExn; |
242 | if (beginCatchFn) |
243 | Exn = CGF.EmitNounwindRuntimeCall(beginCatchFn, RawExn, "exn.adjusted" ); |
244 | |
245 | CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange()); |
246 | |
247 | if (endCatchFn) { |
248 | // Add a cleanup to leave the catch. |
249 | bool EndCatchMightThrow = (Handler.Variable == nullptr); |
250 | |
251 | CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup, |
252 | EndCatchMightThrow, |
253 | endCatchFn); |
254 | } |
255 | |
256 | // Bind the catch parameter if it exists. |
257 | if (const VarDecl *CatchParam = Handler.Variable) { |
258 | llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); |
259 | llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType); |
260 | |
261 | CGF.EmitAutoVarDecl(*CatchParam); |
262 | EmitInitOfCatchParam(CGF, CastExn, CatchParam); |
263 | } |
264 | if (CPI) |
265 | CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI); |
266 | |
267 | CGF.ObjCEHValueStack.push_back(Exn); |
268 | CGF.EmitStmt(Handler.Body); |
269 | CGF.ObjCEHValueStack.pop_back(); |
270 | |
271 | // Leave any cleanups associated with the catch. |
272 | cleanups.ForceCleanup(); |
273 | |
274 | CGF.EmitBranchThroughCleanup(Cont); |
275 | } |
276 | |
277 | // Go back to the try-statement fallthrough. |
278 | CGF.Builder.restoreIP(SavedIP); |
279 | |
280 | // Pop out of the finally. |
281 | if (!useFunclets && S.getFinallyStmt()) |
282 | FinallyInfo.exit(CGF); |
283 | |
284 | if (Cont.isValid()) |
285 | CGF.EmitBlock(Cont.getBlock()); |
286 | } |
287 | |
288 | void CGObjCRuntime::EmitInitOfCatchParam(CodeGenFunction &CGF, |
289 | llvm::Value *exn, |
290 | const VarDecl *paramDecl) { |
291 | |
292 | Address paramAddr = CGF.GetAddrOfLocalVar(paramDecl); |
293 | |
294 | switch (paramDecl->getType().getQualifiers().getObjCLifetime()) { |
295 | case Qualifiers::OCL_Strong: |
296 | exn = CGF.EmitARCRetainNonBlock(exn); |
297 | LLVM_FALLTHROUGH; |
298 | |
299 | case Qualifiers::OCL_None: |
300 | case Qualifiers::OCL_ExplicitNone: |
301 | case Qualifiers::OCL_Autoreleasing: |
302 | CGF.Builder.CreateStore(exn, paramAddr); |
303 | return; |
304 | |
305 | case Qualifiers::OCL_Weak: |
306 | CGF.EmitARCInitWeak(paramAddr, exn); |
307 | return; |
308 | } |
309 | llvm_unreachable("invalid ownership qualifier" ); |
310 | } |
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 | : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} |
318 | |
319 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
320 | CGF.EmitNounwindRuntimeCall(SyncExitFn, SyncArg); |
321 | } |
322 | }; |
323 | } |
324 | |
325 | void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF, |
326 | const ObjCAtSynchronizedStmt &S, |
327 | llvm::FunctionCallee syncEnterFn, |
328 | llvm::FunctionCallee syncExitFn) { |
329 | CodeGenFunction::RunCleanupsScope cleanups(CGF); |
330 | |
331 | // Evaluate the lock operand. This is guaranteed to dominate the |
332 | // ARC release and lock-release cleanups. |
333 | const Expr *lockExpr = S.getSynchExpr(); |
334 | llvm::Value *lock; |
335 | if (CGF.getLangOpts().ObjCAutoRefCount) { |
336 | lock = CGF.EmitARCRetainScalarExpr(lockExpr); |
337 | lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock); |
338 | } else { |
339 | lock = CGF.EmitScalarExpr(lockExpr); |
340 | } |
341 | lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy); |
342 | |
343 | // Acquire the lock. |
344 | CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow(); |
345 | |
346 | // Register an all-paths cleanup to release the lock. |
347 | CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock); |
348 | |
349 | // Emit the body of the statement. |
350 | CGF.EmitStmt(S.getSynchBody()); |
351 | } |
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 | CallArgList &callArgs) { |
364 | // If there's a method, use information from that. |
365 | if (method) { |
366 | const CGFunctionInfo &signature = |
367 | CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty); |
368 | |
369 | llvm::PointerType *signatureType = |
370 | CGM.getTypes().GetFunctionType(signature)->getPointerTo(); |
371 | |
372 | const CGFunctionInfo &signatureForCall = |
373 | CGM.getTypes().arrangeCall(signature, callArgs); |
374 | |
375 | return MessageSendInfo(signatureForCall, signatureType); |
376 | } |
377 | |
378 | // There's no method; just use a default CC. |
379 | const CGFunctionInfo &argsInfo = |
380 | CGM.getTypes().arrangeUnprototypedObjCMessageSend(resultType, callArgs); |
381 | |
382 | // Derive the signature to call from that. |
383 | llvm::PointerType *signatureType = |
384 | CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo(); |
385 | return MessageSendInfo(argsInfo, signatureType); |
386 | } |
387 | |
388 | llvm::Constant * |
389 | clang::CodeGen::emitObjCProtocolObject(CodeGenModule &CGM, |
390 | const ObjCProtocolDecl *protocol) { |
391 | return CGM.getObjCRuntime().GetOrEmitProtocol(protocol); |
392 | } |
393 | |
394 | std::string CGObjCRuntime::getSymbolNameForMethod(const ObjCMethodDecl *OMD, |
395 | bool includeCategoryName) { |
396 | std::string buffer; |
397 | llvm::raw_string_ostream out(buffer); |
398 | CGM.getCXXABI().getMangleContext().mangleObjCMethodName(OMD, out, |
399 | /*includePrefixByte=*/true, |
400 | includeCategoryName); |
401 | return buffer; |
402 | } |
403 | |