setjmp: read the manual(long article)
Hans van Staveren
sater at tjalk.UUCP
Tue Oct 23 01:35:39 AEST 1984
In article <914 at opus.UUCP> rcd at opus.UUCP (Dick Dunn) writes:
>Regarding the setjmp/longjmp interaction with register variables...
>dmr gave one approach and justified it on the basis of "correct" behavior.
>A response...
>> There's a good reason for doing it the other way: efficiency...
>
>Did I really miss something, or did someone just tell us that it is
>reasonable to compromise correctness for efficiency? I have a tough time
>with such compromises.
>
>>...
>> We looked hard at this and decided to change the meaning of
>> setjmp/longjmp (to the above) rather than having EVERY function save...
>
>The parent article goes on to describe problems with saving all the
>registers on a 68000. In fact, there is a "whizzo" (his words) instruction
>on the 68000 to save whatever set of registers you need, and you clearly
>won't need to save all of them.
Setjmp/longjmp and register variables
Hans van Staveren
Vrije Universiteit
Amsterdam, Holland
There has been some discussion going on in net.lang.c
about the semantics of setjmp/longjmp in combination with
register variables. Let me first give a short introduction
to the problem for those of you caught napping during the
start of the discussion:
#include <setjmp.h>
jmp_buf env;
main() {
register foo;
int bar;
foo=1;bar=2;
if (setjmp(env)!=0) {
printf("Foo=%d,bar=%d\n",foo,bar);
exit(0);
}
foo=3;bar=4;
subr();
abort(); /* cannot happen */
}
subr() {
longjmp(env,1);
}
The preceeding program when executed on our 4.1BSD Sys-
tem gave as output:
Foo=1,bar=4
How come? The setjmp routine on our system saves *all*
registers, and the longjmp call reloads them all. This
includes all register variables with the effect that
stackvariables after the longjmp have values as of the time
longjmp was called, while register variables have values as
of the time setjmp was called.
- 2 -
Obviously this is incorrect behaviour. Whatever the
motive may be for this implementation, it will give strange
results when porting software. So as a user I will give
cries from outrage when I encounter this: "Those %$##'&'(&
compiler writers, ...."
Now the problem as seen from the compiler writer's
point of view: In general the word register in front of a
declaration is a hint to the compiler that there may be some
advantage in putting the variable in a register. Now an
optimizing compiler might have different ideas, it might see
other variables more fit to put in registers, it might
notice that the overhead cost of saving and restoring the
register is more than the saving in its use, etc.
So the general problem boils down to this: Suppose
there is a number of registers, of different sizes and pro-
perties, and a number of variables with different sizes and
usage statistics, what is per procedure/function the best
assignment of variables to registers. This is already a
hard problem to solve.
The best solution to this problem will usually use a
different set of registers per procedure, and it is most
efficient to save only those registers that are actually
used in this procedure. At the beginning of the procedure
the registers are saved, at the end they are restored.
After the compiler writer has finished his task, he
will start implementing the library procedures, and what
does he see in chapter III? "Those %$&%%('' language
designers, ...." they put the non-local goto in the library
instead of the language, horrors! Now to implement
setjmp/longjmp as the users want it, there must be some way
to put the registers back to their proper values, if possi-
ble without changing all those closely thought out optimum
decisions for those functions that don't use that devilish
pair.
Solution 1, PDP 11, Unix V7:
Save exactly the same registers every function call,
csv/cret style. This is not optimum, but what the heck,
there are only three usable registers anyhow. At longjmp
time, just walk the stack and put them back. (Rhyme)
Solution 2, VAX 11, 4.1BSD:
Save all registers at setjmp time, put them back at longjmp
time. Just slightly incorrect, but what the heck, who cares
about the value of some locals.
Solution 3, VAX 11, 4.xBSD (don't know really):
Walk the stack at longjmp time, finding all those fancy
masks between the dozens of longwords in each stackframe,
and restore the right value. Lucky to have such a luxury
- 3 -
call mechanism he? It just costs more, but what the heck,
just upgrade to a 785 :-)
General solution, all machines, Amsterdam Compiler Kit:
Hold on to your chair, under 18 stop reading, compiler
writer's porno coming up. All those youngsters gone? Hey,
you there kid, hiding in the back, out with you!!
Well here it is. Have the C-frontend recognize the word
setjmp. In a function containing a call to setjmp save all
registers, use none, and at the end restore them all. At
longjmp time just close your eyes and jump, no registers
need be restored except the frame pointer, stack pointer and
program counter. This means that functions not using
setjmp/longjmp are not bothered, in general the compiler can
continue its fancy register optimizations and all programs
will run correct.
We would be glad if some magician out there would find
a way to do it without having the compiler know the word
setjmp, and without having extra cost for those functions
not using it. However, we don't think it is possible. C is
a language that has evolved, unfortunately the non-local
goto has never been tackled by the designers, and we feel
our solution is the best that can be done under the cir-
cumstances.
Hope I have been a help to the discussion, if you
disagree with our views do not hesitate to reply, flames
reduce the costs of heating :-) !!
--
Hans van Staveren, Vrije Universiteit Amsterdam
..!mcvax!vu44!sater
More information about the Comp.lang.c
mailing list