//
// 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.
#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
#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" {
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;
/// @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,
/// @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());
builder.CreateStore(stringConstant, stringVar);
}
- llvm::Value *cast =
- builder.CreatePointerCast(stringVar,
- builder.getInt8Ty()->getPointerTo());
+ llvm::Value *cast = builder.CreatePointerCast(stringVar,
+ builder.getInt8PtrTy());
builder.CreateCall(printFunct, cast);
}
builder.CreateStore(stringConstant, stringVar);
}
- llvm::Value *cast =
- builder.CreateBitCast(stringVar,
- builder.getInt8Ty()->getPointerTo());
+ llvm::Value *cast = builder.CreateBitCast(stringVar,
+ builder.getInt8PtrTy());
builder.CreateCall2(&printFunct, &toPrint, cast);
}
/// @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,
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.getInt8Ty()->getPointerTo();
- *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,
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);
llvm::Function *toPrint32Int = module.getFunction("print32Int");
ArgTypes argTypes;
- argTypes.push_back(llvm::Type::getInt32Ty(builder.getContext()));
+ argTypes.push_back(builder.getInt32Ty());
ArgNames argNames;
argNames.push_back("exceptTypeToThrow");
"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.
*endBlock,
*unwindResumeBlock,
&exceptionCaughtFlag,
- &exceptionStorage);
+ &exceptionStorage
+#ifndef OLD_EXC_SYSTEM
+ ,&caughtResultStorage
+#endif
+ );
for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
nextName = ourTypeInfoNames[exceptionTypesToCatch[i]];
builder.CreateInvoke(&toInvoke,
normalBlock,
exceptionBlock,
- args.begin(),
- args.end());
+ args);
// End Block
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,
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.getInt8Ty()->getPointerTo());
+ llvm::Value *functPtr = builder.CreatePointerCast(personality,
+ builder.getInt8PtrTy());
args.clear();
args.push_back(unwindException);
// 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
// (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
//
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;
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);
llvm::LLVMContext &context = module.getContext();
namedValues.clear();
ArgTypes unwindArgTypes;
- unwindArgTypes.push_back(llvm::Type::getInt32Ty(builder.getContext()));
+ unwindArgTypes.push_back(builder.getInt32Ty());
ArgNames unwindArgNames;
unwindArgNames.push_back("exceptTypeToThrow");
"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"];
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);
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};
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);
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");
}
// 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(llvm::Type::getInt32Ty(builder.getContext())));
+ 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));
// Does this cause problems?
ourUnwindExceptionType =
llvm::StructType::get(context,
- TypeArray(llvm::Type::getInt64Ty(builder.getContext())));
+ TypeArray(builder.getInt64Ty()));
struct OurBaseException_t dummyException;
// Calculate offset of OurException::unwindException member.
ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) -
- ((uintptr_t) &(dummyException.unwindException));
+ ((uintptr_t) &(dummyException.unwindException));
#ifdef DEBUG
fprintf(stderr,
// print32Int
- const llvm::Type *retType = builder.getVoidTy();
+ llvm::Type *retType = builder.getVoidTy();
argTypes.clear();
- argTypes.push_back(llvm::Type::getInt32Ty(builder.getContext()));
- argTypes.push_back(builder.getInt8Ty()->getPointerTo());
+ argTypes.push_back(builder.getInt32Ty());
+ argTypes.push_back(builder.getInt8PtrTy());
argNames.clear();
retType = builder.getVoidTy();
argTypes.clear();
- argTypes.push_back(llvm::Type::getInt64Ty(builder.getContext()));
- argTypes.push_back(builder.getInt8Ty()->getPointerTo());
+ argTypes.push_back(builder.getInt64Ty());
+ argTypes.push_back(builder.getInt8PtrTy());
argNames.clear();
retType = builder.getVoidTy();
argTypes.clear();
- argTypes.push_back(builder.getInt8Ty()->getPointerTo());
+ argTypes.push_back(builder.getInt8PtrTy());
argNames.clear();
retType = builder.getVoidTy();
argTypes.clear();
- argTypes.push_back(llvm::Type::getInt32Ty(builder.getContext()));
+ argTypes.push_back(builder.getInt32Ty());
argNames.clear();
retType = builder.getVoidTy();
argTypes.clear();
- argTypes.push_back(builder.getInt8Ty()->getPointerTo());
+ argTypes.push_back(builder.getInt8PtrTy());
argNames.clear();
// createOurException
- retType = builder.getInt8Ty()->getPointerTo();
+ retType = builder.getInt8PtrTy();
argTypes.clear();
- argTypes.push_back(llvm::Type::getInt32Ty(builder.getContext()));
+ argTypes.push_back(builder.getInt32Ty());
argNames.clear();
retType = builder.getInt32Ty();
argTypes.clear();
- argTypes.push_back(builder.getInt8Ty()->getPointerTo());
+ argTypes.push_back(builder.getInt8PtrTy());
argNames.clear();
retType = builder.getInt32Ty();
argTypes.clear();
- argTypes.push_back(builder.getInt8Ty()->getPointerTo());
+ argTypes.push_back(builder.getInt8PtrTy());
argNames.clear();
retType = builder.getInt32Ty();
argTypes.clear();
- argTypes.push_back(llvm::Type::getInt32Ty(builder.getContext()));
- argTypes.push_back(llvm::Type::getInt32Ty(builder.getContext()));
- argTypes.push_back(llvm::Type::getInt64Ty(builder.getContext()));
- argTypes.push_back(builder.getInt8Ty()->getPointerTo());
- argTypes.push_back(builder.getInt8Ty()->getPointerTo());
+ argTypes.push_back(builder.getInt32Ty());
+ argTypes.push_back(builder.getInt32Ty());
+ argTypes.push_back(builder.getInt64Ty());
+ argTypes.push_back(builder.getInt8PtrTy());
+ argTypes.push_back(builder.getInt8PtrTy());
argNames.clear();
}
// If not set, exception handling will not be turned on
- llvm::JITExceptionHandling = true;
+ llvm::TargetOptions Opts;
+ Opts.JITExceptionHandling = true;
llvm::InitializeNativeTarget();
llvm::LLVMContext &context = llvm::getGlobalContext();
llvm::EngineBuilder factory(module);
factory.setEngineKind(llvm::EngineKind::JIT);
factory.setAllocateGVsWithCode(false);
+ factory.setTargetOptions(Opts);
llvm::ExecutionEngine *executionEngine = factory.create();
{