[svn r340] Rework exception handling to work with nested tryfinally and trycatch.

This commit is contained in:
Christian Kamm
2008-07-05 10:22:56 +02:00
parent 4fc93770a9
commit ce79feeb9b
6 changed files with 295 additions and 136 deletions

View File

@@ -172,10 +172,6 @@ struct IRState
llvm::BasicBlock* scopeend();
bool scopereturned();
// landing pads for try statements
typedef std::vector<llvm::BasicBlock*> BBVec;
BBVec landingPads;
// create a call or invoke, depending on the landing pad info
// the template function is defined further down in this file
template <typename InputIterator>
@@ -229,15 +225,16 @@ struct IRState
template <typename InputIterator>
CallOrInvoke* IRState::CreateCallOrInvoke(LLValue* Callee, InputIterator ArgBegin, InputIterator ArgEnd, const char* Name)
{
if(landingPads.empty())
return new CallOrInvoke_Call(ir->CreateCall(Callee, ArgBegin, ArgEnd, Name));
else
llvm::BasicBlock* pad;
if(pad = func()->landingPad.get())
{
llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create("postinvoke", topfunc(), scopeend());
llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, *landingPads.rbegin(), ArgBegin, ArgEnd, Name);
llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, pad, ArgBegin, ArgEnd, Name);
scope() = IRScope(postinvoke, scopeend());
return new CallOrInvoke_Invoke(invoke);
}
else
return new CallOrInvoke_Call(ir->CreateCall(Callee, ArgBegin, ArgEnd, Name));
}
#endif // LLVMDC_GEN_IRSTATE_H

View File

@@ -27,6 +27,7 @@
#include "gen/dvalue.h"
#include "ir/irfunction.h"
#include "ir/irlandingpad.h"
//////////////////////////////////////////////////////////////////////////////
@@ -497,19 +498,25 @@ void TryFinallyStatement::toIR(IRState* p)
llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend);
llvm::BasicBlock* finallybb = llvm::BasicBlock::Create("finally", p->topfunc(), oldend);
// the landing pad for statements in the try block
// only reached via eh-unwinding, a call to resume unwinding is appended
llvm::BasicBlock* unwindfinallybb = llvm::BasicBlock::Create("unwindfinally", p->topfunc(), oldend);
llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create("landingpad", p->topfunc(), oldend);
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtryfinally", p->topfunc(), oldend);
// pass the previous BB into this
assert(!gIR->scopereturned());
llvm::BranchInst::Create(trybb, p->scopebb());
//
// set up the landing pad
//
p->scope() = IRScope(landingpadbb, endbb);
gIR->func()->landingPad.addFinally(finalbody);
gIR->func()->landingPad.push(landingpadbb);
//
// do the try block
//
p->scope() = IRScope(trybb,finallybb);
p->landingPads.push_back(unwindfinallybb);
assert(body);
body->toIR(p);
@@ -518,12 +525,12 @@ void TryFinallyStatement::toIR(IRState* p)
if (!p->scopereturned())
llvm::BranchInst::Create(finallybb, p->scopebb());
p->landingPads.pop_back();
gIR->func()->landingPad.pop();
//
// do finally block
//
p->scope() = IRScope(finallybb,unwindfinallybb);
p->scope() = IRScope(finallybb,landingpadbb);
assert(finalbody);
finalbody->toIR(p);
@@ -533,39 +540,6 @@ void TryFinallyStatement::toIR(IRState* p)
llvm::BranchInst::Create(endbb, p->scopebb());
}
//
// do landing pad
//
p->scope() = IRScope(unwindfinallybb,endbb);
// eh_ptr = llvm.eh.exception();
llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception);
LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn);
// eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, 0);
llvm::Function* eh_selector_fn;
if (global.params.is64bit)
eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i64);
else
eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i32);
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty));
LLValue* eh_sel = gIR->ir->CreateCall3(eh_selector_fn, eh_ptr, personality_fn_arg, llvm::ConstantInt::get(LLType::Int32Ty, 0));
// emit finally code
finalbody->toIR(p);
// finally code may not be terminated!
if (gIR->scopereturned()) {
error("finally blocks may not be terminated", loc.toChars());
fatal();
}
llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind");
gIR->ir->CreateCall(unwind_resume_fn, eh_ptr);
gIR->ir->CreateUnreachable();
// rewrite the scope
p->scope() = IRScope(endbb,oldend);
}
@@ -592,11 +566,24 @@ void TryCatchStatement::toIR(IRState* p)
assert(!gIR->scopereturned());
llvm::BranchInst::Create(trybb, p->scopebb());
//
// do catches and the landing pad
//
assert(catches);
gIR->scope() = IRScope(landingpadbb, endbb);
for (int i = 0; i < catches->dim; i++)
{
Catch *c = (Catch *)catches->data[i];
gIR->func()->landingPad.addCatch(c, endbb);
}
gIR->func()->landingPad.push(landingpadbb);
//
// do the try block
//
p->scope() = IRScope(trybb,landingpadbb);
p->landingPads.push_back(landingpadbb);
assert(body);
body->toIR(p);
@@ -604,94 +591,7 @@ void TryCatchStatement::toIR(IRState* p)
if (!gIR->scopereturned())
llvm::BranchInst::Create(endbb, p->scopebb());
p->landingPads.pop_back();
//
// do catches
//
assert(catches);
// get storage for exception var
const LLType* objectTy = DtoType(ClassDeclaration::object->type);
llvm::AllocaInst* catch_var = new llvm::AllocaInst(objectTy,"catchvar",p->topallocapoint());
// for further reference in landing pad
LLSmallVector<llvm::BasicBlock*,4> catch_bbs;
for (int i = 0; i < catches->dim; i++)
{
Catch *c = (Catch *)catches->data[i];
llvm::BasicBlock* catchbb = llvm::BasicBlock::Create("catch", p->topfunc(), oldend);
catch_bbs.push_back(catchbb);
p->scope() = IRScope(catchbb,oldend);
// assign storage to catch var
if(c->var) {
assert(!c->var->ir.irLocal);
c->var->ir.irLocal = new IrLocal(c->var);
c->var->ir.irLocal->value = gIR->ir->CreateBitCast(catch_var, getPtrToType(DtoType(c->var->type)));
}
// emit handler
assert(c->handler);
c->handler->toIR(p);
if (!gIR->scopereturned())
llvm::BranchInst::Create(endbb, p->scopebb());
}
//
// do landing pad
//
p->scope() = IRScope(landingpadbb,endbb);
// eh_ptr = llvm.eh.exception();
llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception);
LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn);
// store eh_ptr in catch_var
gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var);
// eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <classinfos>);
llvm::Function* eh_selector_fn;
if (global.params.is64bit)
eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i64);
else
eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i32);
LLSmallVector<LLValue*,4> args;
args.push_back(eh_ptr);
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
args.push_back(gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty)));
for (int i = 0; i < catches->dim; i++)
{
Catch *c = (Catch *)catches->data[i];
assert(c->type);
ClassDeclaration* cdecl = c->type->isClassHandle();
assert(cdecl);
assert(cdecl->ir.irStruct);
args.push_back(cdecl->ir.irStruct->classInfo);
}
LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, args.begin(), args.end());
// switch on eh_sel and branch to correct case
// setup default target
llvm::BasicBlock* defaulttarget = llvm::BasicBlock::Create("default", p->topfunc(), oldend);
//TODO: Error handling?
new llvm::UnreachableInst(defaulttarget);
llvm::SwitchInst* sw = p->ir->CreateSwitch(eh_sel, defaulttarget, catch_bbs.size());
// add all catches as cases
for(unsigned int c = 0; c < catch_bbs.size(); ++c)
{
llvm::BasicBlock* casebb = llvm::BasicBlock::Create("case", p->topfunc(), oldend);
llvm::BranchInst::Create(catch_bbs[c], casebb);
sw->addCase(llvm::ConstantInt::get(LLType::Int32Ty, c+1), casebb);
}
gIR->func()->landingPad.pop();
// rewrite the scope
p->scope() = IRScope(endbb,oldend);