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