CGException.cpp revision 6a1e0eb557d47e85185e09bdf8721f53f4bf9c9c
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" 19using namespace clang; 20using namespace CodeGen; 21 22static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { 23 // void *__cxa_allocate_exception(size_t thrown_size); 24 const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); 25 std::vector<const llvm::Type*> Args(1, SizeTy); 26 27 const llvm::FunctionType *FTy = 28 llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), 29 Args, false); 30 31 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); 32} 33 34static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) { 35 // void __cxa_free_exception(void *thrown_exception); 36 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 37 std::vector<const llvm::Type*> Args(1, Int8PtrTy); 38 39 const llvm::FunctionType *FTy = 40 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 41 Args, false); 42 43 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); 44} 45 46static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { 47 // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, 48 // void (*dest) (void *)); 49 50 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 51 std::vector<const llvm::Type*> Args(3, Int8PtrTy); 52 53 const llvm::FunctionType *FTy = 54 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 55 Args, false); 56 57 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); 58} 59 60static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { 61 // void __cxa_rethrow(); 62 63 const llvm::FunctionType *FTy = 64 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 65 66 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); 67} 68 69static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { 70 // void* __cxa_begin_catch(); 71 72 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 73 std::vector<const llvm::Type*> Args(1, Int8PtrTy); 74 75 const llvm::FunctionType *FTy = 76 llvm::FunctionType::get(Int8PtrTy, Args, false); 77 78 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); 79} 80 81static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { 82 // void __cxa_end_catch(); 83 84 const llvm::FunctionType *FTy = 85 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 86 87 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); 88} 89 90// FIXME: Eventually this will all go into the backend. Set from the target for 91// now. 92static int using_sjlj_exceptions = 0; 93 94static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { 95 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 96 std::vector<const llvm::Type*> Args(1, Int8PtrTy); 97 98 const llvm::FunctionType *FTy = 99 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, 100 false); 101 102 if (using_sjlj_exceptions) 103 return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); 104 return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); 105} 106 107static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { 108 // void __terminate(); 109 110 const llvm::FunctionType *FTy = 111 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 112 113 return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); 114} 115 116// CopyObject - Utility to copy an object. Calls copy constructor as necessary. 117// N is casted to the right type. 118static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { 119 QualType ObjectType = E->getType(); 120 121 // Store the throw exception in the exception object. 122 if (!CGF.hasAggregateLLVMType(ObjectType)) { 123 llvm::Value *Value = CGF.EmitScalarExpr(E); 124 const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); 125 126 CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); 127 } else { 128 const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); 129 const CXXRecordDecl *RD; 130 RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); 131 llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); 132 if (RD->hasTrivialCopyConstructor()) { 133 CGF.EmitAggExpr(E, This, false); 134 } else if (CXXConstructorDecl *CopyCtor 135 = RD->getCopyConstructor(CGF.getContext(), 0)) { 136 // All temporaries end before we call __cxa_throw 137 // FIXME: Doesn't work well with eh31.C and PopCXXTemporary 138 // CodeGenFunction::CleanupScope TryScope(CGF); 139 { 140 // These actions are only on the exceptional edge. 141 if (0) { 142 // FIXME: Doesn't work well with eh31.C and PopCXXTemporary 143 CodeGenFunction::DelayedCleanupBlock Scope(CGF, true); 144 145 llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); 146 const llvm::Type *Int8PtrTy 147 = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 148 llvm::Value *ExceptionPtr = CGF.Builder.CreateBitCast(N, Int8PtrTy); 149 CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); 150 } 151 } 152 153 llvm::Value *Src = CGF.EmitLValue(E).getAddress(); 154 155 // Stolen from EmitClassAggrMemberwiseCopy 156 llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, 157 Ctor_Complete); 158 CallArgList CallArgs; 159 CallArgs.push_back(std::make_pair(RValue::get(This), 160 CopyCtor->getThisType(CGF.getContext()))); 161 162 // Push the Src ptr. 163 CallArgs.push_back(std::make_pair(RValue::get(Src), 164 CopyCtor->getParamDecl(0)->getType())); 165 QualType ResultType = 166 CopyCtor->getType()->getAs<FunctionType>()->getResultType(); 167 CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), 168 Callee, CallArgs, CopyCtor); 169 } else 170 llvm::llvm_unreachable("uncopyable object"); 171 } 172} 173 174// CopyObject - Utility to copy an object. Calls copy constructor as necessary. 175// N is casted to the right type. 176static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, 177 bool WasPointer, llvm::Value *E, llvm::Value *N) { 178 // Store the throw exception in the exception object. 179 if (!CGF.hasAggregateLLVMType(ObjectType)) { 180 llvm::Value *Value = E; 181 if (!WasPointer) 182 Value = CGF.Builder.CreateLoad(Value); 183 const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); 184 CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); 185 } else { 186 const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); 187 const CXXRecordDecl *RD; 188 RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); 189 llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); 190 if (RD->hasTrivialCopyConstructor()) { 191 CGF.EmitAggregateCopy(This, E, ObjectType); 192 } else if (CXXConstructorDecl *CopyCtor 193 = RD->getCopyConstructor(CGF.getContext(), 0)) { 194 llvm::Value *Src = E; 195 196 // Stolen from EmitClassAggrMemberwiseCopy 197 llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, 198 Ctor_Complete); 199 CallArgList CallArgs; 200 CallArgs.push_back(std::make_pair(RValue::get(This), 201 CopyCtor->getThisType(CGF.getContext()))); 202 203 // Push the Src ptr. 204 CallArgs.push_back(std::make_pair(RValue::get(Src), 205 CopyCtor->getParamDecl(0)->getType())); 206 QualType ResultType = 207 CopyCtor->getType()->getAs<FunctionType>()->getResultType(); 208 CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), 209 Callee, CallArgs, CopyCtor); 210 } else 211 llvm::llvm_unreachable("uncopyable object"); 212 } 213} 214 215void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { 216 if (!E->getSubExpr()) { 217 if (getInvokeDest()) { 218 llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 219 Builder.CreateInvoke(getReThrowFn(*this), Cont, getInvokeDest()) 220 ->setDoesNotReturn(); 221 EmitBlock(Cont); 222 } else 223 Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); 224 Builder.CreateUnreachable(); 225 226 // Clear the insertion point to indicate we are in unreachable code. 227 Builder.ClearInsertionPoint(); 228 return; 229 } 230 231 QualType ThrowType = E->getSubExpr()->getType(); 232 233 // Now allocate the exception object. 234 const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); 235 uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; 236 237 llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); 238 llvm::Value *ExceptionPtr = 239 Builder.CreateCall(AllocExceptionFn, 240 llvm::ConstantInt::get(SizeTy, TypeSize), 241 "exception"); 242 243 CopyObject(*this, E->getSubExpr(), ExceptionPtr); 244 245 // Now throw the exception. 246 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 247 llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType); 248 llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); 249 250 if (getInvokeDest()) { 251 llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 252 llvm::InvokeInst *ThrowCall = 253 Builder.CreateInvoke3(getThrowFn(*this), Cont, getInvokeDest(), 254 ExceptionPtr, TypeInfo, Dtor); 255 ThrowCall->setDoesNotReturn(); 256 EmitBlock(Cont); 257 } else { 258 llvm::CallInst *ThrowCall = 259 Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); 260 ThrowCall->setDoesNotReturn(); 261 } 262 Builder.CreateUnreachable(); 263 264 // Clear the insertion point to indicate we are in unreachable code. 265 Builder.ClearInsertionPoint(); 266} 267 268void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { 269 if (0) { 270 EmitStmt(S.getTryBlock()); 271 return; 272 } 273 274 // FIXME: The below is still just a sketch of the code we need. 275 // Pointer to the personality function 276 llvm::Constant *Personality = 277 CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 278 (VMContext), 279 true), 280 "__gxx_personality_v0"); 281 Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); 282 llvm::Value *llvm_eh_exception = 283 CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 284 llvm::Value *llvm_eh_selector = 285 CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 286 287 llvm::BasicBlock *PrevLandingPad = getInvokeDest(); 288 llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); 289 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); 290 llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); 291 llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); 292 293 // Push an EH context entry, used for handling rethrows. 294 PushCleanupBlock(FinallyBlock); 295 296 // Emit the statements in the try {} block 297 setInvokeDest(TryHandler); 298 299 // FIXME: We should not have to do this here. The AST should have the member 300 // initializers under the CXXTryStmt's TryBlock. 301 if (OuterTryBlock == &S) { 302 GlobalDecl GD = CurGD; 303 const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); 304 305 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { 306 size_t OldCleanupStackSize = CleanupEntries.size(); 307 EmitCtorPrologue(CD, CurGD.getCtorType()); 308 EmitStmt(S.getTryBlock()); 309 310 // If any of the member initializers are temporaries bound to references 311 // make sure to emit their destructors. 312 EmitCleanupBlocks(OldCleanupStackSize); 313 } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { 314 llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); 315 PushCleanupBlock(DtorEpilogue); 316 317 EmitStmt(S.getTryBlock()); 318 319 CleanupBlockInfo Info = PopCleanupBlock(); 320 321 assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); 322 EmitBlock(DtorEpilogue); 323 EmitDtorEpilogue(DD, GD.getDtorType()); 324 325 if (Info.SwitchBlock) 326 EmitBlock(Info.SwitchBlock); 327 if (Info.EndBlock) 328 EmitBlock(Info.EndBlock); 329 } else 330 EmitStmt(S.getTryBlock()); 331 } else 332 EmitStmt(S.getTryBlock()); 333 334 // Jump to end if there is no exception 335 EmitBranchThroughCleanup(FinallyEnd); 336 337 // Set up terminate handler 338 llvm::BasicBlock *TerminateHandler = createBasicBlock("terminate.handler"); 339 EmitBlock(TerminateHandler); 340 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 341 // We are required to emit this call to satisfy LLVM, even 342 // though we don't use the result. 343 llvm::SmallVector<llvm::Value*, 8> Args; 344 Args.clear(); 345 Args.push_back(Exc); 346 Args.push_back(Personality); 347 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 348 0)); 349 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 350 llvm::CallInst *TerminateCall = 351 Builder.CreateCall(getTerminateFn(*this)); 352 TerminateCall->setDoesNotReturn(); 353 TerminateCall->setDoesNotThrow(); 354 Builder.CreateUnreachable(); 355 356 // Clear the insertion point to indicate we are in unreachable code. 357 Builder.ClearInsertionPoint(); 358 359 // Emit the handlers 360 EmitBlock(TryHandler); 361 362 const llvm::IntegerType *Int8Ty; 363 const llvm::PointerType *PtrToInt8Ty; 364 Int8Ty = llvm::Type::getInt8Ty(VMContext); 365 // C string type. Used in lots of places. 366 PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); 367 llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); 368 llvm::SmallVector<llvm::Value*, 8> SelectorArgs; 369 llvm::Value *llvm_eh_typeid_for = 370 CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); 371 // Exception object 372 Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 373 llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); 374 375 Args.clear(); 376 SelectorArgs.push_back(Exc); 377 SelectorArgs.push_back(Personality); 378 379 bool HasCatchAll = false; 380 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 381 const CXXCatchStmt *C = S.getHandler(i); 382 VarDecl *CatchParam = C->getExceptionDecl(); 383 if (CatchParam) { 384 llvm::Value *EHType 385 = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); 386 SelectorArgs.push_back(EHType); 387 } else { 388 // null indicates catch all 389 SelectorArgs.push_back(Null); 390 HasCatchAll = true; 391 } 392 } 393 394 // We use a cleanup unless there was already a catch all. 395 if (!HasCatchAll) { 396 SelectorArgs.push_back(Null); 397 } 398 399 // Find which handler was matched. 400 llvm::Value *Selector 401 = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), 402 SelectorArgs.end(), "selector"); 403 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 404 const CXXCatchStmt *C = S.getHandler(i); 405 VarDecl *CatchParam = C->getExceptionDecl(); 406 Stmt *CatchBody = C->getHandlerBlock(); 407 408 llvm::BasicBlock *Next = 0; 409 410 if (SelectorArgs[i+2] != Null) { 411 llvm::BasicBlock *Match = createBasicBlock("match"); 412 Next = createBasicBlock("catch.next"); 413 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 414 llvm::Value *Id 415 = Builder.CreateCall(llvm_eh_typeid_for, 416 Builder.CreateBitCast(SelectorArgs[i+2], 417 Int8PtrTy)); 418 Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), 419 Match, Next); 420 EmitBlock(Match); 421 } 422 423 llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); 424 llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); 425 426 PushCleanupBlock(MatchEnd); 427 setInvokeDest(MatchHandler); 428 429 llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); 430 431 { 432 CleanupScope CatchScope(*this); 433 // Bind the catch parameter if it exists. 434 if (CatchParam) { 435 QualType CatchType = CatchParam->getType().getNonReferenceType(); 436 setInvokeDest(TerminateHandler); 437 bool WasPointer = true; 438 if (!CatchType.getTypePtr()->isPointerType()) { 439 if (!isa<ReferenceType>(CatchParam->getType())) 440 WasPointer = false; 441 CatchType = getContext().getPointerType(CatchType); 442 } 443 ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); 444 EmitLocalBlockVarDecl(*CatchParam); 445#if 0 446 // FIXME: objects with ctors, references 447 Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); 448#else 449 // FIXME: we need to do this sooner so that the EH region for the 450 // cleanup doesn't start until after the ctor completes, use a decl 451 // init? 452 CopyObject(*this, CatchParam->getType().getNonReferenceType(), 453 WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam)); 454#endif 455 setInvokeDest(MatchHandler); 456 } 457 458 EmitStmt(CatchBody); 459 } 460 461 EmitBranchThroughCleanup(FinallyEnd); 462 463 EmitBlock(MatchHandler); 464 465 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 466 // We are required to emit this call to satisfy LLVM, even 467 // though we don't use the result. 468 Args.clear(); 469 Args.push_back(Exc); 470 Args.push_back(Personality); 471 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 472 0)); 473 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 474 Builder.CreateStore(Exc, RethrowPtr); 475 EmitBranchThroughCleanup(FinallyRethrow); 476 477 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 478 479 EmitBlock(MatchEnd); 480 481 llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 482 Builder.CreateInvoke(getEndCatchFn(*this), 483 Cont, TerminateHandler, 484 Args.begin(), Args.begin()); 485 EmitBlock(Cont); 486 if (Info.SwitchBlock) 487 EmitBlock(Info.SwitchBlock); 488 if (Info.EndBlock) 489 EmitBlock(Info.EndBlock); 490 491 Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 492 Builder.CreateStore(Exc, RethrowPtr); 493 EmitBranchThroughCleanup(FinallyRethrow); 494 495 if (Next) 496 EmitBlock(Next); 497 } 498 if (!HasCatchAll) { 499 Builder.CreateStore(Exc, RethrowPtr); 500 EmitBranchThroughCleanup(FinallyRethrow); 501 } 502 503 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 504 505 setInvokeDest(PrevLandingPad); 506 507 EmitBlock(FinallyBlock); 508 509 if (Info.SwitchBlock) 510 EmitBlock(Info.SwitchBlock); 511 if (Info.EndBlock) 512 EmitBlock(Info.EndBlock); 513 514 // Branch around the rethrow code. 515 EmitBranch(FinallyEnd); 516 517 EmitBlock(FinallyRethrow); 518 // FIXME: Eventually we can chain the handlers together and just do a call 519 // here. 520 if (getInvokeDest()) { 521 llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 522 Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, 523 getInvokeDest(), 524 Builder.CreateLoad(RethrowPtr)); 525 EmitBlock(Cont); 526 } else 527 Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), 528 Builder.CreateLoad(RethrowPtr)); 529 530 Builder.CreateUnreachable(); 531 532 EmitBlock(FinallyEnd); 533} 534