;***
;setjmp3.asm
;
;	Copyright (C) 1994 Microsoft Corporation. All rights reserved.
;
;Purpose:
;	Contains setjmp(), longjmp() & raisex() routines;
;	split from exsup.asm for granularity purposes.
;
;Notes:
;
;Revision History:
;	01-12-94  PML	Split from setjmp.asm, added C9.0 generic EH
;			callback for unwind.
;	02-10-94  GJF	-1 is the end-of-exception-handler chain marker, not
;			0.
;
;*******************************************************************************

;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;

;Define small32 and flat32 since these are not defined in the NT build process
small32 equ 1
flat32  equ 1

.xlist
include pversion.inc
?DFDATA =	1
?NODATA =	1
include cmacros.mas
include exsup.inc
.list

assumes DS,DATA
assumes FS,DATA

BeginCODE
if	@Version LT 600
;this needs to go here to work around a masm5 bug. (emits wrong fixup)
assumes CS,FLAT
endif

; Following symbol defined in exsup.asm
extrn __except_list:near

; int
; _setjmp3 (
;	OUT jmp_buf env,
;	int count,
;	...)
;
; Routine Description:
;
;	(New) implementation of setjmp intrinsic.  Saves the current
;	nonvolatile register state in the specified jump buffer and returns
;	a function value of zero.
;
;	Saves the callee-save registers, stack pointer and return address.
;	Also saves the exception registration list head.  If setjmp is
;	called from a function using any form of exception handling, then
;	additional data is also saved allowing some form of local unwind
;	at longjmp time to restore the proper exception handling state.
;
; Arguments:
;
;	env - Address of the buffer for storing the state information
;	count - count of additional DWORDs of information.  Zero if setjmp
;		not called from a function with any form of EH.
;	...	Additional data pushed by the setjmp intrinsic if called
;		from a function with any form of EH.  The first DWORD is
;		a function ptr which will be called at longjmp time to do
;		the local unwind.  The second DWORD is the try level to be
;		restored (if applicable).  Any further data is saved in the
;		generic data array in the jmp_buf for use by the local
;		unwind function.
;
; Return Value:
;
;	A value of zero is returned.

public __setjmp3
__setjmp3 PROC NEAR
        mov     edx, [esp+4]
        mov     [edx.saved_ebp], ebp    ; old bp and the rest
        mov     [edx.saved_ebx], ebx
        mov     [edx.saved_edi], edi
        mov     [edx.saved_esi], esi
        mov     [edx.saved_esp], esp

        mov     eax, [esp]              ; return address
        mov     [edx.saved_return], eax

	mov	dword ptr [edx.version_cookie], JMPBUF_COOKIE
	mov	dword ptr [edx.unwind_func], 0

        mov     eax, dword ptr fs:__except_list
        mov     [edx.saved_xregistration], eax

	cmp	eax, -1 		; -1 means no higher-level handler
	jnz	short _s3_get_count
        mov     dword ptr [edx.saved_trylevel], -1 ;something invalid
	jmp	short _s3_done

_s3_get_count:
	mov	ecx, [esp+8]		; count of additional data
	or	ecx, ecx
	jz	short _s3_default_trylevel

	mov	eax, [esp+12]		; func to do local unwind at longjmp
	mov	[edx.unwind_func], eax
	dec	ecx
	jnz	_s3_save_trylevel

	; Not called from a function with any form of EH, or no trylevel
	; passed.  Save the TryLevel from the topmost EH node anyway,
	; assuming a C8.0 SEH node.  If we're linked to an obsolete CRTDLL
	; and call the old longjmp, then we'll still do the right thing.
_s3_default_trylevel:
        mov     eax, [eax + C8_TRYLEVEL]
        mov     [edx.saved_trylevel], eax
	jmp	short _s3_done

_s3_save_trylevel:
	mov	eax, [esp+16]		; try level to unwind to
	mov	[edx.saved_trylevel], eax
	dec	ecx
	jz	short _s3_done

	push	esi
	push	edi
	lea	esi, [esp+20+8]
	lea	edi, [edx.unwind_data]
	cmp	ecx, 6			; save up to 6 more DWORDs in jmp_buf
	jbe	_s3_save_data
	mov	ecx, 6

_s3_save_data:
	rep movsd
	pop	edi
	pop	esi

_s3_done:
        sub     eax, eax
        ret
__setjmp3 ENDP

EndCODE
END
