Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!rochester!pt.cs.cmu.edu!sei.cmu.edu!firth From: firth@sei.cmu.edu (Robert Firth) Newsgroups: comp.lang.c Subject: Re: structure function returns -- how? Message-ID: <497@aw.sei.cmu.edu.sei.cmu.edu> Date: Mon, 22-Dec-86 10:48:32 EST Article-I.D.: aw.497 Posted: Mon Dec 22 10:48:32 1986 Date-Received: Mon, 22-Dec-86 22:41:31 EST References: <131@hcx1.UUCP> <773@maynard.BSW.COM> <7403@utzoo.UUCP> <490@aw.sei.cmu.edu.sei.cmu.edu> <7434@utzoo.UUCP> Sender: netnews@sei.cmu.edu Reply-To: firth@bd.sei.cmu.edu.UUCP (PUT YOUR NAME HERE) Organization: Carnegie-Mellon University, SEI, Pgh, Pa Lines: 103 In article <7434@utzoo.UUCP> henry@utzoo.UUCP (Henry Spencer) writes: >> (c) Function allocates static space and returns pointer. Caller copies. >> >> This is not reentrant, as has been pointed out. Nor does it work if >> the function is recursive... > >Not true, given proper code generation. The static area need be in use >only during the return sequence, hence recursion is no problem -- execution >of multiple instances of a recursive function overlaps, but the return >sequences need not. Static-area return values may even speed up recursive >returns, since less copying may be needed. Reentrancy is another story, >although it should be noted that reentrancy is another story for a *whole* >*lot* of things in a C/Unix environment: a signal handler has to be very >careful, since locking out signal handlers during critical sections in (say) >stdio is expensive and hence seldom done. > Agreed, but the codegeneration had better be very careful. The trouble comes if you are returning a composite value, and the computation of one or more components involves a function call. You can't use the return area to build up the value component by component. >>(e) Function leaves result on stack. >> >> This is usually easiest for the function. The problem is that on many >> systems an interrupt or signal will destroy the result. (flame)(This is a >> symptom of a major and persistent system design error: the use of a >> hardware register pointing into user space as a place to dump junk. It >> is compounded by language implementations that use the hardware stack >> to allocate the LIFO address space of local variables)... > >No, it's a symptom of a major and persistent software error: using a stack >pointer as if it were an index register. If you get it firmly into your >head that you are dealing with a *stack*, not just an index register that >happens to increment and decrement automatically in some circumstances, >then the problem goes away. When you say "leaves result on stack", what >you really mean is "leaves result beyond the end of the stack, assuming that >the stack will not be used as a stack until the result is picked up". It >is possible, although often awkward, to leave the result *on the stack*, >i.e. as if it had been pushed onto the stack, in which case there isn't a >problem with interrupts or signals. (This is approximately what your e3 >alternative does, but in an unnecessarily roundabout way using a magic >run-time routine.) Alternatively, it's bad hardware design adding special semantics to one of the index registers... Let's agree that hardware stacks are a mess and agree to differ on the cause of the mess. Pushing the result on the hardware stack and then taking the return can be very hard indeed, since the Return instruction usually pops the link off the stack. So you have to copy maybe the entire call frame below your pushed result. It most cases that's a lot of code, and you probably want it out of line. >> (d) Function allocates heap space, rest as above. >> >> ...always works but can be rather expensive. > >It always works in the absence of reentrancy, or if your memory allocator >is reentrant, which many aren't. Yes, Henry, thank you for the caveat. I confess I had simply forgotten that people design languages in which preemptive parallelism is possible and then don't make the libraries properly reentrant. >Additional alternatives that you have missed are some variations on (b) >(caller preallocates): (1) it isn't necessary for the address to be passed >as a parameter if the caller and callee can establish mutual agreement >on where the result goes, although this is generally practical only if >the stack is contiguous; (2) it may be possible to use the argument area >as the return area, if the caller ensures it is big enough and avoids >popping it off the stack or re-using it before picking up the result, >and the callee makes sure that result copying comes after all uses of >arguments (especially in the case where the returned value is the value >of an argument). Agreed. I was giving only general methods that should work on most machines, but failed to make that clear. These are all possible tricks it's useful to know. Your (1) saves a parameter (and may simplify the stack handling on the caller's side); I'm dubious whether the space saved by (2) is worth the burden it places on the called function. Just to repeat a point, I still think the key factor in the design is whether the caller ALWAYS knows the size of the returned value. If it does, you have a several easy solutions; if it doesn't, you have a harder task. And this does affect implementors of C, if they want to use the same codegenerator for C and for languages with dynamically-sized return values. >[Incidentally, it reflects badly on you to chide us for re-inventing the >wheel when you seem not to be aware of some of the prior art yourself. >You might find Bell Labs Computing Science Tech Report No. 102, "The C >Language Calling Sequence", by Johnson and Ritchie, Sept. 1981, to be >interesting reading.] >-- > Henry Spencer @ U of Toronto Zoology > {allegra,ihnp4,decvax,pyramid}!utzoo!henry Well, what I said was "It's a shame to see people reinvent solutions". If that gave the impression of chiding someone, I apologise; the comment was meant purely as an introduction to what was supposed to be a technically helpful post. Incidentally, why do you think I haven't read a work just because I don't quote it? Now if only C had full type checking of parameter lists!