aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/ExceptionHandler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/ExceptionHandler.cc')
-rw-r--r--lib/CodeGen/ExceptionHandler.cc128
1 files changed, 128 insertions, 0 deletions
diff --git a/lib/CodeGen/ExceptionHandler.cc b/lib/CodeGen/ExceptionHandler.cc
new file mode 100644
index 0000000..048f8a6
--- /dev/null
+++ b/lib/CodeGen/ExceptionHandler.cc
@@ -0,0 +1,128 @@
+#include "cps/ExceptionHandler.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include <cassert>
+
+using namespace llvm;
+using namespace cps;
+
+void ExceptionHandler::ensureRuntime() {
+ if (IntTypeInfo) return;
+ auto *Ptr = PointerType::getUnqual(Context);
+ auto *Void = Type::getVoidTy(Context);
+ Allocate = Module.getOrInsertFunction("__cxa_allocate_exception",
+ FunctionType::get(Ptr, {Type::getInt64Ty(Context)}, false));
+ Throw = Module.getOrInsertFunction("__cxa_throw",
+ FunctionType::get(Void, {Ptr, Ptr, Ptr}, false));
+ BeginCatch = Module.getOrInsertFunction("__cxa_begin_catch",
+ FunctionType::get(Ptr, {Ptr}, false));
+ EndCatch = Module.getOrInsertFunction("__cxa_end_catch",
+ FunctionType::get(Void, false));
+#if defined(__SEH__)
+ const char *PersonalityName = "__gxx_personality_seh0";
+#elif defined(__USING_SJLJ_EXCEPTIONS__)
+ const char *PersonalityName = "__gxx_personality_sj0";
+#else
+ const char *PersonalityName = "__gxx_personality_v0";
+#endif
+ Personality = Module.getOrInsertFunction(PersonalityName,
+ FunctionType::get(Type::getInt32Ty(Context), true));
+ IntTypeInfo = new GlobalVariable(Module, Ptr, true, GlobalValue::ExternalLinkage,
+ nullptr, "_ZTIi");
+ cast<Function>(Allocate.getCallee())->setDoesNotThrow();
+ cast<Function>(BeginCatch.getCallee())->setDoesNotThrow();
+ // Only anonymous integer exceptions are thrown; there is no throwing
+ // exception-object destructor to invoke when a catch ends.
+ cast<Function>(EndCatch.getCallee())->setDoesNotThrow();
+ cast<Function>(Throw.getCallee())->setDoesNotReturn();
+}
+
+void ExceptionHandler::prepareFunction(Function *F) {
+ F->setUWTableKind(UWTableKind::Default);
+}
+
+void ExceptionHandler::pushHandler(BasicBlock *Target) {
+ auto *F = Builder.GetInsertBlock()->getParent();
+ IRBuilder<> Entry(&F->getEntryBlock(), F->getEntryBlock().begin());
+ auto *Exception = Entry.CreateAlloca(PointerType::getUnqual(Context), nullptr,
+ "caught_exception");
+ auto &State = States[F];
+ State.Handlers.push_back({Target, Exception, State.CatchDepth});
+}
+
+AllocaInst *ExceptionHandler::popHandler() {
+ auto &Handlers = States[Builder.GetInsertBlock()->getParent()].Handlers;
+ assert(!Handlers.empty());
+ auto *Exception = Handlers.back().Exception;
+ Handlers.pop_back();
+ return Exception;
+}
+
+void ExceptionHandler::beginCatch(AllocaInst *Exception) {
+ ensureRuntime();
+ auto *Ptr = Builder.CreateLoad(PointerType::getUnqual(Context), Exception);
+ Builder.CreateCall(BeginCatch, {Ptr});
+ ++States[Builder.GetInsertBlock()->getParent()].CatchDepth;
+}
+
+void ExceptionHandler::endCatch() {
+ auto &Depth = States[Builder.GetInsertBlock()->getParent()].CatchDepth;
+ assert(Depth != 0);
+ --Depth;
+ if (!Builder.GetInsertBlock()->getTerminator()) Builder.CreateCall(EndCatch);
+}
+
+void ExceptionHandler::emitReturnCleanup() {
+ auto &State = States[Builder.GetInsertBlock()->getParent()];
+ for (unsigned I = 0; I < State.CatchDepth; ++I) Builder.CreateCall(EndCatch);
+}
+
+BasicBlock *ExceptionHandler::emitUnwindDestination() {
+ auto *F = Builder.GetInsertBlock()->getParent();
+ auto &State = States[F];
+ if (State.Handlers.empty() && State.CatchDepth == 0) return nullptr;
+ ensureRuntime();
+ F->setPersonalityFn(cast<Constant>(Personality.getCallee()));
+ auto Saved = Builder.saveIP();
+ auto *Unwind = BasicBlock::Create(Context, "exception_unwind", F);
+ Builder.SetInsertPoint(Unwind);
+ auto *LPType = StructType::get(PointerType::getUnqual(Context), Type::getInt32Ty(Context));
+ auto *LP = Builder.CreateLandingPad(LPType, 1, "exception");
+ const Handler *Handler = State.Handlers.empty() ? nullptr : &State.Handlers.back();
+ unsigned TargetDepth = Handler ? Handler->CatchDepth : 0;
+ if (Handler) LP->addClause(ConstantPointerNull::get(PointerType::getUnqual(Context)));
+ if (State.CatchDepth > TargetDepth) LP->setCleanup(true);
+ // Finish catches we are leaving before entering the outer handler (or
+ // resuming propagation through a function with no local handler).
+ for (unsigned I = TargetDepth; I < State.CatchDepth; ++I) Builder.CreateCall(EndCatch);
+ if (Handler) {
+ Builder.CreateStore(Builder.CreateExtractValue(LP, 0), Handler->Exception);
+ Builder.CreateBr(Handler->Target);
+ } else {
+ Builder.CreateResume(LP);
+ }
+ Builder.restoreIP(Saved);
+ return Unwind;
+}
+
+Value *ExceptionHandler::emitCall(FunctionCallee Callee, ArrayRef<Value *> Args,
+ const Twine &Name) {
+ auto *Unwind = emitUnwindDestination();
+ if (!Unwind) return Builder.CreateCall(Callee, Args, Name);
+ auto *Cont = BasicBlock::Create(Context, "invoke_cont", Builder.GetInsertBlock()->getParent());
+ auto *Call = Builder.CreateInvoke(Callee, Cont, Unwind, Args, Name);
+ Builder.SetInsertPoint(Cont);
+ return Call;
+}
+
+void ExceptionHandler::emitThrow() {
+ ensureRuntime();
+ // sizeof(int) is a target-folded null GEP, as for every other allocation.
+ auto *I32 = Type::getInt32Ty(Context);
+ auto *Null = ConstantPointerNull::get(PointerType::getUnqual(Context));
+ auto *Size = ConstantExpr::getSizeOf(I32);
+ auto *Object = Builder.CreateCall(Allocate, {Size}, "anonymous_exception");
+ Builder.CreateStore(ConstantInt::get(I32, 0), Object);
+ emitCall(Throw, {Object, IntTypeInfo, Null});
+ Builder.CreateUnreachable();
+}