Path: utzoo!utgpu!attcan!uunet!lll-winken!ames!haven!purdue!decwrl!hplabs!sm.unisys.com!csun!polyslo!cquenel From: cquenel@polyslo.CalPoly.EDU (94 more school days) Newsgroups: comp.lang.c Subject: Re: Behaviour of setjmp/longjmp and registers Message-ID: <7374@polyslo.CalPoly.EDU> Date: 26 Jan 89 05:11:39 GMT References: <25@torsqnt.UUCP> <8867@bloom-beacon.MIT.EDU> <7222@polyslo.CalPoly.EDU> <1989Jan23.005859.24468@utzoo.uucp> <7283@polyslo.CalP <24193@amdcad.AMD.COM> Reply-To: cquenel@polyslo.CalPoly.EDU (94 more school days) Organization: Blue Blaze Irregulars Lines: 217 Sorry for the length guys, but I think this will clear a lot up. Present are responses follow to the following people: henry@utzoo.uucp writes : ark@alice.UUCP (Andrew Koenig) writes: chris@mimsy.UUCP (Chris Torek) writes: geoff@warwick.UUCP (Geoff Rimmer) writes: haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes : tim@crackle.amd.com (Tim Olson) writes: In the last few articles I'm afraid I've been misunderstood a little bit. I'd like to try again. I think some people have there has been some confusion over two behaviours associated with variables at longjmp time. I will use the word CONSERVED when a variable is unaffected by a long jump. I will use the word RESTORED when a variable is given the value that it had at setjmp-time (either "for free" or by copying it's old value back into it). Under older systems, automatic variables were CONSERVED, and register variables were RESTORED. To illustrate the difference consider the following pseudo-code: routine() { /* register */ int i; i = BEFORE_VALUE; call to set_jmp(); i = AFTER_VALUE; call to routine_which_calls_long_jmp(); } If i is declared REGISTER, then "normally" it would be RESTORED. It's value would be BEFORE_VALUE. If i is NOT declared register, then normally it would be CONSERVED. It's value would be AFTER_VALUE. ANSI guarantees that variables declared volatile will be CONSERVED. It does not say that ANY variables have to be restored. On stack-based machines with conventional registers and calling sequences you get automatic variable CONSERVATION for free. (You have to write out all your automatic variables that are alive in registers.) On those conventional systems, you also get RESTORED automatics under the following circumstances: If you declare it to be of register storage class, AND the compiler ACTUALLY puts it in a register. While I don't know of any compiler that GUARANTEES that ALL "register" declarations result in actual registers being used, I'm sure some people would assume that it is a safe bet that ONE or TWO register declarations will be honored. Although this is non-portable strictly speaking, it probably works most of the time. I see no problem with a compiler going beyond the ANSI spec and guaranteeing that ALL automatic variables will be CONSERVED. I think this is a very reasonable thing. And it can be achieved without added setjmp-time baggage, on a fairly conventional machine. No general registers need to stored for this to happen ! My argument is that no code would rely on registers being RESTORED. Returning from a longjmp and having all your local registers trashed would be a hassle to deal with, I admit. But the alternative is to have them be the values at the time the setjmping procedure called the longjmping procedure. From the Pyramid man page on setjmp/longjmp: ... All memory-bound data have values as of the time longjmp was called. The machine registers are restored to the values they had at the time that setjmp was called. But, because the register storage class is only a hint to the C compiler, variables declared as register variables may not necessarily be assigned to machine registers, so their values are unpredictable after a longjmp. This is especially a problem for programmers try- ing to write machine-independent C routines. ... [There follows an example with a careful note NOT to modify register variables after calling setjmp. This is because their values will be indeterminate on a Pyramid. It would not be too much trouble to conserve them, just ignore the register declaration in a routine that calls setjmp.] henry@utzoo.uucp writes : >However, an implementation that simply trashes the registers (rather, >allows them to be trash) or, still worse, does likewise for automatic >variables not declared "register" (i.e. by promoting them to registers >and then not preserving them), is probably not going to sell well when >word gets around. You are correct, perhaps ANSI could have guaranteed that automatics would be CONSERVED. My point was that none should be RESTORED. ark@alice.UUCP (Andrew Koenig) writes: >...John Reiser figured out a way around it -- a nifty version of >longjmp that unwound the stack, restoring the correct registers >at each iteration -- and that went into at least some VAX C >implementations. This allows register variables to be truly RESTORED without the space and time overhead of saving all the registers in the jmp_buf. However, the calling convention that supported it was rather luxurious (read : expensive) in its own right. chris@mimsy.UUCP (Chris Torek) writes: >But the contents of *all* automatic variables (register or not) *can* be >guaranteed without too much trouble, and without requiring `volatile' >qualifiers. Granted, they can be guaranteed CONSERVED. They are not RESTORED. I wrote previously: >I think this newer definition of setjmp/longjmp is much cleaner >and provides only what is necessary and most useful. chris@mimsy.UUCP (Chris Torek) writes: >This is a separate (and much more sensible) line of argument with >which I happen not to agree: opinion as to elegance. I think that CONSERVING all automatic variables but RESTORING none of them is more elegant than CONSERVING all non-register automatic variables and sort-of-restoring or maybe-restoring register variables. I say that CONSERVING them all and RESTORING non of them is best. geoff@warwick.UUCP (Geoff Rimmer) writes: >I don't know what the ANSI standard says, but our manual page for >setjmp() mentions in passing that > > register variables have unpredictable values code after the > return from longjmp > >So, it's probably just luck that the Sequent, Ultrix and Vax C >compiler give what you'd expect from a non-register variable: It seems like restoring register variables to an unknown state is a pretty common thing to do. My argument is that all these venders instead of saying "register variables are in an unknown state" should NOT RESTORE THEM, and should write them to the stack, and should say that they are CONSERVED. It ocurrs to me that this would require the following extra work on the part of their compilers: reserving space for register variables on the stack and dumping even [registers that could be guaranteed across procedure calls] to the stack. haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes : >a setjmp/longjmp implementation that restores all variables (including >those in registers) falls out of a caller saves function call protocol. >no muss, no fuss, just restore the stack pointer and pc. this will >work in the presence of inter-procedural optimization, if setjmp() is >marked as a function that trashes all registers. Using a full caller-saves convention by itself will not even allow you to CONSERVE register variables, much less RESTORE them. (Although when Paul said "restore" he may have meant CONSERVE). When the first return from setjmp takes place, all those nicely saved register values are popped off the stack. NEVER TO BE PUSHED AGAIN. :-) If you want your registers to be RESTORED, you have to save them in the jmp_buf. haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes : >this is one of the several reasons i consider caller-saves a better >approach to function call protocol. Both pure-caller-save and pure-callee-save have their benefits, but I personally believe that a combined caller-callee saves protocal works best. tim@crackle.amd.com (Tim Olson) writes: [In response to my saying that register windows made setjmp a big deal] >Register-windowed machines are usually very easy to write >setjmp()/longjmp() for, because the registers are treated as a >"stack-cache". Thus, all you have to save is the current stack-cache >pointer in the jmpbuf, and restore it upon a longjmp(). This makes >automatic variables act just as statics do: their value is that as of >the time of the longjmp(). This is much cleaner than the botch of >saving the register contents in the jmpbuf and restoring them. > >Of course, you still have to worry about optimizations such as register >coalescing, etc. You are correct. I was in error. Sliding register window machines SHOULD be easy to write setjmp/longjmp for. The simple solution of restoring the Control Stack (or Register Stack) Pointer to its old value have the effect of CONSERVING register variables, but not of RESTORING to their values at setjmp time. I think this is a very sane way to do it. --chris ------------------------------------------------------------------------------- | Nothing the God of Bio-Mechanics wouldn't let you in heaven for ? | ------------------------------------------------------------------------------- | Chris Quenelle | Smart Mailers -> cquenel@polyslo.CalPoly.EDU | | Computer Systems Lab | Dumb Mailers -> !ucbvax!voder!polyslo!cquenel | | Cal Poly State Univ. |-------------------------------------------------| | San Luis Obispo, CA 93407 | On a clear disk you can seek forever. | -------------------------------------------------------------------------------