mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-07 03:16:05 +03:00
179 lines
6.1 KiB
C++
179 lines
6.1 KiB
C++
#include "gen/llvm.h"
|
|
#include "gen/tollvm.h"
|
|
#include "gen/irstate.h"
|
|
#include "gen/runtime.h"
|
|
#include "gen/logger.h"
|
|
#include "gen/classes.h"
|
|
#include "gen/llvmhelpers.h"
|
|
#include "ir/irlandingpad.h"
|
|
|
|
IRLandingPadInfo::IRLandingPadInfo(Catch* catchstmt, llvm::BasicBlock* end)
|
|
: finallyBody(NULL)
|
|
{
|
|
target = llvm::BasicBlock::Create(gIR->context(), "catch", gIR->topfunc(), end);
|
|
gIR->scope() = IRScope(target,end);
|
|
|
|
// assign storage to catch var
|
|
if(catchstmt->var) {
|
|
// use the same storage for all exceptions that are not accessed in
|
|
// nested functions
|
|
#if DMDV2
|
|
if(!catchstmt->var->nestedrefs.dim) {
|
|
#else
|
|
if(!catchstmt->var->nestedref) {
|
|
#endif
|
|
assert(!catchstmt->var->ir.irLocal);
|
|
catchstmt->var->ir.irLocal = new IrLocal(catchstmt->var);
|
|
LLValue* catch_var = gIR->func()->gen->landingPadInfo.getExceptionStorage();
|
|
catchstmt->var->ir.irLocal->value = gIR->ir->CreateBitCast(catch_var, getPtrToType(DtoType(catchstmt->var->type)));
|
|
}
|
|
|
|
// this will alloca if we haven't already and take care of nested refs
|
|
DtoDeclarationExp(catchstmt->var);
|
|
|
|
// the exception will only be stored in catch_var. copy it over if necessary
|
|
if(catchstmt->var->ir.irLocal->value != gIR->func()->gen->landingPadInfo.getExceptionStorage()) {
|
|
LLValue* exc = gIR->ir->CreateBitCast(DtoLoad(gIR->func()->gen->landingPadInfo.getExceptionStorage()), DtoType(catchstmt->var->type));
|
|
DtoStore(exc, catchstmt->var->ir.irLocal->value);
|
|
}
|
|
}
|
|
|
|
// emit handler, if there is one
|
|
// handler is zero for instance for 'catch { debug foo(); }'
|
|
if(catchstmt->handler)
|
|
catchstmt->handler->toIR(gIR);
|
|
|
|
if (!gIR->scopereturned())
|
|
gIR->ir->CreateBr(end);
|
|
|
|
assert(catchstmt->type);
|
|
catchType = catchstmt->type->toBasetype()->isClassHandle();
|
|
assert(catchType);
|
|
catchType->codegen(Type::sir);
|
|
}
|
|
|
|
IRLandingPadInfo::IRLandingPadInfo(Statement* finallystmt)
|
|
: target(NULL), finallyBody(finallystmt), catchType(NULL)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
void IRLandingPad::addCatch(Catch* catchstmt, llvm::BasicBlock* end)
|
|
{
|
|
unpushed_infos.push_front(IRLandingPadInfo(catchstmt, end));
|
|
}
|
|
|
|
void IRLandingPad::addFinally(Statement* finallystmt)
|
|
{
|
|
unpushed_infos.push_front(IRLandingPadInfo(finallystmt));
|
|
}
|
|
|
|
void IRLandingPad::push(llvm::BasicBlock* inBB)
|
|
{
|
|
// store infos such that matches are right to left
|
|
nInfos.push(infos.size());
|
|
infos.insert(infos.end(), unpushed_infos.begin(), unpushed_infos.end());
|
|
unpushed_infos.clear();
|
|
|
|
constructLandingPad(inBB);
|
|
|
|
// store as invoke target
|
|
padBBs.push(inBB);
|
|
}
|
|
|
|
void IRLandingPad::pop()
|
|
{
|
|
padBBs.pop();
|
|
|
|
size_t n = nInfos.top();
|
|
infos.resize(n);
|
|
nInfos.pop();
|
|
}
|
|
|
|
llvm::BasicBlock* IRLandingPad::get()
|
|
{
|
|
if(padBBs.size() == 0)
|
|
return NULL;
|
|
else
|
|
return padBBs.top();
|
|
}
|
|
|
|
void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
|
|
{
|
|
// save and rewrite scope
|
|
IRScope savedscope = gIR->scope();
|
|
gIR->scope() = IRScope(inBB,savedscope.end);
|
|
|
|
// personality fn
|
|
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
|
|
// create landingpad
|
|
LLType *retType = LLStructType::get(LLType::getInt8PtrTy(gIR->context()), LLType::getInt32Ty(gIR->context()), NULL);
|
|
llvm::LandingPadInst *landingPad = gIR->ir->CreateLandingPad(retType, personality_fn, 0);
|
|
LLValue* eh_ptr = DtoExtractValue(landingPad, 0);
|
|
LLValue* eh_sel = DtoExtractValue(landingPad, 1);
|
|
|
|
// add landingpad clauses, emit finallys and 'if' chain to catch the exception
|
|
llvm::Function* eh_typeid_for_fn = GET_INTRINSIC_DECL(eh_typeid_for);
|
|
std::deque<IRLandingPadInfo> infos = this->infos;
|
|
std::stack<size_t> nInfos = this->nInfos;
|
|
std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend();
|
|
bool isFirstCatch = true;
|
|
for(rit = infos.rbegin(); rit != rend; ++rit)
|
|
{
|
|
// if it's a finally, emit its code
|
|
if(rit->finallyBody)
|
|
{
|
|
size_t n = this->nInfos.top();
|
|
this->infos.resize(n);
|
|
this->nInfos.pop();
|
|
rit->finallyBody->toIR(gIR);
|
|
landingPad->setCleanup(true);
|
|
}
|
|
// otherwise it's a catch and we'll add a if-statement
|
|
else
|
|
{
|
|
// if it is a first catch and some catch allocated storage, store exception object
|
|
if(isFirstCatch && catch_var)
|
|
{
|
|
LLType* objectTy = DtoType(ClassDeclaration::object->type);
|
|
gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var);
|
|
isFirstCatch = false;
|
|
}
|
|
// create next block
|
|
llvm::BasicBlock *next = llvm::BasicBlock::Create(gIR->context(), "eh.next", gIR->topfunc(), gIR->scopeend());
|
|
// get class info symbol
|
|
LLValue *classInfo = rit->catchType->ir.irStruct->getClassInfoSymbol();
|
|
// add that symbol as landing pad clause
|
|
landingPad->addClause(classInfo);
|
|
// call llvm.eh.typeid.for to get class info index in the exception table
|
|
classInfo = DtoBitCast(classInfo, getPtrToType(DtoType(Type::tint8)));
|
|
LLValue *eh_id = gIR->ir->CreateCall(eh_typeid_for_fn, classInfo);
|
|
// check exception selector (eh_sel) against the class info index
|
|
gIR->ir->CreateCondBr(gIR->ir->CreateICmpEQ(eh_sel, eh_id), rit->target, next);
|
|
gIR->scope() = IRScope(next, gIR->scopeend());
|
|
}
|
|
}
|
|
|
|
// restore landing pad infos
|
|
this->infos = infos;
|
|
this->nInfos = nInfos;
|
|
|
|
// no catch matched and all finallys executed - resume unwind
|
|
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();
|
|
|
|
// restore scope
|
|
gIR->scope() = savedscope;
|
|
}
|
|
|
|
LLValue* IRLandingPad::getExceptionStorage()
|
|
{
|
|
if(!catch_var)
|
|
{
|
|
Logger::println("Making new catch var");
|
|
catch_var = DtoAlloca(ClassDeclaration::object->type, "catchvar");
|
|
}
|
|
return catch_var;
|
|
}
|