// never return _RTARCTOR::_RTARCTOR // COPY CTOR FOR R/T AR-CTOR ( _RTARCTOR const & ) : _count( 0 ) , _sig( 0 ) , _array( 0 ) { GOOF_EXC( "Attempt to copy RTARCTOR" ); // never return }
static void getProcInfo // GET EXCEPTION INFO FOR PROCEDURE ( __EXC_INFO* inf // - exception info , PD_DISP_CTX* dctx ) // - dispatcher context for procedure { void* frame; // - frame ptr. PData* pd = dctx->pdata; inf->pd = pd; inf->ro = (RO_DTREG*)pd->exc_data; frame = getProcFrame( pd, dctx ); inf->rw = (RW_DTREG*)( (char*)frame + inf->ro->fun.rw_offset ); if( inf->rw->base.ro != inf->ro ) { GOOF_EXC( "getProcInfo: rw->ro != ro" ); } }
static void* getProcFrame // GET PROCEDURE FRAME ( PData* pdata // - procedure descriptor , PD_DISP_CTX* dctx ) // - dispatch context { void* frame; // - frame ptr. #if 0 if( procSetsFP( pdata ) ) { frame = (void*)dctx->fp_actual; } else { frame = (void*)dctx->sp_actual; } #else if( dctx->pdata != pdata ) { GOOF_EXC( "getProcFram: dctx->pdata != pdata" ); } // AFS: this function seems to change a lot and it very brittle; // is it possible to use 'sp' from the handler? frame = dctx->fp_alternate; #endif return frame; }
static DISPATCHABLE dispatchable( // DETERMINE WHERE CATCHABLE WITHIN FUNCTION DISPATCH_EXC *dispatch, // - dispatch information RW_DTREG *rw ) // - current read/write { _RTCTL rt_ctl // - R/T control ( dispatch->rtc->thr ); STAB_TRAVERSE traverse; // - traversal control RO_STATE* state; // - current state entry DISPATCHABLE retn; // - return: dispatchability DTOR_CMD* cmd; // - command pointer ACTIVE_EXC *exc; // - active exception rboolean rethrow; // - true ==> re-throw from top block if( dispatch->rethrow ) { exc = dispatch->exc; if( exc == NULL ) { GOOF_EXC( "dispatchable: missing caught exception" ); } dispatch->ro = exc->throw_ro; dispatch->zero = exc->zero_thrown; rethrow = true; } else { rethrow = false; } rt_ctl.setRwRo( rw ); CPPLIB( stab_trav_init )( &traverse, &rt_ctl ); for( ; ; CPPLIB( stab_trav_next )( &traverse ) ) { state = CPPLIB( stab_trav_move )( &traverse ); if( state == NULL ) { retn = DISPATCHABLE_NONE; break; } if( state->dtor != NULL ) continue; cmd = state->u.cmd_addr; switch( cmd->base.code ) { case DTC_CATCH : if( rethrow ) { if( exc->cat_try == TryFromCatch( cmd ) ) { dispatch->popped = true; } rethrow = false; } continue; case DTC_FN_EXC : if( dispatchableFnExc( dispatch, cmd ) ) { // exception violates fn-exc spec. retn = DISPATCHABLE_FNEXC; break; } continue; case DTC_TRY : if( dispatchableCatch( dispatch, cmd ) ) { retn = DISPATCHABLE_CATCH; break; } continue; default : continue; } dispatch->state_var = traverse.state_var; break; } return retn; }
ACTIVE_EXC *CPPLIB( alloc_exc )(// ALLOCATE AN EXCEPTION void *object, // - address of object THROW_RO *throw_ro, // - throw R/O block _RTCTL* rtc ) // - R/T control { FREE_AREA *fr; // - a freed area FREE_AREA **owner; // - previous freed area FREE_AREA *next; // - next freed area RT_TYPE_SIG sig; // - type signature of thrown item ACTIVE_EXC *active; // - active exception unsigned size; // - size required THREAD_CTL *thr; // - thread control #ifdef __MT__ __EXC_AREA.semaphore.p(); #endif if( __EXC_AREA.freed == NULL ) { fr = (FREE_AREA*)((char*)&__EXC_AREA + sizeof( EXC_AREA )); // initial free list entry fr->next = NULL; fr->size = __EXC_AREA.size - sizeof( EXC_AREA ); __EXC_AREA.freed = fr; #ifndef NDEBUG memset( (char*)fr + sizeof(FREE_AREA) , 0xEF , fr->size - sizeof(FREE_AREA) ); #endif } sig = CPPLIB( ts_refed )( throw_ro->cnvs[0].signature ); size = CPPLIB( ts_size )( sig ) + SIZEOF_HDR + sizeof( size_t ); if( size < sizeof( FREE_AREA ) ) { size = sizeof( FREE_AREA ); } size = ( size + 3 ) & -4; for( owner = &__EXC_AREA.freed; ; owner = &fr->next ) { fr = *owner; if( fr == NULL ) { CPPLIB(fatal_runtime_error)( RTMSG_EXC_NO_SPACE, 1 ); } for( ;; ) { // coalesce next = fr->next; if( (FREE_AREA*)((char*)fr + fr->size) != next ) break; fr->size += next->size; fr->next = next->next; } if( fr->size == size ) { *owner = fr->next; active = (ACTIVE_EXC*)fr; break; } else if( fr->size > ( size + SIZEOF_SPLIT ) ) { fr->size -= size; active = (ACTIVE_EXC*)( (char*)fr + fr->size ); break; } } #ifdef __MT__ __EXC_AREA.semaphore.v(); #endif *(size_t*)active = size; active = (ACTIVE_EXC*)( (char*)active + sizeof( size_t ) ); active->exc_area = &__EXC_AREA; thr = rtc->thr; active->prev = thr->excepts; thr->excepts = active; active->sig = throw_ro->cnvs[0].signature; active->throw_ro = throw_ro; active->state = EXCSTATE_CTOR; active->zero_thrown = false; active->dispatch = NULL; active->rw = NULL; switch( sig->hdr.type ) { case THROBJ_SCALAR : case THROBJ_PTR_FUN : memcpy( active->data, object, sig->scalar.size ); break; case THROBJ_CLASS : { _EXC_PR_FREE marker( rtc, 0, EXCSTATE_CTOR, active ); (*sig->clss.copyctor)( active->data, object ); marker._exc = 0; } break; case THROBJ_CLASS_VIRT : { _EXC_PR_FREE marker( rtc, 0, EXCSTATE_CTOR, active ); (*sig->clss_v.copyctor)( active->data, CTOR_NULL, object ); marker._exc = 0; } break; case THROBJ_PTR_CLASS : case THROBJ_PTR_SCALAR : case THROBJ_VOID_STAR : memcpy( active->data, object, sizeof( void* ) ); size = sizeof( void* ); break; default : GOOF_EXC( "ALLOCEXC: unexpected type signature" ); } return active; }
static void processThrow( // PROCESS A THROW void *object, // - address of object THROW_RO *throw_ro, // - thrown R/O block rboolean is_zero ) // - true ==> thrown object is zero constant { _RTCTL rt_ctl; // - R/T control DISPATCH_EXC dispatch; // - dispatch control auto FsExcRec excrec; // - system exception record volatile rboolean unwound; void *force_this_routine_to_have_an_EBP_frame; // CPPLIB( DbgRtDumpAutoDtor )(); #if 0 // // Check for throws under bad circumstances // ACTIVE_EXC *exc = rt_ctl.thr->excepts; if( exc == NULL ) { if( rt_ctl.thr->flags.terminated ) { CPPLIB( fatal_runtime_error )( RTMSG_THROW_TERMIN, 1 ); } } else { switch( exc->state ) { case EXCSTATE_DISPATCH : case EXCSTATE_UNEXPECTED : case EXCSTATE_BAD_EXC : break; case EXCSTATE_UNWIND : { CPPLIB( free_exc )( &rt_ctl, exc ); _EXC_PR marker( &rt_ctl, 0, EXCSTATE_TERMINATE ); CPPLIB( call_terminate )( RTMSG_THROW_DTOR, rt_ctl.thr ); } case EXCSTATE_TERMINATE : CPPLIB( free_exc )( &rt_ctl, exc ); CPPLIB( fatal_runtime_error )( RTMSG_THROW_TERMIN, 1 ); case EXCSTATE_CTOR : CPPLIB( free_exc )( &rt_ctl, exc ); CPPLIB( fatal_runtime_error )( RTMSG_THROW_CTOR, 1 ); case EXCSTATE_DTOR : CPPLIB( free_exc )( &rt_ctl, exc ); CPPLIB( fatal_runtime_error )( RTMSG_EXC_DTOR, 1 ); default: GOOF_EXC( "getActiveExc: unexpected exception state" ); } } #endif // // Setup for dispatch // rt_ctl.thr->abort_msg = NULL; CPPLIB( exc_setup )( &dispatch , throw_ro , is_zero , &rt_ctl , object , &excrec ); force_this_routine_to_have_an_EBP_frame = alloca(16); unwound = false; // // raising exception locates the catch/fn-exception to be dispatched // also fills in excrec.addr // if( 0 == dispatch.fs_last ) { // no search when no R/W blocks dispatch.type = DISPATCHABLE_NO_CATCH; } else { FS_RAISE_EXCEPTION( &excrec ); } // // comes here twice, unless an error situation: // unwound == 0 : after catch located, before unwinding // unwound == 1 : after unwinding // switch( dispatch.type ) { case DISPATCHABLE_STOP : if( NULL == dispatch.srch_ctl ) { GOOF_EXC( "DISPATCHABLE_STOP: no srch_ctl" ); } switch( dispatch.srch_ctl->_state ) { case EXCSTATE_UNWIND : { _EXC_PR_FREE marker( &rt_ctl , 0 , EXCSTATE_TERMINATE , dispatch.rethrow ? 0 : rt_ctl.thr->excepts ); CPPLIB( call_terminate )( RTMSG_THROW_DTOR, rt_ctl.thr ); } case EXCSTATE_TERMINATE : CPPLIB( fatal_runtime_error )( RTMSG_THROW_TERMIN, 1 ); case EXCSTATE_CTOR : CPPLIB( fatal_runtime_error )( RTMSG_THROW_CTOR, 1 ); case EXCSTATE_DTOR : CPPLIB( fatal_runtime_error )( RTMSG_EXC_DTOR, 1 ); default: GOOF_EXC( "DISPATCHABLE_STOP: unexpected exception state" ); } case DISPATCHABLE_FNEXC : case DISPATCHABLE_CATCH : if( ! unwound ) { ACTIVE_EXC *active; // - saved exception unwound = true; if( dispatch.rethrow ) { // do we still need fnexc_state ? dispatch.exc->fnexc_state = dispatch.exc->state; if( dispatch.popped ) { active = dispatch.exc; active->cat_try = dispatch.try_cmd; active->rw = dispatch.rw; } } else { active = CPPLIB( alloc_exc )( object , dispatch.ro , &rt_ctl ); dispatch.exc = active; active->cat_try = dispatch.try_cmd; active->rw = dispatch.rw; } if( dispatch.type == DISPATCHABLE_FNEXC ) { if( dispatch.rethrow ) { dispatch.exc->state = dispatch.exc->fnexc_state; } break; } dispatch.exc->state = EXCSTATE_UNWIND; #ifdef RW_REGISTRATION FS_UNWIND_GLOBAL( dispatch.rw, excrec.addr, &excrec ); #endif #ifdef PD_REGISTRATION CPPLIB( PdUnwind )( &excrec ); #endif } // NT returns here instead of after RAISE_EXCEPTION if // there are no blocks to pop // nb. need to execute same code as after RAISE_EXCEPTION CPPLIB( destruct_internal )( dispatch.state_var, dispatch.rw ); break; } // // dispatch the exception // switch( dispatch.type ) { case DISPATCHABLE_FNEXC : fneDispatch( &dispatch ); case DISPATCHABLE_CATCH : catchDispatch( &dispatch ); case DISPATCHABLE_NO_CATCH : if( dispatch.rethrow ) { CPPLIB( fatal_runtime_error )( RTMSG_RETHROW, 1 ); } else { { _EXC_PR marker( &rt_ctl, 0, EXCSTATE_TERMINATE ); CPPLIB( call_terminate )( RTMSG_NO_HANDLER, rt_ctl.thr ); } } #if 0 // not now case DISPATCHABLE_SYS_EXC : { char buffer[ sizeof( RTMSG_SYS_EXC ) ]; ::memcpy( buffer, RTMSG_SYS_EXC, sizeof( buffer ) ); ltoa( dispatch.system_exc, buffer + sizeof( buffer) - 9, 16 ); CPPLIB( fatal_runtime_error )( buffer, 1 ); } #endif default : GOOF_EXC( "throw: invalid DISPATCHABLE" ); } }
static void catchDispatch( // DISPATCH A CATCH BLOCK DISPATCH_EXC *dispatch ) // - dispatch control { RW_DTREG* blk; // - function block for dispatch DTOR_CMD* cmd; // - try command jmp_buf *env; // - addr[ jmp_buf ] ACTIVE_EXC *active; // - active exception void *tgt; // - target try variable void *src; // - source address RT_TYPE_SIG sig; // - signature for catch unsigned cnv_offset; // - conversion offset blk = dispatch->rw; cmd = dispatch->try_cmd; active = dispatch->exc; active->state = EXCSTATE_DISPATCH; env = (jmp_buf*)( (char*)blk + cmd->try_cmd.jmp_buf ); sig = cmd->try_cmd.sigs[ dispatch->catch_no ]; if( sig != NULL ) { cnv_offset = dispatch->cnv_try->offset; src = cnv_offset + (char*)active->data; tgt = (char*)blk + cmd->try_cmd.offset; switch( sig->hdr.type ) { case THROBJ_PTR_CLASS : if( dispatch->zero ) { *(void**)tgt = NULL; } else { *(void**)tgt = *(char**)active->data + cnv_offset; } break; case THROBJ_VOID_STAR : case THROBJ_PTR_SCALAR : case THROBJ_PTR_FUN : if( dispatch->zero ) { memset( tgt, 0, sig->scalar.size ); break; } case THROBJ_SCALAR : memcpy( tgt, src, sig->scalar.size ); break; case THROBJ_CLASS : sig = throwCnvSig( dispatch ); (*sig->clss.copyctor)( tgt, src ); break; case THROBJ_CLASS_VIRT : sig = throwCnvSig( dispatch ); (*sig->clss_v.copyctor)( tgt, CTOR_NULL, src ); break; case THROBJ_REFERENCE : sig = CPPLIB( ts_refed )( sig ); switch( sig->hdr.type ) { case THROBJ_PTR_CLASS : if( dispatch->zero ) { active->extra_object = NULL; } else { active->extra_object = *(char**)active->data + cnv_offset; } *(void**)tgt = &active->extra_object; break; case THROBJ_PTR_SCALAR : case THROBJ_PTR_FUN : case THROBJ_VOID_STAR : if( dispatch->zero ) { active->extra_object = NULL; src = &active->extra_object; } case THROBJ_SCALAR : case THROBJ_CLASS : case THROBJ_CLASS_VIRT : *(void**)tgt = src; break; } break; default : GOOF_EXC( "unexpected exception type" ); } } longjmp( *env, dispatch->catch_no + 1 ); }