17
17
#include " gen/tollvm.h"
18
18
#include " ir/irlandingpad.h"
19
19
20
- IRLandingPadInfo::IRLandingPadInfo (Catch* catchstmt_, llvm::BasicBlock* end_) :
21
- finallyBody( NULL ), catchstmt (catchstmt_), end(end_)
20
+ IRLandingPadCatchInfo::IRLandingPadCatchInfo (Catch* catchstmt_, llvm::BasicBlock* end_) :
21
+ catchStmt (catchstmt_), end(end_)
22
22
{
23
23
target = llvm::BasicBlock::Create (gIR ->context (), " catch" , gIR ->topfunc (), end);
24
24
25
- assert (catchstmt ->type );
26
- catchType = catchstmt ->type ->toBasetype ()->isClassHandle ();
25
+ assert (catchStmt ->type );
26
+ catchType = catchStmt ->type ->toBasetype ()->isClassHandle ();
27
27
assert (catchType);
28
28
catchType->codegen (Type::sir);
29
29
30
- if (catchstmt ->var ) {
31
- if (!catchstmt ->var ->nestedrefs .dim ) {
32
- gIR ->func ()->gen ->landingPadInfo .getExceptionStorage ();
33
- }
30
+ if (catchStmt ->var ) {
31
+ if (!catchStmt ->var ->nestedrefs .dim ) {
32
+ gIR ->func ()->gen ->landingPadInfo .getExceptionStorage ();
33
+ }
34
34
}
35
35
}
36
36
37
- IRLandingPadInfo::IRLandingPadInfo (Statement* finallystmt) :
38
- target(NULL ), finallyBody(finallystmt), catchstmt(NULL )
39
- {
40
-
41
- }
42
-
43
- void IRLandingPadInfo::toIR ()
37
+ void IRLandingPadCatchInfo::toIR ()
44
38
{
45
- if (!catchstmt )
39
+ if (!catchStmt )
46
40
return ;
47
41
48
42
gIR ->scope () = IRScope (target, target);
49
- DtoDwarfBlockStart (catchstmt ->loc );
43
+ DtoDwarfBlockStart (catchStmt ->loc );
50
44
51
45
// assign storage to catch var
52
- if (catchstmt ->var ) {
46
+ if (catchStmt ->var ) {
53
47
// use the same storage for all exceptions that are not accessed in
54
48
// nested functions
55
- if (!catchstmt ->var ->nestedrefs .dim ) {
56
- assert (!catchstmt ->var ->ir .irLocal );
57
- catchstmt ->var ->ir .irLocal = new IrLocal (catchstmt ->var );
49
+ if (!catchStmt ->var ->nestedrefs .dim ) {
50
+ assert (!catchStmt ->var ->ir .irLocal );
51
+ catchStmt ->var ->ir .irLocal = new IrLocal (catchStmt ->var );
58
52
LLValue* catch_var = gIR ->func ()->gen ->landingPadInfo .getExceptionStorage ();
59
- catchstmt ->var ->ir .irLocal ->value = gIR ->ir ->CreateBitCast (catch_var, getPtrToType (DtoType (catchstmt ->var ->type )));
53
+ catchStmt ->var ->ir .irLocal ->value = gIR ->ir ->CreateBitCast (catch_var, getPtrToType (DtoType (catchStmt ->var ->type )));
60
54
}
61
55
62
56
// this will alloca if we haven't already and take care of nested refs
63
- DtoDeclarationExp (catchstmt ->var );
57
+ DtoDeclarationExp (catchStmt ->var );
64
58
65
59
// the exception will only be stored in catch_var. copy it over if necessary
66
- if (catchstmt ->var ->ir .irLocal ->value != gIR ->func ()->gen ->landingPadInfo .getExceptionStorage ()) {
67
- LLValue* exc = gIR ->ir ->CreateBitCast (DtoLoad (gIR ->func ()->gen ->landingPadInfo .getExceptionStorage ()), DtoType (catchstmt ->var ->type ));
68
- DtoStore (exc, catchstmt ->var ->ir .irLocal ->value );
60
+ if (catchStmt ->var ->ir .irLocal ->value != gIR ->func ()->gen ->landingPadInfo .getExceptionStorage ()) {
61
+ LLValue* exc = gIR ->ir ->CreateBitCast (DtoLoad (gIR ->func ()->gen ->landingPadInfo .getExceptionStorage ()), DtoType (catchStmt ->var ->type ));
62
+ DtoStore (exc, catchStmt ->var ->ir .irLocal ->value );
69
63
}
70
64
}
71
65
72
66
// emit handler, if there is one
73
67
// handler is zero for instance for 'catch { debug foo(); }'
74
- if (catchstmt ->handler )
75
- catchstmt ->handler ->toIR (gIR );
68
+ if (catchStmt ->handler )
69
+ catchStmt ->handler ->toIR (gIR );
76
70
77
71
if (!gIR ->scopereturned ())
78
72
gIR ->ir ->CreateBr (end);
79
73
80
74
DtoDwarfBlockEnd ();
81
75
}
82
76
83
-
84
77
void IRLandingPad::addCatch (Catch* catchstmt, llvm::BasicBlock* end)
85
78
{
86
- unpushed_infos. push_front ( IRLandingPadInfo (catchstmt, end));
79
+ unpushedScope. catches . push_back ( IRLandingPadCatchInfo (catchstmt, end));
87
80
}
88
81
89
82
void IRLandingPad::addFinally (Statement* finallystmt)
90
83
{
91
- unpushed_infos.push_front (IRLandingPadInfo (finallystmt));
84
+ assert (unpushedScope.finallyBody == NULL && " only one finally per try-finally block" );
85
+ unpushedScope.finallyBody = finallystmt;
92
86
}
93
87
94
88
void IRLandingPad::push (llvm::BasicBlock* inBB)
95
89
{
96
- // store infos such that matches are right to left
97
- nInfos.push (infos.size ());
98
- infos.insert (infos.end (), unpushed_infos.begin (), unpushed_infos.end ());
99
- unpushed_infos.clear ();
100
-
101
- // store as invoke target
102
- padBBs.push (inBB);
90
+ unpushedScope.target = inBB;
91
+ scopeStack.push (unpushedScope);
92
+ unpushedScope = IRLandingPadScope ();
103
93
gIR ->func ()->gen ->landingPad = get ();
104
94
}
105
95
106
96
void IRLandingPad::pop ()
107
97
{
108
- llvm::BasicBlock *inBB = padBBs .top ();
109
- padBBs .pop ();
98
+ IRLandingPadScope scope = scopeStack .top ();
99
+ scopeStack .pop ();
110
100
gIR ->func ()->gen ->landingPad = get ();
111
101
112
- size_t n = nInfos.top ();
113
- for (int i = n, c = infos.size (); i < c; ++i)
114
- infos.at (i).toIR ();
115
- constructLandingPad (inBB);
116
-
117
- infos.resize (n);
118
- nInfos.pop ();
102
+ std::deque<IRLandingPadCatchInfo>::iterator itr, end = scope.catches .end ();
103
+ for (itr = scope.catches .begin (); itr != end; ++itr)
104
+ itr->toIR ();
105
+ constructLandingPad (scope);
119
106
}
120
107
121
108
llvm::BasicBlock* IRLandingPad::get ()
122
109
{
123
- if (padBBs .size () == 0 )
110
+ if (scopeStack .size () == 0 )
124
111
return NULL ;
125
112
else
126
- return padBBs .top ();
113
+ return scopeStack .top (). target ;
127
114
}
128
115
129
- void IRLandingPad::constructLandingPad (llvm::BasicBlock* inBB)
116
+ // creates new landing pad
117
+ static llvm::LandingPadInst *createLandingPadInst ()
118
+ {
119
+ llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction (gIR ->module , " _d_eh_personality" );
120
+ LLType *retType = LLStructType::get (LLType::getInt8PtrTy (gIR ->context ()),
121
+ LLType::getInt32Ty (gIR ->context ()),
122
+ NULL );
123
+ return gIR ->ir ->CreateLandingPad (retType, personality_fn, 0 , " landing_pad" );
124
+ }
125
+
126
+ void IRLandingPad::constructLandingPad (IRLandingPadScope scope)
130
127
{
131
128
// save and rewrite scope
132
- IRScope savedscope = gIR ->scope ();
133
- gIR ->scope () = IRScope (inBB,savedscope .end );
129
+ IRScope savedIRScope = gIR ->scope ();
130
+ gIR ->scope () = IRScope (scope. target , savedIRScope .end );
134
131
135
- // personality fn
136
- llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction (gIR ->module , " _d_eh_personality" );
137
132
// create landingpad
138
- LLType *retType = LLStructType::get (LLType::getInt8PtrTy (gIR ->context ()), LLType::getInt32Ty (gIR ->context ()), NULL );
139
- llvm::LandingPadInst *landingPad = gIR ->ir ->CreateLandingPad (retType, personality_fn, 0 );
133
+ llvm::LandingPadInst *landingPad = createLandingPadInst ();
140
134
LLValue* eh_ptr = DtoExtractValue (landingPad, 0 );
141
135
LLValue* eh_sel = DtoExtractValue (landingPad, 1 );
142
136
143
137
// add landingpad clauses, emit finallys and 'if' chain to catch the exception
144
138
llvm::Function* eh_typeid_for_fn = GET_INTRINSIC_DECL (eh_typeid_for);
145
- std::deque<IRLandingPadInfo> infos = this ->infos ;
146
- std::stack<size_t > nInfos = this ->nInfos ;
147
- std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend ();
148
139
bool isFirstCatch = true ;
149
- for (rit = infos.rbegin (); rit != rend; ++rit)
150
- {
151
- // if it's a finally, emit its code
152
- if (rit->finallyBody )
153
- {
154
- size_t n = this ->nInfos .top ();
155
- this ->infos .resize (n);
156
- this ->nInfos .pop ();
157
- rit->finallyBody ->toIR (gIR );
158
- landingPad->setCleanup (true );
159
- }
160
- // otherwise it's a catch and we'll add a if-statement
161
- else
162
- {
140
+ std::stack<IRLandingPadScope> savedScopeStack = scopeStack;
141
+ std::deque<IRLandingPadCatchInfo>::iterator catchItr, catchItrEnd;
142
+ while (true ) {
143
+ catchItr = scope.catches .begin ();
144
+ catchItrEnd = scope.catches .end ();
145
+ for (; catchItr != catchItrEnd; ++catchItr) {
163
146
// if it is a first catch and some catch allocated storage, store exception object
164
- if (isFirstCatch && catch_var)
165
- {
147
+ if (isFirstCatch && catch_var) {
166
148
// eh_ptr is a pointer to _d_exception, which has a reference
167
149
// to the Throwable object at offset 0.
168
150
LLType *objectPtrTy = DtoType (ClassDeclaration::object->type ->pointerTo ());
@@ -173,35 +155,64 @@ void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
173
155
// create next block
174
156
llvm::BasicBlock *next = llvm::BasicBlock::Create (gIR ->context (), " eh.next" , gIR ->topfunc (), gIR ->scopeend ());
175
157
// get class info symbol
176
- LLValue *classInfo = rit ->catchType ->ir .irAggr ->getClassInfoSymbol ();
158
+ LLValue *classInfo = catchItr ->catchType ->ir .irAggr ->getClassInfoSymbol ();
177
159
// add that symbol as landing pad clause
178
160
landingPad->addClause (classInfo);
179
161
// call llvm.eh.typeid.for to get class info index in the exception table
180
162
classInfo = DtoBitCast (classInfo, getPtrToType (DtoType (Type::tint8)));
181
163
LLValue *eh_id = gIR ->ir ->CreateCall (eh_typeid_for_fn, classInfo);
182
164
// check exception selector (eh_sel) against the class info index
183
- gIR ->ir ->CreateCondBr (gIR ->ir ->CreateICmpEQ (eh_sel, eh_id), rit ->target , next);
165
+ gIR ->ir ->CreateCondBr (gIR ->ir ->CreateICmpEQ (eh_sel, eh_id), catchItr ->target , next);
184
166
gIR ->scope () = IRScope (next, gIR ->scopeend ());
185
167
}
168
+
169
+ if (scope.finallyBody ) {
170
+ // create collision landing pad that handles exceptions thrown inside the finally block
171
+ llvm::BasicBlock *collision = llvm::BasicBlock::Create (gIR ->context (), " eh.collision" , gIR ->topfunc (), gIR ->scopeend ());
172
+ llvm::BasicBlock *bb = gIR ->scopebb ();
173
+ gIR ->scope () = IRScope (collision, gIR ->scopeend ());
174
+ llvm::LandingPadInst *collisionLandingPad = createLandingPadInst ();
175
+ LLValue* collision_eh_ptr = DtoExtractValue (collisionLandingPad, 0 );
176
+ collisionLandingPad->setCleanup (true );
177
+ llvm::Function* collision_fn = LLVM_D_GetRuntimeFunction (gIR ->module , " _d_eh_handle_collision" );
178
+ gIR ->CreateCallOrInvoke2 (collision_fn, collision_eh_ptr, eh_ptr);
179
+ gIR ->ir ->CreateUnreachable ();
180
+ gIR ->scope () = IRScope (bb, gIR ->scopeend ());
181
+
182
+ // set collision landing pad as unwind target and emit the body of the finally
183
+ DtoDwarfBlockStart (scope.finallyBody ->loc );
184
+ scopeStack.push (IRLandingPadScope (collision));
185
+ gIR ->func ()->gen ->landingPad = collision;
186
+ scope.finallyBody ->toIR (gIR );
187
+ scopeStack.pop ();
188
+ gIR ->func ()->gen ->landingPad = get ();
189
+ DtoDwarfBlockEnd ();
190
+ landingPad->setCleanup (true );
191
+ }
192
+
193
+ if (scopeStack.empty ())
194
+ break ;
195
+ scope = scopeStack.top ();
196
+ scopeStack.pop ();
197
+ gIR ->func ()->gen ->landingPad = get ();
186
198
}
187
199
188
200
// restore landing pad infos
189
- this -> infos = infos ;
190
- this -> nInfos = nInfos ;
201
+ scopeStack = savedScopeStack ;
202
+ gIR -> func ()-> gen -> landingPad = get () ;
191
203
192
204
// no catch matched and all finallys executed - resume unwind
193
205
llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction (gIR ->module , " _d_eh_resume_unwind" );
194
206
gIR ->ir ->CreateCall (unwind_resume_fn, eh_ptr);
195
207
gIR ->ir ->CreateUnreachable ();
196
208
197
209
// restore scope
198
- gIR ->scope () = savedscope ;
210
+ gIR ->scope () = savedIRScope ;
199
211
}
200
212
201
213
LLValue* IRLandingPad::getExceptionStorage ()
202
214
{
203
- if (!catch_var)
204
- {
215
+ if (!catch_var) {
205
216
Logger::println (" Making new catch var" );
206
217
catch_var = DtoAlloca (ClassDeclaration::object->type , " catchvar" );
207
218
}
0 commit comments