/// forwardResume - Forward the 'resume' instruction to the caller's landing pad /// block. When the landing pad block has only one predecessor, this is a simple /// branch. When there is more than one predecessor, we need to split the /// landing pad block after the landingpad instruction and jump to there. void InvokeInliningInfo::forwardResume(ResumeInst *RI, SmallPtrSet<LandingPadInst*, 16> &InlinedLPads) { BasicBlock *Dest = getInnerResumeDest(); LandingPadInst *OuterLPad = getLandingPadInst(); BasicBlock *Src = RI->getParent(); BranchInst::Create(Dest, Src); // Update the PHIs in the destination. They were inserted in an order which // makes this work. addIncomingPHIValuesForInto(Src, Dest); InnerEHValuesPHI->addIncoming(RI->getOperand(0), Src); RI->eraseFromParent(); // Append the clauses from the outer landing pad instruction into the inlined // landing pad instructions. for (SmallPtrSet<LandingPadInst*, 16>::iterator I = InlinedLPads.begin(), E = InlinedLPads.end(); I != E; ++I) { LandingPadInst *InlinedLPad = *I; for (unsigned OuterIdx = 0, OuterNum = OuterLPad->getNumClauses(); OuterIdx != OuterNum; ++OuterIdx) InlinedLPad->addClause(OuterLPad->getClause(OuterIdx)); } }
/// HandleInlinedInvoke - If we inlined an invoke site, we need to convert calls /// in the body of the inlined function into invokes. /// /// II is the invoke instruction being inlined. FirstNewBlock is the first /// block of the inlined code (the last block is the end of the function), /// and InlineCodeInfo is information about the code that got inlined. static void HandleInlinedInvoke(InvokeInst *II, BasicBlock *FirstNewBlock, ClonedCodeInfo &InlinedCodeInfo) { BasicBlock *InvokeDest = II->getUnwindDest(); Function *Caller = FirstNewBlock->getParent(); // The inlined code is currently at the end of the function, scan from the // start of the inlined code to its end, checking for stuff we need to // rewrite. InvokeInliningInfo Invoke(II); // Get all of the inlined landing pad instructions. SmallPtrSet<LandingPadInst*, 16> InlinedLPads; for (Function::iterator I = FirstNewBlock, E = Caller->end(); I != E; ++I) if (InvokeInst *II = dyn_cast<InvokeInst>(I->getTerminator())) InlinedLPads.insert(II->getLandingPadInst()); // Append the clauses from the outer landing pad instruction into the inlined // landing pad instructions. LandingPadInst *OuterLPad = Invoke.getLandingPadInst(); for (SmallPtrSet<LandingPadInst*, 16>::iterator I = InlinedLPads.begin(), E = InlinedLPads.end(); I != E; ++I) { LandingPadInst *InlinedLPad = *I; unsigned OuterNum = OuterLPad->getNumClauses(); InlinedLPad->reserveClauses(OuterNum); for (unsigned OuterIdx = 0; OuterIdx != OuterNum; ++OuterIdx) InlinedLPad->addClause(OuterLPad->getClause(OuterIdx)); if (OuterLPad->isCleanup()) InlinedLPad->setCleanup(true); } for (Function::iterator BB = FirstNewBlock, E = Caller->end(); BB != E; ++BB) { if (InlinedCodeInfo.ContainsCalls) HandleCallsInBlockInlinedThroughInvoke(BB, Invoke); // Forward any resumes that are remaining here. if (ResumeInst *RI = dyn_cast<ResumeInst>(BB->getTerminator())) Invoke.forwardResume(RI, InlinedLPads); } // Now that everything is happy, we have one final detail. The PHI nodes in // the exception destination block still have entries due to the original // invoke instruction. Eliminate these entries (which might even delete the // PHI node) now. InvokeDest->removePredecessor(II->getParent()); }
int main() { InitializeNativeTarget(); LLVMContext& Context = getGlobalContext(); Module *M = new Module("test C++ exception handling ", Context); StructType* MyStructType = StructType::create(Context, "struct.MyStruct"); Type* MyStructFields[] = { Type::getInt32Ty(Context), Type::getInt32Ty(Context) }; MyStructType->setBody(MyStructFields); GlobalValue* throwFunc = cast<GlobalValue>(M->getOrInsertFunction("throwMyStruct", Type::getVoidTy(Context), NULL)); GlobalValue* MyStructTypeInfo = cast<GlobalValue>(M->getOrInsertGlobal("MyStructTypeInfo", Type::getInt8Ty(Context))); Function* gxx_personality = Function::Create(FunctionType::get(Type::getInt32Ty(Context), true), Function::ExternalLinkage, "__gxx_personality_v0", M); Function* begin_catch = Function::Create(FunctionType::get(Type::getInt8PtrTy(Context), Type::getInt8PtrTy(Context), false), Function::ExternalLinkage, "__cxa_begin_catch", M); Function* end_catch = Function::Create(FunctionType::get(Type::getVoidTy(Context), false), Function::ExternalLinkage, "__cxa_end_catch", M); Function* testExceptions = cast<Function>(M->getOrInsertFunction("testExceptions", Type::getInt32Ty(Context), NULL)); BasicBlock* entryBB = BasicBlock::Create(Context, "", testExceptions); BasicBlock* landPadBB = BasicBlock::Create(Context, "landPad", testExceptions); BasicBlock* noErrorBB = BasicBlock::Create(Context, "noError", testExceptions); IRBuilder<> builder(entryBB); Value* invokeThrow = builder.CreateInvoke(throwFunc, noErrorBB, landPadBB); builder.SetInsertPoint(noErrorBB); builder.CreateRet( builder.getInt32(666) ); // should never happen //writing landingpad! <<<<<<< builder.SetInsertPoint(landPadBB); Value* gxx_personality_i8 = builder.CreateBitCast(gxx_personality, Type::getInt8PtrTy(Context)); Type* caughtType = StructType::get(builder.getInt8PtrTy(), builder.getInt32Ty(), NULL); LandingPadInst* caughtResult = builder.CreateLandingPad(caughtType, gxx_personality_i8, 1); // we can catch any C++ exception we want // but now we are catching MyStruct caughtResult->addClause(MyStructTypeInfo); //we are sure to catch MyStruct so no other checks are needed //if throwMyStruct() throws anything but MyStruct it won't pass to the current landingpad BB Value* thrownExctn = builder.CreateExtractValue(caughtResult, 0); Value* thrownObject = builder.CreateCall(begin_catch, thrownExctn); Value* object = builder.CreateBitCast(thrownObject, MyStructType->getPointerTo()); Value* resultPtr = builder.CreateStructGEP(object, 1); Value* result = builder.CreateLoad(resultPtr); builder.CreateCall(end_catch); builder.CreateRet( result ); // << z.y TargetOptions Opts; Opts.JITExceptionHandling = true; // DO NOT FORGET THIS OPTION !!!!!!11 ExecutionEngine* EE = EngineBuilder(M) .setEngineKind(EngineKind::JIT) .setTargetOptions(Opts) .create(); EE->addGlobalMapping(throwFunc, reinterpret_cast<void*>(&throwMyStruct)); EE->addGlobalMapping(MyStructTypeInfo, MyStruct::getTypeInfo()); verifyFunction(*testExceptions); outs() << *testExceptions; std::vector<GenericValue> noArgs; GenericValue gv = EE->runFunction(testExceptions, noArgs); outs() << "\ntestExceptions result: " << gv.IntVal << "\n"; delete EE; llvm_shutdown(); return 0; }