<p>In Guy Steele’s famous paper <a href="https://doi.org/10.1145/800179.810196" rel="noreferrer">Debunking the “expensive procedure call” myth or, procedure call implementations considered harmful or, LAMBDA: The Ultimate GOTO</a>, he describes the poor performance of procedure calls on what was then a state-of-the-art optimizing compiler:</p>
<blockquote>
<p>Auslander and Strong [<a href="https://doi.org/10.1145/359340.359344" rel="noreferrer">Aus76</a>] report that one simple procedure call, compiled by the OS/360 PL/I optimizing compiler, pushes 336 bytes onto the stack! Yourdon [You75,98] reports that on a 360/50 a PL/I procedure call costs 198 microseconds. It is no wonder that programmers feel that procedure calls are slow — they are!</p>
</blockquote>
<p>Following the citations does not provide much insight into why things were so bad. Aus76 points to <a href="https://doi.org/10.1145/359340.359344" rel="noreferrer">Systematic recursion removal</a>, which merely mentions the size of the stack frames in passing. You75 appears to be a textbook, which I could not find online, but it is unlikely to go into such details, either.</p>
<p>This leaves one wondering why precisely this system’s procedure calls were so expensive. Steele provides a few broad possible explanations, but 336 bytes is quite a lot for a supposedly “simple” call. What were all these bytes used for? And how many more bytes did OS/360 PL/I use for this procedure call relative to an equivalent in MacLISP?</p>

<functions><calling-conventions><history><call-stack>
Why were OS/360 PL/I procedure calls so expensive?
CC BY-SA 4.0
2023-07-24T19:26:49.907Z
This might be better asked on [retrocomputing.se].
Karl Knechtel
CC BY-SA 4.0
2023-07-24T19:45:57.420Z
Looking at the [IBM System/360 calling convention](https://en.wikipedia.org/wiki/Calling_convention#IBM_System/360_and_successors) it seems each procedure allocates enough space for its callees to save all of the registers, so that’s 72 bytes (16 32-bit registers, plus the 64-bit program status word) but I don’t know where the rest comes from.
Jon Purdy
CC BY-SA 4.0
2023-07-24T20:28:05.393Z
I was looking for the You75 reference and I found a very harsh review which reads like something some clinically online troll would write. https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://www.cs.utexas.edu/users/EWD/ewd05xx/EWD564.PDF&ved=2ahUKEwjZwfGOlqiAAxUicaQEHTDCAPgQFnoECA0QAQ&usg=AOvVaw0vXa4tXYM86AI6Pud_vzxL   but it's from Dijkstra
coredump
CC BY-SA 4.0
2023-07-25T06:26:31.270Z
@coredump: I like the appearance of [Muphry's Law](https://en.wikipedia.org/wiki/Muphry%27s_law) on the second page ("speal").  He walked right into that one.
Nate Eldredge
CC BY-SA 4.0
2023-07-25T08:22:12.377Z
In Aus76, it says *"At each recursive call each locally declared identifier is a candidate for storage (by stacking)."* Were all local variables usually pushed on stack? (which is different from stack frames as implemented nowadays)
coredump
CC BY-SA 4.0
2023-07-25T21:35:14.443Z
I think that the answer will ultimately boil down to the fact that the IBM System/360 was designed back in 1964, when the very concept of "procedure calls" (especially *recursive* ones) was new, and neither hardware nor compiler designers really understood how to implement them efficiently.
dan04
CC BY-SA 4.0
2023-07-25T22:01:09.223Z
@dan04 This may be true, but I’d still like to understand the specific *way* in which the compiler failed to do a good job. Also, it’s worth saying that MacLISP, presented as an alternative in the paper that does a much better job, dates back to 1966, so it’s not as though such things were unheard of back then.
Alexis King
CC BY-SA 4.0
2023-07-27T00:00:14.310Z
I suspect the reason is that PL/I procedure calls used the same stack protocol as calling into the OS. MacLisp implemented its own stack, so it could do it more efficiently than the general mechanism used in PL/I.
Barmar
# Why were OS/360 PL/I procedure calls so expensive?
Posted by: username_0 on 2023-07-24
In Guy Steele’s famous paper [Debunking the “expensive procedure call” myth or, procedure call implementations considered harmful or, LAMBDA: The Ultimate GOTO](https://doi.org/10.1145/800179.810196), he describes the poor performance of procedure calls on what was then a state-of-the-art optimizing compiler:

> Auslander and Strong [[Aus76](https://doi.org/10.1145/359340.359344)] report that one simple procedure call, compiled by the OS/360 PL/I optimizing compiler, pushes 336 bytes onto the stack! Yourdon [You75,98] reports that on a 360/50 a PL/I procedure call costs 198 microseconds. It is no wonder that programmers feel that procedure calls are slow — they are!

Following the citations does not provide much insight into why things were so bad. Aus76 points to [Systematic recursion removal](https://doi.org/10.1145/359340.359344), which merely mentions the size of the stack frames in passing. You75 appears to be a textbook, which I could not find online, but it is unlikely to go into such details, either.

This leaves one wondering why precisely this system’s procedure calls were so expensive. Steele provides a few broad possible explanations, but 336 bytes is quite a lot for a supposedly “simple” call. What were all these bytes used for? And how many more bytes did OS/360 PL/I use for this procedure call relative to an equivalent in MacLISP?
**Tags:** functions calling-conventions history call-stack
> **Comments:**
> **username_1**: This might be better asked on [retrocomputing.se].  
> **username_2**: Looking at the [IBM System/360 calling convention](https://en.wikipedia.org/wiki/Calling_convention#IBM_System/360_and_successors) it seems each procedure allocates enough space for its callees to save all of the registers, so that’s 72 bytes (16 32-bit registers, plus the 64-bit program status word) but I don’t know where the rest comes from.  
> **username_3**: I was looking for the You75 reference and I found a very harsh review which reads like something some clinically online troll would write. https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://www.cs.utexas.edu/users/EWD/ewd05xx/EWD564.PDF&ved=2ahUKEwjZwfGOlqiAAxUicaQEHTDCAPgQFnoECA0QAQ&usg=AOvVaw0vXa4tXYM86AI6Pud_vzxL   but it's from Dijkstra  
> **username_4**: @coredump: I like the appearance of [Muphry's Law](https://en.wikipedia.org/wiki/Muphry%27s_law) on the second page ("speal").  He walked right into that one.  
> **username_3**: In Aus76, it says *"At each recursive call each locally declared identifier is a candidate for storage (by stacking)."* Were all local variables usually pushed on stack? (which is different from stack frames as implemented nowadays)  
> **username_5**: I think that the answer will ultimately boil down to the fact that the IBM System/360 was designed back in 1964, when the very concept of "procedure calls" (especially *recursive* ones) was new, and neither hardware nor compiler designers really understood how to implement them efficiently.  
> **username_0**: @dan04 This may be true, but I’d still like to understand the specific *way* in which the compiler failed to do a good job. Also, it’s worth saying that MacLISP, presented as an alternative in the paper that does a much better job, dates back to 1966, so it’s not as though such things were unheard of back then.  
> **username_6**: I suspect the reason is that PL/I procedure calls used the same stack protocol as calling into the OS. MacLisp implemented its own stack, so it could do it more efficiently than the general mechanism used in PL/I.  
---
## 0 answers
