CGException.cpp revision 204643
1198893Srdivacky//===--- CGException.cpp - Emit LLVM Code for C++ exceptions --------------===// 2198893Srdivacky// 3198893Srdivacky// The LLVM Compiler Infrastructure 4198893Srdivacky// 5198893Srdivacky// This file is distributed under the University of Illinois Open Source 6198893Srdivacky// License. See LICENSE.TXT for details. 7198893Srdivacky// 8198893Srdivacky//===----------------------------------------------------------------------===// 9198893Srdivacky// 10198893Srdivacky// This contains code dealing with C++ exception related code generation. 11198893Srdivacky// 12198893Srdivacky//===----------------------------------------------------------------------===// 13198893Srdivacky 14199990Srdivacky#include "clang/AST/StmtCXX.h" 15199990Srdivacky 16199990Srdivacky#include "llvm/Intrinsics.h" 17199990Srdivacky 18198893Srdivacky#include "CodeGenFunction.h" 19198893Srdivackyusing namespace clang; 20198893Srdivackyusing namespace CodeGen; 21198893Srdivacky 22198893Srdivackystatic llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { 23198893Srdivacky // void *__cxa_allocate_exception(size_t thrown_size); 24198893Srdivacky const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); 25198893Srdivacky std::vector<const llvm::Type*> Args(1, SizeTy); 26200583Srdivacky 27200583Srdivacky const llvm::FunctionType *FTy = 28198893Srdivacky llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), 29198893Srdivacky Args, false); 30200583Srdivacky 31198893Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); 32198893Srdivacky} 33198893Srdivacky 34200583Srdivackystatic llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) { 35200583Srdivacky // void __cxa_free_exception(void *thrown_exception); 36200583Srdivacky const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 37200583Srdivacky std::vector<const llvm::Type*> Args(1, Int8PtrTy); 38200583Srdivacky 39200583Srdivacky const llvm::FunctionType *FTy = 40200583Srdivacky llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 41200583Srdivacky Args, false); 42200583Srdivacky 43200583Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); 44200583Srdivacky} 45200583Srdivacky 46198893Srdivackystatic llvm::Constant *getThrowFn(CodeGenFunction &CGF) { 47200583Srdivacky // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, 48200583Srdivacky // void (*dest) (void *)); 49198893Srdivacky 50198893Srdivacky const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 51198893Srdivacky std::vector<const llvm::Type*> Args(3, Int8PtrTy); 52200583Srdivacky 53200583Srdivacky const llvm::FunctionType *FTy = 54199990Srdivacky llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 55199990Srdivacky Args, false); 56200583Srdivacky 57198893Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); 58198893Srdivacky} 59198893Srdivacky 60199990Srdivackystatic llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { 61200583Srdivacky // void __cxa_rethrow(); 62199990Srdivacky 63200583Srdivacky const llvm::FunctionType *FTy = 64199990Srdivacky llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 65200583Srdivacky 66199990Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); 67199990Srdivacky} 68199990Srdivacky 69199990Srdivackystatic llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { 70200583Srdivacky // void* __cxa_begin_catch(); 71199990Srdivacky 72199990Srdivacky const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 73199990Srdivacky std::vector<const llvm::Type*> Args(1, Int8PtrTy); 74200583Srdivacky 75200583Srdivacky const llvm::FunctionType *FTy = 76199990Srdivacky llvm::FunctionType::get(Int8PtrTy, Args, false); 77200583Srdivacky 78199990Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); 79199990Srdivacky} 80199990Srdivacky 81199990Srdivackystatic llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { 82200583Srdivacky // void __cxa_end_catch(); 83199990Srdivacky 84200583Srdivacky const llvm::FunctionType *FTy = 85199990Srdivacky llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 86200583Srdivacky 87199990Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); 88199990Srdivacky} 89199990Srdivacky 90200583Srdivackystatic llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { 91200583Srdivacky // void __cxa_call_unexepcted(void *thrown_exception); 92200583Srdivacky 93200583Srdivacky const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 94200583Srdivacky std::vector<const llvm::Type*> Args(1, Int8PtrTy); 95200583Srdivacky 96200583Srdivacky const llvm::FunctionType *FTy = 97200583Srdivacky llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 98200583Srdivacky Args, false); 99200583Srdivacky 100200583Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); 101200583Srdivacky} 102200583Srdivacky 103199990Srdivackystatic llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { 104199990Srdivacky const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 105199990Srdivacky std::vector<const llvm::Type*> Args(1, Int8PtrTy); 106200583Srdivacky 107200583Srdivacky const llvm::FunctionType *FTy = 108199990Srdivacky llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, 109199990Srdivacky false); 110200583Srdivacky 111203955Srdivacky if (CGF.CGM.getLangOptions().SjLjExceptions) 112199990Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); 113199990Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); 114199990Srdivacky} 115199990Srdivacky 116200583Srdivackystatic llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { 117200583Srdivacky // void __terminate(); 118200583Srdivacky 119200583Srdivacky const llvm::FunctionType *FTy = 120200583Srdivacky llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 121200583Srdivacky 122200583Srdivacky return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); 123200583Srdivacky} 124200583Srdivacky 125199990Srdivacky// CopyObject - Utility to copy an object. Calls copy constructor as necessary. 126200583Srdivacky// DestPtr is casted to the right type. 127200583Srdivackystatic void CopyObject(CodeGenFunction &CGF, const Expr *E, 128200583Srdivacky llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) { 129199990Srdivacky QualType ObjectType = E->getType(); 130199990Srdivacky 131199990Srdivacky // Store the throw exception in the exception object. 132199990Srdivacky if (!CGF.hasAggregateLLVMType(ObjectType)) { 133199990Srdivacky llvm::Value *Value = CGF.EmitScalarExpr(E); 134200583Srdivacky const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(); 135200583Srdivacky 136200583Srdivacky CGF.Builder.CreateStore(Value, 137200583Srdivacky CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy)); 138200583Srdivacky } else { 139200583Srdivacky const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(); 140200583Srdivacky const CXXRecordDecl *RD = 141200583Srdivacky cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); 142199990Srdivacky 143200583Srdivacky llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty); 144199990Srdivacky if (RD->hasTrivialCopyConstructor()) { 145199990Srdivacky CGF.EmitAggExpr(E, This, false); 146199990Srdivacky } else if (CXXConstructorDecl *CopyCtor 147199990Srdivacky = RD->getCopyConstructor(CGF.getContext(), 0)) { 148201361Srdivacky llvm::Value *CondPtr = 0; 149200583Srdivacky if (CGF.Exceptions) { 150200583Srdivacky CodeGenFunction::EHCleanupBlock Cleanup(CGF); 151200583Srdivacky llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); 152200583Srdivacky 153201361Srdivacky llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free"); 154201361Srdivacky llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); 155201361Srdivacky CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), 156201361Srdivacky "doEHfree"); 157201361Srdivacky 158201361Srdivacky CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr), 159201361Srdivacky CondBlock, Cont); 160201361Srdivacky CGF.EmitBlock(CondBlock); 161201361Srdivacky 162200583Srdivacky // Load the exception pointer. 163200583Srdivacky llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr); 164200583Srdivacky CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); 165201361Srdivacky 166201361Srdivacky CGF.EmitBlock(Cont); 167200583Srdivacky } 168200583Srdivacky 169201361Srdivacky if (CondPtr) 170201361Srdivacky CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), 171201361Srdivacky CondPtr); 172201361Srdivacky 173199990Srdivacky llvm::Value *Src = CGF.EmitLValue(E).getAddress(); 174201361Srdivacky 175201361Srdivacky if (CondPtr) 176201361Srdivacky CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), 177201361Srdivacky CondPtr); 178199990Srdivacky 179200583Srdivacky llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); 180201361Srdivacky llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); 181200583Srdivacky CGF.setInvokeDest(TerminateHandler); 182200583Srdivacky 183199990Srdivacky // Stolen from EmitClassAggrMemberwiseCopy 184199990Srdivacky llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, 185199990Srdivacky Ctor_Complete); 186199990Srdivacky CallArgList CallArgs; 187199990Srdivacky CallArgs.push_back(std::make_pair(RValue::get(This), 188199990Srdivacky CopyCtor->getThisType(CGF.getContext()))); 189199990Srdivacky 190199990Srdivacky // Push the Src ptr. 191199990Srdivacky CallArgs.push_back(std::make_pair(RValue::get(Src), 192199990Srdivacky CopyCtor->getParamDecl(0)->getType())); 193203955Srdivacky const FunctionProtoType *FPT 194203955Srdivacky = CopyCtor->getType()->getAs<FunctionProtoType>(); 195203955Srdivacky CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), 196201361Srdivacky Callee, ReturnValueSlot(), CallArgs, CopyCtor); 197200583Srdivacky CGF.setInvokeDest(PrevLandingPad); 198199990Srdivacky } else 199200583Srdivacky llvm_unreachable("uncopyable object"); 200199990Srdivacky } 201199990Srdivacky} 202199990Srdivacky 203199990Srdivacky// CopyObject - Utility to copy an object. Calls copy constructor as necessary. 204199990Srdivacky// N is casted to the right type. 205199990Srdivackystatic void CopyObject(CodeGenFunction &CGF, QualType ObjectType, 206201361Srdivacky bool WasPointer, bool WasPointerReference, 207201361Srdivacky llvm::Value *E, llvm::Value *N) { 208199990Srdivacky // Store the throw exception in the exception object. 209200583Srdivacky if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) { 210199990Srdivacky llvm::Value *Value = E; 211200583Srdivacky if (!WasPointer) 212200583Srdivacky Value = CGF.Builder.CreateLoad(Value); 213199990Srdivacky const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); 214201361Srdivacky if (WasPointerReference) { 215201361Srdivacky llvm::Value *Tmp = CGF.CreateTempAlloca(Value->getType(), "catch.param"); 216201361Srdivacky CGF.Builder.CreateStore(Value, Tmp); 217201361Srdivacky Value = Tmp; 218201361Srdivacky ValuePtrTy = Value->getType()->getPointerTo(0); 219201361Srdivacky } 220201361Srdivacky N = CGF.Builder.CreateBitCast(N, ValuePtrTy); 221201361Srdivacky CGF.Builder.CreateStore(Value, N); 222199990Srdivacky } else { 223199990Srdivacky const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); 224199990Srdivacky const CXXRecordDecl *RD; 225199990Srdivacky RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); 226199990Srdivacky llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); 227199990Srdivacky if (RD->hasTrivialCopyConstructor()) { 228199990Srdivacky CGF.EmitAggregateCopy(This, E, ObjectType); 229199990Srdivacky } else if (CXXConstructorDecl *CopyCtor 230199990Srdivacky = RD->getCopyConstructor(CGF.getContext(), 0)) { 231199990Srdivacky llvm::Value *Src = E; 232199990Srdivacky 233199990Srdivacky // Stolen from EmitClassAggrMemberwiseCopy 234199990Srdivacky llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, 235199990Srdivacky Ctor_Complete); 236199990Srdivacky CallArgList CallArgs; 237199990Srdivacky CallArgs.push_back(std::make_pair(RValue::get(This), 238199990Srdivacky CopyCtor->getThisType(CGF.getContext()))); 239199990Srdivacky 240199990Srdivacky // Push the Src ptr. 241199990Srdivacky CallArgs.push_back(std::make_pair(RValue::get(Src), 242199990Srdivacky CopyCtor->getParamDecl(0)->getType())); 243203955Srdivacky 244203955Srdivacky const FunctionProtoType *FPT 245203955Srdivacky = CopyCtor->getType()->getAs<FunctionProtoType>(); 246203955Srdivacky CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), 247201361Srdivacky Callee, ReturnValueSlot(), CallArgs, CopyCtor); 248199990Srdivacky } else 249200583Srdivacky llvm_unreachable("uncopyable object"); 250199990Srdivacky } 251199990Srdivacky} 252199990Srdivacky 253198893Srdivackyvoid CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { 254198893Srdivacky if (!E->getSubExpr()) { 255200583Srdivacky if (getInvokeDest()) { 256200583Srdivacky llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 257200583Srdivacky Builder.CreateInvoke(getReThrowFn(*this), Cont, getInvokeDest()) 258200583Srdivacky ->setDoesNotReturn(); 259200583Srdivacky EmitBlock(Cont); 260200583Srdivacky } else 261200583Srdivacky Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); 262199990Srdivacky Builder.CreateUnreachable(); 263199990Srdivacky 264199990Srdivacky // Clear the insertion point to indicate we are in unreachable code. 265199990Srdivacky Builder.ClearInsertionPoint(); 266198893Srdivacky return; 267198893Srdivacky } 268200583Srdivacky 269198893Srdivacky QualType ThrowType = E->getSubExpr()->getType(); 270200583Srdivacky 271198893Srdivacky // Now allocate the exception object. 272198893Srdivacky const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); 273198893Srdivacky uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; 274200583Srdivacky 275198893Srdivacky llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); 276200583Srdivacky llvm::Value *ExceptionPtr = 277200583Srdivacky Builder.CreateCall(AllocExceptionFn, 278198893Srdivacky llvm::ConstantInt::get(SizeTy, TypeSize), 279198893Srdivacky "exception"); 280200583Srdivacky 281200583Srdivacky llvm::Value *ExceptionPtrPtr = 282200583Srdivacky CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr"); 283200583Srdivacky Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr); 284198893Srdivacky 285200583Srdivacky 286200583Srdivacky CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr); 287200583Srdivacky 288198893Srdivacky // Now throw the exception. 289198893Srdivacky const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 290201361Srdivacky llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType); 291198893Srdivacky llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); 292200583Srdivacky 293200583Srdivacky if (getInvokeDest()) { 294200583Srdivacky llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 295200583Srdivacky llvm::InvokeInst *ThrowCall = 296200583Srdivacky Builder.CreateInvoke3(getThrowFn(*this), Cont, getInvokeDest(), 297200583Srdivacky ExceptionPtr, TypeInfo, Dtor); 298200583Srdivacky ThrowCall->setDoesNotReturn(); 299200583Srdivacky EmitBlock(Cont); 300200583Srdivacky } else { 301200583Srdivacky llvm::CallInst *ThrowCall = 302200583Srdivacky Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); 303200583Srdivacky ThrowCall->setDoesNotReturn(); 304200583Srdivacky } 305198893Srdivacky Builder.CreateUnreachable(); 306200583Srdivacky 307198893Srdivacky // Clear the insertion point to indicate we are in unreachable code. 308198893Srdivacky Builder.ClearInsertionPoint(); 309200583Srdivacky 310200583Srdivacky // FIXME: For now, emit a dummy basic block because expr emitters in generally 311200583Srdivacky // are not ready to handle emitting expressions at unreachable points. 312200583Srdivacky EnsureInsertPoint(); 313198893Srdivacky} 314199990Srdivacky 315200583Srdivackyvoid CodeGenFunction::EmitStartEHSpec(const Decl *D) { 316203955Srdivacky if (!Exceptions) 317203955Srdivacky return; 318203955Srdivacky 319200583Srdivacky const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); 320200583Srdivacky if (FD == 0) 321200583Srdivacky return; 322200583Srdivacky const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); 323200583Srdivacky if (Proto == 0) 324200583Srdivacky return; 325200583Srdivacky 326200583Srdivacky assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack"); 327200583Srdivacky 328200583Srdivacky if (!Proto->hasExceptionSpec()) 329200583Srdivacky return; 330200583Srdivacky 331200583Srdivacky llvm::Constant *Personality = 332200583Srdivacky CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 333200583Srdivacky (VMContext), 334200583Srdivacky true), 335200583Srdivacky "__gxx_personality_v0"); 336200583Srdivacky Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); 337200583Srdivacky llvm::Value *llvm_eh_exception = 338200583Srdivacky CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 339200583Srdivacky llvm::Value *llvm_eh_selector = 340200583Srdivacky CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 341200583Srdivacky const llvm::IntegerType *Int8Ty; 342200583Srdivacky const llvm::PointerType *PtrToInt8Ty; 343200583Srdivacky Int8Ty = llvm::Type::getInt8Ty(VMContext); 344200583Srdivacky // C string type. Used in lots of places. 345200583Srdivacky PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); 346200583Srdivacky llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); 347200583Srdivacky llvm::SmallVector<llvm::Value*, 8> SelectorArgs; 348200583Srdivacky 349200583Srdivacky llvm::BasicBlock *PrevLandingPad = getInvokeDest(); 350200583Srdivacky llvm::BasicBlock *EHSpecHandler = createBasicBlock("ehspec.handler"); 351200583Srdivacky llvm::BasicBlock *Match = createBasicBlock("match"); 352200583Srdivacky llvm::BasicBlock *Unwind = 0; 353200583Srdivacky 354200583Srdivacky assert(PrevLandingPad == 0 && "EHSpec has invoke context"); 355200583Srdivacky (void)PrevLandingPad; 356200583Srdivacky 357200583Srdivacky llvm::BasicBlock *Cont = createBasicBlock("cont"); 358200583Srdivacky 359200583Srdivacky EmitBranchThroughCleanup(Cont); 360200583Srdivacky 361200583Srdivacky // Emit the statements in the try {} block 362200583Srdivacky setInvokeDest(EHSpecHandler); 363200583Srdivacky 364200583Srdivacky EmitBlock(EHSpecHandler); 365200583Srdivacky // Exception object 366200583Srdivacky llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 367200583Srdivacky llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); 368200583Srdivacky 369200583Srdivacky SelectorArgs.push_back(Exc); 370200583Srdivacky SelectorArgs.push_back(Personality); 371200583Srdivacky SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 372200583Srdivacky Proto->getNumExceptions()+1)); 373200583Srdivacky 374200583Srdivacky for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) { 375200583Srdivacky QualType Ty = Proto->getExceptionType(i); 376201361Srdivacky QualType ExceptType 377201361Srdivacky = Ty.getNonReferenceType().getUnqualifiedType(); 378201361Srdivacky llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType); 379200583Srdivacky SelectorArgs.push_back(EHType); 380200583Srdivacky } 381200583Srdivacky if (Proto->getNumExceptions()) 382200583Srdivacky SelectorArgs.push_back(Null); 383200583Srdivacky 384200583Srdivacky // Find which handler was matched. 385200583Srdivacky llvm::Value *Selector 386200583Srdivacky = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), 387200583Srdivacky SelectorArgs.end(), "selector"); 388200583Srdivacky if (Proto->getNumExceptions()) { 389200583Srdivacky Unwind = createBasicBlock("Unwind"); 390200583Srdivacky 391200583Srdivacky Builder.CreateStore(Exc, RethrowPtr); 392200583Srdivacky Builder.CreateCondBr(Builder.CreateICmpSLT(Selector, 393200583Srdivacky llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 394200583Srdivacky 0)), 395200583Srdivacky Match, Unwind); 396200583Srdivacky 397200583Srdivacky EmitBlock(Match); 398200583Srdivacky } 399200583Srdivacky Builder.CreateCall(getUnexpectedFn(*this), Exc)->setDoesNotReturn(); 400200583Srdivacky Builder.CreateUnreachable(); 401200583Srdivacky 402200583Srdivacky if (Proto->getNumExceptions()) { 403200583Srdivacky EmitBlock(Unwind); 404200583Srdivacky Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), 405200583Srdivacky Builder.CreateLoad(RethrowPtr)); 406200583Srdivacky Builder.CreateUnreachable(); 407200583Srdivacky } 408200583Srdivacky 409200583Srdivacky EmitBlock(Cont); 410200583Srdivacky} 411200583Srdivacky 412200583Srdivackyvoid CodeGenFunction::EmitEndEHSpec(const Decl *D) { 413203955Srdivacky if (!Exceptions) 414203955Srdivacky return; 415203955Srdivacky 416200583Srdivacky const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); 417200583Srdivacky if (FD == 0) 418200583Srdivacky return; 419200583Srdivacky const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); 420200583Srdivacky if (Proto == 0) 421200583Srdivacky return; 422200583Srdivacky 423200583Srdivacky if (!Proto->hasExceptionSpec()) 424200583Srdivacky return; 425200583Srdivacky 426200583Srdivacky setInvokeDest(0); 427200583Srdivacky} 428200583Srdivacky 429199990Srdivackyvoid CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { 430204643Srdivacky CXXTryStmtInfo Info = EnterCXXTryStmt(S); 431204643Srdivacky EmitStmt(S.getTryBlock()); 432204643Srdivacky ExitCXXTryStmt(S, Info); 433204643Srdivacky} 434204643Srdivacky 435204643SrdivackyCodeGenFunction::CXXTryStmtInfo 436204643SrdivackyCodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S) { 437204643Srdivacky CXXTryStmtInfo Info; 438204643Srdivacky Info.SavedLandingPad = getInvokeDest(); 439204643Srdivacky Info.HandlerBlock = createBasicBlock("try.handler"); 440204643Srdivacky Info.FinallyBlock = createBasicBlock("finally"); 441204643Srdivacky 442204643Srdivacky PushCleanupBlock(Info.FinallyBlock); 443204643Srdivacky setInvokeDest(Info.HandlerBlock); 444204643Srdivacky 445204643Srdivacky return Info; 446204643Srdivacky} 447204643Srdivacky 448204643Srdivackyvoid CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, 449204643Srdivacky CXXTryStmtInfo TryInfo) { 450199990Srdivacky // Pointer to the personality function 451199990Srdivacky llvm::Constant *Personality = 452199990Srdivacky CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 453199990Srdivacky (VMContext), 454199990Srdivacky true), 455199990Srdivacky "__gxx_personality_v0"); 456199990Srdivacky Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); 457200583Srdivacky llvm::Value *llvm_eh_exception = 458200583Srdivacky CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 459200583Srdivacky llvm::Value *llvm_eh_selector = 460200583Srdivacky CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 461199990Srdivacky 462204643Srdivacky llvm::BasicBlock *PrevLandingPad = TryInfo.SavedLandingPad; 463204643Srdivacky llvm::BasicBlock *TryHandler = TryInfo.HandlerBlock; 464204643Srdivacky llvm::BasicBlock *FinallyBlock = TryInfo.FinallyBlock; 465199990Srdivacky llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); 466199990Srdivacky llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); 467199990Srdivacky 468199990Srdivacky // Jump to end if there is no exception 469199990Srdivacky EmitBranchThroughCleanup(FinallyEnd); 470199990Srdivacky 471200583Srdivacky llvm::BasicBlock *TerminateHandler = getTerminateHandler(); 472200583Srdivacky 473199990Srdivacky // Emit the handlers 474199990Srdivacky EmitBlock(TryHandler); 475200583Srdivacky 476199990Srdivacky const llvm::IntegerType *Int8Ty; 477199990Srdivacky const llvm::PointerType *PtrToInt8Ty; 478199990Srdivacky Int8Ty = llvm::Type::getInt8Ty(VMContext); 479199990Srdivacky // C string type. Used in lots of places. 480199990Srdivacky PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); 481199990Srdivacky llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); 482199990Srdivacky llvm::SmallVector<llvm::Value*, 8> SelectorArgs; 483199990Srdivacky llvm::Value *llvm_eh_typeid_for = 484199990Srdivacky CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); 485199990Srdivacky // Exception object 486199990Srdivacky llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 487199990Srdivacky llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); 488199990Srdivacky 489200583Srdivacky llvm::SmallVector<llvm::Value*, 8> Args; 490200583Srdivacky Args.clear(); 491199990Srdivacky SelectorArgs.push_back(Exc); 492199990Srdivacky SelectorArgs.push_back(Personality); 493199990Srdivacky 494199990Srdivacky bool HasCatchAll = false; 495199990Srdivacky for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 496199990Srdivacky const CXXCatchStmt *C = S.getHandler(i); 497199990Srdivacky VarDecl *CatchParam = C->getExceptionDecl(); 498199990Srdivacky if (CatchParam) { 499201361Srdivacky // C++ [except.handle]p3 indicates that top-level cv-qualifiers 500201361Srdivacky // are ignored. 501201361Srdivacky QualType CaughtType = C->getCaughtType().getNonReferenceType(); 502201361Srdivacky llvm::Value *EHTypeInfo 503201361Srdivacky = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType()); 504201361Srdivacky SelectorArgs.push_back(EHTypeInfo); 505199990Srdivacky } else { 506199990Srdivacky // null indicates catch all 507199990Srdivacky SelectorArgs.push_back(Null); 508199990Srdivacky HasCatchAll = true; 509199990Srdivacky } 510199990Srdivacky } 511199990Srdivacky 512199990Srdivacky // We use a cleanup unless there was already a catch all. 513199990Srdivacky if (!HasCatchAll) { 514199990Srdivacky SelectorArgs.push_back(Null); 515199990Srdivacky } 516199990Srdivacky 517199990Srdivacky // Find which handler was matched. 518199990Srdivacky llvm::Value *Selector 519199990Srdivacky = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), 520199990Srdivacky SelectorArgs.end(), "selector"); 521199990Srdivacky for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 522199990Srdivacky const CXXCatchStmt *C = S.getHandler(i); 523199990Srdivacky VarDecl *CatchParam = C->getExceptionDecl(); 524199990Srdivacky Stmt *CatchBody = C->getHandlerBlock(); 525199990Srdivacky 526199990Srdivacky llvm::BasicBlock *Next = 0; 527199990Srdivacky 528199990Srdivacky if (SelectorArgs[i+2] != Null) { 529199990Srdivacky llvm::BasicBlock *Match = createBasicBlock("match"); 530199990Srdivacky Next = createBasicBlock("catch.next"); 531199990Srdivacky const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 532199990Srdivacky llvm::Value *Id 533199990Srdivacky = Builder.CreateCall(llvm_eh_typeid_for, 534199990Srdivacky Builder.CreateBitCast(SelectorArgs[i+2], 535199990Srdivacky Int8PtrTy)); 536199990Srdivacky Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), 537199990Srdivacky Match, Next); 538199990Srdivacky EmitBlock(Match); 539199990Srdivacky } 540199990Srdivacky 541199990Srdivacky llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); 542199990Srdivacky llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); 543199990Srdivacky 544199990Srdivacky PushCleanupBlock(MatchEnd); 545199990Srdivacky setInvokeDest(MatchHandler); 546199990Srdivacky 547199990Srdivacky llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); 548199990Srdivacky 549200583Srdivacky { 550200583Srdivacky CleanupScope CatchScope(*this); 551200583Srdivacky // Bind the catch parameter if it exists. 552200583Srdivacky if (CatchParam) { 553200583Srdivacky QualType CatchType = CatchParam->getType().getNonReferenceType(); 554200583Srdivacky setInvokeDest(TerminateHandler); 555200583Srdivacky bool WasPointer = true; 556201361Srdivacky bool WasPointerReference = false; 557201361Srdivacky CatchType = CGM.getContext().getCanonicalType(CatchType); 558201361Srdivacky if (CatchType.getTypePtr()->isPointerType()) { 559201361Srdivacky if (isa<ReferenceType>(CatchParam->getType())) 560201361Srdivacky WasPointerReference = true; 561201361Srdivacky } else { 562200583Srdivacky if (!isa<ReferenceType>(CatchParam->getType())) 563200583Srdivacky WasPointer = false; 564200583Srdivacky CatchType = getContext().getPointerType(CatchType); 565200583Srdivacky } 566200583Srdivacky ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); 567200583Srdivacky EmitLocalBlockVarDecl(*CatchParam); 568200583Srdivacky // FIXME: we need to do this sooner so that the EH region for the 569200583Srdivacky // cleanup doesn't start until after the ctor completes, use a decl 570200583Srdivacky // init? 571200583Srdivacky CopyObject(*this, CatchParam->getType().getNonReferenceType(), 572201361Srdivacky WasPointer, WasPointerReference, ExcObject, 573201361Srdivacky GetAddrOfLocalVar(CatchParam)); 574200583Srdivacky setInvokeDest(MatchHandler); 575200583Srdivacky } 576200583Srdivacky 577200583Srdivacky EmitStmt(CatchBody); 578199990Srdivacky } 579199990Srdivacky 580199990Srdivacky EmitBranchThroughCleanup(FinallyEnd); 581199990Srdivacky 582199990Srdivacky EmitBlock(MatchHandler); 583199990Srdivacky 584199990Srdivacky llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 585199990Srdivacky // We are required to emit this call to satisfy LLVM, even 586199990Srdivacky // though we don't use the result. 587200583Srdivacky Args.clear(); 588199990Srdivacky Args.push_back(Exc); 589199990Srdivacky Args.push_back(Personality); 590199990Srdivacky Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 591199990Srdivacky 0)); 592199990Srdivacky Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 593199990Srdivacky Builder.CreateStore(Exc, RethrowPtr); 594199990Srdivacky EmitBranchThroughCleanup(FinallyRethrow); 595199990Srdivacky 596199990Srdivacky CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 597199990Srdivacky 598199990Srdivacky EmitBlock(MatchEnd); 599199990Srdivacky 600200583Srdivacky llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 601199990Srdivacky Builder.CreateInvoke(getEndCatchFn(*this), 602200583Srdivacky Cont, TerminateHandler, 603199990Srdivacky Args.begin(), Args.begin()); 604199990Srdivacky EmitBlock(Cont); 605199990Srdivacky if (Info.SwitchBlock) 606199990Srdivacky EmitBlock(Info.SwitchBlock); 607199990Srdivacky if (Info.EndBlock) 608199990Srdivacky EmitBlock(Info.EndBlock); 609199990Srdivacky 610199990Srdivacky Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 611199990Srdivacky Builder.CreateStore(Exc, RethrowPtr); 612199990Srdivacky EmitBranchThroughCleanup(FinallyRethrow); 613199990Srdivacky 614199990Srdivacky if (Next) 615199990Srdivacky EmitBlock(Next); 616199990Srdivacky } 617200583Srdivacky if (!HasCatchAll) { 618200583Srdivacky Builder.CreateStore(Exc, RethrowPtr); 619199990Srdivacky EmitBranchThroughCleanup(FinallyRethrow); 620200583Srdivacky } 621199990Srdivacky 622199990Srdivacky CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 623199990Srdivacky 624199990Srdivacky setInvokeDest(PrevLandingPad); 625199990Srdivacky 626199990Srdivacky EmitBlock(FinallyBlock); 627199990Srdivacky 628199990Srdivacky if (Info.SwitchBlock) 629199990Srdivacky EmitBlock(Info.SwitchBlock); 630199990Srdivacky if (Info.EndBlock) 631199990Srdivacky EmitBlock(Info.EndBlock); 632199990Srdivacky 633199990Srdivacky // Branch around the rethrow code. 634199990Srdivacky EmitBranch(FinallyEnd); 635199990Srdivacky 636199990Srdivacky EmitBlock(FinallyRethrow); 637200583Srdivacky // FIXME: Eventually we can chain the handlers together and just do a call 638200583Srdivacky // here. 639200583Srdivacky if (getInvokeDest()) { 640200583Srdivacky llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); 641200583Srdivacky Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, 642200583Srdivacky getInvokeDest(), 643200583Srdivacky Builder.CreateLoad(RethrowPtr)); 644200583Srdivacky EmitBlock(Cont); 645200583Srdivacky } else 646200583Srdivacky Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), 647200583Srdivacky Builder.CreateLoad(RethrowPtr)); 648200583Srdivacky 649199990Srdivacky Builder.CreateUnreachable(); 650199990Srdivacky 651199990Srdivacky EmitBlock(FinallyEnd); 652199990Srdivacky} 653200583Srdivacky 654200583SrdivackyCodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { 655200583Srdivacky llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont"); 656200583Srdivacky CGF.EmitBranch(Cont1); 657200583Srdivacky CGF.setInvokeDest(PreviousInvokeDest); 658200583Srdivacky 659200583Srdivacky 660200583Srdivacky CGF.EmitBlock(CleanupHandler); 661200583Srdivacky 662200583Srdivacky llvm::Constant *Personality = 663200583Srdivacky CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 664200583Srdivacky (CGF.VMContext), 665200583Srdivacky true), 666200583Srdivacky "__gxx_personality_v0"); 667200583Srdivacky Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty); 668200583Srdivacky llvm::Value *llvm_eh_exception = 669200583Srdivacky CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 670200583Srdivacky llvm::Value *llvm_eh_selector = 671200583Srdivacky CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 672200583Srdivacky 673200583Srdivacky llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); 674200583Srdivacky const llvm::IntegerType *Int8Ty; 675200583Srdivacky const llvm::PointerType *PtrToInt8Ty; 676200583Srdivacky Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext); 677200583Srdivacky // C string type. Used in lots of places. 678200583Srdivacky PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); 679200583Srdivacky llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); 680200583Srdivacky llvm::SmallVector<llvm::Value*, 8> Args; 681200583Srdivacky Args.clear(); 682200583Srdivacky Args.push_back(Exc); 683200583Srdivacky Args.push_back(Personality); 684200583Srdivacky Args.push_back(Null); 685200583Srdivacky CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 686200583Srdivacky 687200583Srdivacky CGF.EmitBlock(CleanupEntryBB); 688200583Srdivacky 689200583Srdivacky CGF.EmitBlock(Cont1); 690200583Srdivacky 691200583Srdivacky if (CGF.getInvokeDest()) { 692200583Srdivacky llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); 693200583Srdivacky CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont, 694200583Srdivacky CGF.getInvokeDest(), Exc); 695200583Srdivacky CGF.EmitBlock(Cont); 696200583Srdivacky } else 697200583Srdivacky CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc); 698200583Srdivacky 699200583Srdivacky CGF.Builder.CreateUnreachable(); 700200583Srdivacky 701200583Srdivacky CGF.EmitBlock(Cont); 702200583Srdivacky if (CGF.Exceptions) 703200583Srdivacky CGF.setInvokeDest(CleanupHandler); 704200583Srdivacky} 705200583Srdivacky 706200583Srdivackyllvm::BasicBlock *CodeGenFunction::getTerminateHandler() { 707200583Srdivacky if (TerminateHandler) 708200583Srdivacky return TerminateHandler; 709200583Srdivacky 710200583Srdivacky llvm::BasicBlock *Cont = 0; 711200583Srdivacky 712200583Srdivacky if (HaveInsertPoint()) { 713200583Srdivacky Cont = createBasicBlock("cont"); 714200583Srdivacky EmitBranch(Cont); 715200583Srdivacky } 716200583Srdivacky 717200583Srdivacky llvm::Constant *Personality = 718200583Srdivacky CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 719200583Srdivacky (VMContext), 720200583Srdivacky true), 721200583Srdivacky "__gxx_personality_v0"); 722200583Srdivacky Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); 723200583Srdivacky llvm::Value *llvm_eh_exception = 724200583Srdivacky CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 725200583Srdivacky llvm::Value *llvm_eh_selector = 726200583Srdivacky CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 727200583Srdivacky 728200583Srdivacky // Set up terminate handler 729200583Srdivacky TerminateHandler = createBasicBlock("terminate.handler"); 730200583Srdivacky EmitBlock(TerminateHandler); 731200583Srdivacky llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 732200583Srdivacky // We are required to emit this call to satisfy LLVM, even 733200583Srdivacky // though we don't use the result. 734200583Srdivacky llvm::SmallVector<llvm::Value*, 8> Args; 735200583Srdivacky Args.push_back(Exc); 736200583Srdivacky Args.push_back(Personality); 737200583Srdivacky Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 738200583Srdivacky 1)); 739200583Srdivacky Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); 740200583Srdivacky llvm::CallInst *TerminateCall = 741200583Srdivacky Builder.CreateCall(getTerminateFn(*this)); 742200583Srdivacky TerminateCall->setDoesNotReturn(); 743200583Srdivacky TerminateCall->setDoesNotThrow(); 744200583Srdivacky Builder.CreateUnreachable(); 745200583Srdivacky 746200583Srdivacky // Clear the insertion point to indicate we are in unreachable code. 747200583Srdivacky Builder.ClearInsertionPoint(); 748200583Srdivacky 749200583Srdivacky if (Cont) 750200583Srdivacky EmitBlock(Cont); 751200583Srdivacky 752200583Srdivacky return TerminateHandler; 753200583Srdivacky} 754