CGException.cpp revision de05057932cebc3f43911f87d75869cb7b705a19
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 // FIXME: Handle cleanup. 224 if (!CleanupEntries.empty()){ 225 ErrorUnsupported(E, "throw expression with cleanup entries"); 226 return; 227 } 228 229 // Now allocate the exception object. 230 const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); 231 uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; 232 233 llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); 234 llvm::Value *ExceptionPtr = 235 Builder.CreateCall(AllocExceptionFn, 236 llvm::ConstantInt::get(SizeTy, TypeSize), 237 "exception"); 238 239 CopyObject(*this, E->getSubExpr(), ExceptionPtr); 240 241 // Now throw the exception. 242 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 243 llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType); 244 llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); 245 246 llvm::CallInst *ThrowCall = 247 Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); 248 ThrowCall->setDoesNotReturn(); 249 Builder.CreateUnreachable(); 250 251 // Clear the insertion point to indicate we are in unreachable code. 252 Builder.ClearInsertionPoint(); 253} 254 255void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { 256 if (1) { 257 EmitStmt(S.getTryBlock()); 258 return; 259 } 260 // FIXME: The below is still just a sketch of the code we need. 261 // Pointer to the personality function 262 llvm::Constant *Personality = 263 CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 264 (VMContext), 265 true), 266 "__gxx_personality_v0"); 267 Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); 268 269 llvm::BasicBlock *PrevLandingPad = getInvokeDest(); 270 llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); 271 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); 272 llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); 273 llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); 274 275 // Push an EH context entry, used for handling rethrows. 276 PushCleanupBlock(FinallyBlock); 277 278 // Emit the statements in the try {} block 279 setInvokeDest(TryHandler); 280 281 EmitStmt(S.getTryBlock()); 282 283 // Jump to end if there is no exception 284 EmitBranchThroughCleanup(FinallyEnd); 285 286 // Emit the handlers 287 EmitBlock(TryHandler); 288 289 const llvm::IntegerType *Int8Ty; 290 const llvm::PointerType *PtrToInt8Ty; 291 Int8Ty = llvm::Type::getInt8Ty(VMContext); 292 // C string type. Used in lots of places. 293 PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); 294 llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); 295 llvm::SmallVector<llvm::Value*, 8> SelectorArgs; 296 llvm::Value *llvm_eh_exception = 297 CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 298 llvm::Value *llvm_eh_selector = 299 CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 300 llvm::Value *llvm_eh_typeid_for = 301 CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); 302 // Exception object 303 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 304 llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); 305 306 SelectorArgs.push_back(Exc); 307 SelectorArgs.push_back(Personality); 308 309 bool HasCatchAll = false; 310 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 311 const CXXCatchStmt *C = S.getHandler(i); 312 VarDecl *CatchParam = C->getExceptionDecl(); 313 if (CatchParam) { 314 llvm::Value *EHType 315 = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); 316 SelectorArgs.push_back(EHType); 317 } else { 318 // null indicates catch all 319 SelectorArgs.push_back(Null); 320 HasCatchAll = true; 321 } 322 } 323 324 // We use a cleanup unless there was already a catch all. 325 if (!HasCatchAll) { 326 SelectorArgs.push_back(Null); 327 } 328 329 // Find which handler was matched. 330 llvm::Value *Selector 331 = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), 332 SelectorArgs.end(), "selector"); 333 llvm::BasicBlock *TerminateHandler = 0; 334 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 335 const CXXCatchStmt *C = S.getHandler(i); 336 VarDecl *CatchParam = C->getExceptionDecl(); 337 Stmt *CatchBody = C->getHandlerBlock(); 338 339 llvm::BasicBlock *Next = 0; 340 341 if (SelectorArgs[i+2] != Null) { 342 llvm::BasicBlock *Match = createBasicBlock("match"); 343 Next = createBasicBlock("catch.next"); 344 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 345 llvm::Value *Id 346 = Builder.CreateCall(llvm_eh_typeid_for, 347 Builder.CreateBitCast(SelectorArgs[i+2], 348 Int8PtrTy)); 349 Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), 350 Match, Next); 351 EmitBlock(Match); 352 } 353 354 llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); 355 llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); 356 357 PushCleanupBlock(MatchEnd); 358 setInvokeDest(MatchHandler); 359 360 llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); 361 362 // Bind the catch parameter if it exists. 363 if (CatchParam) { 364 QualType CatchType = CatchParam->getType().getNonReferenceType(); 365 if (!CatchType.getTypePtr()->isPointerType()) 366 CatchType = getContext().getPointerType(CatchType); 367 ExcObject = 368 Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); 369 // CatchParam is a ParmVarDecl because of the grammar 370 // construction used to handle this, but for codegen purposes 371 // we treat this as a local decl. 372 EmitLocalBlockVarDecl(*CatchParam); 373#if 0 374 // FIXME: objects with ctors, references 375 Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); 376#else 377 CopyObject(*this, CatchParam->getType().getNonReferenceType(), 378 ExcObject, GetAddrOfLocalVar(CatchParam)); 379#endif 380 } 381 382 EmitStmt(CatchBody); 383 EmitBranchThroughCleanup(FinallyEnd); 384 385 EmitBlock(MatchHandler); 386 387 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 388 // We are required to emit this call to satisfy LLVM, even 389 // though we don't use the result. 390 llvm::SmallVector<llvm::Value*, 8> Args; 391 Args.push_back(Exc); 392 Args.push_back(Personality); 393 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 394 0)); 395 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 396 Builder.CreateStore(Exc, RethrowPtr); 397 EmitBranchThroughCleanup(FinallyRethrow); 398 399 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 400 401 EmitBlock(MatchEnd); 402 403 // Set up terminate handler 404 bool GenerateTerminate = false; 405 if (!TerminateHandler) { 406 TerminateHandler = createBasicBlock("terminate.handler"); 407 GenerateTerminate = true; 408 } 409 llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 410 Builder.CreateInvoke(getEndCatchFn(*this), 411 Cont, TerminateHandler, 412 Args.begin(), Args.begin()); 413 414 EmitBlock(Cont); 415 if (Info.SwitchBlock) 416 EmitBlock(Info.SwitchBlock); 417 if (Info.EndBlock) 418 EmitBlock(Info.EndBlock); 419 420 Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 421 Builder.CreateStore(Exc, RethrowPtr); 422 EmitBranchThroughCleanup(FinallyRethrow); 423 424 if (GenerateTerminate) { 425 GenerateTerminate = false; 426 EmitBlock(TerminateHandler); 427 Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 428 // We are required to emit this call to satisfy LLVM, even 429 // though we don't use the result. 430 Args.clear(); 431 Args.push_back(Exc); 432 Args.push_back(Personality); 433 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 434 0)); 435 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 436 llvm::CallInst *TerminateCall = 437 Builder.CreateCall(getTerminateFn(*this)); 438 TerminateCall->setDoesNotReturn(); 439 TerminateCall->setDoesNotThrow(); 440 Builder.CreateUnreachable(); 441 442 // Clear the insertion point to indicate we are in unreachable code. 443 Builder.ClearInsertionPoint(); 444 } 445 446 if (Next) 447 EmitBlock(Next); 448 } 449 if (!HasCatchAll) 450 EmitBranchThroughCleanup(FinallyRethrow); 451 452 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 453 454 setInvokeDest(PrevLandingPad); 455 456 EmitBlock(FinallyBlock); 457 458 if (Info.SwitchBlock) 459 EmitBlock(Info.SwitchBlock); 460 if (Info.EndBlock) 461 EmitBlock(Info.EndBlock); 462 463 // Branch around the rethrow code. 464 EmitBranch(FinallyEnd); 465 466 EmitBlock(FinallyRethrow); 467 Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), 468 Builder.CreateLoad(RethrowPtr)); 469 Builder.CreateUnreachable(); 470 471 EmitBlock(FinallyEnd); 472} 473