1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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()->hasTerminator()) 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();
}
|