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