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");