CGException.cpp revision 2bf701ee4babb5c4a9ea99ca4675c5ef040bd402
1//===--- CGException.cpp - Emit LLVM Code for C++ exceptions --------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This contains code dealing with C++ exception related code generation. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/AST/StmtCXX.h" 15 16#include "llvm/Intrinsics.h" 17 18#include "CodeGenFunction.h" 19using namespace clang; 20using namespace CodeGen; 21 22static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { 23 // void *__cxa_allocate_exception(size_t thrown_size); 24 const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); 25 std::vector<const llvm::Type*> Args(1, SizeTy); 26 27 const llvm::FunctionType *FTy = 28 llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), 29 Args, false); 30 31 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); 32} 33 34static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { 35 // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, 36 // void (*dest) (void *) ); 37 38 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 39 std::vector<const llvm::Type*> Args(3, Int8PtrTy); 40 41 const llvm::FunctionType *FTy = 42 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 43 Args, false); 44 45 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); 46} 47 48static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { 49 // void __cxa_rethrow (); 50 51 const llvm::FunctionType *FTy = 52 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 53 54 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); 55} 56 57static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { 58 // void __cxa_begin_catch (); 59 60 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); 61 std::vector<const llvm::Type*> Args(1, Int8PtrTy); 62 63 const llvm::FunctionType *FTy = 64 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, 65 false); 66 67 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); 68} 69 70static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { 71 // void __cxa_end_catch (); 72 73 const llvm::FunctionType *FTy = 74 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); 75 76 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); 77} 78 79void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { 80 if (!E->getSubExpr()) { 81 Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); 82 Builder.CreateUnreachable(); 83 84 // Clear the insertion point to indicate we are in unreachable code. 85 Builder.ClearInsertionPoint(); 86 return; 87 } 88 89 QualType ThrowType = E->getSubExpr()->getType(); 90 // FIXME: Handle cleanup. 91 if (!CleanupEntries.empty()){ 92 ErrorUnsupported(E, "throw expression with cleanup entries"); 93 return; 94 } 95 96 // Now allocate the exception object. 97 const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); 98 uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; 99 100 llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); 101 llvm::Value *ExceptionPtr = 102 Builder.CreateCall(AllocExceptionFn, 103 llvm::ConstantInt::get(SizeTy, TypeSize), 104 "exception"); 105 106 // Store the throw exception in the exception object. 107 if (!hasAggregateLLVMType(ThrowType)) { 108 llvm::Value *Value = EmitScalarExpr(E->getSubExpr()); 109 const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); 110 111 Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy)); 112 } else { 113 const llvm::Type *Ty = ConvertType(ThrowType)->getPointerTo(0); 114 const CXXRecordDecl *RD; 115 RD = cast<CXXRecordDecl>(ThrowType->getAs<RecordType>()->getDecl()); 116 llvm::Value *This = Builder.CreateBitCast(ExceptionPtr, Ty); 117 if (RD->hasTrivialCopyConstructor()) { 118 EmitAggExpr(E->getSubExpr(), This, false); 119 } else if (CXXConstructorDecl *CopyCtor 120 = RD->getCopyConstructor(getContext(), 0)) { 121 // FIXME: region management 122 llvm::Value *Src = EmitLValue(E->getSubExpr()).getAddress(); 123 124 // Stolen from EmitClassAggrMemberwiseCopy 125 llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(CopyCtor, 126 Ctor_Complete); 127 CallArgList CallArgs; 128 CallArgs.push_back(std::make_pair(RValue::get(This), 129 CopyCtor->getThisType(getContext()))); 130 131 // Push the Src ptr. 132 CallArgs.push_back(std::make_pair(RValue::get(Src), 133 CopyCtor->getParamDecl(0)->getType())); 134 QualType ResultType = 135 CopyCtor->getType()->getAs<FunctionType>()->getResultType(); 136 EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), 137 Callee, CallArgs, CopyCtor); 138 // FIXME: region management 139 } else 140 ErrorUnsupported(E, "throw expression with copy ctor"); 141 } 142 143 // Now throw the exception. 144 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 145 llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType); 146 llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); 147 148 llvm::CallInst *ThrowCall = 149 Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); 150 ThrowCall->setDoesNotReturn(); 151 Builder.CreateUnreachable(); 152 153 // Clear the insertion point to indicate we are in unreachable code. 154 Builder.ClearInsertionPoint(); 155} 156 157void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { 158 // FIXME: We need to do more here. 159 EmitStmt(S.getTryBlock()); 160 getBeginCatchFn(*this); 161 getEndCatchFn(*this); 162 163#if 0 164 // WIP. Can't enable until the basic structure is correct. 165 // Pointer to the personality function 166 llvm::Constant *Personality = 167 CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty 168 (VMContext), 169 true), 170 "__gxx_personality_v0"); 171 Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); 172 173 llvm::BasicBlock *TryBlock = createBasicBlock("try"); 174 llvm::BasicBlock *PrevLandingPad = getInvokeDest(); 175 llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); 176 llvm::BasicBlock *CatchInCatch = createBasicBlock("catch.rethrow"); 177 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); 178 llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); 179 180 // Push an EH context entry, used for handling rethrows. 181 PushCleanupBlock(FinallyBlock); 182 183 // Emit the statements in the try {} block 184 setInvokeDest(TryHandler); 185 186 EmitStmt(S.getTryBlock()); 187 188 // Jump to end if there is no exception 189 EmitBranchThroughCleanup(FinallyEnd); 190 191 // Emit the handlers 192 EmitBlock(TryHandler); 193 194 const llvm::IntegerType *Int8Ty; 195 const llvm::PointerType *PtrToInt8Ty; 196 Int8Ty = llvm::Type::getInt8Ty(VMContext); 197 // C string type. Used in lots of places. 198 PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); 199 llvm::Constant *NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); 200 llvm::SmallVector<llvm::Value*, 8> ESelArgs; 201 llvm::Value *llvm_eh_exception = 202 CGM.getIntrinsic(llvm::Intrinsic::eh_exception); 203 llvm::Value *llvm_eh_selector = 204 CGM.getIntrinsic(llvm::Intrinsic::eh_selector); 205 // Exception object 206 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); 207 208 ESelArgs.push_back(Exc); 209 ESelArgs.push_back(Personality); 210 211 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 212 const CXXCatchStmt *C = S.getHandler(i); 213 VarDecl *VD = C->getExceptionDecl(); 214 if (VD) { 215#if 0 216 // FIXME: Handle type matching. 217 llvm::Value *EHType = 0; 218 ESelArgs.push_back(EHType); 219#endif 220 } else { 221 // null indicates catch all 222 ESelArgs.push_back(NULLPtr); 223 } 224 } 225 226 // Find which handler was matched. 227 llvm::Value *ESelector 228 = Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(), 229 "selector"); 230 231 for (unsigned i = 0; i<S.getNumHandlers(); ++i) { 232 const CXXCatchStmt *C = S.getHandler(i); 233 getBeginCatchFn(*this); 234 getEndCatchFn(*this); 235 } 236 237 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); 238 239 setInvokeDest(PrevLandingPad); 240 241 EmitBlock(FinallyBlock); 242 243#if 0 244 // Branch around the rethrow code. 245 EmitBranch(FinallyEnd); 246 247 EmitBlock(FinallyRethrow); 248 Builder.CreateCall(RethrowFn, Builder.CreateLoad(RethrowPtr)); 249 Builder.CreateUnreachable(); 250#endif 251 252 EmitBlock(FinallyEnd); 253#endif 254} 255