From 9f0b3fb062111ddd73098b07ca40361d4c9e4e66 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Wed, 2 Jul 2008 22:20:18 +0200 Subject: [PATCH] [svn r335] The basics of exception handling are in place. Still need to make sure calls are turned into invokes everywhere. (NewExpression for instance) Still some rough edges and corner cases to figure out. Needs testing! --- gen/irstate.h | 5 +- gen/runtime.cpp | 26 +++ gen/statements.cpp | 152 ++++++++++++++++-- gen/toir.cpp | 94 ++++++++--- tango/lib/compiler/llvmdc/eh.d | 285 ++++++++++++++++++++++++++++++++- 5 files changed, 520 insertions(+), 42 deletions(-) diff --git a/gen/irstate.h b/gen/irstate.h index 7c67e4f2..13420561 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -136,8 +136,11 @@ struct IRState llvm::BasicBlock* scopeend(); bool scopereturned(); + // landing pads for try statements + typedef std::vector BBVec; + BBVec landingPads; + // loop blocks - typedef std::vector BBVec; typedef std::vector LoopScopeVec; LoopScopeVec loopbbs; diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 33dee756..29113154 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -880,4 +880,30 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); } + + ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + + // int _d_eh_personality(int ver, int actions, ulong eh_class, ptr eh_info, ptr context) + { + std::string fname("_d_eh_personality"); + std::vector types; + types.push_back(intTy); + types.push_back(intTy); + types.push_back(longTy); + types.push_back(voidPtrTy); + types.push_back(voidPtrTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + } + + // void _d_eh_resume_unwind(ptr exc_struct) + { + std::string fname("_d_eh_resume_unwind"); + std::vector types; + types.push_back(voidPtrTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + } } diff --git a/gen/statements.cpp b/gen/statements.cpp index 34f7d57c..58113042 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -496,14 +496,20 @@ 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* endbb = llvm::BasicBlock::Create("endtryfinally", p->topfunc(), oldend); // pass the previous BB into this assert(!gIR->scopereturned()); llvm::BranchInst::Create(trybb, p->scopebb()); + // // do the try block + // p->scope() = IRScope(trybb,finallybb); + p->landingPads.push_back(unwindfinallybb); assert(body); body->toIR(p); @@ -512,16 +518,54 @@ void TryFinallyStatement::toIR(IRState* p) if (!p->scopereturned()) llvm::BranchInst::Create(finallybb, p->scopebb()); + p->landingPads.pop_back(); + + // // do finally block - p->scope() = IRScope(finallybb,endbb); + // + p->scope() = IRScope(finallybb,unwindfinallybb); assert(finalbody); finalbody->toIR(p); // terminate finally + //TODO: isn't it an error to have a 'returned' finally block? if (!gIR->scopereturned()) { 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); } @@ -533,8 +577,6 @@ void TryCatchStatement::toIR(IRState* p) Logger::println("TryCatchStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; - Logger::attention(loc, "try-catch is not yet fully implemented"); - if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); @@ -542,30 +584,114 @@ void TryCatchStatement::toIR(IRState* p) llvm::BasicBlock* oldend = p->scopeend(); llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend); - llvm::BasicBlock* catchbb = llvm::BasicBlock::Create("catch", p->topfunc(), oldend); + // the landing pad will be responsible for branching to the correct catch block + llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create("landingpad", p->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtrycatch", p->topfunc(), oldend); // pass the previous BB into this assert(!gIR->scopereturned()); llvm::BranchInst::Create(trybb, p->scopebb()); + // // do the try block - p->scope() = IRScope(trybb,catchbb); + // + p->scope() = IRScope(trybb,landingpadbb); + p->landingPads.push_back(landingpadbb); + assert(body); body->toIR(p); if (!gIR->scopereturned()) llvm::BranchInst::Create(endbb, p->scopebb()); - // do catch - p->scope() = IRScope(catchbb,oldend); - llvm::BranchInst::Create(endbb, p->scopebb()); - /*assert(catches); - for(size_t i=0; idim; ++i) + 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 catch_bbs; + + for (int i = 0; i < catches->dim; i++) { - Catch* c = (Catch*)catches->data[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, ); + 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 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); + } // rewrite the scope p->scope() = IRScope(endbb,oldend); @@ -578,8 +704,6 @@ void ThrowStatement::toIR(IRState* p) Logger::println("ThrowStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; - Logger::attention(loc, "throw is not yet fully implemented"); - if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); diff --git a/gen/toir.cpp b/gen/toir.cpp index e420bf63..f36620ee 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1246,37 +1246,81 @@ DValue* CallExp::toElem(IRState* p) //Logger::cout() << "Calling: " << *funcval << '\n'; // call the function - llvm::CallInst* call = llvm::CallInst::Create(funcval, llargs.begin(), llargs.end(), varname, p->scopebb()); - LLValue* retllval = (retinptr) ? llargs[0] : call; + LLValue* retllval; + if(p->landingPads.empty()) + { + llvm::CallInst* call = llvm::CallInst::Create(funcval, llargs.begin(), llargs.end(), varname, p->scopebb()); - if (retinptr && dfn && dfn->func && dfn->func->runTimeHack) { - const LLType* rettype = getPtrToType(DtoType(type)); - if (retllval->getType() != rettype) { - Logger::println("llvmRunTimeHack==true - force casting return value"); - Logger::cout() << "from: " << *retllval->getType() << " to: " << *rettype << '\n'; - retllval = DtoBitCast(retllval, rettype); + retllval = (retinptr) ? llargs[0] : call; + + if (retinptr && dfn && dfn->func && dfn->func->runTimeHack) { + const LLType* rettype = getPtrToType(DtoType(type)); + if (retllval->getType() != rettype) { + Logger::println("llvmRunTimeHack==true - force casting return value"); + Logger::cout() << "from: " << *retllval->getType() << " to: " << *rettype << '\n'; + retllval = DtoBitCast(retllval, rettype); + } } - } - // set calling convention - if (dfn && dfn->func) { - int li = dfn->func->llvmInternal; - if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) { + // set calling convention + if (dfn && dfn->func) { + int li = dfn->func->llvmInternal; + if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) { + call->setCallingConv(DtoCallingConv(dlink)); + } + } + /*else if (delegateCall) { + call->setCallingConv(DtoCallingConv(dlink)); + }*/ + else if (dfn && dfn->cc != (unsigned)-1) { + call->setCallingConv(dfn->cc); + } + else { call->setCallingConv(DtoCallingConv(dlink)); } - } - /*else if (delegateCall) { - call->setCallingConv(DtoCallingConv(dlink)); - }*/ - else if (dfn && dfn->cc != (unsigned)-1) { - call->setCallingConv(dfn->cc); - } - else { - call->setCallingConv(DtoCallingConv(dlink)); - } - // param attrs - call->setParamAttrs(palist); + // param attrs + call->setParamAttrs(palist); + } + else + { + llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create("postinvoke", p->topfunc(), p->scopeend()); + llvm::InvokeInst* call = llvm::InvokeInst::Create(funcval, postinvoke, *p->landingPads.rbegin(), llargs.begin(), llargs.end(), varname, p->scopebb()); + p->scope() = IRScope(postinvoke, p->scopeend()); + + + //FIXME: Code duplication! + retllval = (retinptr) ? llargs[0] : call; + + if (retinptr && dfn && dfn->func && dfn->func->runTimeHack) { + const LLType* rettype = getPtrToType(DtoType(type)); + if (retllval->getType() != rettype) { + Logger::println("llvmRunTimeHack==true - force casting return value"); + Logger::cout() << "from: " << *retllval->getType() << " to: " << *rettype << '\n'; + retllval = DtoBitCast(retllval, rettype); + } + } + + // set calling convention + if (dfn && dfn->func) { + int li = dfn->func->llvmInternal; + if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) { + call->setCallingConv(DtoCallingConv(dlink)); + } + } + /*else if (delegateCall) { + call->setCallingConv(DtoCallingConv(dlink)); + }*/ + else if (dfn && dfn->cc != (unsigned)-1) { + call->setCallingConv(dfn->cc); + } + else { + call->setCallingConv(DtoCallingConv(dlink)); + } + + // param attrs + call->setParamAttrs(palist); + } return new DImValue(type, retllval, isInPlace); } diff --git a/tango/lib/compiler/llvmdc/eh.d b/tango/lib/compiler/llvmdc/eh.d index 7918db4b..adae4376 100644 --- a/tango/lib/compiler/llvmdc/eh.d +++ b/tango/lib/compiler/llvmdc/eh.d @@ -4,14 +4,295 @@ import util.console; +//debug = EH_personality; + private extern(C) void abort(); +private extern(C) int printf(char*, ...); + +// D runtime functions +extern(C) { + int _d_isbaseof(ClassInfo oc, ClassInfo c); +} + +// libunwind stuff +extern(C) +{ + enum _Unwind_Reason_Code + { + NO_REASON = 0, + FOREIGN_EXCEPTION_CAUGHT = 1, + FATAL_PHASE2_ERROR = 2, + FATAL_PHASE1_ERROR = 3, + NORMAL_STOP = 4, + END_OF_STACK = 5, + HANDLER_FOUND = 6, + INSTALL_CONTEXT = 7, + CONTINUE_UNWIND = 8 + } + + enum _Unwind_Action + { + SEARCH_PHASE = 1, + CLEANUP_PHASE = 2, + HANDLER_PHASE = 3, + FORCE_UNWIND = 4 + } + + alias void* _Unwind_Context_Ptr; + + alias void function(_Unwind_Reason_Code, _Unwind_Exception*) _Unwind_Exception_Cleanup_Fn; + + struct _Unwind_Exception + { + char[8] exception_class; + _Unwind_Exception_Cleanup_Fn exception_cleanup; + int private_1; + int private_2; + } + + void _Unwind_Resume(_Unwind_Exception*); + _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*); + ulong _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context); + ulong _Unwind_GetIP(_Unwind_Context_Ptr context); + ulong _Unwind_SetIP(_Unwind_Context_Ptr context, ulong new_value); + ulong _Unwind_SetGR(_Unwind_Context_Ptr context, int index, ulong new_value); + ulong _Unwind_GetRegionStart(_Unwind_Context_Ptr context); +} + + +// helpers +private ubyte* get_uleb128(ubyte* addr, ref size_t res) +{ + res = 0; + size_t bitsize = 0; + + // read as long as high bit is set + while(*addr & 0x80) { + res |= (*addr & 0x7f) << bitsize; + bitsize += 7; + addr += 1; + if(bitsize >= size_t.sizeof*8) + throw new Exception("tried to read uleb128 that exceeded size of size_t"); + } + // read last + if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize) + throw new Exception("tried to read uleb128 that exceeded size of size_t"); + res |= (*addr) << bitsize; + + return addr + 1; +} + +private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res) +{ + res = 0; + size_t bitsize = 0; + + // read as long as high bit is set + while(*addr & 0x80) { + res |= (*addr & 0x7f) << bitsize; + bitsize += 7; + addr += 1; + if(bitsize >= size_t.sizeof*8) + throw new Exception("tried to read sleb128 that exceeded size of size_t"); + } + // read last + if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize) + throw new Exception("tried to read sleb128 that exceeded size of size_t"); + res |= (*addr) << bitsize; + + // take care of sign + if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40)) + res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1); + + return addr + 1; +} + + + +struct _d_exception +{ + Object exception_object; + _Unwind_Exception unwind_info; +} + +char[8] _d_exception_class = "LLDCD1\0\0"; + +//TODO: cleanup handling +extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context) +{ + // check ver: the C++ Itanium ABI only allows ver == 1 + if(ver != 1) + return _Unwind_Reason_Code.FATAL_PHASE1_ERROR; + + // check exceptionClass + //TODO: Treat foreign exceptions with more respect + if((cast(char*)&exception_class)[0..8] != _d_exception_class) + return _Unwind_Reason_Code.FATAL_PHASE1_ERROR; + + // find call site table, action table and classinfo table + // Note: callsite and action tables do not contain static-length + // data and will be parsed as needed + // Note: classinfo_table points past the end of the table + ubyte* callsite_table; + ubyte* action_table; + ClassInfo* classinfo_table; + _d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table); + + + /* + find landing pad and action table index belonging to ip by walking + the callsite_table + */ + ubyte* callsite_walker = callsite_table; + + // get the instruction pointer + // will be used to find the right entry in the callsite_table + // -1 because it will point past the last instruction + ulong ip = _Unwind_GetIP(context) - 1; + + // address block_start is relative to + ulong region_start = _Unwind_GetRegionStart(context); + + // table entries + uint block_start_offset, block_size; + ulong landing_pad; + size_t action_offset; + + while(true) { + // if we've gone through the list and found nothing... + if(callsite_walker >= action_table) + return _Unwind_Reason_Code.CONTINUE_UNWIND; + + block_start_offset = *cast(uint*)callsite_walker; + block_size = *(cast(uint*)callsite_walker + 1); + landing_pad = *(cast(uint*)callsite_walker + 2); + if(landing_pad) + landing_pad += region_start; + callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset); + + debug(EH_personality_verbose) printf("%d %d %d\n", block_start_offset, block_size, landing_pad); + + // since the list is sorted, as soon as we're past the ip + // there's no handler to be found + if(ip < region_start + block_start_offset) + return _Unwind_Reason_Code.CONTINUE_UNWIND; + + // if we've found our block, exit + if(ip < region_start + block_start_offset + block_size) + break; + } + + debug(EH_personality) printf("Found correct landing pad and actionOffset %d\n", action_offset); + + // now we need the exception's classinfo to find a handler + // the exceptionObject is actually a member of a larger struct that + // the runtime allocated. get that now + _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof); + + // if there's no actionOffset and no landingpad, continue unwinding + if(!action_offset && !landing_pad) + return _Unwind_Reason_Code.CONTINUE_UNWIND; + + // if there's no action offset but a landing pad, this is a cleanup handler + else if(!action_offset && landing_pad) { + // but only if we're asked to! + if(!(actions & _Unwind_Action.CLEANUP_PHASE)) + return _Unwind_Reason_Code.CONTINUE_UNWIND; + + debug(EH_personality) printf("Calling cleanup routine...\n"); + + _Unwind_SetGR(context, 0, cast(ulong)exception_struct); + _Unwind_SetIP(context, landing_pad); + return _Unwind_Reason_Code.INSTALL_CONTEXT; + } + + /* + walk action table chain, comparing classinfos using _d_isbaseof + */ + ubyte* action_walker = action_table + action_offset - 1; + + ptrdiff_t ti_offset, next_action_offset; + while(true) { + action_walker = get_sleb128(action_walker, ti_offset); + // it is intentional that we not modify action_walker here + // next_action_offset is from current action_walker position + get_sleb128(action_walker, next_action_offset); + + // negative are 'filters' which we don't use + assert(ti_offset >= 0); + + //TODO: Implement cleanups + assert(ti_offset != 0); + + // get classinfo for action and check if the one in the + // exception structure is a base + ClassInfo catch_ci = classinfo_table[-ti_offset]; + debug(EH_personality) printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr); + if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci)) + return _d_eh_success(actions, ti_offset, landing_pad, exception_struct, context); + + // we've walked through all actions and found nothing... + if(next_action_offset == 0) + return _Unwind_Reason_Code.CONTINUE_UNWIND; + else + action_walker += next_action_offset; + } + + assert(false); +} + +private _Unwind_Reason_Code _d_eh_success(_Unwind_Action actions, ptrdiff_t switchval, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context) +{ + debug(EH_personality) printf("Found catch clause!\n"); + + if(actions & _Unwind_Action.SEARCH_PHASE) + return _Unwind_Reason_Code.HANDLER_FOUND; + else if(actions & _Unwind_Action.HANDLER_PHASE) + { + //TODO: Set sensible value for eh_ptr + _Unwind_SetGR(context, 0, cast(ulong)cast(void*)(exception_struct.exception_object)); + _Unwind_SetGR(context, 2, switchval); + _Unwind_SetIP(context, landing_pad); + return _Unwind_Reason_Code.INSTALL_CONTEXT; + } + + assert(false); +} + +private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci) +{ + ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context); + + //TODO: Do proper DWARF reading here + assert(*data++ == 0xff); + + assert(*data++ == 0x00); + size_t cioffset; + data = get_uleb128(data, cioffset); + ci = cast(ClassInfo*)(data + cioffset); + + assert(*data++ == 0x03); + size_t callsitelength; + data = get_uleb128(data, callsitelength); + action = data + callsitelength; + + callsite = data; +} extern(C) void _d_throw_exception(Object e) { - console("Exception: "); if (e !is null) { - console(e.toString())("\n"); + _d_exception* exc_struct = new _d_exception; + exc_struct.unwind_info.exception_class[] = _d_exception_class; + exc_struct.exception_object = e; + _Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info); + console("_Unwind_RaiseException failed with reason code: ")(ret)("\n"); } abort(); } + +extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct) +{ + _Unwind_Resume(&exception_struct.unwind_info); +}