 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
55.0% |
66 / 120 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
81.7% |
98 / 120 |
| |
|
Line Coverage: |
82.8% |
338 / 408 |
| |
 |
|
 |
1 : //===--- CGException.cpp - Emit LLVM Code for C++ exceptions --------------===//
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 contains code dealing with C++ exception related code generation.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "clang/AST/StmtCXX.h"
15 :
16 : #include "llvm/Intrinsics.h"
17 :
18 : #include "CodeGenFunction.h"
19 : using namespace clang;
20 : using namespace CodeGen;
21 :
22 7: static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
23 : // void *__cxa_allocate_exception(size_t thrown_size);
24 7: const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
25 7: std::vector<const llvm::Type*> Args(1, SizeTy);
26 :
27 : const llvm::FunctionType *FTy =
28 : llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()),
29 7: Args, false);
30 :
31 7: return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
32 : }
33 :
34 1: static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
35 : // void __cxa_free_exception(void *thrown_exception);
36 1: const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
37 1: std::vector<const llvm::Type*> Args(1, Int8PtrTy);
38 :
39 : const llvm::FunctionType *FTy =
40 : llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
41 1: Args, false);
42 :
43 1: return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
44 : }
45 :
46 7: static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
47 : // void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
48 : // void (*dest) (void *));
49 :
50 7: const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
51 7: std::vector<const llvm::Type*> Args(3, Int8PtrTy);
52 :
53 : const llvm::FunctionType *FTy =
54 : llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
55 7: Args, false);
56 :
57 7: return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
58 : }
59 :
60 1: static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
61 : // void __cxa_rethrow();
62 :
63 : const llvm::FunctionType *FTy =
64 1: llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
65 :
66 1: return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
67 : }
68 :
69 1: static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
70 : // void* __cxa_begin_catch();
71 :
72 1: const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
73 1: std::vector<const llvm::Type*> Args(1, Int8PtrTy);
74 :
75 : const llvm::FunctionType *FTy =
76 1: llvm::FunctionType::get(Int8PtrTy, Args, false);
77 :
78 1: return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
79 : }
80 :
81 1: static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
82 : // void __cxa_end_catch();
83 :
84 : const llvm::FunctionType *FTy =
85 1: llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
86 :
87 1: return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
88 : }
89 :
90 2: static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
91 : // void __cxa_call_unexepcted(void *thrown_exception);
92 :
93 2: const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
94 2: std::vector<const llvm::Type*> Args(1, Int8PtrTy);
95 :
96 : const llvm::FunctionType *FTy =
97 : llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
98 2: Args, false);
99 :
100 2: return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
101 : }
102 :
103 : // FIXME: Eventually this will all go into the backend. Set from the target for
104 : // now.
105 : static int using_sjlj_exceptions = 0;
106 :
107 8: static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
108 8: const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
109 8: std::vector<const llvm::Type*> Args(1, Int8PtrTy);
110 :
111 : const llvm::FunctionType *FTy =
112 : llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
113 8: false);
114 :
0: branch 0 not taken
8: branch 1 taken
115 8: if (using_sjlj_exceptions)
116 0: return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
117 8: return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
118 : }
119 :
120 4: static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
121 : // void __terminate();
122 :
123 : const llvm::FunctionType *FTy =
124 4: llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
125 :
126 4: return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
127 : }
128 :
129 : // CopyObject - Utility to copy an object. Calls copy constructor as necessary.
130 : // DestPtr is casted to the right type.
131 : static void CopyObject(CodeGenFunction &CGF, const Expr *E,
132 7: llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) {
133 7: QualType ObjectType = E->getType();
134 :
135 : // Store the throw exception in the exception object.
3: branch 1 taken
4: branch 2 taken
136 7: if (!CGF.hasAggregateLLVMType(ObjectType)) {
137 3: llvm::Value *Value = CGF.EmitScalarExpr(E);
138 3: const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo();
139 :
140 : CGF.Builder.CreateStore(Value,
141 3: CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy));
142 : } else {
143 4: const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo();
144 : const CXXRecordDecl *RD =
145 4: cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
146 :
147 4: llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty);
2: branch 1 taken
2: branch 2 taken
148 4: if (RD->hasTrivialCopyConstructor()) {
149 2: CGF.EmitAggExpr(E, This, false);
2: branch 0 taken
0: branch 1 not taken
150 2: } else if (CXXConstructorDecl *CopyCtor
151 2: = RD->getCopyConstructor(CGF.getContext(), 0)) {
152 2: llvm::Value *CondPtr = 0;
1: branch 0 taken
1: branch 1 taken
153 2: if (CGF.Exceptions) {
154 1: CodeGenFunction::EHCleanupBlock Cleanup(CGF);
155 1: llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
156 :
157 1: llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free");
158 1: llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
159 : CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
160 1: "doEHfree");
161 :
162 : CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr),
163 1: CondBlock, Cont);
164 1: CGF.EmitBlock(CondBlock);
165 :
166 : // Load the exception pointer.
167 1: llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr);
168 1: CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
169 :
170 1: CGF.EmitBlock(Cont);
171 : }
172 :
1: branch 0 taken
1: branch 1 taken
173 2: if (CondPtr)
174 : CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
175 1: CondPtr);
176 :
177 2: llvm::Value *Src = CGF.EmitLValue(E).getAddress();
178 :
1: branch 0 taken
1: branch 1 taken
179 2: if (CondPtr)
180 : CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
181 1: CondPtr);
182 :
183 2: llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
184 2: llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
185 2: CGF.setInvokeDest(TerminateHandler);
186 :
187 : // Stolen from EmitClassAggrMemberwiseCopy
188 : llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
189 2: Ctor_Complete);
190 2: CallArgList CallArgs;
191 : CallArgs.push_back(std::make_pair(RValue::get(This),
192 2: CopyCtor->getThisType(CGF.getContext())));
193 :
194 : // Push the Src ptr.
195 : CallArgs.push_back(std::make_pair(RValue::get(Src),
196 2: CopyCtor->getParamDecl(0)->getType()));
197 : const FunctionProtoType *FPT
198 2: = CopyCtor->getType()->getAs<FunctionProtoType>();
199 : CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
200 2: Callee, ReturnValueSlot(), CallArgs, CopyCtor);
201 2: CGF.setInvokeDest(PrevLandingPad);
202 : } else
203 0: llvm_unreachable("uncopyable object");
204 : }
205 7: }
206 :
207 : // CopyObject - Utility to copy an object. Calls copy constructor as necessary.
208 : // N is casted to the right type.
209 : static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
210 : bool WasPointer, bool WasPointerReference,
211 1: llvm::Value *E, llvm::Value *N) {
212 : // Store the throw exception in the exception object.
1: branch 0 taken
0: branch 1 not taken
0: branch 3 not taken
1: branch 4 taken
0: branch 5 not taken
1: branch 6 taken
213 1: if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) {
214 0: llvm::Value *Value = E;
0: branch 0 not taken
0: branch 1 not taken
215 0: if (!WasPointer)
216 0: Value = CGF.Builder.CreateLoad(Value);
217 0: const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
0: branch 0 not taken
0: branch 1 not taken
218 0: if (WasPointerReference) {
219 0: llvm::Value *Tmp = CGF.CreateTempAlloca(Value->getType(), "catch.param");
220 0: CGF.Builder.CreateStore(Value, Tmp);
221 0: Value = Tmp;
222 0: ValuePtrTy = Value->getType()->getPointerTo(0);
223 : }
224 0: N = CGF.Builder.CreateBitCast(N, ValuePtrTy);
225 0: CGF.Builder.CreateStore(Value, N);
226 : } else {
227 1: const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0);
228 : const CXXRecordDecl *RD;
229 1: RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
230 1: llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty);
1: branch 1 taken
0: branch 2 not taken
231 1: if (RD->hasTrivialCopyConstructor()) {
232 1: CGF.EmitAggregateCopy(This, E, ObjectType);
0: branch 0 not taken
0: branch 1 not taken
233 0: } else if (CXXConstructorDecl *CopyCtor
234 0: = RD->getCopyConstructor(CGF.getContext(), 0)) {
235 0: llvm::Value *Src = E;
236 :
237 : // Stolen from EmitClassAggrMemberwiseCopy
238 : llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
239 0: Ctor_Complete);
240 0: CallArgList CallArgs;
241 : CallArgs.push_back(std::make_pair(RValue::get(This),
242 0: CopyCtor->getThisType(CGF.getContext())));
243 :
244 : // Push the Src ptr.
245 : CallArgs.push_back(std::make_pair(RValue::get(Src),
246 0: CopyCtor->getParamDecl(0)->getType()));
247 :
248 : const FunctionProtoType *FPT
249 0: = CopyCtor->getType()->getAs<FunctionProtoType>();
250 : CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
251 0: Callee, ReturnValueSlot(), CallArgs, CopyCtor);
252 : } else
253 0: llvm_unreachable("uncopyable object");
254 : }
255 1: }
256 :
257 8: void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
1: branch 1 taken
7: branch 2 taken
258 8: if (!E->getSubExpr()) {
0: branch 1 not taken
1: branch 2 taken
259 1: if (getInvokeDest()) {
260 0: llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
261 : Builder.CreateInvoke(getReThrowFn(*this), Cont, getInvokeDest())
262 0: ->setDoesNotReturn();
263 0: EmitBlock(Cont);
264 : } else
265 1: Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
266 1: Builder.CreateUnreachable();
267 :
268 : // Clear the insertion point to indicate we are in unreachable code.
269 1: Builder.ClearInsertionPoint();
270 1: return;
271 : }
272 :
273 7: QualType ThrowType = E->getSubExpr()->getType();
274 :
275 : // Now allocate the exception object.
276 7: const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
277 7: uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8;
278 :
279 7: llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
280 : llvm::Value *ExceptionPtr =
281 : Builder.CreateCall(AllocExceptionFn,
282 : llvm::ConstantInt::get(SizeTy, TypeSize),
283 7: "exception");
284 :
285 : llvm::Value *ExceptionPtrPtr =
286 7: CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr");
287 7: Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr);
288 :
289 :
290 7: CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr);
291 :
292 : // Now throw the exception.
293 7: const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
294 7: llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType);
295 7: llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
296 :
2: branch 1 taken
5: branch 2 taken
297 7: if (getInvokeDest()) {
298 2: llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
299 : llvm::InvokeInst *ThrowCall =
300 : Builder.CreateInvoke3(getThrowFn(*this), Cont, getInvokeDest(),
301 2: ExceptionPtr, TypeInfo, Dtor);
302 2: ThrowCall->setDoesNotReturn();
303 2: EmitBlock(Cont);
304 : } else {
305 : llvm::CallInst *ThrowCall =
306 5: Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor);
307 5: ThrowCall->setDoesNotReturn();
308 : }
309 7: Builder.CreateUnreachable();
310 :
311 : // Clear the insertion point to indicate we are in unreachable code.
312 7: Builder.ClearInsertionPoint();
313 :
314 : // FIXME: For now, emit a dummy basic block because expr emitters in generally
315 : // are not ready to handle emitting expressions at unreachable points.
316 7: EnsureInsertPoint();
317 : }
318 :
319 3076: void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
3046: branch 0 taken
30: branch 1 taken
320 3076: if (!Exceptions)
321 3046: return;
322 :
323 30: const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
0: branch 0 not taken
30: branch 1 taken
324 30: if (FD == 0)
325 0: return;
326 30: const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
0: branch 0 not taken
30: branch 1 taken
327 30: if (Proto == 0)
328 0: return;
329 :
30: branch 1 taken
0: branch 2 not taken
330 30: assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack");
331 :
28: branch 1 taken
2: branch 2 taken
332 30: if (!Proto->hasExceptionSpec())
333 28: return;
334 :
335 : llvm::Constant *Personality =
336 : CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
337 : (VMContext),
338 : true),
339 2: "__gxx_personality_v0");
340 2: Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
341 : llvm::Value *llvm_eh_exception =
342 2: CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
343 : llvm::Value *llvm_eh_selector =
344 2: CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
345 : const llvm::IntegerType *Int8Ty;
346 : const llvm::PointerType *PtrToInt8Ty;
347 2: Int8Ty = llvm::Type::getInt8Ty(VMContext);
348 : // C string type. Used in lots of places.
349 2: PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
350 2: llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
351 2: llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
352 :
353 2: llvm::BasicBlock *PrevLandingPad = getInvokeDest();
354 2: llvm::BasicBlock *EHSpecHandler = createBasicBlock("ehspec.handler");
355 2: llvm::BasicBlock *Match = createBasicBlock("match");
356 2: llvm::BasicBlock *Unwind = 0;
357 :
0: branch 0 not taken
2: branch 1 taken
358 2: assert(PrevLandingPad == 0 && "EHSpec has invoke context");
359 : (void)PrevLandingPad;
360 :
361 2: llvm::BasicBlock *Cont = createBasicBlock("cont");
362 :
363 2: EmitBranchThroughCleanup(Cont);
364 :
365 : // Emit the statements in the try {} block
366 2: setInvokeDest(EHSpecHandler);
367 :
368 2: EmitBlock(EHSpecHandler);
369 : // Exception object
370 2: llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
371 2: llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
372 :
373 2: SelectorArgs.push_back(Exc);
374 2: SelectorArgs.push_back(Personality);
375 : SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
376 2: Proto->getNumExceptions()+1));
377 :
0: branch 1 not taken
2: branch 2 taken
378 2: for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) {
379 0: QualType Ty = Proto->getExceptionType(i);
380 : QualType ExceptType
381 0: = Ty.getNonReferenceType().getUnqualifiedType();
382 0: llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType);
383 0: SelectorArgs.push_back(EHType);
384 : }
0: branch 1 not taken
2: branch 2 taken
385 2: if (Proto->getNumExceptions())
386 0: SelectorArgs.push_back(Null);
387 :
388 : // Find which handler was matched.
389 : llvm::Value *Selector
390 : = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
391 2: SelectorArgs.end(), "selector");
0: branch 1 not taken
2: branch 2 taken
392 2: if (Proto->getNumExceptions()) {
393 0: Unwind = createBasicBlock("Unwind");
394 :
395 0: Builder.CreateStore(Exc, RethrowPtr);
396 : Builder.CreateCondBr(Builder.CreateICmpSLT(Selector,
397 : llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
398 : 0)),
399 0: Match, Unwind);
400 :
401 0: EmitBlock(Match);
402 : }
403 2: Builder.CreateCall(getUnexpectedFn(*this), Exc)->setDoesNotReturn();
404 2: Builder.CreateUnreachable();
405 :
0: branch 1 not taken
2: branch 2 taken
406 2: if (Proto->getNumExceptions()) {
407 0: EmitBlock(Unwind);
408 : Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
409 0: Builder.CreateLoad(RethrowPtr));
410 0: Builder.CreateUnreachable();
411 : }
412 :
413 2: EmitBlock(Cont);
414 : }
415 :
416 3076: void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
3046: branch 0 taken
30: branch 1 taken
417 3076: if (!Exceptions)
418 3046: return;
419 :
420 30: const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
0: branch 0 not taken
30: branch 1 taken
421 30: if (FD == 0)
422 0: return;
423 30: const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
0: branch 0 not taken
30: branch 1 taken
424 30: if (Proto == 0)
425 0: return;
426 :
28: branch 1 taken
2: branch 2 taken
427 30: if (!Proto->hasExceptionSpec())
428 28: return;
429 :
430 2: setInvokeDest(0);
431 : }
432 :
433 1: void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
434 : // Pointer to the personality function
435 : llvm::Constant *Personality =
436 : CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
437 : (VMContext),
438 : true),
439 1: "__gxx_personality_v0");
440 1: Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
441 : llvm::Value *llvm_eh_exception =
442 1: CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
443 : llvm::Value *llvm_eh_selector =
444 1: CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
445 :
446 1: llvm::BasicBlock *PrevLandingPad = getInvokeDest();
447 1: llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
448 1: llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
449 1: llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
450 1: llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
451 :
452 : // Push an EH context entry, used for handling rethrows.
453 1: PushCleanupBlock(FinallyBlock);
454 :
455 : // Emit the statements in the try {} block
456 1: setInvokeDest(TryHandler);
457 :
458 : // FIXME: We should not have to do this here. The AST should have the member
459 : // initializers under the CXXTryStmt's TryBlock.
0: branch 0 not taken
1: branch 1 taken
460 1: if (OuterTryBlock == &S) {
461 0: GlobalDecl GD = CurGD;
462 0: const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
463 :
0: branch 1 not taken
0: branch 2 not taken
464 0: if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
465 0: size_t OldCleanupStackSize = CleanupEntries.size();
466 0: EmitCtorPrologue(CD, CurGD.getCtorType());
467 0: EmitStmt(S.getTryBlock());
468 :
469 : // If any of the member initializers are temporaries bound to references
470 : // make sure to emit their destructors.
471 0: EmitCleanupBlocks(OldCleanupStackSize);
0: branch 1 not taken
0: branch 2 not taken
472 0: } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
473 0: llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
474 0: PushCleanupBlock(DtorEpilogue);
475 :
476 0: InitializeVtablePtrs(DD->getParent());
477 0: EmitStmt(S.getTryBlock());
478 :
479 0: CleanupBlockInfo Info = PopCleanupBlock();
480 :
0: branch 0 not taken
0: branch 1 not taken
481 0: assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
482 0: EmitBlock(DtorEpilogue);
483 0: EmitDtorEpilogue(DD, GD.getDtorType());
484 :
0: branch 0 not taken
0: branch 1 not taken
485 0: if (Info.SwitchBlock)
486 0: EmitBlock(Info.SwitchBlock);
0: branch 0 not taken
0: branch 1 not taken
487 0: if (Info.EndBlock)
488 0: EmitBlock(Info.EndBlock);
489 : } else
490 0: EmitStmt(S.getTryBlock());
491 : } else
492 1: EmitStmt(S.getTryBlock());
493 :
494 : // Jump to end if there is no exception
495 1: EmitBranchThroughCleanup(FinallyEnd);
496 :
497 1: llvm::BasicBlock *TerminateHandler = getTerminateHandler();
498 :
499 : // Emit the handlers
500 1: EmitBlock(TryHandler);
501 :
502 : const llvm::IntegerType *Int8Ty;
503 : const llvm::PointerType *PtrToInt8Ty;
504 1: Int8Ty = llvm::Type::getInt8Ty(VMContext);
505 : // C string type. Used in lots of places.
506 1: PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
507 1: llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
508 1: llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
509 : llvm::Value *llvm_eh_typeid_for =
510 1: CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
511 : // Exception object
512 1: llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
513 1: llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
514 :
515 1: llvm::SmallVector<llvm::Value*, 8> Args;
516 1: Args.clear();
517 1: SelectorArgs.push_back(Exc);
518 1: SelectorArgs.push_back(Personality);
519 :
520 1: bool HasCatchAll = false;
1: branch 1 taken
1: branch 2 taken
521 2: for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
522 1: const CXXCatchStmt *C = S.getHandler(i);
523 1: VarDecl *CatchParam = C->getExceptionDecl();
1: branch 0 taken
0: branch 1 not taken
524 1: if (CatchParam) {
525 : // C++ [except.handle]p3 indicates that top-level cv-qualifiers
526 : // are ignored.
527 1: QualType CaughtType = C->getCaughtType().getNonReferenceType();
528 : llvm::Value *EHTypeInfo
529 1: = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType());
530 1: SelectorArgs.push_back(EHTypeInfo);
531 : } else {
532 : // null indicates catch all
533 0: SelectorArgs.push_back(Null);
534 0: HasCatchAll = true;
535 : }
536 : }
537 :
538 : // We use a cleanup unless there was already a catch all.
1: branch 0 taken
0: branch 1 not taken
539 1: if (!HasCatchAll) {
540 1: SelectorArgs.push_back(Null);
541 : }
542 :
543 : // Find which handler was matched.
544 : llvm::Value *Selector
545 : = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
546 1: SelectorArgs.end(), "selector");
1: branch 1 taken
1: branch 2 taken
547 2: for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
548 1: const CXXCatchStmt *C = S.getHandler(i);
549 1: VarDecl *CatchParam = C->getExceptionDecl();
550 1: Stmt *CatchBody = C->getHandlerBlock();
551 :
552 1: llvm::BasicBlock *Next = 0;
553 :
1: branch 1 taken
0: branch 2 not taken
554 1: if (SelectorArgs[i+2] != Null) {
555 1: llvm::BasicBlock *Match = createBasicBlock("match");
556 1: Next = createBasicBlock("catch.next");
557 1: const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
558 : llvm::Value *Id
559 : = Builder.CreateCall(llvm_eh_typeid_for,
560 : Builder.CreateBitCast(SelectorArgs[i+2],
561 1: Int8PtrTy));
562 : Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id),
563 1: Match, Next);
564 1: EmitBlock(Match);
565 : }
566 :
567 1: llvm::BasicBlock *MatchEnd = createBasicBlock("match.end");
568 1: llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler");
569 :
570 1: PushCleanupBlock(MatchEnd);
571 1: setInvokeDest(MatchHandler);
572 :
573 1: llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc);
574 :
575 : {
576 1: CleanupScope CatchScope(*this);
577 : // Bind the catch parameter if it exists.
1: branch 0 taken
0: branch 1 not taken
578 1: if (CatchParam) {
579 1: QualType CatchType = CatchParam->getType().getNonReferenceType();
580 1: setInvokeDest(TerminateHandler);
581 1: bool WasPointer = true;
582 1: bool WasPointerReference = false;
583 1: CatchType = CGM.getContext().getCanonicalType(CatchType);
0: branch 2 not taken
1: branch 3 taken
584 1: if (CatchType.getTypePtr()->isPointerType()) {
0: branch 2 not taken
0: branch 3 not taken
585 0: if (isa<ReferenceType>(CatchParam->getType()))
586 0: WasPointerReference = true;
587 : } else {
1: branch 2 taken
0: branch 3 not taken
588 1: if (!isa<ReferenceType>(CatchParam->getType()))
589 1: WasPointer = false;
590 1: CatchType = getContext().getPointerType(CatchType);
591 : }
592 1: ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType));
593 1: EmitLocalBlockVarDecl(*CatchParam);
594 : // FIXME: we need to do this sooner so that the EH region for the
595 : // cleanup doesn't start until after the ctor completes, use a decl
596 : // init?
597 : CopyObject(*this, CatchParam->getType().getNonReferenceType(),
598 : WasPointer, WasPointerReference, ExcObject,
599 1: GetAddrOfLocalVar(CatchParam));
600 1: setInvokeDest(MatchHandler);
601 : }
602 :
603 1: EmitStmt(CatchBody);
604 : }
605 :
606 1: EmitBranchThroughCleanup(FinallyEnd);
607 :
608 1: EmitBlock(MatchHandler);
609 :
610 1: llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
611 : // We are required to emit this call to satisfy LLVM, even
612 : // though we don't use the result.
613 1: Args.clear();
614 1: Args.push_back(Exc);
615 1: Args.push_back(Personality);
616 : Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
617 1: 0));
618 1: Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
619 1: Builder.CreateStore(Exc, RethrowPtr);
620 1: EmitBranchThroughCleanup(FinallyRethrow);
621 :
622 1: CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
623 :
624 1: EmitBlock(MatchEnd);
625 :
626 1: llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
627 : Builder.CreateInvoke(getEndCatchFn(*this),
628 : Cont, TerminateHandler,
629 1: Args.begin(), Args.begin());
630 1: EmitBlock(Cont);
1: branch 0 taken
0: branch 1 not taken
631 1: if (Info.SwitchBlock)
632 1: EmitBlock(Info.SwitchBlock);
1: branch 0 taken
0: branch 1 not taken
633 1: if (Info.EndBlock)
634 1: EmitBlock(Info.EndBlock);
635 :
636 1: Exc = Builder.CreateCall(llvm_eh_exception, "exc");
637 1: Builder.CreateStore(Exc, RethrowPtr);
638 1: EmitBranchThroughCleanup(FinallyRethrow);
639 :
1: branch 0 taken
0: branch 1 not taken
640 1: if (Next)
641 1: EmitBlock(Next);
642 : }
1: branch 0 taken
0: branch 1 not taken
643 1: if (!HasCatchAll) {
644 1: Builder.CreateStore(Exc, RethrowPtr);
645 1: EmitBranchThroughCleanup(FinallyRethrow);
646 : }
647 :
648 1: CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
649 :
650 1: setInvokeDest(PrevLandingPad);
651 :
652 1: EmitBlock(FinallyBlock);
653 :
1: branch 0 taken
0: branch 1 not taken
654 1: if (Info.SwitchBlock)
655 1: EmitBlock(Info.SwitchBlock);
1: branch 0 taken
0: branch 1 not taken
656 1: if (Info.EndBlock)
657 1: EmitBlock(Info.EndBlock);
658 :
659 : // Branch around the rethrow code.
660 1: EmitBranch(FinallyEnd);
661 :
662 1: EmitBlock(FinallyRethrow);
663 : // FIXME: Eventually we can chain the handlers together and just do a call
664 : // here.
0: branch 1 not taken
1: branch 2 taken
665 1: if (getInvokeDest()) {
666 0: llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
667 : Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont,
668 : getInvokeDest(),
669 0: Builder.CreateLoad(RethrowPtr));
670 0: EmitBlock(Cont);
671 : } else
672 : Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
673 1: Builder.CreateLoad(RethrowPtr));
674 :
675 1: Builder.CreateUnreachable();
676 :
677 1: EmitBlock(FinallyEnd);
678 1: }
679 :
680 7: CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
681 7: llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont");
682 7: CGF.EmitBranch(Cont1);
683 7: CGF.setInvokeDest(PreviousInvokeDest);
684 :
685 :
686 7: CGF.EmitBlock(CleanupHandler);
687 :
688 : llvm::Constant *Personality =
689 : CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
690 : (CGF.VMContext),
691 : true),
692 7: "__gxx_personality_v0");
693 7: Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty);
694 : llvm::Value *llvm_eh_exception =
695 7: CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
696 : llvm::Value *llvm_eh_selector =
697 7: CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
698 :
699 7: llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
700 : const llvm::IntegerType *Int8Ty;
701 : const llvm::PointerType *PtrToInt8Ty;
702 7: Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext);
703 : // C string type. Used in lots of places.
704 7: PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
705 7: llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
706 7: llvm::SmallVector<llvm::Value*, 8> Args;
707 7: Args.clear();
708 7: Args.push_back(Exc);
709 7: Args.push_back(Personality);
710 7: Args.push_back(Null);
711 7: CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
712 :
713 7: CGF.EmitBlock(CleanupEntryBB);
714 :
715 7: CGF.EmitBlock(Cont1);
716 :
5: branch 1 taken
2: branch 2 taken
0: branch 4 not taken
0: branch 5 not taken
717 7: if (CGF.getInvokeDest()) {
718 5: llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
719 : CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
720 5: CGF.getInvokeDest(), Exc);
721 5: CGF.EmitBlock(Cont);
722 : } else
723 2: CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
724 :
725 7: CGF.Builder.CreateUnreachable();
726 :
727 7: CGF.EmitBlock(Cont);
7: branch 0 taken
0: branch 1 not taken
0: branch 2 not taken
0: branch 3 not taken
728 7: if (CGF.Exceptions)
729 7: CGF.setInvokeDest(CleanupHandler);
730 7: }
731 :
732 10: llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
6: branch 0 taken
4: branch 1 taken
733 10: if (TerminateHandler)
734 6: return TerminateHandler;
735 :
736 4: llvm::BasicBlock *Cont = 0;
737 :
1: branch 1 taken
3: branch 2 taken
738 4: if (HaveInsertPoint()) {
739 1: Cont = createBasicBlock("cont");
740 1: EmitBranch(Cont);
741 : }
742 :
743 : llvm::Constant *Personality =
744 : CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
745 : (VMContext),
746 : true),
747 4: "__gxx_personality_v0");
748 4: Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
749 : llvm::Value *llvm_eh_exception =
750 4: CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
751 : llvm::Value *llvm_eh_selector =
752 4: CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
753 :
754 : // Set up terminate handler
755 4: TerminateHandler = createBasicBlock("terminate.handler");
756 4: EmitBlock(TerminateHandler);
757 4: llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
758 : // We are required to emit this call to satisfy LLVM, even
759 : // though we don't use the result.
760 4: llvm::SmallVector<llvm::Value*, 8> Args;
761 4: Args.push_back(Exc);
762 4: Args.push_back(Personality);
763 : Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
764 4: 1));
765 4: Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
766 : llvm::CallInst *TerminateCall =
767 4: Builder.CreateCall(getTerminateFn(*this));
768 4: TerminateCall->setDoesNotReturn();
769 4: TerminateCall->setDoesNotThrow();
770 4: Builder.CreateUnreachable();
771 :
772 : // Clear the insertion point to indicate we are in unreachable code.
773 4: Builder.ClearInsertionPoint();
774 :
1: branch 0 taken
3: branch 1 taken
775 4: if (Cont)
776 1: EmitBlock(Cont);
777 :
778 4: return TerminateHandler;
779 : }
Generated: 2010-02-10 01:31 by zcov