zcov: / lib/CodeGen/CGException.cpp


Files: 1 Branches Taken: 55.0% 66 / 120
Generated: 2010-02-10 01:31 Branches Executed: 81.7% 98 / 120
Line Coverage: 82.8% 338 / 408


Programs: 1 Runs 2897


       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"
      19                 : using namespace clang;
      20                 : using namespace CodeGen;
      21                 : 
      22                7: static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
      23                 :   // void *__cxa_allocate_exception(size_t thrown_size);
      24                7:   const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
      25                7:   std::vector<const llvm::Type*> Args(1, SizeTy);
      26                 : 
      27                 :   const llvm::FunctionType *FTy =
      28                 :   llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()),
      29                7:                           Args, false);
      30                 : 
      31                7:   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
      32                 : }
      33                 : 
      34                1: static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
      35                 :   // void __cxa_free_exception(void *thrown_exception);
      36                1:   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
      37                1:   std::vector<const llvm::Type*> Args(1, Int8PtrTy);
      38                 : 
      39                 :   const llvm::FunctionType *FTy =
      40                 :   llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
      41                1:                           Args, false);
      42                 : 
      43                1:   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
      44                 : }
      45                 : 
      46                7: static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
      47                 :   // void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
      48                 :   //                  void (*dest) (void *));
      49                 : 
      50                7:   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
      51                7:   std::vector<const llvm::Type*> Args(3, Int8PtrTy);
      52                 : 
      53                 :   const llvm::FunctionType *FTy =
      54                 :     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
      55                7:                             Args, false);
      56                 : 
      57                7:   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
      58                 : }
      59                 : 
      60                1: static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
      61                 :   // void __cxa_rethrow();
      62                 : 
      63                 :   const llvm::FunctionType *FTy =
      64                1:     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
      65                 : 
      66                1:   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
      67                 : }
      68                 : 
      69                1: static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
      70                 :   // void* __cxa_begin_catch();
      71                 : 
      72                1:   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
      73                1:   std::vector<const llvm::Type*> Args(1, Int8PtrTy);
      74                 : 
      75                 :   const llvm::FunctionType *FTy =
      76                1:     llvm::FunctionType::get(Int8PtrTy, Args, false);
      77                 : 
      78                1:   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
      79                 : }
      80                 : 
      81                1: static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
      82                 :   // void __cxa_end_catch();
      83                 : 
      84                 :   const llvm::FunctionType *FTy =
      85                1:     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
      86                 : 
      87                1:   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
      88                 : }
      89                 : 
      90                2: static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
      91                 :   // void __cxa_call_unexepcted(void *thrown_exception);
      92                 : 
      93                2:   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
      94                2:   std::vector<const llvm::Type*> Args(1, Int8PtrTy);
      95                 : 
      96                 :   const llvm::FunctionType *FTy =
      97                 :     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
      98                2:                             Args, false);
      99                 : 
     100                2:   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
     101                 : }
     102                 : 
     103                 : // FIXME: Eventually this will all go into the backend.  Set from the target for
     104                 : // now.
     105                 : static int using_sjlj_exceptions = 0;
     106                 : 
     107                8: static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
     108                8:   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
     109                8:   std::vector<const llvm::Type*> Args(1, Int8PtrTy);
     110                 : 
     111                 :   const llvm::FunctionType *FTy =
     112                 :     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
     113                8:                             false);
     114                 : 
                        0: branch 0 not taken
                        8: branch 1 taken
     115                8:   if (using_sjlj_exceptions)
     116                0:     return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
     117                8:   return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
     118                 : }
     119                 : 
     120                4: static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
     121                 :   // void __terminate();
     122                 : 
     123                 :   const llvm::FunctionType *FTy =
     124                4:     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
     125                 : 
     126                4:   return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
     127                 : }
     128                 : 
     129                 : // CopyObject - Utility to copy an object.  Calls copy constructor as necessary.
     130                 : // DestPtr is casted to the right type.
     131                 : static void CopyObject(CodeGenFunction &CGF, const Expr *E, 
     132                7:                        llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) {
     133                7:   QualType ObjectType = E->getType();
     134                 : 
     135                 :   // Store the throw exception in the exception object.
                        3: branch 1 taken
                        4: branch 2 taken
     136                7:   if (!CGF.hasAggregateLLVMType(ObjectType)) {
     137                3:     llvm::Value *Value = CGF.EmitScalarExpr(E);
     138                3:     const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo();
     139                 : 
     140                 :     CGF.Builder.CreateStore(Value, 
     141                3:                             CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy));
     142                 :   } else {
     143                4:     const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo();
     144                 :     const CXXRecordDecl *RD =
     145                4:       cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
     146                 :     
     147                4:     llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty);
                        2: branch 1 taken
                        2: branch 2 taken
     148                4:     if (RD->hasTrivialCopyConstructor()) {
     149                2:       CGF.EmitAggExpr(E, This, false);
                        2: branch 0 taken
                        0: branch 1 not taken
     150                2:     } else if (CXXConstructorDecl *CopyCtor
     151                2:                = RD->getCopyConstructor(CGF.getContext(), 0)) {
     152                2:       llvm::Value *CondPtr = 0;
                        1: branch 0 taken
                        1: branch 1 taken
     153                2:       if (CGF.Exceptions) {
     154                1:         CodeGenFunction::EHCleanupBlock Cleanup(CGF);
     155                1:         llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
     156                 :         
     157                1:         llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free");
     158                1:         llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
     159                 :         CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
     160                1:                                        "doEHfree");
     161                 : 
     162                 :         CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr),
     163                1:                                  CondBlock, Cont);
     164                1:         CGF.EmitBlock(CondBlock);
     165                 : 
     166                 :         // Load the exception pointer.
     167                1:         llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr);
     168                1:         CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
     169                 : 
     170                1:         CGF.EmitBlock(Cont);
     171                 :       }
     172                 : 
                        1: branch 0 taken
                        1: branch 1 taken
     173                2:       if (CondPtr)
     174                 :         CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
     175                1:                                 CondPtr);
     176                 : 
     177                2:       llvm::Value *Src = CGF.EmitLValue(E).getAddress();
     178                 :         
                        1: branch 0 taken
                        1: branch 1 taken
     179                2:       if (CondPtr)
     180                 :         CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
     181                1:                                 CondPtr);
     182                 : 
     183                2:       llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
     184                2:       llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
     185                2:       CGF.setInvokeDest(TerminateHandler);
     186                 : 
     187                 :       // Stolen from EmitClassAggrMemberwiseCopy
     188                 :       llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
     189                2:                                                             Ctor_Complete);
     190                2:       CallArgList CallArgs;
     191                 :       CallArgs.push_back(std::make_pair(RValue::get(This),
     192                2:                                       CopyCtor->getThisType(CGF.getContext())));
     193                 : 
     194                 :       // Push the Src ptr.
     195                 :       CallArgs.push_back(std::make_pair(RValue::get(Src),
     196                2:                                         CopyCtor->getParamDecl(0)->getType()));
     197                 :       const FunctionProtoType *FPT
     198                2:         = CopyCtor->getType()->getAs<FunctionProtoType>();
     199                 :       CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
     200                2:                    Callee, ReturnValueSlot(), CallArgs, CopyCtor);
     201                2:       CGF.setInvokeDest(PrevLandingPad);
     202                 :     } else
     203                0:       llvm_unreachable("uncopyable object");
     204                 :   }
     205                7: }
     206                 : 
     207                 : // CopyObject - Utility to copy an object.  Calls copy constructor as necessary.
     208                 : // N is casted to the right type.
     209                 : static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
     210                 :                        bool WasPointer, bool WasPointerReference,
     211                1:                        llvm::Value *E, llvm::Value *N) {
     212                 :   // Store the throw exception in the exception object.
                        1: branch 0 taken
                        0: branch 1 not taken
                        0: branch 3 not taken
                        1: branch 4 taken
                        0: branch 5 not taken
                        1: branch 6 taken
     213                1:   if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) {
     214                0:     llvm::Value *Value = E;
                        0: branch 0 not taken
                        0: branch 1 not taken
     215                0:     if (!WasPointer)
     216                0:       Value = CGF.Builder.CreateLoad(Value);
     217                0:     const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
                        0: branch 0 not taken
                        0: branch 1 not taken
     218                0:     if (WasPointerReference) {
     219                0:       llvm::Value *Tmp = CGF.CreateTempAlloca(Value->getType(), "catch.param");
     220                0:       CGF.Builder.CreateStore(Value, Tmp);
     221                0:       Value = Tmp;
     222                0:       ValuePtrTy = Value->getType()->getPointerTo(0);
     223                 :     }
     224                0:     N = CGF.Builder.CreateBitCast(N, ValuePtrTy);
     225                0:     CGF.Builder.CreateStore(Value, N);
     226                 :   } else {
     227                1:     const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0);
     228                 :     const CXXRecordDecl *RD;
     229                1:     RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
     230                1:     llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty);
                        1: branch 1 taken
                        0: branch 2 not taken
     231                1:     if (RD->hasTrivialCopyConstructor()) {
     232                1:       CGF.EmitAggregateCopy(This, E, ObjectType);
                        0: branch 0 not taken
                        0: branch 1 not taken
     233                0:     } else if (CXXConstructorDecl *CopyCtor
     234                0:                = RD->getCopyConstructor(CGF.getContext(), 0)) {
     235                0:       llvm::Value *Src = E;
     236                 : 
     237                 :       // Stolen from EmitClassAggrMemberwiseCopy
     238                 :       llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
     239                0:                                                             Ctor_Complete);
     240                0:       CallArgList CallArgs;
     241                 :       CallArgs.push_back(std::make_pair(RValue::get(This),
     242                0:                                       CopyCtor->getThisType(CGF.getContext())));
     243                 : 
     244                 :       // Push the Src ptr.
     245                 :       CallArgs.push_back(std::make_pair(RValue::get(Src),
     246                0:                                         CopyCtor->getParamDecl(0)->getType()));
     247                 : 
     248                 :       const FunctionProtoType *FPT
     249                0:         = CopyCtor->getType()->getAs<FunctionProtoType>();
     250                 :       CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
     251                0:                    Callee, ReturnValueSlot(), CallArgs, CopyCtor);
     252                 :     } else
     253                0:       llvm_unreachable("uncopyable object");
     254                 :   }
     255                1: }
     256                 : 
     257                8: void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
                        1: branch 1 taken
                        7: branch 2 taken
     258                8:   if (!E->getSubExpr()) {
                        0: branch 1 not taken
                        1: branch 2 taken
     259                1:     if (getInvokeDest()) {
     260                0:       llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
     261                 :       Builder.CreateInvoke(getReThrowFn(*this), Cont, getInvokeDest())
     262                0:         ->setDoesNotReturn();
     263                0:       EmitBlock(Cont);
     264                 :     } else
     265                1:       Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
     266                1:     Builder.CreateUnreachable();
     267                 : 
     268                 :     // Clear the insertion point to indicate we are in unreachable code.
     269                1:     Builder.ClearInsertionPoint();
     270                1:     return;
     271                 :   }
     272                 : 
     273                7:   QualType ThrowType = E->getSubExpr()->getType();
     274                 : 
     275                 :   // Now allocate the exception object.
     276                7:   const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
     277                7:   uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8;
     278                 : 
     279                7:   llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
     280                 :   llvm::Value *ExceptionPtr =
     281                 :     Builder.CreateCall(AllocExceptionFn,
     282                 :                        llvm::ConstantInt::get(SizeTy, TypeSize),
     283                7:                        "exception");
     284                 :   
     285                 :   llvm::Value *ExceptionPtrPtr = 
     286                7:     CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr");
     287                7:   Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr);
     288                 : 
     289                 : 
     290                7:   CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr);
     291                 : 
     292                 :   // Now throw the exception.
     293                7:   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
     294                7:   llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType);
     295                7:   llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
     296                 : 
                        2: branch 1 taken
                        5: branch 2 taken
     297                7:   if (getInvokeDest()) {
     298                2:     llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
     299                 :     llvm::InvokeInst *ThrowCall =
     300                 :       Builder.CreateInvoke3(getThrowFn(*this), Cont, getInvokeDest(),
     301                2:                             ExceptionPtr, TypeInfo, Dtor);
     302                2:     ThrowCall->setDoesNotReturn();
     303                2:     EmitBlock(Cont);
     304                 :   } else {
     305                 :     llvm::CallInst *ThrowCall =
     306                5:       Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor);
     307                5:     ThrowCall->setDoesNotReturn();
     308                 :   }
     309                7:   Builder.CreateUnreachable();
     310                 : 
     311                 :   // Clear the insertion point to indicate we are in unreachable code.
     312                7:   Builder.ClearInsertionPoint();
     313                 : 
     314                 :   // FIXME: For now, emit a dummy basic block because expr emitters in generally
     315                 :   // are not ready to handle emitting expressions at unreachable points.
     316                7:   EnsureInsertPoint();
     317                 : }
     318                 : 
     319             3076: void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
                     3046: branch 0 taken
                       30: branch 1 taken
     320             3076:   if (!Exceptions)
     321             3046:     return;
     322                 :   
     323               30:   const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
                        0: branch 0 not taken
                       30: branch 1 taken
     324               30:   if (FD == 0)
     325                0:     return;
     326               30:   const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
                        0: branch 0 not taken
                       30: branch 1 taken
     327               30:   if (Proto == 0)
     328                0:     return;
     329                 : 
                       30: branch 1 taken
                        0: branch 2 not taken
     330               30:   assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack");
     331                 : 
                       28: branch 1 taken
                        2: branch 2 taken
     332               30:   if (!Proto->hasExceptionSpec())
     333               28:     return;
     334                 : 
     335                 :   llvm::Constant *Personality =
     336                 :     CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
     337                 :                                                       (VMContext),
     338                 :                                                       true),
     339                2:                               "__gxx_personality_v0");
     340                2:   Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
     341                 :   llvm::Value *llvm_eh_exception =
     342                2:     CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
     343                 :   llvm::Value *llvm_eh_selector =
     344                2:     CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
     345                 :   const llvm::IntegerType *Int8Ty;
     346                 :   const llvm::PointerType *PtrToInt8Ty;
     347                2:   Int8Ty = llvm::Type::getInt8Ty(VMContext);
     348                 :   // C string type.  Used in lots of places.
     349                2:   PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
     350                2:   llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
     351                2:   llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
     352                 : 
     353                2:   llvm::BasicBlock *PrevLandingPad = getInvokeDest();
     354                2:   llvm::BasicBlock *EHSpecHandler = createBasicBlock("ehspec.handler");
     355                2:   llvm::BasicBlock *Match = createBasicBlock("match");
     356                2:   llvm::BasicBlock *Unwind = 0;
     357                 : 
                        0: branch 0 not taken
                        2: branch 1 taken
     358                2:   assert(PrevLandingPad == 0 && "EHSpec has invoke context");
     359                 :   (void)PrevLandingPad;
     360                 : 
     361                2:   llvm::BasicBlock *Cont = createBasicBlock("cont");
     362                 : 
     363                2:   EmitBranchThroughCleanup(Cont);
     364                 : 
     365                 :   // Emit the statements in the try {} block
     366                2:   setInvokeDest(EHSpecHandler);
     367                 : 
     368                2:   EmitBlock(EHSpecHandler);
     369                 :   // Exception object
     370                2:   llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
     371                2:   llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
     372                 : 
     373                2:   SelectorArgs.push_back(Exc);
     374                2:   SelectorArgs.push_back(Personality);
     375                 :   SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
     376                2:                                                 Proto->getNumExceptions()+1));
     377                 : 
                        0: branch 1 not taken
                        2: branch 2 taken
     378                2:   for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) {
     379                0:     QualType Ty = Proto->getExceptionType(i);
     380                 :     QualType ExceptType
     381                0:       = Ty.getNonReferenceType().getUnqualifiedType();
     382                0:     llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType);
     383                0:     SelectorArgs.push_back(EHType);
     384                 :   }
                        0: branch 1 not taken
                        2: branch 2 taken
     385                2:   if (Proto->getNumExceptions())
     386                0:     SelectorArgs.push_back(Null);
     387                 : 
     388                 :   // Find which handler was matched.
     389                 :   llvm::Value *Selector
     390                 :     = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
     391                2:                          SelectorArgs.end(), "selector");
                        0: branch 1 not taken
                        2: branch 2 taken
     392                2:   if (Proto->getNumExceptions()) {
     393                0:     Unwind = createBasicBlock("Unwind");
     394                 : 
     395                0:     Builder.CreateStore(Exc, RethrowPtr);
     396                 :     Builder.CreateCondBr(Builder.CreateICmpSLT(Selector,
     397                 :                                                llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
     398                 :                                                                       0)),
     399                0:                          Match, Unwind);
     400                 : 
     401                0:     EmitBlock(Match);
     402                 :   }
     403                2:   Builder.CreateCall(getUnexpectedFn(*this), Exc)->setDoesNotReturn();
     404                2:   Builder.CreateUnreachable();
     405                 : 
                        0: branch 1 not taken
                        2: branch 2 taken
     406                2:   if (Proto->getNumExceptions()) {
     407                0:     EmitBlock(Unwind);
     408                 :     Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
     409                0:                        Builder.CreateLoad(RethrowPtr));
     410                0:     Builder.CreateUnreachable();
     411                 :   }
     412                 : 
     413                2:   EmitBlock(Cont);
     414                 : }
     415                 : 
     416             3076: void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
                     3046: branch 0 taken
                       30: branch 1 taken
     417             3076:   if (!Exceptions)
     418             3046:     return;
     419                 :   
     420               30:   const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
                        0: branch 0 not taken
                       30: branch 1 taken
     421               30:   if (FD == 0)
     422                0:     return;
     423               30:   const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
                        0: branch 0 not taken
                       30: branch 1 taken
     424               30:   if (Proto == 0)
     425                0:     return;
     426                 : 
                       28: branch 1 taken
                        2: branch 2 taken
     427               30:   if (!Proto->hasExceptionSpec())
     428               28:     return;
     429                 : 
     430                2:   setInvokeDest(0);
     431                 : }
     432                 : 
     433                1: void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
     434                 :   // Pointer to the personality function
     435                 :   llvm::Constant *Personality =
     436                 :     CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
     437                 :                                                       (VMContext),
     438                 :                                                       true),
     439                1:                               "__gxx_personality_v0");
     440                1:   Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
     441                 :   llvm::Value *llvm_eh_exception =
     442                1:     CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
     443                 :   llvm::Value *llvm_eh_selector =
     444                1:     CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
     445                 : 
     446                1:   llvm::BasicBlock *PrevLandingPad = getInvokeDest();
     447                1:   llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
     448                1:   llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
     449                1:   llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
     450                1:   llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
     451                 : 
     452                 :   // Push an EH context entry, used for handling rethrows.
     453                1:   PushCleanupBlock(FinallyBlock);
     454                 : 
     455                 :   // Emit the statements in the try {} block
     456                1:   setInvokeDest(TryHandler);
     457                 : 
     458                 :   // FIXME: We should not have to do this here.  The AST should have the member
     459                 :   // initializers under the CXXTryStmt's TryBlock.
                        0: branch 0 not taken
                        1: branch 1 taken
     460                1:   if (OuterTryBlock == &S) {
     461                0:     GlobalDecl GD = CurGD;
     462                0:     const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
     463                 : 
                        0: branch 1 not taken
                        0: branch 2 not taken
     464                0:     if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
     465                0:       size_t OldCleanupStackSize = CleanupEntries.size();
     466                0:       EmitCtorPrologue(CD, CurGD.getCtorType());
     467                0:       EmitStmt(S.getTryBlock());
     468                 : 
     469                 :       // If any of the member initializers are temporaries bound to references
     470                 :       // make sure to emit their destructors.
     471                0:       EmitCleanupBlocks(OldCleanupStackSize);
                        0: branch 1 not taken
                        0: branch 2 not taken
     472                0:     } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
     473                0:       llvm::BasicBlock *DtorEpilogue  = createBasicBlock("dtor.epilogue");
     474                0:       PushCleanupBlock(DtorEpilogue);
     475                 : 
     476                0:       InitializeVtablePtrs(DD->getParent());
     477                0:       EmitStmt(S.getTryBlock());
     478                 : 
     479                0:       CleanupBlockInfo Info = PopCleanupBlock();
     480                 : 
                        0: branch 0 not taken
                        0: branch 1 not taken
     481                0:       assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
     482                0:       EmitBlock(DtorEpilogue);
     483                0:       EmitDtorEpilogue(DD, GD.getDtorType());
     484                 : 
                        0: branch 0 not taken
                        0: branch 1 not taken
     485                0:       if (Info.SwitchBlock)
     486                0:         EmitBlock(Info.SwitchBlock);
                        0: branch 0 not taken
                        0: branch 1 not taken
     487                0:       if (Info.EndBlock)
     488                0:         EmitBlock(Info.EndBlock);
     489                 :     } else
     490                0:       EmitStmt(S.getTryBlock());
     491                 :   } else
     492                1:     EmitStmt(S.getTryBlock());
     493                 : 
     494                 :   // Jump to end if there is no exception
     495                1:   EmitBranchThroughCleanup(FinallyEnd);
     496                 : 
     497                1:   llvm::BasicBlock *TerminateHandler = getTerminateHandler();
     498                 : 
     499                 :   // Emit the handlers
     500                1:   EmitBlock(TryHandler);
     501                 : 
     502                 :   const llvm::IntegerType *Int8Ty;
     503                 :   const llvm::PointerType *PtrToInt8Ty;
     504                1:   Int8Ty = llvm::Type::getInt8Ty(VMContext);
     505                 :   // C string type.  Used in lots of places.
     506                1:   PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
     507                1:   llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
     508                1:   llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
     509                 :   llvm::Value *llvm_eh_typeid_for =
     510                1:     CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
     511                 :   // Exception object
     512                1:   llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
     513                1:   llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
     514                 : 
     515                1:   llvm::SmallVector<llvm::Value*, 8> Args;
     516                1:   Args.clear();
     517                1:   SelectorArgs.push_back(Exc);
     518                1:   SelectorArgs.push_back(Personality);
     519                 : 
     520                1:   bool HasCatchAll = false;
                        1: branch 1 taken
                        1: branch 2 taken
     521                2:   for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
     522                1:     const CXXCatchStmt *C = S.getHandler(i);
     523                1:     VarDecl *CatchParam = C->getExceptionDecl();
                        1: branch 0 taken
                        0: branch 1 not taken
     524                1:     if (CatchParam) {
     525                 :       // C++ [except.handle]p3 indicates that top-level cv-qualifiers
     526                 :       // are ignored.
     527                1:       QualType CaughtType = C->getCaughtType().getNonReferenceType();
     528                 :       llvm::Value *EHTypeInfo
     529                1:         = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType());
     530                1:       SelectorArgs.push_back(EHTypeInfo);
     531                 :     } else {
     532                 :       // null indicates catch all
     533                0:       SelectorArgs.push_back(Null);
     534                0:       HasCatchAll = true;
     535                 :     }
     536                 :   }
     537                 : 
     538                 :   // We use a cleanup unless there was already a catch all.
                        1: branch 0 taken
                        0: branch 1 not taken
     539                1:   if (!HasCatchAll) {
     540                1:     SelectorArgs.push_back(Null);
     541                 :   }
     542                 : 
     543                 :   // Find which handler was matched.
     544                 :   llvm::Value *Selector
     545                 :     = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
     546                1:                          SelectorArgs.end(), "selector");
                        1: branch 1 taken
                        1: branch 2 taken
     547                2:   for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
     548                1:     const CXXCatchStmt *C = S.getHandler(i);
     549                1:     VarDecl *CatchParam = C->getExceptionDecl();
     550                1:     Stmt *CatchBody = C->getHandlerBlock();
     551                 : 
     552                1:     llvm::BasicBlock *Next = 0;
     553                 : 
                        1: branch 1 taken
                        0: branch 2 not taken
     554                1:     if (SelectorArgs[i+2] != Null) {
     555                1:       llvm::BasicBlock *Match = createBasicBlock("match");
     556                1:       Next = createBasicBlock("catch.next");
     557                1:       const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
     558                 :       llvm::Value *Id
     559                 :         = Builder.CreateCall(llvm_eh_typeid_for,
     560                 :                              Builder.CreateBitCast(SelectorArgs[i+2],
     561                1:                                                    Int8PtrTy));
     562                 :       Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id),
     563                1:                            Match, Next);
     564                1:       EmitBlock(Match);
     565                 :     }
     566                 : 
     567                1:     llvm::BasicBlock *MatchEnd = createBasicBlock("match.end");
     568                1:     llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler");
     569                 : 
     570                1:     PushCleanupBlock(MatchEnd);
     571                1:     setInvokeDest(MatchHandler);
     572                 : 
     573                1:     llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc);
     574                 : 
     575                 :     {
     576                1:       CleanupScope CatchScope(*this);
     577                 :       // Bind the catch parameter if it exists.
                        1: branch 0 taken
                        0: branch 1 not taken
     578                1:       if (CatchParam) {
     579                1:         QualType CatchType = CatchParam->getType().getNonReferenceType();
     580                1:         setInvokeDest(TerminateHandler);
     581                1:         bool WasPointer = true;
     582                1:         bool WasPointerReference = false;
     583                1:         CatchType = CGM.getContext().getCanonicalType(CatchType);
                        0: branch 2 not taken
                        1: branch 3 taken
     584                1:         if (CatchType.getTypePtr()->isPointerType()) {
                        0: branch 2 not taken
                        0: branch 3 not taken
     585                0:           if (isa<ReferenceType>(CatchParam->getType()))
     586                0:             WasPointerReference = true;
     587                 :         } else {
                        1: branch 2 taken
                        0: branch 3 not taken
     588                1:           if (!isa<ReferenceType>(CatchParam->getType()))
     589                1:             WasPointer = false;
     590                1:           CatchType = getContext().getPointerType(CatchType);
     591                 :         }
     592                1:         ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType));
     593                1:         EmitLocalBlockVarDecl(*CatchParam);
     594                 :         // FIXME: we need to do this sooner so that the EH region for the
     595                 :         // cleanup doesn't start until after the ctor completes, use a decl
     596                 :         // init?
     597                 :         CopyObject(*this, CatchParam->getType().getNonReferenceType(),
     598                 :                    WasPointer, WasPointerReference, ExcObject,
     599                1:                    GetAddrOfLocalVar(CatchParam));
     600                1:         setInvokeDest(MatchHandler);
     601                 :       }
     602                 : 
     603                1:       EmitStmt(CatchBody);
     604                 :     }
     605                 : 
     606                1:     EmitBranchThroughCleanup(FinallyEnd);
     607                 : 
     608                1:     EmitBlock(MatchHandler);
     609                 : 
     610                1:     llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
     611                 :     // We are required to emit this call to satisfy LLVM, even
     612                 :     // though we don't use the result.
     613                1:     Args.clear();
     614                1:     Args.push_back(Exc);
     615                1:     Args.push_back(Personality);
     616                 :     Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
     617                1:                                           0));
     618                1:     Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
     619                1:     Builder.CreateStore(Exc, RethrowPtr);
     620                1:     EmitBranchThroughCleanup(FinallyRethrow);
     621                 : 
     622                1:     CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
     623                 : 
     624                1:     EmitBlock(MatchEnd);
     625                 : 
     626                1:     llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
     627                 :     Builder.CreateInvoke(getEndCatchFn(*this),
     628                 :                          Cont, TerminateHandler,
     629                1:                          Args.begin(), Args.begin());
     630                1:     EmitBlock(Cont);
                        1: branch 0 taken
                        0: branch 1 not taken
     631                1:     if (Info.SwitchBlock)
     632                1:       EmitBlock(Info.SwitchBlock);
                        1: branch 0 taken
                        0: branch 1 not taken
     633                1:     if (Info.EndBlock)
     634                1:       EmitBlock(Info.EndBlock);
     635                 : 
     636                1:     Exc = Builder.CreateCall(llvm_eh_exception, "exc");
     637                1:     Builder.CreateStore(Exc, RethrowPtr);
     638                1:     EmitBranchThroughCleanup(FinallyRethrow);
     639                 : 
                        1: branch 0 taken
                        0: branch 1 not taken
     640                1:     if (Next)
     641                1:       EmitBlock(Next);
     642                 :   }
                        1: branch 0 taken
                        0: branch 1 not taken
     643                1:   if (!HasCatchAll) {
     644                1:     Builder.CreateStore(Exc, RethrowPtr);
     645                1:     EmitBranchThroughCleanup(FinallyRethrow);
     646                 :   }
     647                 : 
     648                1:   CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
     649                 : 
     650                1:   setInvokeDest(PrevLandingPad);
     651                 : 
     652                1:   EmitBlock(FinallyBlock);
     653                 : 
                        1: branch 0 taken
                        0: branch 1 not taken
     654                1:   if (Info.SwitchBlock)
     655                1:     EmitBlock(Info.SwitchBlock);
                        1: branch 0 taken
                        0: branch 1 not taken
     656                1:   if (Info.EndBlock)
     657                1:     EmitBlock(Info.EndBlock);
     658                 : 
     659                 :   // Branch around the rethrow code.
     660                1:   EmitBranch(FinallyEnd);
     661                 : 
     662                1:   EmitBlock(FinallyRethrow);
     663                 :   // FIXME: Eventually we can chain the handlers together and just do a call
     664                 :   // here.
                        0: branch 1 not taken
                        1: branch 2 taken
     665                1:   if (getInvokeDest()) {
     666                0:     llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
     667                 :     Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont,
     668                 :                          getInvokeDest(),
     669                0:                          Builder.CreateLoad(RethrowPtr));
     670                0:     EmitBlock(Cont);
     671                 :   } else
     672                 :     Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
     673                1:                        Builder.CreateLoad(RethrowPtr));
     674                 : 
     675                1:   Builder.CreateUnreachable();
     676                 : 
     677                1:   EmitBlock(FinallyEnd);
     678                1: }
     679                 : 
     680                7: CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
     681                7:   llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont");
     682                7:   CGF.EmitBranch(Cont1);
     683                7:   CGF.setInvokeDest(PreviousInvokeDest);
     684                 : 
     685                 : 
     686                7:   CGF.EmitBlock(CleanupHandler);
     687                 : 
     688                 :   llvm::Constant *Personality =
     689                 :     CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
     690                 :                                                           (CGF.VMContext),
     691                 :                                                           true),
     692                7:                                   "__gxx_personality_v0");
     693                7:   Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty);
     694                 :   llvm::Value *llvm_eh_exception =
     695                7:     CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
     696                 :   llvm::Value *llvm_eh_selector =
     697                7:     CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
     698                 : 
     699                7:   llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
     700                 :   const llvm::IntegerType *Int8Ty;
     701                 :   const llvm::PointerType *PtrToInt8Ty;
     702                7:   Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext);
     703                 :   // C string type.  Used in lots of places.
     704                7:   PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
     705                7:   llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
     706                7:   llvm::SmallVector<llvm::Value*, 8> Args;
     707                7:   Args.clear();
     708                7:   Args.push_back(Exc);
     709                7:   Args.push_back(Personality);
     710                7:   Args.push_back(Null);
     711                7:   CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
     712                 : 
     713                7:   CGF.EmitBlock(CleanupEntryBB);
     714                 : 
     715                7:   CGF.EmitBlock(Cont1);
     716                 : 
                        5: branch 1 taken
                        2: branch 2 taken
                        0: branch 4 not taken
                        0: branch 5 not taken
     717                7:   if (CGF.getInvokeDest()) {
     718                5:     llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
     719                 :     CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
     720                5:                              CGF.getInvokeDest(), Exc);
     721                5:     CGF.EmitBlock(Cont);
     722                 :   } else
     723                2:     CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
     724                 : 
     725                7:   CGF.Builder.CreateUnreachable();
     726                 : 
     727                7:   CGF.EmitBlock(Cont);
                        7: branch 0 taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                        0: branch 3 not taken
     728                7:   if (CGF.Exceptions)
     729                7:     CGF.setInvokeDest(CleanupHandler);
     730                7: }
     731                 : 
     732               10: llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
                        6: branch 0 taken
                        4: branch 1 taken
     733               10:   if (TerminateHandler)
     734                6:     return TerminateHandler;
     735                 : 
     736                4:   llvm::BasicBlock *Cont = 0;
     737                 : 
                        1: branch 1 taken
                        3: branch 2 taken
     738                4:   if (HaveInsertPoint()) {
     739                1:     Cont = createBasicBlock("cont");
     740                1:     EmitBranch(Cont);
     741                 :   }
     742                 : 
     743                 :   llvm::Constant *Personality =
     744                 :     CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
     745                 :                                                       (VMContext),
     746                 :                                                       true),
     747                4:                               "__gxx_personality_v0");
     748                4:   Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
     749                 :   llvm::Value *llvm_eh_exception =
     750                4:     CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
     751                 :   llvm::Value *llvm_eh_selector =
     752                4:     CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
     753                 : 
     754                 :   // Set up terminate handler
     755                4:   TerminateHandler = createBasicBlock("terminate.handler");
     756                4:   EmitBlock(TerminateHandler);
     757                4:   llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
     758                 :   // We are required to emit this call to satisfy LLVM, even
     759                 :   // though we don't use the result.
     760                4:   llvm::SmallVector<llvm::Value*, 8> Args;
     761                4:   Args.push_back(Exc);
     762                4:   Args.push_back(Personality);
     763                 :   Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
     764                4:                                         1));
     765                4:   Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
     766                 :   llvm::CallInst *TerminateCall =
     767                4:     Builder.CreateCall(getTerminateFn(*this));
     768                4:   TerminateCall->setDoesNotReturn();
     769                4:   TerminateCall->setDoesNotThrow();
     770                4:   Builder.CreateUnreachable();
     771                 : 
     772                 :   // Clear the insertion point to indicate we are in unreachable code.
     773                4:   Builder.ClearInsertionPoint();
     774                 : 
                        1: branch 0 taken
                        3: branch 1 taken
     775                4:   if (Cont)
     776                1:     EmitBlock(Cont);
     777                 : 
     778                4:   return TerminateHandler;
     779                 : }

Generated: 2010-02-10 01:31 by zcov