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 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; i < TASK_EXCEPT_CALLERS; i++) Fs->except_callers[i] = Caller(i + 1); Fs->except_rbp = RBPGet; Fs->catch_except = FALSE; if (!no_log) SysLog("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 <CTRL-ALT-c>. 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 <CTRL-ALT-c>. if (!task) task = Fs; return !LBts(&task->task_flags, TASKf_BREAK_LOCKED); } Bool BreakUnlock(CTask *task=NULL) {//Reenables <CTRL-ALT-c> 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; }