comparison ir/irlandingpad.cpp @ 319:e9c93739bc4c trunk

[svn r340] Rework exception handling to work with nested tryfinally and trycatch.
author ChristianK
date Sat, 05 Jul 2008 10:22:56 +0200
parents
children d772927ca496
comparison
equal deleted inserted replaced
318:8e570dbe4087 319:e9c93739bc4c
1 #include "gen/llvm.h"
2 #include "gen/tollvm.h"
3 #include "gen/irstate.h"
4 #include "gen/runtime.h"
5 #include "gen/logger.h"
6 #include "gen/classes.h"
7 #include "gen/llvmhelpers.h"
8 #include "ir/irlandingpad.h"
9
10 IRLandingPadInfo::IRLandingPadInfo(Catch* catchstmt, llvm::BasicBlock* end)
11 : finallyBody(NULL)
12 {
13 target = llvm::BasicBlock::Create("catch", gIR->topfunc(), end);
14 gIR->scope() = IRScope(target,end);
15
16 // assign storage to catch var
17 if(catchstmt->var) {
18 assert(!catchstmt->var->ir.irLocal);
19 catchstmt->var->ir.irLocal = new IrLocal(catchstmt->var);
20 LLValue* catch_var = gIR->func()->landingPad.getExceptionStorage();
21 catchstmt->var->ir.irLocal->value = gIR->ir->CreateBitCast(catch_var, getPtrToType(DtoType(catchstmt->var->type)));
22 }
23
24 // emit handler
25 assert(catchstmt->handler);
26 catchstmt->handler->toIR(gIR);
27
28 if (!gIR->scopereturned())
29 gIR->ir->CreateBr(end);
30
31 assert(catchstmt->type);
32 catchType = catchstmt->type->isClassHandle();
33 DtoForceDeclareDsymbol(catchType);
34 assert(catchType);
35 }
36
37 IRLandingPadInfo::IRLandingPadInfo(Statement* finallystmt)
38 : target(NULL), finallyBody(finallystmt), catchType(NULL)
39 {
40
41 }
42
43
44 void IRLandingPad::addCatch(Catch* catchstmt, llvm::BasicBlock* end)
45 {
46 unpushed_infos.push_front(IRLandingPadInfo(catchstmt, end));
47 }
48
49 void IRLandingPad::addFinally(Statement* finallystmt)
50 {
51 unpushed_infos.push_front(IRLandingPadInfo(finallystmt));
52 }
53
54 void IRLandingPad::push(llvm::BasicBlock* inBB)
55 {
56 // store infos such that matches are right to left
57 nInfos.push(infos.size());
58 infos.insert(infos.end(), unpushed_infos.begin(), unpushed_infos.end());
59 unpushed_infos.clear();
60
61 constructLandingPad(inBB);
62
63 // store as invoke target
64 padBBs.push(inBB);
65 }
66
67 void IRLandingPad::pop()
68 {
69 padBBs.pop();
70
71 size_t n = nInfos.top();
72 infos.resize(n);
73 nInfos.pop();
74 }
75
76 llvm::BasicBlock* IRLandingPad::get()
77 {
78 if(padBBs.size() == 0)
79 return NULL;
80 else
81 return padBBs.top();
82 }
83
84 void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
85 {
86 // save and rewrite scope
87 IRScope savedscope = gIR->scope();
88 gIR->scope() = IRScope(inBB,savedscope.end);
89
90 // eh_ptr = llvm.eh.exception();
91 llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception);
92 LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn);
93
94 // build selector arguments
95 LLSmallVector<LLValue*, 6> selectorargs;
96 selectorargs.push_back(eh_ptr);
97
98 llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
99 LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty));
100 selectorargs.push_back(personality_fn_arg);
101
102 bool hasFinally = false;
103 // associate increasing ints with each unique classdecl encountered
104 std::map<ClassDeclaration*, int> catchToInt;
105 std::deque<IRLandingPadInfo>::reverse_iterator it = infos.rbegin(), end = infos.rend();
106 for(size_t i = infos.size() - 1; it != end; ++it, --i)
107 {
108 if(it->finallyBody)
109 hasFinally = true;
110 else
111 {
112 if(catchToInt.find(it->catchType) == catchToInt.end())
113 {
114 int newval = catchToInt.size();
115 catchToInt[it->catchType] = newval;
116 }
117 assert(it->catchType);
118 assert(it->catchType->ir.irStruct);
119 selectorargs.push_back(it->catchType->ir.irStruct->classInfo);
120 }
121 }
122 // if there's a finally, the eh table has to have a 0 action
123 if(hasFinally)
124 selectorargs.push_back(llvm::ConstantInt::get(LLType::Int32Ty, 0));
125 // if there is a catch, store exception object
126 if(catchToInt.size())
127 {
128 const LLType* objectTy = DtoType(ClassDeclaration::object->type);
129 assert(catch_var);
130 gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var);
131 }
132
133 // eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <selectorargs>);
134 llvm::Function* eh_selector_fn;
135 if (global.params.is64bit)
136 eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i64);
137 else
138 eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i32);
139 LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end());
140
141 // emit finallys and switches that branch to catches until there are no more catches
142 // then simply branch to the finally chain
143 llvm::SwitchInst* switchinst = NULL;
144 for(it = infos.rbegin(); it != end; ++it)
145 {
146 // if it's a finally, emit its code
147 if(it->finallyBody)
148 {
149 if(switchinst)
150 switchinst = NULL;
151 it->finallyBody->toIR(gIR);
152 }
153 // otherwise it's a catch and we'll add a switch case
154 else
155 {
156 if(!switchinst)
157 {
158 switchinst = gIR->ir->CreateSwitch(eh_sel, llvm::BasicBlock::Create("switchdefault", gIR->topfunc(), gIR->scopeend()), infos.size());
159 gIR->scope() = IRScope(switchinst->getDefaultDest(), gIR->scopeend());
160 }
161 // catches matched first get the largest switchval, so do size - unique int
162 llvm::ConstantInt* switchval = llvm::ConstantInt::get(LLType::Int32Ty, catchToInt.size() - catchToInt[it->catchType]);
163 // and make sure we don't add the same switchval twice, may happen with nested trys
164 if(!switchinst->findCaseValue(switchval))
165 switchinst->addCase(switchval, it->target);
166 }
167 }
168
169 // no catch matched and all finallys executed - resume unwind
170 llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind");
171 gIR->ir->CreateCall(unwind_resume_fn, eh_ptr);
172 gIR->ir->CreateUnreachable();
173
174 gIR->scope() = savedscope;
175 }
176
177 LLValue* IRLandingPad::getExceptionStorage()
178 {
179 if(!catch_var)
180 {
181 Logger::println("Making new catch var");
182 const LLType* objectTy = DtoType(ClassDeclaration::object->type);
183 catch_var = new llvm::AllocaInst(objectTy,"catchvar",gIR->topallocapoint());
184 }
185 return catch_var;
186 }