static bool IsDeletingDtor(GlobalDecl GD) { const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl()); if (isa<CXXDestructorDecl>(MD)) { return GD.getDtorType() == Dtor_Deleting; } return false; }
void CodeGenVTables::EmitThunks(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl(); // We don't need to generate thunks for the base destructor. if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) return; const VTableContextBase::ThunkInfoVectorTy *ThunkInfoVector = VTContext->getThunkInfo(GD); if (!ThunkInfoVector) return; for (const ThunkInfo& Thunk : *ThunkInfoVector) maybeEmitThunk(GD, Thunk, /*ForVTable=*/false); }
bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); // We don't have any virtual bases, just return early. if (!MD->getParent()->getNumVBases()) return false; // Check if we have a base constructor. if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) return true; // Check if we have a base destructor. if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) return true; return false; }
void CodeGenVTables::EmitThunks(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl(); // We don't need to generate thunks for the base destructor. if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) return; const VTableContext::ThunkInfoVectorTy *ThunkInfoVector = VTContext.getThunkInfo(MD); if (!ThunkInfoVector) return; for (unsigned I = 0, E = ThunkInfoVector->size(); I != E; ++I) EmitThunk(GD, (*ThunkInfoVector)[I], /*UseAvailableExternallyLinkage=*/false); }
void CodeGenVTables::EmitThunks(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl(); // We don't need to generate thunks for the base destructor. if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) return; const VTableContextBase::ThunkInfoVectorTy *ThunkInfoVector; if (MicrosoftVTContext.isValid()) { ThunkInfoVector = MicrosoftVTContext->getThunkInfo(GD); } else { ThunkInfoVector = ItaniumVTContext.getThunkInfo(GD); } if (!ThunkInfoVector) return; for (unsigned I = 0, E = ThunkInfoVector->size(); I != E; ++I) emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false); }
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // Pointer to the personality function 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); llvm::BasicBlock *PrevLandingPad = getInvokeDest(); llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); // Push an EH context entry, used for handling rethrows. PushCleanupBlock(FinallyBlock); // Emit the statements in the try {} block setInvokeDest(TryHandler); // FIXME: We should not have to do this here. The AST should have the member // initializers under the CXXTryStmt's TryBlock. if (OuterTryBlock == &S) { GlobalDecl GD = CurGD; const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { size_t OldCleanupStackSize = CleanupEntries.size(); EmitCtorPrologue(CD, CurGD.getCtorType()); EmitStmt(S.getTryBlock()); // If any of the member initializers are temporaries bound to references // make sure to emit their destructors. EmitCleanupBlocks(OldCleanupStackSize); } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); PushCleanupBlock(DtorEpilogue); EmitStmt(S.getTryBlock()); CleanupBlockInfo Info = PopCleanupBlock(); assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); EmitBlock(DtorEpilogue); EmitDtorEpilogue(DD, GD.getDtorType()); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); } else EmitStmt(S.getTryBlock()); } else EmitStmt(S.getTryBlock()); // Jump to end if there is no exception EmitBranchThroughCleanup(FinallyEnd); llvm::BasicBlock *TerminateHandler = getTerminateHandler(); // Emit the handlers EmitBlock(TryHandler); 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::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"); llvm::SmallVector<llvm::Value*, 8> Args; Args.clear(); 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 *CatchParam = C->getExceptionDecl(); if (CatchParam) { llvm::Value *EHType = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); SelectorArgs.push_back(EHType); } else { // null indicates catch all SelectorArgs.push_back(Null); HasCatchAll = true; } } // 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); 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); { CleanupScope CatchScope(*this); // Bind the catch parameter if it exists. if (CatchParam) { QualType CatchType = CatchParam->getType().getNonReferenceType(); setInvokeDest(TerminateHandler); bool WasPointer = true; if (!CatchType.getTypePtr()->isPointerType()) { if (!isa<ReferenceType>(CatchParam->getType())) WasPointer = false; CatchType = getContext().getPointerType(CatchType); } ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); EmitLocalBlockVarDecl(*CatchParam); // FIXME: we need to do this sooner so that the EH region for the // cleanup doesn't start until after the ctor completes, use a decl // init? CopyObject(*this, CatchParam->getType().getNonReferenceType(), WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam)); setInvokeDest(MatchHandler); } 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. 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); CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); EmitBlock(MatchEnd); llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getEndCatchFn(*this), Cont, TerminateHandler, Args.begin(), Args.begin()); EmitBlock(Cont); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); Exc = Builder.CreateCall(llvm_eh_exception, "exc"); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); if (Next) EmitBlock(Next); } if (!HasCatchAll) { Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); } CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); setInvokeDest(PrevLandingPad); EmitBlock(FinallyBlock); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); // Branch around the rethrow code. EmitBranch(FinallyEnd); EmitBlock(FinallyRethrow); // FIXME: Eventually we can chain the handlers together and just do a call // here. if (getInvokeDest()) { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, getInvokeDest(), Builder.CreateLoad(RethrowPtr)); EmitBlock(Cont); } else Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), Builder.CreateLoad(RethrowPtr)); Builder.CreateUnreachable(); EmitBlock(FinallyEnd); }