1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | #include "CGObjCRuntime.h" |
16 | #include "CGCleanup.h" |
17 | #include "CGCXXABI.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 "llvm/Support/SaveAndRestore.h" |
25 | |
26 | using namespace clang; |
27 | using namespace CodeGen; |
28 | |
29 | uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
30 | const ObjCInterfaceDecl *OID, |
31 | const ObjCIvarDecl *Ivar) { |
32 | return CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar) / |
33 | CGM.getContext().getCharWidth(); |
34 | } |
35 | |
36 | uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, |
37 | const ObjCImplementationDecl *OID, |
38 | const ObjCIvarDecl *Ivar) { |
39 | return CGM.getContext().lookupFieldBitOffset(OID->getClassInterface(), OID, |
40 | Ivar) / |
41 | CGM.getContext().getCharWidth(); |
42 | } |
43 | |
44 | unsigned CGObjCRuntime::ComputeBitfieldBitOffset( |
45 | CodeGen::CodeGenModule &CGM, |
46 | const ObjCInterfaceDecl *ID, |
47 | const ObjCIvarDecl *Ivar) { |
48 | return CGM.getContext().lookupFieldBitOffset(ID, ID->getImplementation(), |
49 | Ivar); |
50 | } |
51 | |
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 | |
59 | QualType InterfaceTy{OID->getTypeForDecl(), 0}; |
60 | QualType ObjectPtrTy = |
61 | CGF.CGM.getContext().getObjCObjectPointerType(InterfaceTy); |
62 | QualType IvarTy = |
63 | Ivar->getUsageType(ObjectPtrTy).withCVRQualifiers(CVRQualifiers); |
64 | llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); |
65 | llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy); |
66 | V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr"); |
67 | |
68 | if (!Ivar->isBitField()) { |
69 | V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); |
70 | LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy); |
71 | return LV; |
72 | } |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | uint64_t FieldBitOffset = |
89 | CGF.CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar); |
90 | uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); |
91 | uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign(); |
92 | uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); |
93 | CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits( |
94 | llvm::alignTo(BitOffset + BitFieldSize, AlignmentBits)); |
95 | CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits); |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( |
104 | CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, |
105 | CGF.CGM.getContext().toBits(StorageSize), |
106 | CharUnits::fromQuantity(0))); |
107 | |
108 | Address Addr(V, Alignment); |
109 | Addr = CGF.Builder.CreateElementBitCast(Addr, |
110 | llvm::Type::getIntNTy(CGF.getLLVMContext(), |
111 | Info->StorageSize)); |
112 | return LValue::MakeBitfield(Addr, *Info, IvarTy, |
113 | LValueBaseInfo(AlignmentSource::Decl), |
114 | TBAAAccessInfo()); |
115 | } |
116 | |
117 | namespace { |
118 | struct CatchHandler { |
119 | const VarDecl *Variable; |
120 | const Stmt *Body; |
121 | llvm::BasicBlock *Block; |
122 | llvm::Constant *TypeInfo; |
123 | |
124 | unsigned Flags; |
125 | }; |
126 | |
127 | struct CallObjCEndCatch final : EHScopeStack::Cleanup { |
128 | CallObjCEndCatch(bool MightThrow, llvm::FunctionCallee Fn) |
129 | : MightThrow(MightThrow), Fn(Fn) {} |
130 | bool MightThrow; |
131 | llvm::FunctionCallee Fn; |
132 | |
133 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
134 | if (MightThrow) |
135 | CGF.EmitRuntimeCallOrInvoke(Fn); |
136 | else |
137 | CGF.EmitNounwindRuntimeCall(Fn); |
138 | } |
139 | }; |
140 | } |
141 | |
142 | void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, |
143 | const ObjCAtTryStmt &S, |
144 | llvm::FunctionCallee beginCatchFn, |
145 | llvm::FunctionCallee endCatchFn, |
146 | llvm::FunctionCallee exceptionRethrowFn) { |
147 | |
148 | CodeGenFunction::JumpDest Cont; |
149 | if (S.getNumCatchStmts()) |
150 | Cont = CGF.getJumpDestInCurrentScope("eh.cont"); |
151 | |
152 | bool useFunclets = EHPersonality::get(CGF).usesFuncletPads(); |
153 | |
154 | CodeGenFunction::FinallyInfo FinallyInfo; |
155 | if (!useFunclets) |
156 | if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) |
157 | FinallyInfo.enter(CGF, Finally->getFinallyBody(), |
158 | beginCatchFn, endCatchFn, exceptionRethrowFn); |
159 | |
160 | SmallVector<CatchHandler, 8> Handlers; |
161 | |
162 | |
163 | |
164 | if (S.getNumCatchStmts()) { |
165 | for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) { |
166 | const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I); |
167 | const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); |
168 | |
169 | Handlers.push_back(CatchHandler()); |
170 | CatchHandler &Handler = Handlers.back(); |
171 | Handler.Variable = CatchDecl; |
172 | Handler.Body = CatchStmt->getCatchBody(); |
173 | Handler.Block = CGF.createBasicBlock("catch"); |
174 | Handler.Flags = 0; |
175 | |
176 | |
177 | if (!CatchDecl) { |
178 | auto catchAll = getCatchAllTypeInfo(); |
179 | Handler.TypeInfo = catchAll.RTTI; |
180 | Handler.Flags = catchAll.Flags; |
181 | |
182 | break; |
183 | } |
184 | |
185 | Handler.TypeInfo = GetEHType(CatchDecl->getType()); |
186 | } |
187 | |
188 | EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size()); |
189 | for (unsigned I = 0, E = Handlers.size(); I != E; ++I) |
190 | Catch->setHandler(I, { Handlers[I].TypeInfo, Handlers[I].Flags }, Handlers[I].Block); |
191 | } |
192 | |
193 | if (useFunclets) |
194 | if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) { |
195 | CodeGenFunction HelperCGF(CGM, ); |
196 | if (!CGF.CurSEHParent) |
197 | CGF.CurSEHParent = cast<NamedDecl>(CGF.CurFuncDecl); |
198 | |
199 | const Stmt *FinallyBlock = Finally->getFinallyBody(); |
200 | HelperCGF.startOutlinedSEHHelper(CGF, , FinallyBlock); |
201 | |
202 | |
203 | HelperCGF.EmitStmt(FinallyBlock); |
204 | |
205 | HelperCGF.FinishFunction(FinallyBlock->getEndLoc()); |
206 | |
207 | llvm::Function *FinallyFunc = HelperCGF.CurFn; |
208 | |
209 | |
210 | |
211 | CGF.pushSEHCleanup(NormalAndEHCleanup, FinallyFunc); |
212 | } |
213 | |
214 | |
215 | |
216 | CGF.EmitStmt(S.getTryBody()); |
217 | |
218 | |
219 | if (S.getNumCatchStmts()) |
220 | CGF.popCatchScope(); |
221 | |
222 | |
223 | CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); |
224 | |
225 | |
226 | for (unsigned I = 0, E = Handlers.size(); I != E; ++I) { |
227 | CatchHandler &Handler = Handlers[I]; |
228 | |
229 | CGF.EmitBlock(Handler.Block); |
230 | llvm::CatchPadInst *CPI = nullptr; |
231 | SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(CGF.CurrentFuncletPad); |
232 | if (useFunclets) |
233 | if ((CPI = dyn_cast_or_null<llvm::CatchPadInst>(Handler.Block->getFirstNonPHI()))) { |
234 | CGF.CurrentFuncletPad = CPI; |
235 | CPI->setOperand(2, CGF.getExceptionSlot().getPointer()); |
236 | } |
237 | llvm::Value *RawExn = CGF.getExceptionFromSlot(); |
238 | |
239 | |
240 | llvm::Value *Exn = RawExn; |
241 | if (beginCatchFn) |
242 | Exn = CGF.EmitNounwindRuntimeCall(beginCatchFn, RawExn, "exn.adjusted"); |
243 | |
244 | CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange()); |
245 | |
246 | if (endCatchFn) { |
247 | |
248 | bool EndCatchMightThrow = (Handler.Variable == nullptr); |
249 | |
250 | CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup, |
251 | EndCatchMightThrow, |
252 | endCatchFn); |
253 | } |
254 | |
255 | |
256 | if (const VarDecl *CatchParam = Handler.Variable) { |
257 | llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); |
258 | llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType); |
259 | |
260 | CGF.EmitAutoVarDecl(*CatchParam); |
261 | EmitInitOfCatchParam(CGF, CastExn, CatchParam); |
262 | } |
263 | if (CPI) |
264 | CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI); |
265 | |
266 | CGF.ObjCEHValueStack.push_back(Exn); |
267 | CGF.EmitStmt(Handler.Body); |
268 | CGF.ObjCEHValueStack.pop_back(); |
269 | |
270 | |
271 | cleanups.ForceCleanup(); |
272 | |
273 | CGF.EmitBranchThroughCleanup(Cont); |
274 | } |
275 | |
276 | |
277 | CGF.Builder.restoreIP(SavedIP); |
278 | |
279 | |
280 | if (!useFunclets && S.getFinallyStmt()) |
281 | FinallyInfo.exit(CGF); |
282 | |
283 | if (Cont.isValid()) |
284 | CGF.EmitBlock(Cont.getBlock()); |
285 | } |
286 | |
287 | void CGObjCRuntime::EmitInitOfCatchParam(CodeGenFunction &CGF, |
288 | llvm::Value *exn, |
289 | const VarDecl *paramDecl) { |
290 | |
291 | Address paramAddr = CGF.GetAddrOfLocalVar(paramDecl); |
292 | |
293 | switch (paramDecl->getType().getQualifiers().getObjCLifetime()) { |
294 | case Qualifiers::OCL_Strong: |
295 | exn = CGF.EmitARCRetainNonBlock(exn); |
296 | LLVM_FALLTHROUGH; |
297 | |
298 | case Qualifiers::OCL_None: |
299 | case Qualifiers::OCL_ExplicitNone: |
300 | case Qualifiers::OCL_Autoreleasing: |
301 | CGF.Builder.CreateStore(exn, paramAddr); |
302 | return; |
303 | |
304 | case Qualifiers::OCL_Weak: |
305 | CGF.EmitARCInitWeak(paramAddr, exn); |
306 | return; |
307 | } |
308 | llvm_unreachable("invalid ownership qualifier"); |
309 | } |
310 | |
311 | namespace { |
312 | struct CallSyncExit final : EHScopeStack::Cleanup { |
313 | llvm::FunctionCallee SyncExitFn; |
314 | llvm::Value *SyncArg; |
315 | CallSyncExit(llvm::FunctionCallee SyncExitFn, llvm::Value *SyncArg) |
316 | : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} |
317 | |
318 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
319 | CGF.EmitNounwindRuntimeCall(SyncExitFn, SyncArg); |
320 | } |
321 | }; |
322 | } |
323 | |
324 | void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF, |
325 | const ObjCAtSynchronizedStmt &S, |
326 | llvm::FunctionCallee syncEnterFn, |
327 | llvm::FunctionCallee syncExitFn) { |
328 | CodeGenFunction::RunCleanupsScope cleanups(CGF); |
329 | |
330 | |
331 | |
332 | const Expr *lockExpr = S.getSynchExpr(); |
333 | llvm::Value *lock; |
334 | if (CGF.getLangOpts().ObjCAutoRefCount) { |
335 | lock = CGF.EmitARCRetainScalarExpr(lockExpr); |
336 | lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock); |
337 | } else { |
338 | lock = CGF.EmitScalarExpr(lockExpr); |
339 | } |
340 | lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy); |
341 | |
342 | |
343 | CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow(); |
344 | |
345 | |
346 | CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock); |
347 | |
348 | |
349 | CGF.EmitStmt(S.getSynchBody()); |
350 | } |
351 | |
352 | |
353 | |
354 | |
355 | |
356 | |
357 | |
358 | |
359 | CGObjCRuntime::MessageSendInfo |
360 | CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method, |
361 | QualType resultType, |
362 | CallArgList &callArgs) { |
363 | |
364 | if (method) { |
365 | const CGFunctionInfo &signature = |
366 | CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty); |
367 | |
368 | llvm::PointerType *signatureType = |
369 | CGM.getTypes().GetFunctionType(signature)->getPointerTo(); |
370 | |
371 | const CGFunctionInfo &signatureForCall = |
372 | CGM.getTypes().arrangeCall(signature, callArgs); |
373 | |
374 | return MessageSendInfo(signatureForCall, signatureType); |
375 | } |
376 | |
377 | |
378 | const CGFunctionInfo &argsInfo = |
379 | CGM.getTypes().arrangeUnprototypedObjCMessageSend(resultType, callArgs); |
380 | |
381 | |
382 | llvm::PointerType *signatureType = |
383 | CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo(); |
384 | return MessageSendInfo(argsInfo, signatureType); |
385 | } |
386 | |