Mercurial > projects > ldc
comparison ir/irlandingpad.cpp @ 612:d97b017a8aef
Fix issue with EH table indices and nested try-catch.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Sun, 21 Sep 2008 17:18:35 +0200 |
parents | 672eb4893b55 |
children | 5761d7e6f628 |
comparison
equal
deleted
inserted
replaced
611:83ca663ecc20 | 612:d97b017a8aef |
---|---|
28 | 28 |
29 if (!gIR->scopereturned()) | 29 if (!gIR->scopereturned()) |
30 gIR->ir->CreateBr(end); | 30 gIR->ir->CreateBr(end); |
31 | 31 |
32 assert(catchstmt->type); | 32 assert(catchstmt->type); |
33 //TODO: Is toBasetype correct here? Should catch handlers with typedefed | |
34 // classes behave differently? | |
35 catchType = catchstmt->type->toBasetype()->isClassHandle(); | 33 catchType = catchstmt->type->toBasetype()->isClassHandle(); |
36 assert(catchType); | 34 assert(catchType); |
37 DtoForceDeclareDsymbol(catchType); | 35 DtoForceDeclareDsymbol(catchType); |
38 } | 36 } |
39 | 37 |
94 llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception); | 92 llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception); |
95 LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn); | 93 LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn); |
96 | 94 |
97 // build selector arguments | 95 // build selector arguments |
98 LLSmallVector<LLValue*, 6> selectorargs; | 96 LLSmallVector<LLValue*, 6> selectorargs; |
99 selectorargs.push_back(eh_ptr); | |
100 | 97 |
101 llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); | 98 // put in classinfos in the right order |
102 LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty)); | |
103 selectorargs.push_back(personality_fn_arg); | |
104 | |
105 bool hasFinally = false; | 99 bool hasFinally = false; |
106 // associate increasing ints with each unique classdecl encountered | 100 std::deque<IRLandingPadInfo>::iterator it = infos.begin(), end = infos.end(); |
107 std::map<ClassDeclaration*, int> catchToInt; | 101 for(; it != end; ++it) |
108 std::deque<IRLandingPadInfo>::reverse_iterator it = infos.rbegin(), end = infos.rend(); | |
109 for(size_t i = infos.size() - 1; it != end; ++it, --i) | |
110 { | 102 { |
111 if(it->finallyBody) | 103 if(it->finallyBody) |
112 hasFinally = true; | 104 hasFinally = true; |
113 else | 105 else |
114 { | 106 { |
115 if(catchToInt.find(it->catchType) == catchToInt.end()) | 107 if(catchToInt.find(it->catchType) == catchToInt.end()) |
116 { | 108 { |
117 int newval = catchToInt.size(); | 109 int newval = 1 + catchToInt.size(); |
118 catchToInt[it->catchType] = newval; | 110 catchToInt[it->catchType] = newval; |
119 } | 111 } |
120 assert(it->catchType); | 112 assert(it->catchType); |
121 assert(it->catchType->ir.irStruct); | 113 assert(it->catchType->ir.irStruct); |
122 selectorargs.push_back(it->catchType->ir.irStruct->classInfo); | 114 selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->classInfo); |
123 } | 115 } |
124 } | 116 } |
125 // if there's a finally, the eh table has to have a 0 action | 117 // if there's a finally, the eh table has to have a 0 action |
126 if(hasFinally) | 118 if(hasFinally) |
127 selectorargs.push_back(llvm::ConstantInt::get(LLType::Int32Ty, 0)); | 119 selectorargs.push_back(llvm::ConstantInt::get(LLType::Int32Ty, 0)); |
120 | |
121 // personality fn | |
122 llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); | |
123 LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty)); | |
124 selectorargs.insert(selectorargs.begin(), personality_fn_arg); | |
125 | |
126 // eh storage target | |
127 selectorargs.insert(selectorargs.begin(), eh_ptr); | |
128 | |
128 // if there is a catch and some catch allocated storage, store exception object | 129 // if there is a catch and some catch allocated storage, store exception object |
129 if(catchToInt.size() && catch_var) | 130 if(catchToInt.size() && catch_var) |
130 { | 131 { |
131 const LLType* objectTy = DtoType(ClassDeclaration::object->type); | 132 const LLType* objectTy = DtoType(ClassDeclaration::object->type); |
132 gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var); | 133 gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var); |
141 LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end()); | 142 LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end()); |
142 | 143 |
143 // emit finallys and switches that branch to catches until there are no more catches | 144 // emit finallys and switches that branch to catches until there are no more catches |
144 // then simply branch to the finally chain | 145 // then simply branch to the finally chain |
145 llvm::SwitchInst* switchinst = NULL; | 146 llvm::SwitchInst* switchinst = NULL; |
146 for(it = infos.rbegin(); it != end; ++it) | 147 std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend(); |
148 for(rit = infos.rbegin(); rit != rend; ++rit) | |
147 { | 149 { |
148 // if it's a finally, emit its code | 150 // if it's a finally, emit its code |
149 if(it->finallyBody) | 151 if(rit->finallyBody) |
150 { | 152 { |
151 if(switchinst) | 153 if(switchinst) |
152 switchinst = NULL; | 154 switchinst = NULL; |
153 | 155 |
154 // since this may be emitted multiple times | 156 // since this may be emitted multiple times |
155 // give the labels a new scope | 157 // give the labels a new scope |
156 gIR->func()->pushUniqueLabelScope("finally"); | 158 gIR->func()->pushUniqueLabelScope("finally"); |
157 it->finallyBody->toIR(gIR); | 159 rit->finallyBody->toIR(gIR); |
158 gIR->func()->popLabelScope(); | 160 gIR->func()->popLabelScope(); |
159 } | 161 } |
160 // otherwise it's a catch and we'll add a switch case | 162 // otherwise it's a catch and we'll add a switch case |
161 else | 163 else |
162 { | 164 { |
163 if(!switchinst) | 165 if(!switchinst) |
164 { | 166 { |
165 switchinst = gIR->ir->CreateSwitch(eh_sel, llvm::BasicBlock::Create("switchdefault", gIR->topfunc(), gIR->scopeend()), infos.size()); | 167 switchinst = gIR->ir->CreateSwitch(eh_sel, llvm::BasicBlock::Create("switchdefault", gIR->topfunc(), gIR->scopeend()), infos.size()); |
166 gIR->scope() = IRScope(switchinst->getDefaultDest(), gIR->scopeend()); | 168 gIR->scope() = IRScope(switchinst->getDefaultDest(), gIR->scopeend()); |
167 } | 169 } |
170 // dubious comment | |
168 // catches matched first get the largest switchval, so do size - unique int | 171 // catches matched first get the largest switchval, so do size - unique int |
169 llvm::ConstantInt* switchval = llvm::ConstantInt::get(DtoSize_t(), catchToInt.size() - catchToInt[it->catchType]); | 172 llvm::ConstantInt* switchval = llvm::ConstantInt::get(DtoSize_t(), catchToInt[rit->catchType]); |
170 // and make sure we don't add the same switchval twice, may happen with nested trys | 173 // and make sure we don't add the same switchval twice, may happen with nested trys |
171 if(!switchinst->findCaseValue(switchval)) | 174 if(!switchinst->findCaseValue(switchval)) |
172 switchinst->addCase(switchval, it->target); | 175 switchinst->addCase(switchval, rit->target); |
173 } | 176 } |
174 } | 177 } |
175 | 178 |
176 // no catch matched and all finallys executed - resume unwind | 179 // no catch matched and all finallys executed - resume unwind |
177 llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind"); | 180 llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind"); |