diff options
Diffstat (limited to 'lib/CodeGen/CGException.cpp')
-rw-r--r-- | lib/CodeGen/CGException.cpp | 319 |
1 files changed, 250 insertions, 69 deletions
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index cf84b3fcd2..420e275bec 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -55,14 +55,13 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { } static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { - // void __cxa_begin_catch (); + // void* __cxa_begin_catch (); 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); + llvm::FunctionType::get(Int8PtrTy, Args, false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); } @@ -76,6 +75,108 @@ static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); } +// FIXME: Eventually this will all go into the backend. Set from the target for +// now. +static int using_sjlj_exceptions = 0; + +static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { + 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); + + if (using_sjlj_exceptions) + return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); + return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); +} + +// CopyObject - Utility to copy an object. Calls copy constructor as necessary. +// N is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { + QualType ObjectType = E->getType(); + + // Store the throw exception in the exception object. + if (!CGF.hasAggregateLLVMType(ObjectType)) { + llvm::Value *Value = CGF.EmitScalarExpr(E); + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); + + CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + } else { + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); + const CXXRecordDecl *RD; + RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); + llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + if (RD->hasTrivialCopyConstructor()) { + CGF.EmitAggExpr(E, This, false); + } else if (CXXConstructorDecl *CopyCtor + = RD->getCopyConstructor(CGF.getContext(), 0)) { + // FIXME: region management + llvm::Value *Src = CGF.EmitLValue(E).getAddress(); + + // Stolen from EmitClassAggrMemberwiseCopy + llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, + Ctor_Complete); + CallArgList CallArgs; + CallArgs.push_back(std::make_pair(RValue::get(This), + CopyCtor->getThisType(CGF.getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + CopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + CopyCtor->getType()->getAs<FunctionType>()->getResultType(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, CopyCtor); + // FIXME: region management + } else + CGF.ErrorUnsupported(E, "uncopyable object"); + } +} + +// CopyObject - Utility to copy an object. Calls copy constructor as necessary. +// N is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, + llvm::Value *E, llvm::Value *N) { + // Store the throw exception in the exception object. + if (!CGF.hasAggregateLLVMType(ObjectType)) { + llvm::Value *Value = E; + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); + + CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + } else { + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); + const CXXRecordDecl *RD; + RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); + llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + if (RD->hasTrivialCopyConstructor()) { + CGF.EmitAggregateCopy(This, E, ObjectType); + } else if (CXXConstructorDecl *CopyCtor + = RD->getCopyConstructor(CGF.getContext(), 0)) { + // FIXME: region management + llvm::Value *Src = E; + + // Stolen from EmitClassAggrMemberwiseCopy + llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, + Ctor_Complete); + CallArgList CallArgs; + CallArgs.push_back(std::make_pair(RValue::get(This), + CopyCtor->getThisType(CGF.getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + CopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + CopyCtor->getType()->getAs<FunctionType>()->getResultType(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, CopyCtor); + // FIXME: region management + } else + llvm::llvm_unreachable("uncopyable object"); + } +} + void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { if (!E->getSubExpr()) { Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); @@ -103,42 +204,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - // Store the throw exception in the exception object. - if (!hasAggregateLLVMType(ThrowType)) { - llvm::Value *Value = EmitScalarExpr(E->getSubExpr()); - const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - - Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy)); - } else { - const llvm::Type *Ty = ConvertType(ThrowType)->getPointerTo(0); - const CXXRecordDecl *RD; - RD = cast<CXXRecordDecl>(ThrowType->getAs<RecordType>()->getDecl()); - llvm::Value *This = Builder.CreateBitCast(ExceptionPtr, Ty); - if (RD->hasTrivialCopyConstructor()) { - EmitAggExpr(E->getSubExpr(), This, false); - } else if (CXXConstructorDecl *CopyCtor - = RD->getCopyConstructor(getContext(), 0)) { - // FIXME: region management - llvm::Value *Src = EmitLValue(E->getSubExpr()).getAddress(); - - // Stolen from EmitClassAggrMemberwiseCopy - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(CopyCtor, - Ctor_Complete); - CallArgList CallArgs; - CallArgs.push_back(std::make_pair(RValue::get(This), - CopyCtor->getThisType(getContext()))); - - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - CopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - CopyCtor->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), - Callee, CallArgs, CopyCtor); - // FIXME: region management - } else - ErrorUnsupported(E, "throw expression with copy ctor"); - } + CopyObject(*this, E->getSubExpr(), ExceptionPtr); // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); @@ -155,13 +221,16 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { } void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { - // FIXME: We need to do more here. +#if 1 EmitStmt(S.getTryBlock()); - getBeginCatchFn(*this); - getEndCatchFn(*this); - -#if 0 - // WIP. Can't enable until the basic structure is correct. + if (0) { + getBeginCatchFn(*this); + getEndCatchFn(*this); + getUnwindResumeOrRethrowFn(*this); + CopyObject(*this, QualType(), 0, 0); + } +#else + // FIXME: The below is still just a sketch of the code we need. // Pointer to the personality function llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty @@ -170,15 +239,18 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); - llvm::BasicBlock *TryBlock = createBasicBlock("try"); llvm::BasicBlock *PrevLandingPad = getInvokeDest(); llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); - llvm::BasicBlock *CatchInCatch = createBasicBlock("catch.rethrow"); +#if 0 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); +#endif + llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); +#if 0 // Push an EH context entry, used for handling rethrows. PushCleanupBlock(FinallyBlock); +#endif // Emit the statements in the try {} block setInvokeDest(TryHandler); @@ -196,58 +268,167 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { Int8Ty = llvm::Type::getInt8Ty(VMContext); // C string type. Used in lots of places. PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); - llvm::Constant *NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); - llvm::SmallVector<llvm::Value*, 8> ESelArgs; + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector<llvm::Value*, 8> SelectorArgs; llvm::Value *llvm_eh_exception = CGM.getIntrinsic(llvm::Intrinsic::eh_exception); llvm::Value *llvm_eh_selector = CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + llvm::Value *llvm_eh_typeid_for = + CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); // Exception object llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); - ESelArgs.push_back(Exc); - ESelArgs.push_back(Personality); + SelectorArgs.push_back(Exc); + SelectorArgs.push_back(Personality); + bool HasCatchAll = false; for (unsigned i = 0; i<S.getNumHandlers(); ++i) { const CXXCatchStmt *C = S.getHandler(i); - VarDecl *VD = C->getExceptionDecl(); - if (VD) { -#if 0 - // FIXME: Handle type matching. - llvm::Value *EHType = 0; - ESelArgs.push_back(EHType); -#endif + VarDecl *CatchParam = C->getExceptionDecl(); + if (CatchParam) { + llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType()); + SelectorArgs.push_back(EHType); } else { // null indicates catch all - ESelArgs.push_back(NULLPtr); + SelectorArgs.push_back(Null); + HasCatchAll = true; } } - // Find which handler was matched. - llvm::Value *ESelector - = Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(), - "selector"); + // We use a cleanup unless there was already a catch all. + if (!HasCatchAll) { + SelectorArgs.push_back(Null); + } + // Find which handler was matched. + llvm::Value *Selector + = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), + SelectorArgs.end(), "selector"); for (unsigned i = 0; i<S.getNumHandlers(); ++i) { const CXXCatchStmt *C = S.getHandler(i); - getBeginCatchFn(*this); - getEndCatchFn(*this); - } + VarDecl *CatchParam = C->getExceptionDecl(); + Stmt *CatchBody = C->getHandlerBlock(); + + llvm::BasicBlock *Next = 0; + + if (SelectorArgs[i+2] != Null) { + llvm::BasicBlock *Match = createBasicBlock("match"); + Next = createBasicBlock("catch.next"); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + llvm::Value *Id + = Builder.CreateCall(llvm_eh_typeid_for, + Builder.CreateBitCast(SelectorArgs[i+2], + Int8PtrTy)); + Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), + Match, Next); + EmitBlock(Match); + } + + llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); + llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); + + PushCleanupBlock(MatchEnd); + setInvokeDest(MatchHandler); + + llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); + + // Bind the catch parameter if it exists. + if (CatchParam) { + QualType CatchType = CatchParam->getType().getNonReferenceType(); + if (!CatchType.getTypePtr()->isPointerType()) + CatchType = getContext().getPointerType(CatchType); + ExcObject = + Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); + // CatchParam is a ParmVarDecl because of the grammar + // construction used to handle this, but for codegen purposes + // we treat this as a local decl. + EmitLocalBlockVarDecl(*CatchParam); +#if 0 + // FIXME: objects with ctors, references + Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); +#else + CopyObject(*this, CatchParam->getType().getNonReferenceType(), + ExcObject, GetAddrOfLocalVar(CatchParam)); +#endif + } + + EmitStmt(CatchBody); + EmitBranchThroughCleanup(FinallyEnd); + + EmitBlock(MatchHandler); + + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + llvm::SmallVector<llvm::Value*, 8> Args; + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + Builder.CreateStore(Exc, RethrowPtr); + EmitBranchThroughCleanup(FinallyRethrow); + + CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); + + EmitBlock(MatchEnd); + + // Unfortunately, we also have to generate another EH frame here + // in case this throws. + llvm::BasicBlock *MatchEndHandler = + createBasicBlock("match.end.handler"); + llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont"); + Builder.CreateInvoke(getEndCatchFn(*this), + Cont, MatchEndHandler, + Args.begin(), Args.begin()); + + EmitBlock(Cont); + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + + EmitBlock(MatchEndHandler); + Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + Args.clear(); + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + Builder.CreateStore(Exc, RethrowPtr); + EmitBranchThroughCleanup(FinallyRethrow); + + if (Next) + EmitBlock(Next); + } + if (!HasCatchAll) + EmitBranchThroughCleanup(FinallyRethrow); CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); setInvokeDest(PrevLandingPad); +#if 0 EmitBlock(FinallyBlock); -#if 0 + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + // Branch around the rethrow code. EmitBranch(FinallyEnd); +#endif EmitBlock(FinallyRethrow); - Builder.CreateCall(RethrowFn, Builder.CreateLoad(RethrowPtr)); + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); Builder.CreateUnreachable(); -#endif EmitBlock(FinallyEnd); #endif |