CGException.cpp revision 6b85fa41214d9d3e8ef635f964fdc1c74f4702d6
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 CodeGenFunction::CleanupScope TryScope(CGF); 138 { 139 // These actions are only on the exceptional edge. 140 CodeGenFunction::DelayedCleanupBlock Scope(CGF, true); 141 142 llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); 143 const llvm::Type *Int8PtrTy 144 = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 145 llvm::Value *ExceptionPtr = CGF.Builder.CreateBitCast(N, Int8PtrTy); 146 CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); 147 } 148 149 llvm::Value *Src = CGF.EmitLValue(E).getAddress(); 150 151 // Stolen from EmitClassAggrMemberwiseCopy 152 llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, 153 Ctor_Complete); 154 CallArgList CallArgs; 155 CallArgs.push_back(std::make_pair(RValue::get(This), 156 CopyCtor->getThisType(CGF.getContext()))); 157 158 // Push the Src ptr. 159 CallArgs.push_back(std::make_pair(RValue::get(Src), 160 CopyCtor->getParamDecl(0)->getType())); 161 QualType ResultType = 162 CopyCtor->getType()->getAs<FunctionType>()->getResultType(); 163 CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), 164 Callee, CallArgs, CopyCtor); 165 } else 166 llvm::llvm_unreachable("uncopyable object"); 167 } 168} 169 170// CopyObject - Utility to copy an object. Calls copy constructor as necessary. 171// N is casted to the right type. 172static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, 173 llvm::Value *E, llvm::Value *N) { 174 // Store the throw exception in the exception object. 175 if (!CGF.hasAggregateLLVMType(ObjectType)) { 176 llvm::Value *Value = E; 177 const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); 178 179 CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); 180 } else { 181 const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); 182 const CXXRecordDecl *RD; 183 RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); 184 llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); 185 if (RD->hasTrivialCopyConstructor()) { 186 CGF.EmitAggregateCopy(This, E, ObjectType); 187 } else if (CXXConstructorDecl *CopyCtor 188 = RD->getCopyConstructor(CGF.getContext(), 0)) { 189 // FIXME: region management, call terminate 190 llvm::Value *Src = E; 191 192 // Stolen from EmitClassAggrMemberwiseCopy 193 llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, 194 Ctor_Complete); 195 CallArgList CallArgs; 196 CallArgs.push_back(std::make_pair(RValue::get(This), 197 CopyCtor->getThisType(CGF.getContext()))); 198 199 // Push the Src ptr. 200 CallArgs.push_back(std::make_pair(RValue::get(Src), 201 CopyCtor->getParamDecl(0)->getType())); 202 QualType ResultType = 203 CopyCtor->getType()->getAs<FunctionType>()->getResultType(); 204 CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), 205 Callee, CallArgs, CopyCtor); 206 // FIXME: region management 207 } else 208 llvm::llvm_unreachable("uncopyable object"); 209 } 210} 211 212void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { 213 if (!E->getSubExpr()) { 214 Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); 215 Builder.CreateUnreachable(); 216 217 // Clear the insertion point to indicate we are in unreachable code. 218 Builder.ClearInsertionPoint(); 219 return; 220 } 221 222 QualType ThrowType = E->getSubExpr()->getType(); 223 224 // Now allocate the exception object. 225 const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); 226 uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; 227 228 llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); 229 llvm::Value *ExceptionPtr = 230 Builder.CreateCall(AllocExceptionFn, 231 llvm::ConstantInt::get(SizeTy, TypeSize), 232 "exception"); 233 234 CopyObject(*this, E->getSubExpr(), ExceptionPtr); 235 236 // Now throw the exception. 237 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 238 llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType); 239 llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); 240 241 llvm::CallInst *ThrowCall = 242 Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); 243 ThrowCall->setDoesNotReturn(); 244 Builder.CreateUnreachable(); 245 246 // Clear the insertion point to indicate we are in unreachable code. 247 Builder.ClearInsertionPoint(); 248} 249 250void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { 251 if (1) { 252 EmitStmt(S.getTryBlock()); 253 return; 254 } 255 // FIXME: The below is still just a sketch of the code we need. 256 // Pointer to the personality function 257 llvm::Constant *Personality = 258 CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 259 (VMContext), 260 true), 261 "__gxx_personality_v0"); 262 Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); 263 llvm::Value *llvm_eh_exception = 264 CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 265 llvm::Value *llvm_eh_selector = 266 CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 267 268 llvm::BasicBlock *PrevLandingPad = getInvokeDest(); 269 llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); 270 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); 271 llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); 272 llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); 273 274 // Push an EH context entry, used for handling rethrows. 275 PushCleanupBlock(FinallyBlock); 276 277 // Emit the statements in the try {} block 278 setInvokeDest(TryHandler); 279 280 EmitStmt(S.getTryBlock()); 281 282 // Jump to end if there is no exception 283 EmitBranchThroughCleanup(FinallyEnd); 284 285 // Set up terminate handler 286 llvm::BasicBlock *TerminateHandler = createBasicBlock("terminate.handler"); 287 EmitBlock(TerminateHandler); 288 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 289 // We are required to emit this call to satisfy LLVM, even 290 // though we don't use the result. 291 llvm::SmallVector<llvm::Value*, 8> Args; 292 Args.clear(); 293 Args.push_back(Exc); 294 Args.push_back(Personality); 295 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 296 0)); 297 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 298 llvm::CallInst *TerminateCall = 299 Builder.CreateCall(getTerminateFn(*this)); 300 TerminateCall->setDoesNotReturn(); 301 TerminateCall->setDoesNotThrow(); 302 Builder.CreateUnreachable(); 303 304 // Clear the insertion point to indicate we are in unreachable code. 305 Builder.ClearInsertionPoint(); 306 307 // Emit the handlers 308 EmitBlock(TryHandler); 309 310 const llvm::IntegerType *Int8Ty; 311 const llvm::PointerType *PtrToInt8Ty; 312 Int8Ty = llvm::Type::getInt8Ty(VMContext); 313 // C string type. Used in lots of places. 314 PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); 315 llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); 316 llvm::SmallVector<llvm::Value*, 8> SelectorArgs; 317 llvm::Value *llvm_eh_typeid_for = 318 CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); 319 // Exception object 320 Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 321 llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); 322 323 Args.clear(); 324 SelectorArgs.push_back(Exc); 325 SelectorArgs.push_back(Personality); 326 327 bool HasCatchAll = false; 328 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 329 const CXXCatchStmt *C = S.getHandler(i); 330 VarDecl *CatchParam = C->getExceptionDecl(); 331 if (CatchParam) { 332 llvm::Value *EHType 333 = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); 334 SelectorArgs.push_back(EHType); 335 } else { 336 // null indicates catch all 337 SelectorArgs.push_back(Null); 338 HasCatchAll = true; 339 } 340 } 341 342 // We use a cleanup unless there was already a catch all. 343 if (!HasCatchAll) { 344 SelectorArgs.push_back(Null); 345 } 346 347 // Find which handler was matched. 348 llvm::Value *Selector 349 = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), 350 SelectorArgs.end(), "selector"); 351 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 352 const CXXCatchStmt *C = S.getHandler(i); 353 VarDecl *CatchParam = C->getExceptionDecl(); 354 Stmt *CatchBody = C->getHandlerBlock(); 355 356 llvm::BasicBlock *Next = 0; 357 358 if (SelectorArgs[i+2] != Null) { 359 llvm::BasicBlock *Match = createBasicBlock("match"); 360 Next = createBasicBlock("catch.next"); 361 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 362 llvm::Value *Id 363 = Builder.CreateCall(llvm_eh_typeid_for, 364 Builder.CreateBitCast(SelectorArgs[i+2], 365 Int8PtrTy)); 366 Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), 367 Match, Next); 368 EmitBlock(Match); 369 } 370 371 llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); 372 llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); 373 374 PushCleanupBlock(MatchEnd); 375 setInvokeDest(MatchHandler); 376 377 llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); 378 379 { 380 CleanupScope CatchScope(*this); 381 // Bind the catch parameter if it exists. 382 if (CatchParam) { 383 QualType CatchType = CatchParam->getType().getNonReferenceType(); 384 setInvokeDest(TerminateHandler); 385 if (!CatchType.getTypePtr()->isPointerType()) 386 CatchType = getContext().getPointerType(CatchType); 387 ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); 388 EmitLocalBlockVarDecl(*CatchParam); 389#if 0 390 // FIXME: objects with ctors, references 391 Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); 392#else 393 // FIXME: we need to do this sooner so that the EH region for the cleanup doesn't start until after the ctor completes, use a decl init? 394 CopyObject(*this, CatchParam->getType().getNonReferenceType(), 395 ExcObject, GetAddrOfLocalVar(CatchParam)); 396#endif 397 setInvokeDest(MatchHandler); 398 } 399 400 EmitStmt(CatchBody); 401 } 402 403 EmitBranchThroughCleanup(FinallyEnd); 404 405 EmitBlock(MatchHandler); 406 407 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 408 // We are required to emit this call to satisfy LLVM, even 409 // though we don't use the result. 410 Args.clear(); 411 Args.push_back(Exc); 412 Args.push_back(Personality); 413 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 414 0)); 415 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 416 Builder.CreateStore(Exc, RethrowPtr); 417 EmitBranchThroughCleanup(FinallyRethrow); 418 419 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 420 421 EmitBlock(MatchEnd); 422 423 llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 424 Builder.CreateInvoke(getEndCatchFn(*this), 425 Cont, TerminateHandler, 426 Args.begin(), Args.begin()); 427 428 EmitBlock(Cont); 429 if (Info.SwitchBlock) 430 EmitBlock(Info.SwitchBlock); 431 if (Info.EndBlock) 432 EmitBlock(Info.EndBlock); 433 434 Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 435 Builder.CreateStore(Exc, RethrowPtr); 436 EmitBranchThroughCleanup(FinallyRethrow); 437 438 if (Next) 439 EmitBlock(Next); 440 } 441 if (!HasCatchAll) 442 EmitBranchThroughCleanup(FinallyRethrow); 443 444 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 445 446 setInvokeDest(PrevLandingPad); 447 448 EmitBlock(FinallyBlock); 449 450 if (Info.SwitchBlock) 451 EmitBlock(Info.SwitchBlock); 452 if (Info.EndBlock) 453 EmitBlock(Info.EndBlock); 454 455 // Branch around the rethrow code. 456 EmitBranch(FinallyEnd); 457 458 EmitBlock(FinallyRethrow); 459 Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), 460 Builder.CreateLoad(RethrowPtr)); 461 Builder.CreateUnreachable(); 462 463 EmitBlock(FinallyEnd); 464} 465