diff options
Diffstat (limited to 'examples/ExceptionDemo/ExceptionDemo.cpp')
-rw-r--r-- | examples/ExceptionDemo/ExceptionDemo.cpp | 301 |
1 files changed, 186 insertions, 115 deletions
diff --git a/examples/ExceptionDemo/ExceptionDemo.cpp b/examples/ExceptionDemo/ExceptionDemo.cpp index e5d9451..20516a7 100644 --- a/examples/ExceptionDemo/ExceptionDemo.cpp +++ b/examples/ExceptionDemo/ExceptionDemo.cpp @@ -40,7 +40,8 @@ // // Cases -1 and 7 are caught by a C++ test harness where the validity of // of a C++ catch(...) clause catching a generated exception with a -// type info type of 7 is questionable. +// type info type of 7 is explained by: example in rules 1.6.4 in +// http://sourcery.mentor.com/public/cxx-abi/abi-eh.html (v1.22) // // This code uses code from the llvm compiler-rt project and the llvm // Kaleidoscope project. @@ -56,11 +57,16 @@ #include "llvm/Intrinsics.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetSelect.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Support/IRBuilder.h" #include "llvm/Support/Dwarf.h" +#include "llvm/Support/TargetSelect.h" + +#ifdef OLD_EXC_SYSTEM +// See use of UpgradeExceptionHandling(...) below +#include "llvm/AutoUpgrade.h" +#endif // FIXME: Although all systems tested with (Linux, OS X), do not need this // header file included. A user on ubuntu reported, undefined symbols @@ -81,7 +87,7 @@ #endif // System C++ ABI unwind types from: -// http://refspecs.freestandards.org/abi-eh-1.21.html +// http://sourcery.mentor.com/public/cxx-abi/abi-eh.html (v1.22) extern "C" { @@ -182,6 +188,9 @@ static std::vector<std::string> ourTypeInfoNames; static std::map<int, std::string> ourTypeInfoNamesIndex; static llvm::StructType *ourTypeInfoType; +#ifndef OLD_EXC_SYSTEM +static llvm::StructType *ourCaughtResultType; +#endif static llvm::StructType *ourExceptionType; static llvm::StructType *ourUnwindExceptionType; @@ -209,7 +218,7 @@ typedef std::vector<llvm::Type*> ArgTypes; /// @param isVarArg function uses vararg arguments /// @returns function instance llvm::Function *createFunction(llvm::Module &module, - const llvm::Type *retType, + llvm::Type *retType, const ArgTypes &theArgTypes, const ArgNames &theArgNames, const std::string &functName, @@ -246,7 +255,7 @@ llvm::Function *createFunction(llvm::Module &module, /// @returns AllocaInst instance static llvm::AllocaInst *createEntryBlockAlloca(llvm::Function &function, const std::string &varName, - const llvm::Type *type, + llvm::Type *type, llvm::Constant *initWith = 0) { llvm::BasicBlock &block = function.getEntryBlock(); llvm::IRBuilder<> tmp(&block, block.begin()); @@ -893,9 +902,8 @@ void generateStringPrint(llvm::LLVMContext &context, builder.CreateStore(stringConstant, stringVar); } - llvm::Value *cast = - builder.CreatePointerCast(stringVar, - builder.getInt8PtrTy()); + llvm::Value *cast = builder.CreatePointerCast(stringVar, + builder.getInt8PtrTy()); builder.CreateCall(printFunct, cast); } @@ -937,9 +945,8 @@ void generateIntegerPrint(llvm::LLVMContext &context, builder.CreateStore(stringConstant, stringVar); } - llvm::Value *cast = - builder.CreateBitCast(stringVar, - builder.getInt8PtrTy()); + llvm::Value *cast = builder.CreateBitCast(stringVar, + builder.getInt8PtrTy()); builder.CreateCall2(&printFunct, &toPrint, cast); } @@ -962,6 +969,9 @@ void generateIntegerPrint(llvm::LLVMContext &context, /// @param unwindResumeBlock unwind resume block /// @param exceptionCaughtFlag reference exception caught/thrown status storage /// @param exceptionStorage reference to exception pointer storage +#ifndef OLD_EXC_SYSTEM +/// @param caughtResultStorage reference to landingpad result storage +#endif /// @returns newly created block static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context, llvm::Module &module, @@ -972,28 +982,42 @@ static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context, llvm::BasicBlock &terminatorBlock, llvm::BasicBlock &unwindResumeBlock, llvm::Value **exceptionCaughtFlag, - llvm::Value **exceptionStorage) { + llvm::Value **exceptionStorage +#ifndef OLD_EXC_SYSTEM + ,llvm::Value **caughtResultStorage +#endif + ) { assert(exceptionCaughtFlag && "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag " "is NULL"); assert(exceptionStorage && "ExceptionDemo::createFinallyBlock(...):exceptionStorage " "is NULL"); + +#ifndef OLD_EXC_SYSTEM + assert(caughtResultStorage && + "ExceptionDemo::createFinallyBlock(...):caughtResultStorage " + "is NULL"); +#endif - *exceptionCaughtFlag = - createEntryBlockAlloca(toAddTo, - "exceptionCaught", - ourExceptionNotThrownState->getType(), - ourExceptionNotThrownState); - - const llvm::PointerType *exceptionStorageType = - builder.getInt8PtrTy(); - *exceptionStorage = - createEntryBlockAlloca(toAddTo, - "exceptionStorage", - exceptionStorageType, - llvm::ConstantPointerNull::get( - exceptionStorageType)); + *exceptionCaughtFlag = createEntryBlockAlloca(toAddTo, + "exceptionCaught", + ourExceptionNotThrownState->getType(), + ourExceptionNotThrownState); + + llvm::PointerType *exceptionStorageType = builder.getInt8PtrTy(); + *exceptionStorage = createEntryBlockAlloca(toAddTo, + "exceptionStorage", + exceptionStorageType, + llvm::ConstantPointerNull::get( + exceptionStorageType)); +#ifndef OLD_EXC_SYSTEM + *caughtResultStorage = createEntryBlockAlloca(toAddTo, + "caughtResultStorage", + ourCaughtResultType, + llvm::ConstantAggregateZero::get( + ourCaughtResultType)); +#endif llvm::BasicBlock *ret = llvm::BasicBlock::Create(context, blockName, @@ -1010,10 +1034,10 @@ static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context, bufferToPrint.str(), USE_GLOBAL_STR_CONSTS); - llvm::SwitchInst *theSwitch = - builder.CreateSwitch(builder.CreateLoad(*exceptionCaughtFlag), - &terminatorBlock, - 2); + llvm::SwitchInst *theSwitch = builder.CreateSwitch(builder.CreateLoad( + *exceptionCaughtFlag), + &terminatorBlock, + 2); theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock); theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock); @@ -1121,29 +1145,35 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, "normal", ret); // Unwind block for invoke - llvm::BasicBlock *exceptionBlock = - llvm::BasicBlock::Create(context, "exception", ret); + llvm::BasicBlock *exceptionBlock = llvm::BasicBlock::Create(context, + "exception", + ret); // Block which routes exception to correct catch handler block - llvm::BasicBlock *exceptionRouteBlock = - llvm::BasicBlock::Create(context, "exceptionRoute", ret); + llvm::BasicBlock *exceptionRouteBlock = llvm::BasicBlock::Create(context, + "exceptionRoute", + ret); // Foreign exception handler - llvm::BasicBlock *externalExceptionBlock = - llvm::BasicBlock::Create(context, "externalException", ret); + llvm::BasicBlock *externalExceptionBlock = llvm::BasicBlock::Create(context, + "externalException", + ret); // Block which calls _Unwind_Resume - llvm::BasicBlock *unwindResumeBlock = - llvm::BasicBlock::Create(context, "unwindResume", ret); + llvm::BasicBlock *unwindResumeBlock = llvm::BasicBlock::Create(context, + "unwindResume", + ret); // Clean up block which delete exception if needed - llvm::BasicBlock *endBlock = - llvm::BasicBlock::Create(context, "end", ret); + llvm::BasicBlock *endBlock = llvm::BasicBlock::Create(context, "end", ret); std::string nextName; std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch); llvm::Value *exceptionCaughtFlag = NULL; llvm::Value *exceptionStorage = NULL; +#ifndef OLD_EXC_SYSTEM + llvm::Value *caughtResultStorage = NULL; +#endif // Finally block which will branch to unwindResumeBlock if // exception is not caught. Initializes/allocates stack locations. @@ -1156,7 +1186,11 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, *endBlock, *unwindResumeBlock, &exceptionCaughtFlag, - &exceptionStorage); + &exceptionStorage +#ifndef OLD_EXC_SYSTEM + ,&caughtResultStorage +#endif + ); for (unsigned i = 0; i < numExceptionsToCatch; ++i) { nextName = ourTypeInfoNames[exceptionTypesToCatch[i]]; @@ -1181,8 +1215,7 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, builder.CreateInvoke(&toInvoke, normalBlock, exceptionBlock, - args.begin(), - args.end()); + args); // End Block @@ -1193,8 +1226,7 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, builder, "Gen: In end block: exiting in " + ourId + ".\n", USE_GLOBAL_STR_CONSTS); - llvm::Function *deleteOurException = - module.getFunction("deleteOurException"); + llvm::Function *deleteOurException = module.getFunction("deleteOurException"); // Note: function handles NULL exceptions builder.CreateCall(deleteOurException, @@ -1218,28 +1250,57 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, builder.SetInsertPoint(unwindResumeBlock); - llvm::Function *resumeOurException = - module.getFunction("_Unwind_Resume"); + +#ifndef OLD_EXC_SYSTEM + builder.CreateResume(builder.CreateLoad(caughtResultStorage)); +#else + llvm::Function *resumeOurException = module.getFunction("_Unwind_Resume"); builder.CreateCall(resumeOurException, builder.CreateLoad(exceptionStorage)); builder.CreateUnreachable(); +#endif // Exception Block builder.SetInsertPoint(exceptionBlock); - llvm::Function *ehException = module.getFunction("llvm.eh.exception"); + llvm::Function *personality = module.getFunction("ourPersonality"); +#ifndef OLD_EXC_SYSTEM + llvm::LandingPadInst *caughtResult = + builder.CreateLandingPad(ourCaughtResultType, + personality, + numExceptionsToCatch, + "landingPad"); + + caughtResult->setCleanup(true); + + for (unsigned i = 0; i < numExceptionsToCatch; ++i) { + // Set up type infos to be caught + caughtResult->addClause(module.getGlobalVariable( + ourTypeInfoNames[exceptionTypesToCatch[i]])); + } + + llvm::Value *unwindException = builder.CreateExtractValue(caughtResult, 0); + llvm::Value *retTypeInfoIndex = builder.CreateExtractValue(caughtResult, 1); + + // FIXME: Redundant storage which, beyond utilizing value of + // caughtResultStore for unwindException storage, may be alleviated + // alltogether with a block rearrangement + builder.CreateStore(caughtResult, caughtResultStorage); + builder.CreateStore(unwindException, exceptionStorage); + builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag); +#else + llvm::Function *ehException = module.getFunction("llvm.eh.exception"); + // Retrieve thrown exception llvm::Value *unwindException = builder.CreateCall(ehException); // Store exception and flag builder.CreateStore(unwindException, exceptionStorage); builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag); - llvm::Function *personality = module.getFunction("ourPersonality"); - llvm::Value *functPtr = - builder.CreatePointerCast(personality, - builder.getInt8PtrTy()); + llvm::Value *functPtr = builder.CreatePointerCast(personality, + builder.getInt8PtrTy()); args.clear(); args.push_back(unwindException); @@ -1263,9 +1324,8 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, // handles this call. This landing pad (this exception block), will be // called either because it nees to cleanup (call finally) or a type // info was found which matched the thrown exception. - llvm::Value *retTypeInfoIndex = builder.CreateCall(ehSelector, - args.begin(), - args.end()); + llvm::Value *retTypeInfoIndex = builder.CreateCall(ehSelector, args); +#endif // Retrieve exception_class member from thrown exception // (_Unwind_Exception instance). This member tells us whether or not @@ -1305,10 +1365,10 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, // (OurException instance). // // Note: ourBaseFromUnwindOffset is usually negative - llvm::Value *typeInfoThrown = - builder.CreatePointerCast(builder.CreateConstGEP1_64(unwindException, + llvm::Value *typeInfoThrown = builder.CreatePointerCast( + builder.CreateConstGEP1_64(unwindException, ourBaseFromUnwindOffset), - ourExceptionType->getPointerTo()); + ourExceptionType->getPointerTo()); // Retrieve thrown exception type info type // @@ -1331,10 +1391,9 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, USE_GLOBAL_STR_CONSTS); // Route to matched type info catch block or run cleanup finally block - llvm::SwitchInst *switchToCatchBlock = - builder.CreateSwitch(retTypeInfoIndex, - finallyBlock, - numExceptionsToCatch); + llvm::SwitchInst *switchToCatchBlock = builder.CreateSwitch(retTypeInfoIndex, + finallyBlock, + numExceptionsToCatch); unsigned nextTypeToCatch; @@ -1344,6 +1403,12 @@ llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, llvm::Type::getInt32Ty(context), i), catchBlocks[nextTypeToCatch]); } + +#ifdef OLD_EXC_SYSTEM + // Must be run before verifier + UpgradeExceptionHandling(&module); +#endif + llvm::verifyFunction(*ret); fpm.run(*ret); @@ -1395,15 +1460,13 @@ llvm::Function *createThrowExceptionFunction(llvm::Module &module, "entry", ret); // Throws a foreign exception - llvm::BasicBlock *nativeThrowBlock = - llvm::BasicBlock::Create(context, - "nativeThrow", - ret); + llvm::BasicBlock *nativeThrowBlock = llvm::BasicBlock::Create(context, + "nativeThrow", + ret); // Throws one of our Exceptions - llvm::BasicBlock *generatedThrowBlock = - llvm::BasicBlock::Create(context, - "generatedThrow", - ret); + llvm::BasicBlock *generatedThrowBlock = llvm::BasicBlock::Create(context, + "generatedThrow", + ret); // Retrieved runtime type info type to throw llvm::Value *exceptionType = namedValues["exceptTypeToThrow"]; @@ -1445,15 +1508,13 @@ llvm::Function *createThrowExceptionFunction(llvm::Module &module, builder.SetInsertPoint(generatedThrowBlock); - llvm::Function *createOurException = - module.getFunction("createOurException"); - llvm::Function *raiseOurException = - module.getFunction("_Unwind_RaiseException"); + llvm::Function *createOurException = module.getFunction("createOurException"); + llvm::Function *raiseOurException = module.getFunction( + "_Unwind_RaiseException"); // Creates exception to throw with runtime type info type. - llvm::Value *exception = - builder.CreateCall(createOurException, - namedValues["exceptTypeToThrow"]); + llvm::Value *exception = builder.CreateCall(createOurException, + namedValues["exceptTypeToThrow"]); // Throw generated Exception builder.CreateCall(raiseOurException, exception); @@ -1501,32 +1562,29 @@ llvm::Function *createUnwindExceptionTest(llvm::Module &module, createStandardUtilityFunctions(numTypeInfos, module, builder); - llvm::Function *nativeThrowFunct = - module.getFunction(nativeThrowFunctName); + llvm::Function *nativeThrowFunct = module.getFunction(nativeThrowFunctName); // Create exception throw function using the value ~0 to cause // foreign exceptions to be thrown. - llvm::Function *throwFunct = - createThrowExceptionFunction(module, - builder, - fpm, - "throwFunct", - ~0, - *nativeThrowFunct); + llvm::Function *throwFunct = createThrowExceptionFunction(module, + builder, + fpm, + "throwFunct", + ~0, + *nativeThrowFunct); // Inner function will catch even type infos unsigned innerExceptionTypesToCatch[] = {6, 2, 4}; size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) / - sizeof(unsigned); + sizeof(unsigned); // Generate inner function. - llvm::Function *innerCatchFunct = - createCatchWrappedInvokeFunction(module, - builder, - fpm, - *throwFunct, - "innerCatchFunct", - numExceptionTypesToCatch, - innerExceptionTypesToCatch); + llvm::Function *innerCatchFunct = createCatchWrappedInvokeFunction(module, + builder, + fpm, + *throwFunct, + "innerCatchFunct", + numExceptionTypesToCatch, + innerExceptionTypesToCatch); // Outer function will catch odd type infos unsigned outerExceptionTypesToCatch[] = {3, 1, 5}; @@ -1534,14 +1592,13 @@ llvm::Function *createUnwindExceptionTest(llvm::Module &module, sizeof(unsigned); // Generate outer function - llvm::Function *outerCatchFunct = - createCatchWrappedInvokeFunction(module, - builder, - fpm, - *innerCatchFunct, - "outerCatchFunct", - numExceptionTypesToCatch, - outerExceptionTypesToCatch); + llvm::Function *outerCatchFunct = createCatchWrappedInvokeFunction(module, + builder, + fpm, + *innerCatchFunct, + "outerCatchFunct", + numExceptionTypesToCatch, + outerExceptionTypesToCatch); // Return outer function to run return(outerCatchFunct); @@ -1607,12 +1664,12 @@ void runExceptionThrow(llvm::ExecutionEngine *engine, exc.what()); } catch (...) { - // Catch all exceptions including our generated ones. I'm not sure - // why this latter functionality should work, as it seems that - // our exceptions should be foreign to C++ (the _Unwind_Exception:: - // exception_class should be different from the one used by C++), and - // therefore C++ should ignore the generated exceptions. - + // Catch all exceptions including our generated ones. This latter + // functionality works according to the example in rules 1.6.4 of + // http://sourcery.mentor.com/public/cxx-abi/abi-eh.html (v1.22), + // given that these will be exceptions foreign to C++ + // (the _Unwind_Exception::exception_class should be different from + // the one used by C++). fprintf(stderr, "\nrunExceptionThrow(...):In C++ catch all.\n"); } @@ -1640,17 +1697,31 @@ static void createStandardUtilityFunctions(unsigned numTypeInfos, // Setup exception catch state ourExceptionNotThrownState = - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0), + llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0), ourExceptionThrownState = - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1), + llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1), ourExceptionCaughtState = - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2), + llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2), // Create our type info type ourTypeInfoType = llvm::StructType::get(context, - TypeArray(builder.getInt32Ty())); + TypeArray(builder.getInt32Ty())); + +#ifndef OLD_EXC_SYSTEM + + llvm::Type *caughtResultFieldTypes[] = { + builder.getInt8PtrTy(), + builder.getInt32Ty() + }; + + // Create our landingpad result type + ourCaughtResultType = llvm::StructType::get(context, + TypeArray(caughtResultFieldTypes)); + +#endif + // Create OurException type ourExceptionType = llvm::StructType::get(context, TypeArray(ourTypeInfoType)); @@ -1667,7 +1738,7 @@ static void createStandardUtilityFunctions(unsigned numTypeInfos, // Calculate offset of OurException::unwindException member. ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) - - ((uintptr_t) &(dummyException.unwindException)); + ((uintptr_t) &(dummyException.unwindException)); #ifdef DEBUG fprintf(stderr, @@ -1724,7 +1795,7 @@ static void createStandardUtilityFunctions(unsigned numTypeInfos, // print32Int - const llvm::Type *retType = builder.getVoidTy(); + llvm::Type *retType = builder.getVoidTy(); argTypes.clear(); argTypes.push_back(builder.getInt32Ty()); |