asm { #assert !((REGG_LOCAL_NON_PTR_VARS|REGG_LOCAL_VARS)&~0xFCC0) _TEST_EXCEPT:: XOR RAX,RAX MOV RAX,FS:U64 CTask.last_except[RAX] MOV RBP,U64 CExcept.rbp[RAX] MOV RSI,U64 CExcept.rsi[RAX] MOV RDI,U64 CExcept.rdi[RAX] MOV R10,U64 CExcept.r10[RAX] MOV R11,U64 CExcept.r11[RAX] MOV R12,U64 CExcept.r12[RAX] MOV R13,U64 CExcept.r13[RAX] MOV R14,U64 CExcept.r14[RAX] MOV R15,U64 CExcept.r15[RAX] PUSH U64 CExcept.rflags[RAX] POPFD JMP U64 CExcept.handler_catch[RAX] _TAKE_EXCEPT:: XOR RAX,RAX MOV RAX,FS:U64 CTask.last_except[RAX] MOV RSP,U64 CExcept.rsp[RAX] JMP U64 CExcept.handler_untry[RAX] _SAVE_EXCEPT_REGS:: PUSH RBP MOV RBP,RSP MOV RAX,U64 SF_ARG1[RBP] MOV U64 CExcept.rsi[RAX],RSI MOV U64 CExcept.rdi[RAX],RDI MOV U64 CExcept.r10[RAX],R10 MOV U64 CExcept.r11[RAX],R11 MOV U64 CExcept.r12[RAX],R12 MOV U64 CExcept.r13[RAX],R13 MOV U64 CExcept.r14[RAX],R14 MOV U64 CExcept.r15[RAX],R15 POP RBP RET1 8 } _extern _TEST_EXCEPT U0 TestExcept(); _extern _TAKE_EXCEPT U0 TakeExcept(); _extern _SAVE_EXCEPT_REGS U0 SaveExceptRegs(CExcept *t); U0 PutExcept(Bool catch_it=TRUE) {//Print exception message and catch exception. "Except:%c:",Fs->except_ch; "%P:%P:%P:%P:%P:%P\n",Fs->except_callers[0],Fs->except_callers[1], Fs->except_callers[2],Fs->except_callers[3],Fs->except_callers[4], Fs->except_callers[5],Fs->except_callers[6],Fs->except_callers[7]; Fs->catch_except=catch_it; } #exe {Option(OPTf_NO_REG_VAR,ON);}; class CTryStack { I64 rbp; I64 ret_rip; I64 arg1; I64 arg2; }; U0 SysTry(U8 *catch_start,U8 *untry_start) { I64 *rbp=RBPGet; CExcept *tmpt=MAlloc(sizeof(CExcept)); tmpt->handler_catch=catch_start; tmpt->handler_untry=untry_start; tmpt->rsp=rbp(U8 *)+sizeof(CTryStack); tmpt->rbp=*rbp; tmpt->rflags=RFlagsGet; SaveExceptRegs(tmpt); QueueInsert(tmpt,Fs->last_except); } U0 SysUntry() { CExcept *tmpt=Fs->last_except; QueueRemove(tmpt); Free(tmpt); } U0 throw(I64 ch=0,Bool no_log=FALSE) {//ch can be up to 8 chars like $LK,"PutChars",A="MN:PutChars"$(). //In the catcher, fetch ch from Fs->except_ch. CExcept *tmpt=Fs->last_except; Bool was_raw; I64 i; Fs->except_ch=ch; for (i=0;iexcept_callers[i]=Caller(i+1); Fs->except_rbp=RBPGet; Fs->catch_except=FALSE; if (!no_log) ZenithLog("Except:%c:%p:%p:%p:%p:%p:%p\n",ch,Fs->except_callers[0], Fs->except_callers[1],Fs->except_callers[2],Fs->except_callers[3], Fs->except_callers[4],Fs->except_callers[5],Fs->except_callers[6], Fs->except_callers[7]); while (Fs->next_except!=&Fs->next_except) { TestExcept; if (Fs->catch_except) TakeExcept; RBPSet(Fs->except_rbp); tmpt=Fs->last_except; QueueRemove(tmpt); Free(tmpt); } was_raw=Raw(ON); PutExcept(FALSE); Panic("Unhandled Exception"); Raw(was_raw); } #exe {Option(OPTf_NO_REG_VAR,OFF);}; U0 Break() {//Send . if (Bt(&Fs->task_flags,TASKf_BREAK_TO_SHIFT_ESC)) Message(MESSAGE_KEY_DOWN,CH_SHIFT_ESC,0x20100000201); else { Fs->wake_jiffy=0; TaskResetAwaitingMessage; DrivesRelease(); BlkDevsRelease(); FlushMessages; throw('Break'); } } Bool BreakLock(CTask *task=NULL) {//Disables . if (!task) task=Fs; return !LBts(&task->task_flags,TASKf_BREAK_LOCKED); } Bool BreakUnlock(CTask *task=NULL) {//Reenables and issues any pending breaks. Bool res; if (!task) task=Fs; res=LBtr(&task->task_flags,TASKf_BREAK_LOCKED); if (LBtr(&task->task_flags,TASKf_PENDING_BREAK)) { if (task==Fs) Break; else task->rip=&Break; } return res; }