CGException.cpp revision 199990
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 *getThrowFn(CodeGenFunction &CGF) { 35 // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, 36 // void (*dest) (void *) ); 37 38 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 39 std::vector<const llvm::Type*> Args(3, Int8PtrTy); 40 41 const llvm::FunctionType *FTy = 42 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 43 Args, false); 44 45 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); 46} 47 48static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { 49 // void __cxa_rethrow (); 50 51 const llvm::FunctionType *FTy = 52 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 53 54 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); 55} 56 57static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { 58 // void* __cxa_begin_catch (); 59 60 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 61 std::vector<const llvm::Type*> Args(1, Int8PtrTy); 62 63 const llvm::FunctionType *FTy = 64 llvm::FunctionType::get(Int8PtrTy, Args, false); 65 66 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); 67} 68 69static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { 70 // void __cxa_end_catch (); 71 72 const llvm::FunctionType *FTy = 73 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 74 75 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); 76} 77 78// FIXME: Eventually this will all go into the backend. Set from the target for 79// now. 80static int using_sjlj_exceptions = 0; 81 82static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { 83 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 84 std::vector<const llvm::Type*> Args(1, Int8PtrTy); 85 86 const llvm::FunctionType *FTy = 87 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, 88 false); 89 90 if (using_sjlj_exceptions) 91 return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); 92 return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); 93} 94 95// CopyObject - Utility to copy an object. Calls copy constructor as necessary. 96// N is casted to the right type. 97static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { 98 QualType ObjectType = E->getType(); 99 100 // Store the throw exception in the exception object. 101 if (!CGF.hasAggregateLLVMType(ObjectType)) { 102 llvm::Value *Value = CGF.EmitScalarExpr(E); 103 const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); 104 105 CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); 106 } else { 107 const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); 108 const CXXRecordDecl *RD; 109 RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); 110 llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); 111 if (RD->hasTrivialCopyConstructor()) { 112 CGF.EmitAggExpr(E, This, false); 113 } else if (CXXConstructorDecl *CopyCtor 114 = RD->getCopyConstructor(CGF.getContext(), 0)) { 115 // FIXME: region management 116 llvm::Value *Src = CGF.EmitLValue(E).getAddress(); 117 118 // Stolen from EmitClassAggrMemberwiseCopy 119 llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, 120 Ctor_Complete); 121 CallArgList CallArgs; 122 CallArgs.push_back(std::make_pair(RValue::get(This), 123 CopyCtor->getThisType(CGF.getContext()))); 124 125 // Push the Src ptr. 126 CallArgs.push_back(std::make_pair(RValue::get(Src), 127 CopyCtor->getParamDecl(0)->getType())); 128 QualType ResultType = 129 CopyCtor->getType()->getAs<FunctionType>()->getResultType(); 130 CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), 131 Callee, CallArgs, CopyCtor); 132 // FIXME: region management 133 } else 134 CGF.ErrorUnsupported(E, "uncopyable object"); 135 } 136} 137 138// CopyObject - Utility to copy an object. Calls copy constructor as necessary. 139// N is casted to the right type. 140static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, 141 llvm::Value *E, llvm::Value *N) { 142 // Store the throw exception in the exception object. 143 if (!CGF.hasAggregateLLVMType(ObjectType)) { 144 llvm::Value *Value = E; 145 const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); 146 147 CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); 148 } else { 149 const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); 150 const CXXRecordDecl *RD; 151 RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); 152 llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); 153 if (RD->hasTrivialCopyConstructor()) { 154 CGF.EmitAggregateCopy(This, E, ObjectType); 155 } else if (CXXConstructorDecl *CopyCtor 156 = RD->getCopyConstructor(CGF.getContext(), 0)) { 157 // FIXME: region management 158 llvm::Value *Src = E; 159 160 // Stolen from EmitClassAggrMemberwiseCopy 161 llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, 162 Ctor_Complete); 163 CallArgList CallArgs; 164 CallArgs.push_back(std::make_pair(RValue::get(This), 165 CopyCtor->getThisType(CGF.getContext()))); 166 167 // Push the Src ptr. 168 CallArgs.push_back(std::make_pair(RValue::get(Src), 169 CopyCtor->getParamDecl(0)->getType())); 170 QualType ResultType = 171 CopyCtor->getType()->getAs<FunctionType>()->getResultType(); 172 CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), 173 Callee, CallArgs, CopyCtor); 174 // FIXME: region management 175 } else 176 llvm::llvm_unreachable("uncopyable object"); 177 } 178} 179 180void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { 181 if (!E->getSubExpr()) { 182 Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); 183 Builder.CreateUnreachable(); 184 185 // Clear the insertion point to indicate we are in unreachable code. 186 Builder.ClearInsertionPoint(); 187 return; 188 } 189 190 QualType ThrowType = E->getSubExpr()->getType(); 191 // FIXME: Handle cleanup. 192 if (!CleanupEntries.empty()){ 193 ErrorUnsupported(E, "throw expression with cleanup entries"); 194 return; 195 } 196 197 // Now allocate the exception object. 198 const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); 199 uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; 200 201 llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); 202 llvm::Value *ExceptionPtr = 203 Builder.CreateCall(AllocExceptionFn, 204 llvm::ConstantInt::get(SizeTy, TypeSize), 205 "exception"); 206 207 CopyObject(*this, E->getSubExpr(), ExceptionPtr); 208 209 // Now throw the exception. 210 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 211 llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType); 212 llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); 213 214 llvm::CallInst *ThrowCall = 215 Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); 216 ThrowCall->setDoesNotReturn(); 217 Builder.CreateUnreachable(); 218 219 // Clear the insertion point to indicate we are in unreachable code. 220 Builder.ClearInsertionPoint(); 221} 222 223void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { 224#if 1 225 EmitStmt(S.getTryBlock()); 226 if (0) { 227 getBeginCatchFn(*this); 228 getEndCatchFn(*this); 229 getUnwindResumeOrRethrowFn(*this); 230 CopyObject(*this, QualType(), 0, 0); 231 } 232#else 233 // FIXME: The below is still just a sketch of the code we need. 234 // Pointer to the personality function 235 llvm::Constant *Personality = 236 CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 237 (VMContext), 238 true), 239 "__gxx_personality_v0"); 240 Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); 241 242 llvm::BasicBlock *PrevLandingPad = getInvokeDest(); 243 llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); 244#if 0 245 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); 246#endif 247 llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); 248 llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); 249 250#if 0 251 // Push an EH context entry, used for handling rethrows. 252 PushCleanupBlock(FinallyBlock); 253#endif 254 255 // Emit the statements in the try {} block 256 setInvokeDest(TryHandler); 257 258 EmitStmt(S.getTryBlock()); 259 260 // Jump to end if there is no exception 261 EmitBranchThroughCleanup(FinallyEnd); 262 263 // Emit the handlers 264 EmitBlock(TryHandler); 265 266 const llvm::IntegerType *Int8Ty; 267 const llvm::PointerType *PtrToInt8Ty; 268 Int8Ty = llvm::Type::getInt8Ty(VMContext); 269 // C string type. Used in lots of places. 270 PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); 271 llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); 272 llvm::SmallVector<llvm::Value*, 8> SelectorArgs; 273 llvm::Value *llvm_eh_exception = 274 CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 275 llvm::Value *llvm_eh_selector = 276 CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 277 llvm::Value *llvm_eh_typeid_for = 278 CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); 279 // Exception object 280 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 281 llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); 282 283 SelectorArgs.push_back(Exc); 284 SelectorArgs.push_back(Personality); 285 286 bool HasCatchAll = false; 287 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 288 const CXXCatchStmt *C = S.getHandler(i); 289 VarDecl *CatchParam = C->getExceptionDecl(); 290 if (CatchParam) { 291 llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType()); 292 SelectorArgs.push_back(EHType); 293 } else { 294 // null indicates catch all 295 SelectorArgs.push_back(Null); 296 HasCatchAll = true; 297 } 298 } 299 300 // We use a cleanup unless there was already a catch all. 301 if (!HasCatchAll) { 302 SelectorArgs.push_back(Null); 303 } 304 305 // Find which handler was matched. 306 llvm::Value *Selector 307 = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), 308 SelectorArgs.end(), "selector"); 309 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 310 const CXXCatchStmt *C = S.getHandler(i); 311 VarDecl *CatchParam = C->getExceptionDecl(); 312 Stmt *CatchBody = C->getHandlerBlock(); 313 314 llvm::BasicBlock *Next = 0; 315 316 if (SelectorArgs[i+2] != Null) { 317 llvm::BasicBlock *Match = createBasicBlock("match"); 318 Next = createBasicBlock("catch.next"); 319 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 320 llvm::Value *Id 321 = Builder.CreateCall(llvm_eh_typeid_for, 322 Builder.CreateBitCast(SelectorArgs[i+2], 323 Int8PtrTy)); 324 Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), 325 Match, Next); 326 EmitBlock(Match); 327 } 328 329 llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); 330 llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); 331 332 PushCleanupBlock(MatchEnd); 333 setInvokeDest(MatchHandler); 334 335 llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); 336 337 // Bind the catch parameter if it exists. 338 if (CatchParam) { 339 QualType CatchType = CatchParam->getType().getNonReferenceType(); 340 if (!CatchType.getTypePtr()->isPointerType()) 341 CatchType = getContext().getPointerType(CatchType); 342 ExcObject = 343 Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); 344 // CatchParam is a ParmVarDecl because of the grammar 345 // construction used to handle this, but for codegen purposes 346 // we treat this as a local decl. 347 EmitLocalBlockVarDecl(*CatchParam); 348#if 0 349 // FIXME: objects with ctors, references 350 Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); 351#else 352 CopyObject(*this, CatchParam->getType().getNonReferenceType(), 353 ExcObject, GetAddrOfLocalVar(CatchParam)); 354#endif 355 } 356 357 EmitStmt(CatchBody); 358 EmitBranchThroughCleanup(FinallyEnd); 359 360 EmitBlock(MatchHandler); 361 362 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 363 // We are required to emit this call to satisfy LLVM, even 364 // though we don't use the result. 365 llvm::SmallVector<llvm::Value*, 8> Args; 366 Args.push_back(Exc); 367 Args.push_back(Personality); 368 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 369 0)); 370 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 371 Builder.CreateStore(Exc, RethrowPtr); 372 EmitBranchThroughCleanup(FinallyRethrow); 373 374 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 375 376 EmitBlock(MatchEnd); 377 378 // Unfortunately, we also have to generate another EH frame here 379 // in case this throws. 380 llvm::BasicBlock *MatchEndHandler = 381 createBasicBlock("match.end.handler"); 382 llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont"); 383 Builder.CreateInvoke(getEndCatchFn(*this), 384 Cont, MatchEndHandler, 385 Args.begin(), Args.begin()); 386 387 EmitBlock(Cont); 388 if (Info.SwitchBlock) 389 EmitBlock(Info.SwitchBlock); 390 if (Info.EndBlock) 391 EmitBlock(Info.EndBlock); 392 393 EmitBlock(MatchEndHandler); 394 Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 395 // We are required to emit this call to satisfy LLVM, even 396 // though we don't use the result. 397 Args.clear(); 398 Args.push_back(Exc); 399 Args.push_back(Personality); 400 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 401 0)); 402 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 403 Builder.CreateStore(Exc, RethrowPtr); 404 EmitBranchThroughCleanup(FinallyRethrow); 405 406 if (Next) 407 EmitBlock(Next); 408 } 409 if (!HasCatchAll) 410 EmitBranchThroughCleanup(FinallyRethrow); 411 412 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 413 414 setInvokeDest(PrevLandingPad); 415 416#if 0 417 EmitBlock(FinallyBlock); 418 419 if (Info.SwitchBlock) 420 EmitBlock(Info.SwitchBlock); 421 if (Info.EndBlock) 422 EmitBlock(Info.EndBlock); 423 424 // Branch around the rethrow code. 425 EmitBranch(FinallyEnd); 426#endif 427 428 EmitBlock(FinallyRethrow); 429 Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), 430 Builder.CreateLoad(RethrowPtr)); 431 Builder.CreateUnreachable(); 432 433 EmitBlock(FinallyEnd); 434#endif 435} 436