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; i < TASK_EXCEPT_CALLERS; i++)
		Fs->except_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 <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;
}
