ack/lang/cem/libcc/gen/setjmp.e
1987-01-27 15:57:55 +00:00

148 lines
3.4 KiB
Plaintext

#
mes 2,EM_WSIZE,EM_PSIZE
exp $setjmp
pro $setjmp,2*EM_WSIZE
; setjmp saves the StackPointer and the LocalBase, and the chunk of
; memory between the StackPointer and the ArgumentBase, + its size in a
; buffer, pointed to by the parameter.
; longjump can then restore this buffer and return.
; Notice that this does not work on EM implementations in which every
; procedure frame has a different fragment in memory, because in this case
; the ArgumentBase will point into the fragment of the caller.
; What really is needed is a way to find out the size of the return
; status block.
; On EM-implementations in which the stack grows upwards it is untested,
; as there are no such implementations available now.
; This implementation of setjmp/longjmp
; depends on the assumption that the routine calling
; setjmp does not have register variables, and that it saves all registers
; that are available for variables.
loc 0
stl -2*EM_WSIZE
lor 1 ; load StackPointer
lal 0
loi EM_PSIZE
sti EM_PSIZE ; save it
lxl 0 ; load LocalBase
lal 0
loi EM_PSIZE
adp EM_PSIZE
sti EM_PSIZE ; save it
lxa 0 ; load ArgumentBase
lal 0
loi EM_PSIZE
loi EM_PSIZE ; load saved StackPointer
sbs EM_WSIZE ; gives size of block that is to be saved, or negative size
dup EM_WSIZE
zgt *5
ngi EM_WSIZE
loc 1
stl -2*EM_WSIZE; one if the stack grows upwards
5
stl -EM_WSIZE ; save size of block in local
lol -EM_WSIZE
lal 0
loi EM_PSIZE
adp 2*EM_PSIZE
sti EM_WSIZE ; and also in the buffer
lal 0
loi EM_PSIZE
loi EM_PSIZE ; load saved StackPointer
lol -2*EM_WSIZE; positive if the stack grows upwards
zle *6
asp EM_PSIZE
lxa 0
adp EM_WSIZE ; in this case the source address = ArgumentBase+EM_WSIZE
6
lal 0
loi EM_PSIZE
adp 2*EM_PSIZE+EM_WSIZE
; destination address
lol -EM_WSIZE ; count
bls EM_WSIZE ; block copy
loc 0
ret EM_WSIZE
end 2*EM_WSIZE
exp $longjmp
pro $longjmp,2*EM_WSIZE
; first, find out wether the stack grows upwards
loc 0
stl -2*EM_WSIZE
lxa 0
lxl 0
cmp
zge *7
loc 1
stl -2*EM_WSIZE; this local contains 1 if it does, otherwise it contains 0
7
; then, adjust StackPointer until it is below the saved StackPointer (or
; above if it grows upwards)
; then push parameters
; then copy the saved block in its proper place
; notice that the parameters can not be used anymore now
; then restore the LocalBase and the Stackpointer and return.
1
loc 0
2
lor 1
lal 0
loi EM_PSIZE
loi EM_PSIZE ; saved StackPointer
cmp ; compare with current one
lol -2*EM_WSIZE
zle *8
zlt *1
bra *10
8
zgt *1
10
lal 0
loi EM_PSIZE
loi EM_PSIZE ; push saved StackPointer
lol EM_PSIZE ; push value to be returned by longjmp
lal 0
loi EM_PSIZE
adp EM_PSIZE
loi EM_PSIZE ; push saved LocalBase
lal 0
loi EM_PSIZE
adp 2*EM_PSIZE+EM_WSIZE
; source address
lal 0
loi EM_PSIZE
loi EM_PSIZE ; saved stackpointer
lol -2*EM_WSIZE
zle *9 ; if not positive, this is the destination address,
; otherwise subtract the size of the saved area and add EM_WSIZE
adp EM_WSIZE
lal 0
loi EM_PSIZE
adp 2*EM_PSIZE
loi EM_WSIZE
ngi EM_WSIZE
ads EM_WSIZE
9 ; destination address
lal 0
loi EM_PSIZE
adp 2*EM_PSIZE
loi EM_WSIZE ; size
bls EM_WSIZE ; now we have a frame exactly as it was in setjmp,
; and exactly at the same place
str 0 ; restore LocalBase
stl -EM_WSIZE ; saves the return value
str 1 ; restores the StackPointer
lol -EM_WSIZE
dup EM_WSIZE
zne *3
; of course, longjmp may not return 0!
asp EM_WSIZE
loc 1
3
ret EM_WSIZE
end 2*EM_WSIZE