diff options
-rw-r--r-- | lib/CodeGen/CGException.cpp | 119 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 6 |
3 files changed, 127 insertions, 0 deletions
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 1c3f06e358..829f114411 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -87,6 +87,19 @@ static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); } +static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { + // void __cxa_call_unexepcted(void *thrown_exception); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); +} + // FIXME: Eventually this will all go into the backend. Set from the target for // now. static int using_sjlj_exceptions = 0; @@ -269,6 +282,112 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { EnsureInsertPoint(); } +void CodeGenFunction::EmitStartEHSpec(const Decl *D) { + const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); + if (FD == 0) + return; + const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); + if (Proto == 0) + return; + + assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack"); + + if (!Proto->hasExceptionSpec()) + return; + + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector<llvm::Value*, 8> SelectorArgs; + + llvm::BasicBlock *PrevLandingPad = getInvokeDest(); + llvm::BasicBlock *EHSpecHandler = createBasicBlock("ehspec.handler"); + llvm::BasicBlock *Match = createBasicBlock("match"); + llvm::BasicBlock *Unwind = 0; + + assert(PrevLandingPad == 0 && "EHSpec has invoke context"); + + llvm::BasicBlock *Cont = createBasicBlock("cont"); + + EmitBranchThroughCleanup(Cont); + + // Emit the statements in the try {} block + setInvokeDest(EHSpecHandler); + + EmitBlock(EHSpecHandler); + // Exception object + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + + SelectorArgs.push_back(Exc); + SelectorArgs.push_back(Personality); + SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + Proto->getNumExceptions()+1)); + + for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) { + QualType Ty = Proto->getExceptionType(i); + llvm::Value *EHType + = CGM.GenerateRTTI(Ty.getNonReferenceType()); + SelectorArgs.push_back(EHType); + } + if (Proto->getNumExceptions()) + SelectorArgs.push_back(Null); + + // Find which handler was matched. + llvm::Value *Selector + = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), + SelectorArgs.end(), "selector"); + if (Proto->getNumExceptions()) { + Unwind = createBasicBlock("Unwind"); + + Builder.CreateStore(Exc, RethrowPtr); + Builder.CreateCondBr(Builder.CreateICmpSLT(Selector, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)), + Match, Unwind); + + EmitBlock(Match); + } + Builder.CreateCall(getUnexpectedFn(*this), Exc)->setDoesNotReturn(); + Builder.CreateUnreachable(); + + if (Proto->getNumExceptions()) { + EmitBlock(Unwind); + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); + } + + EmitBlock(Cont); +} + +void CodeGenFunction::EmitEndEHSpec(const Decl *D) { + const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); + if (FD == 0) + return; + const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); + if (Proto == 0) + return; + + if (!Proto->hasExceptionSpec()) + return; + + setInvokeDest(0); +} + void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { if (0) { EmitStmt(S.getTryBlock()); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index d35c962112..78aa95686a 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -131,6 +131,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { } EmitFunctionEpilog(*CurFnInfo, ReturnValue); + EmitEndEHSpec(CurCodeDecl); // If someone did an indirect goto, emit the indirect goto block at the end of // the function. @@ -215,6 +216,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); } + EmitStartEHSpec(CurCodeDecl); EmitFunctionProlog(*CurFnInfo, CurFn, Args); // If any of the arguments have a variably modified type, make sure to diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 1a49c944a2..ead2b5df7d 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -504,6 +504,12 @@ public: /// given temporary. void EmitFunctionEpilog(const CGFunctionInfo &FI, llvm::Value *ReturnValue); + /// EmitStartEHSpec - Emit the start of the exception spec. + void EmitStartEHSpec(const Decl *D); + + /// EmitEndEHSpec - Emit the end of the exception spec. + void EmitEndEHSpec(const Decl *D); + const llvm::Type *ConvertTypeForMem(QualType T); const llvm::Type *ConvertType(QualType T); |