static DISPATCHABLE catch_any( // DETERMINE WHERE CATCH(...) 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 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; if( cmd->base.code == DTC_TRY ) { if( 0 == cmd->try_cmd.sigs[ cmd->try_cmd.count - 1 ] ) { dispatch->non_watcom = true; retn = DISPATCHABLE_CATCH; break; } } dispatch->state_var = traverse.state_var; break; } return retn; }
DISPATCHABLE CPPLIB( dispatchable )(// TEST IF R/W BLOCK IS DISPATCHABLE DISPATCH_EXC *dispatch, // - dispatch control RW_DTREG* rw ) // - R/W block: search block { DISPATCHABLE dispatch_type; // - type of dispatch // check if r/w on stack if( rw == 0 ) { CPPLIB( corrupted_stack )(); } dispatch->rw = rw; dispatch->rtc->setRwRo( rw ); RO_DTREG* ro = dispatch->rtc->ro; switch( ro->base.reg_type ) { default : CPPLIB( corrupted_stack )(); case DTRG_FUN : dispatch_type = dispatchable( dispatch, rw ); break; case DTRG_STATIC_INITLS : case DTRG_ARRAY : case DTRG_OBJECT : dispatch_type = DISPATCHABLE_NONE; break; } return dispatch_type; }
DISPATCHABLE CPPLIB( catch_any )// TEST IF R/W BLOCK IS DISPATCHABLE FOR ... ( FsExcRec* // - exception record , RW_DTREG* rw ) // - R/W block: search block { _RTCTL rt_ctl; // - R/T control DISPATCHABLE dispatch_type; // - type of dispatch DISPATCH_EXC dispatch; // - dispatch control // check if r/w on stack if( rw == 0 ) { CPPLIB( corrupted_stack )(); } CPPLIB( dispatch_dummy )( &dispatch, &rt_ctl ); dispatch.rw = rw; dispatch.rtc->setRwRo( rw ); RO_DTREG* ro = dispatch.rtc->ro; switch( ro->base.reg_type ) { default : CPPLIB( corrupted_stack )(); case DTRG_FUN : dispatch_type = catch_any( &dispatch, rw ); break; case DTRG_STATIC_INITLS : case DTRG_ARRAY : case DTRG_OBJECT : dispatch_type = DISPATCHABLE_NONE; break; } return dispatch_type; }
static void fneDispatch( // DISPATCH "unexpected" DISPATCH_EXC *dispatch ) // - dispatch control { THREAD_CTL *ctl; // - thread-specific data ACTIVE_EXC *exc; // - active exception ACTIVE_EXC *srch; // - previous exception for this FNEXC ctl = dispatch->rtc->thr; ctl->abort_msg = RTMSG_FNEXC; exc = ctl->excepts; exc->dispatch = dispatch; for( srch = exc; ; ) { if( srch == NULL ) { // first time through fn_exc exc->dispatch = dispatch; exc->fnexc_state = exc->state; exc->state = EXCSTATE_UNEXPECTED; _EXC_PR_FNEXC marker( dispatch->rtc , 0 , dispatch->rw , dispatch->rethrow ? 0 : exc ); unexpected(); marker._state = EXCSTATE_TERMINATE; CPPLIB( call_terminate )( RTMSG_RET_UNEXPECT, ctl ); // never return } DISPATCH_EXC *cand = srch->dispatch; if( NULL != cand && dispatch->rw == cand->rw && dispatch->state_var == cand->state_var ) { if( srch->state == EXCSTATE_UNEXPECTED ) { // throw/rethrow did not get through fn-exc exc->state = EXCSTATE_BAD_EXC; _EXC_PR_FNEXC marker( dispatch->rtc , 0 , dispatch->rw , dispatch->rethrow ? 0 : exc ); throw bad_exception(); } if( srch->state == EXCSTATE_BAD_EXC ) { // throw of bad_exception did not get through fn-exc _EXC_PR_DTOR marker( dispatch->rtc , 0 , EXCSTATE_TERMINATE , dispatch->rethrow ? 0 :exc ); CPPLIB( call_terminate )( RTMSG_FNEXC, ctl ); // never return } if( srch != exc ) { CPPLIB( corrupted_stack )(); // never return } } srch = srch->prev; if( exc == srch ) { CPPLIB( corrupted_stack )(); // never return } } }
void CPPLIB( module_dtor ) // DTOR STATICS FOR PROGRAM ( void ) { THREAD_CTL *thr; // - thread control ptr. RW_DTREG* rw; // - read/write entry union { RW_DTREG inlined; // - inlined copy for destruction RW_DTREG_INITLS ls; // - inlined copy for destruction }; #ifdef RW_REGISTRATION inlined.base.handler = & CPPLIB( fs_handler_rtn ); thr = 0; #else thr = &_RWD_ThreadData; #endif for( ; ; ) { #ifdef __MT__ _RWD_StaticInitSema.p(); #endif rw = _RWD_ModuleInit; if( rw != 0 ) { _RWD_ModuleInit = rw->base_st.prev; } #ifdef __MT__ _RWD_StaticInitSema.v(); #endif if( rw == 0) break; RO_STATE* state = &rw->base_st.ro->init_ls.state_table[0]; (*state->dtor)( state->u.data_addr, DTOR_NULL ); } }
_EXC_PR_DTOR::~_EXC_PR_DTOR // _EXC_PR_DTOR DESTRUCTOR ( void ) { ACTIVE_EXC* exc = _exc; CPPLIB( dtor_free_exc )( _exc, _rtc ); _exc = 0; }
static size_t typesigIndex( // FIND BASE-1 INDEX OF MATCHING TYPE SIGNATURE DISPATCH_EXC* dispatch, // - dispatch control size_t count, // - number of elements RT_TYPE_SIG* tsigs ) // - type signatures { size_t index; // - base-1 index THROW_RO* throw_ro; // - throw R/O block rboolean zero_thrown; // - true ==> zero was thrown unsigned thr_ctr; // - throw ctr. unsigned ctr; // - testing ctr. RT_TYPE_SIG tsig; // - current type signature, in tsigs RT_TYPE_SIG thr_sig; // - current type signature, from throw throw_ro = dispatch->ro; zero_thrown = dispatch->zero; for( ctr = 0; ctr < count; ++ctr ) { tsig = tsigs[ ctr ]; if( tsig == NULL ) { index = ctr + 1; goto done; } for( thr_ctr = 0; thr_ctr < throw_ro->count; ++thr_ctr ) { dispatch->cnv_try = &throw_ro->cnvs[ thr_ctr ]; thr_sig = dispatch->cnv_try->signature; if( CPPLIB( ts_equiv )( tsig, thr_sig, zero_thrown ) ) { index = ctr + 1; goto done; } } } index = 0; done: return index; }
_WPRTLINK void CPPLIB( fun_register )( // REGISTRATION FOR FUNCTION RW_DTREG* rw, // - R/W block RO_DTREG* ro ) // - R/O block { CPPLIB( base_register )( rw, ro, 0 ); }
THREAD_CTL* CPPLIB( fs_lookup ) // LOOK THRU FS ENTRIES FOR LAST, THREAD_CTL ( RW_DTREG** a_last ) // - addr[ ptr to last WATCOM entry ] { _RTCTL rt_ctl( 0 ); // - fake R/T control FsExcRec excrec; // - system exception record DISPATCH_EXC dispatch; // - dispatch control RW_DTREG* last; // - last WATCOM R/W block RW_DTREG *ctl; // R/W block (based fs:0) THREAD_CTL* retn; // PGM THREAD (first WATCOM .EXE, .DLL active) THREAD_CTL* base; // PGM THREAD (call base) #ifdef SYSIND_REGISTRATION #define LIST_END 0 // - link-list ending #else #define LIST_END (void*)(-1L)// - link-list ending #endif CPPLIB( dispatch_dummy )( &dispatch, &rt_ctl ); excrec.code = EXCREC_CODE; excrec.flags = EXCREC_FLAGS; excrec.rec = 0; excrec.addr = 0; excrec.parm_count = EXCREC_PARM_COUNT; excrec.object = 0; excrec.dispatch = &dispatch; last = 0; retn = 0; for( ctl = FsTop(); ctl != LIST_END; ctl = ctl->base.prev ) { #ifdef FS_REGISTRATION uint_8* handler = findHandler( (uint_8*)ctl->base.handler ); if( handler[5] == 'W' && handler[6] == 'A' && handler[7] == 'T' && handler[8] == 'C' && handler[9] == 'O' && handler[10] == 'M' ) { #endif if( EXC_HAND_CATCH == (*ctl->base.handler)( &excrec, 0, 0, 0 ) ) { last = ctl; base = dispatch.rtc->thr; if( base->flags.executable ) { retn = base; } } #ifdef FS_REGISTRATION } #endif } if( retn == 0 ) { retn = dispatch.rtc->thr; if( retn == 0 ) { retn = &_RWD_ThreadData; } } *a_last = last; return retn; }
_WPRTLINK void CPPLIB(pure_error)( // TRAP NON-OVERRIDDEN PURE VIRTUAL CALLS void ) { if( !_RWD_PureErrorFlag ) { _RWD_PureErrorFlag = 1; CPPLIB(fatal_runtime_error)( RTMSG_PURE_ERR, 1 ); } }
_EXC_PR_FREE::~_EXC_PR_FREE // _EXC_PR_FREE DESTRUCTOR ( void ) { if( NULL != _exc ) { ACTIVE_EXC* exc = _exc; _exc = 0; CPPLIB( free_exc )( _rtc, exc ); } }
void CPPLIB( dtor_free_exc ) // DESTRUCT AND FREE EXCEPTION ( ACTIVE_EXC* active // - exception , _RTCTL* rtc ) // - R/T control { if( 0 != active ) { RT_TYPE_SIG sig = CPPLIB( ts_refed )( active->sig ); if( sig->hdr.type == THROBJ_CLASS || sig->hdr.type == THROBJ_CLASS_VIRT ) { pFUNdtor dtor = sig->clss.dtor; if( dtor != NULL ) { _EXC_PR_FREE marker( rtc, 0, EXCSTATE_DTOR, active ); active->state = EXCSTATE_DTOR; (*dtor)( active->data, DTOR_NULL ); marker._exc = 0; } } CPPLIB( free_exc )( rtc, active ); } }
void CPPLIB( raise_exception ) // RAISE AN EXCEPTION ( FsExcRec* excrec ) // - exception record { RW_DTREG* curr; // - current R/W block THREAD_CTL* ctl; // - thread control unsigned retn; // - search return ctl = excrec->dispatch->rtc->thr; for( curr = ctl->registered; ; curr = curr->base.prev ) { retn = CPPLIB( fs_handler_rtn )( excrec, curr, NULL, 0 ); if( retn != EXC_HAND_CONTINUE ) break; } }
_WPRTLINK void CPPLIB( catch_done )( // COMPLETION OF CATCH #ifdef RW_REGISTRATION void #else RW_DTREG *rw // - current R/W block #endif ) { _RTCTL rt_ctl; // - R/T control #ifdef RW_REGISTRATION RW_DTREG* rw = RwTop( rt_ctl.thr ); #endif rt_ctl.setRwRo( rw ); RO_STATE* state = CPPLIB( stab_entry )( rw->base.ro , rw->fun.base.state_var ); DTOR_CMD* cmd = TryFromCatch( state->u.cmd_addr ); ACTIVE_EXC* exc = CPPLIB( find_active )( &rt_ctl, rw, cmd ); CPPLIB( dtor_free_exc )( exc, &rt_ctl ); STAB_TRAVERSE traverse; CPPLIB( stab_trav_init )( &traverse, &rt_ctl ); CPPLIB( stab_trav_next )( &traverse ); rw->fun.base.state_var = traverse.state_var; }
void * CPPLIB( new_array )( // CALL CONSTRUCTORS FOR NEW ARRAY ELEMENTS ARRAY_STORAGE *new_alloc, // - what was allocated unsigned count, // - number of elements RT_TYPE_SIG sig ) // - type signature for array type { void *retn; // - return: NULL or first element if( new_alloc == NULL ) { retn = NULL; } else { new_alloc->element_count = count; retn = new_alloc->apparent_address; retn = CPPLIB( ctor_array )( retn, count, sig ); } return( retn ); }
void CPPLIB( unwind_global ) // GLOBAL UNWIND ROUTINE ( RW_DTREG* rw // - bounding R/W block , uint_32 // - return address (not used) , FsExcRec* excrec ) // - exception record { RW_DTREG* curr; // - current R/W block THREAD_CTL* ctl; // - thread control excrec->flags = EXC_TYPE_UNWIND_NORMAL; ctl = excrec->dispatch->rtc->thr; for( curr = ctl->registered; curr != rw; ) { CPPLIB( fs_handler_rtn )( excrec, curr, NULL, 0 ); curr = curr->base.prev; ctl->registered = curr; } }
_EXC_PR::_EXC_PR // _EXC_PR CONSTRUCTOR ( _RTCTL* rtc // - run-time control , RW_DTREG *rw // - current read/write , EXCSTATE state ) // - state : _state( state ) , _rw( rw ) , _prev( rtc->thr->exc_pr ) , _rtc( rtc ) #ifndef NDEBUG , _type( EXCPR_BASIC ) #endif { rtc->thr->exc_pr = this; if( 0 == rw ) { #ifdef RW_REGISTRATION _rw = FsTop(); #else _rw = CPPLIB( pd_top )(); #endif } }
_WPRTLINK void terminate( void ) // HANDLE TERMINATE { PFV handler; // - NULL or handler set by "set_terminate" THREAD_CTL *thr; // - thread ptr char* msg; // - error message thr = &_RWD_ThreadData; handler = thr->terminate; if( NULL == handler ) { thr = PgmThread(); msg = thr->abort_msg; if( msg == NULL ) { __exit( 1 ); } } else { (*handler)(); msg = RTMSG_RET_TERMIN; } CPPLIB(fatal_runtime_error)( msg, 1 ); }
void CPPLIB( PdUnwind ) // UNWIND USING PROCEDURE DESCRIPTORS ( FsExcRec* exc_rec ) // - exception record { DISPATCH_EXC* dispatch; // - dispatch control RW_DTREG* rw; // - R/W block being dispatched void* frame; // - frame for rtn. (SP or FP) void* pc; // - PC for continuation (after the setjmp) _CONTEXT ctx; // - context for function unsigned save_area[3*2]; // - save area RtlCaptureContext( &ctx ); pc = CPPLIB( PdCtx )( &ctx, save_area ); if( pc ) { dispatch = exc_rec->dispatch; rw = dispatch->rw; frame = (void*)( (char*)rw - rw->base.ro->fun.rw_offset ); if( procSetsFP( dispatch->pdata ) ) { RtlUnwindRfp( frame, pc, exc_rec, save_area ); } else { RtlUnwind( frame, pc, exc_rec, save_area ); } } }
_WPRTLINK unsigned CPPLIB( pd_handler_rtn ) // HANDLER FOR FS REGISTRATIONS ( FsExcRec* rec_exc // - exception record , void* sp // - frame pointer function entry , _CONTEXT* // - context record , PD_DISP_CTX* dctx // - dispatch context ) { unsigned retn; // - return code __EXC_INFO info; // - procedure exception information if( 0 == sp ) { // sp == 0 only when called from pd_lookup THREAD_CTL* ctl = &_RWD_ThreadData; retn = unsigned( ctl ); } else { getProcInfo( &info, dctx ); if( rec_exc->flags & EXC_TYPE_UNWIND_NORMAL ) { if( rec_exc->parm_count != 1 || rec_exc->object != sp || EXCREC_CODE_SETJMP != ( EXCREC_CODE_MASK & rec_exc->code ) ) { CPPLIB( destruct_internal )( 0, info.rw ); } retn = EXC_HAND_CONTINUE; } else if( rec_exc->flags & EXC_TYPE_UNWIND_EXIT ) { if( info.ro->base.reg_type == DTRG_STATIC_INITLS ) { // always unwind static initialization CPPLIB( destruct_internal )( 0, info.rw ); } retn = EXC_HAND_CONTINUE; } else if( EXCREC_CODE_WATCOM == ( EXCREC_CODE_MASK & rec_exc->code ) ) { // WATCOM C++ Exception raised #if 0 DISPATCHABLE type = CPPLIB( dispatchable )( rec_exc->dispatch , info.rw ); DISPATCH_EXC* dispatch = rec_exc->dispatch; if( DISPATCHABLE_NONE == type ) { if( info.rw == dispatch->fs_last ) { type = DISPATCHABLE_NO_CATCH; dispatch->type = type; retn = EXC_HAND_CATCH; } else { retn = EXC_HAND_CONTINUE; } } else { dispatch->pdata = info.pd; dispatch->type = type; retn = EXC_HAND_CATCH; } #else DISPATCHABLE type; // - type of dispatchability DISPATCH_EXC *dispatch; // - dispatch control _EXC_PR *srch_ctl; dispatch = rec_exc->dispatch; if( dispatch->fnexc_skip == info.rw ) { dispatch->fnexc_skip = NULL; } for( srch_ctl = dispatch->srch_ctl ; NULL != srch_ctl && srch_ctl->_rw == info.rw ; srch_ctl = srch_ctl->_prev ) { if( NULL == dispatch->fnexc_skip ) { switch( srch_ctl->_state ) { case EXCSTATE_UNEXPECTED : case EXCSTATE_BAD_EXC : dispatch->fnexc_skip = ((_EXC_PR_FNEXC*)srch_ctl)->_fnexc_skip; continue; } break; } } if( NULL != srch_ctl && srch_ctl->_rw == info.rw ) { type = DISPATCHABLE_STOP; } else if( NULL == dispatch->fnexc_skip ) { type = CPPLIB( dispatchable )( dispatch, info.rw ); } else { type = DISPATCHABLE_NONE; } if( DISPATCHABLE_NONE == type ) { if( info.rw == dispatch->fs_last ) { type = DISPATCHABLE_NO_CATCH; dispatch->type = type; retn = EXC_HAND_CATCH; } else { retn = EXC_HAND_CONTINUE; } } else { dispatch->pdata = info.pd; dispatch->type = type; retn = EXC_HAND_CATCH; } #endif } else { // not WATCOM throw / re-throw retn = EXC_HAND_CONTINUE; } } return retn; }
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 ); }
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 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; }
rboolean CPPLIB( ts_equiv )( // TEST IF TYPE SIG.S ARE EQUIVALENT RT_TYPE_SIG tgt, // - target type signature RT_TYPE_SIG src, // - source type signature rboolean zero_thrown ) // - TRUE ==> zero was thrown { rboolean retn; // - TRUE ==> conversion possible if( tgt == NULL ) { retn = TRUE; } else { tgt = CPPLIB( ts_refed )( tgt ); retn = FALSE; if( zero_thrown ) { switch( tgt->hdr.type ) { case THROBJ_PTR_SCALAR : case THROBJ_VOID_STAR : case THROBJ_PTR_CLASS : retn = TRUE; break; } } if( ! retn ) { src = CPPLIB( ts_refed )( src ); if( src == tgt ) { retn = TRUE; } else if( tgt->hdr.type != src->hdr.type ) { retn = FALSE; } else switch( tgt->hdr.type ) { case THROBJ_VOID_STAR : case THROBJ_ANYTHING : retn = TRUE; break; case THROBJ_PTR_SCALAR : if( tgt->base.indirect != src->base.indirect ) { retn = FALSE; break; } // drops thru case THROBJ_PTR_CLASS : retn = CPPLIB( ts_equiv )( CPPLIB( ts_pnted )( tgt ) , CPPLIB( ts_pnted )( src ) , zero_thrown ); break; case THROBJ_CLASS : case THROBJ_CLASS_VIRT : if( tgt->clss.size == src->clss.size ) { if( 0 == strcmp( tgt->clss.name, src->clss.name ) ) { retn = TRUE; } else { retn = FALSE; } } else { retn = FALSE; } break; case THROBJ_PTR_FUN : case THROBJ_SCALAR : if( tgt->scalar.size == src->scalar.size ) { if( 0 == strcmp( tgt->scalar.name, src->scalar.name ) ) { retn = TRUE; } else { retn = FALSE; } } else { retn = FALSE; } break; default : GOOF( "TsEquiv -- bad THROBJ_..." ); } } } 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; }
void CPPLIB( lcl_register )( // REGISTRATION OF LOCAL INITIALIZATION RW_DTREG RT_FAR *rw ) // - read/write block { CPPLIB( mod_register )( rw ); }
FSREGAPI unsigned CPPLIB( fs_handler_rtn ) // HANDLER FOR FS REGISTRATIONS ( FsExcRec* rec_exc // - exception record , RW_DTREG* rw // - current R/W block , FsCtxRec* // - context record , unsigned // - dispatch context ) { unsigned retn; // - return code #ifdef RT_EXC_ENABLED if( 0 == rw ) { // rw == 0 only when called from pgm_thread THREAD_CTL* ctl = &_RWD_ThreadData; rec_exc->dispatch->rtc->thr = ctl; retn = EXC_HAND_CATCH; } else if( rec_exc->flags & EXC_TYPE_UNWIND_NORMAL ) { CPPLIB( destruct_internal )( 0, rw ); retn = EXC_HAND_CONTINUE; } else if( rec_exc->flags & EXC_TYPE_UNWIND_EXIT ) { if( rw->base.ro->base.reg_type == DTRG_STATIC_INITLS ) { // always unwind static initialization CPPLIB( destruct_internal )( 0, rw ); } retn = EXC_HAND_CONTINUE; } else if( EXCREC_CODE_WATCOM == ( EXCREC_CODE_MASK & rec_exc->code ) ) { // WATCOM EXCEPTION DISPATCHABLE type; // - type of dispatchability DISPATCH_EXC* dispatch; // - dispatch control dispatch = rec_exc->dispatch; if( dispatch->fnexc_skip == rw ) { dispatch->fnexc_skip = NULL; } _EXC_PR* srch_ctl; for( srch_ctl = dispatch->srch_ctl ; NULL != srch_ctl && srch_ctl->_rw == rw ; srch_ctl = srch_ctl->_prev ) { if( NULL == dispatch->fnexc_skip ) { switch( srch_ctl->_state ) { case EXCSTATE_UNEXPECTED : case EXCSTATE_BAD_EXC : dispatch->fnexc_skip = ((_EXC_PR_FNEXC*)srch_ctl)->_fnexc_skip; continue; } break; } } if( NULL != srch_ctl && srch_ctl->_rw == rw ) { type = DISPATCHABLE_STOP; } else if( NULL == dispatch->fnexc_skip ) { type = CPPLIB( dispatchable )( dispatch, rw ); } else { type = DISPATCHABLE_NONE; } if( DISPATCHABLE_NONE == type ) { if( rw == dispatch->fs_last ) { type = DISPATCHABLE_NO_CATCH; dispatch->type = type; retn = EXC_HAND_CATCH; } else { retn = EXC_HAND_CONTINUE; } } else { dispatch->type = type; retn = EXC_HAND_CATCH; } } else { #if 0 // future support for catch(...) to catch anything // not WATCOM throw / re-throw DISPATCHABLE type = CPPLIB( catch_any )( rec_exc, rw ); if( DISPATCHABLE_NONE == type ) { retn = EXC_HAND_CONTINUE; } else { retn = EXC_HAND_CATCH; } #else retn = EXC_HAND_CONTINUE; #endif } #else rw = rw; rec_exc = rec_exc; retn = EXC_HAND_CONTINUE; #endif return retn; }