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;
}