<p>This is more a question about compiler design than language design, but in low level languages, when a function is called, the parameters are pushed onto the stack, and when the function returns, the parameters are cleared from the stack.</p>
<p>As I understand this, one way that the stack is cleared is that the caller clears up the stack, where instructions to clear the parameters are inserted after the call instruction at the call site. Another way is that callee clears the parameters, where the last instructions of the function body are the instructions to clean up the parameters.</p>
<p>What are the reasons to choose one implementation over the other?</p>
<p><em>Inspired by <a href="https://langdev.stackexchange.com/a/2217/38">this answer</a>.</em></p>

<calling-conventions><assembly>
What are the advantages and disadvantages of the callee versus caller clearing the stack after a call?
CC BY-SA 4.0
2023-07-09T05:58:49.807Z
Does this answer your question? [Why was C implemented with a register preservation convention that seems to be far less efficient than its predecessor's?](https://langdev.stackexchange.com/questions/618/why-was-c-implemented-with-a-register-preservation-convention-that-seems-to-be-f)
Gilles 'SO- stop being evil'
CC BY-SA 4.0
2023-07-09T09:40:41.600Z
Can someone explain the votes to close this? It seems on topic to me.
Bruce Adams
CC BY-SA 4.0
2023-07-09T12:29:36.697Z
@BruceAdams they're dupe votes
Seggan
CC BY-SA 4.0
2023-07-09T12:58:31.947Z
I see. Sometimes two very differently phrased questions can have the same answer. I don't think that makes the questions themselves duplicates. I reserve the close and duplicate vote for when the question is actually the same.
Bruce Adams
CC BY-SA 4.0
2023-07-09T14:04:35.390Z
By "clearing the stack" do you mean only resetting the stack pointer and frame pointer registers or also something else?
Bergi
CC BY-SA 4.0
2023-07-09T15:48:16.773Z
@BruceAdams I believe general SE policy is that if a single answer answers two questions, one of them should be closed as a duplicate (so any one searching either question gets led to the one answer). Think of it as "_There is an existing answer_", rather than "_This is a duplicate question_".
TripeHound
CC BY-SA 4.0
2023-07-09T16:34:38.613Z
That would only work if closed questions weren't deleted. Is it the case the questions closed as duplicates are excluded from being hoovered?
Bruce Adams
CC BY-SA 4.0
2023-07-10T03:24:41.870Z
In fact yes, @BruceAdams, questions closed as dupes *are* (partially) protected from automatic deletion.  There are several alternative sets of [criteria for automatic question deletion](https://meta.stackexchange.com/help/auto-deleted-questions), but the one based on question closure not accompanied by site migration does exclude questions closed as duplicates.
John Bollinger
CC BY-SA 4.0
2023-07-12T13:02:48.727Z
Is it obvious what "*clearing the stack*" means here? Is it simply changing the stack pointer, or is there more to it than that?
Ray Butterworth
<p>Consider interrupts.</p>
<p>An interrupt can happen at any point of the program. The caller is not the one calling the interrupt - outside events cause the CPU to autonomously call the interrupt function with no action from the running program.</p>
<p>If the caller is responsible for saving and restoring state then correctly handling interrupts would be impossible since the program did not call the interrupt (also, most CPU designs will <strong>not</strong> save state for you with rare exceptions like Sun's Sparc register windows - even then, the hardware does not save all states).</p>
<p>You can of course design a runtime where the caller is responsible for saving and restoring state except for interrupt handlers - but this would require you to implement 2 types of functions: caller-save functions and callee-save functions. If you <strong>must</strong> implement callee-save functions why bother implement the caller-save mechanism?</p>

CC BY-SA 4.0
2023-07-09T13:13:18.607Z
2023-07-09T13:13:18.607Z
slebetman
CC BY-SA 4.0
2023-07-09T14:01:02.697Z
ISR prologue and epilogue are usually different from normal function prologue and epilogue anyway, aren't they?
Bergi
<p>Some advantages of &quot;caller clears stack&quot;:</p>
<ul>
<li>Depending on whether/how you have variadic parameters, the calling code would statically know how many arguments are present, whereas the callee would have to dynamically determine how many arguments to clear, which would cost a level of indirection</li>
<li>If the function has multiple exit points, then each &quot;return&quot; position is a simple <code>ret</code> (or equivalent) instruction, rather than a recitation of the cleanup sequence or a <code>jmp</code> to the cleanup block. This is effectively moot if you have a built-in &quot;ret after clearing N bytes&quot; instruction like x86 does</li>
</ul>
<p>Some advantages of &quot;callee clears stack&quot;:</p>
<ul>
<li>Most functions are called more than once, so you'll have fewer overall instruction bytes</li>
<li>The callee can optimize exactly where the stack adjustment occurs, whereas the caller likely has fewer options of exactly where that instruction is placed</li>
</ul>

CC BY-SA 4.0
2023-07-09T06:03:23.153Z
2023-07-09T06:03:23.153Z
Ryan Cavanaugh
CC BY-SA 4.0
2023-07-09T14:27:22.570Z
I wonder, do any languages switch between these? E.g., use caller-clears for cold functions and callee-clears for ones where it makes more sense?
rydwolf
CC BY-SA 4.0
2023-07-09T14:48:50.803Z
@RydwolfPrograms Languages like C using the Windows calling conventions can make a choice as to which convention to use on a function by function level (__stdcall, __cdecl, etc).  It would be hard to do more dynamically unless the language doesn't support libraries - the library would have to have every possible convention.  Doing it at runtime (JIT) would be expensive, because you would have to re-compile all of the caller functions to match the new convention.
Cort Ammon
CC BY-SA 4.0
2023-07-09T19:00:21.590Z
But wouldn't the callee have to discover how many variadic arguments there are, *in order to use them productively*, anyway?
Karl Knechtel
CC BY-SA 4.0
2023-07-10T13:26:08.340Z
@KarlKnechtel, the callee would see `[return-address][size-of-arguments][arguments]` starting at the stack-pointer address, and knowing the type-size of the arguments, it can calculate the number of variadic arguments.  The callee would adjust the stack pointer only when calling another function.
Ray Butterworth
CC BY-SA 4.0
2023-07-10T13:35:21.240Z
@KarlKnechtel Not necessarily. See, for example, C's `printf`: I can write `printf("hello %d\n", a, b, c);` and `printf` only needs know it's been passed >1 int-sized argument. (Test-case: `printf '#include <stdio.h>\nint main(int c){printf("hello %%d\\n",c,12,16,20);return 0;}' | tcc -run - a b c`)
wizzwizz4
CC BY-SA 4.0
2023-07-28T17:55:55.277Z
@CortAmmon: An 8051 compiler I used would use linker names that matched function names when using the calling convention associated with non-prototyped calls, but use an underscore when defining or invoking prototyped functions that would use an incompatible convention.  A good convept, IMHO, and one which should have been employed on a wider range of platforms.
supercat
# What are the advantages and disadvantages of the callee versus caller clearing the stack after a call?
Posted by: username_0 on 2023-07-09
This is more a question about compiler design than language design, but in low level languages, when a function is called, the parameters are pushed onto the stack, and when the function returns, the parameters are cleared from the stack.

As I understand this, one way that the stack is cleared is that the caller clears up the stack, where instructions to clear the parameters are inserted after the call instruction at the call site. Another way is that callee clears the parameters, where the last instructions of the function body are the instructions to clean up the parameters.

What are the reasons to choose one implementation over the other?

*Inspired by [this answer](https://langdev.stackexchange.com/a/2217/38).*
**Tags:** calling-conventions assembly
> **Comments:**
> **username_1**: Does this answer your question? [Why was C implemented with a register preservation convention that seems to be far less efficient than its predecessor's?](https://langdev.stackexchange.com/questions/618/why-was-c-implemented-with-a-register-preservation-convention-that-seems-to-be-f)  
> **username_2**: Can someone explain the votes to close this? It seems on topic to me.  
> **username_3**: @BruceAdams they're dupe votes  
> **username_2**: I see. Sometimes two very differently phrased questions can have the same answer. I don't think that makes the questions themselves duplicates. I reserve the close and duplicate vote for when the question is actually the same.  
> **username_4**: By "clearing the stack" do you mean only resetting the stack pointer and frame pointer registers or also something else?  
> **username_5**: @BruceAdams I believe general SE policy is that if a single answer answers two questions, one of them should be closed as a duplicate (so any one searching either question gets led to the one answer). Think of it as "_There is an existing answer_", rather than "_This is a duplicate question_".  
> **username_2**: That would only work if closed questions weren't deleted. Is it the case the questions closed as duplicates are excluded from being hoovered?  
> **username_6**: In fact yes, @BruceAdams, questions closed as dupes *are* (partially) protected from automatic deletion.  There are several alternative sets of [criteria for automatic question deletion](https://meta.stackexchange.com/help/auto-deleted-questions), but the one based on question closure not accompanied by site migration does exclude questions closed as duplicates.  
> **username_7**: Is it obvious what "*clearing the stack*" means here? Is it simply changing the stack pointer, or is there more to it than that?  
---
## 2 answers
### Answer by username_9 on 2023-07-09. Score: 16 | Accepted answer
Some advantages of "caller clears stack":

* Depending on whether/how you have variadic parameters, the calling code would statically know how many arguments are present, whereas the callee would have to dynamically determine how many arguments to clear, which would cost a level of indirection
* If the function has multiple exit points, then each "return" position is a simple `ret` (or equivalent) instruction, rather than a recitation of the cleanup sequence or a `jmp` to the cleanup block. This is effectively moot if you have a built-in "ret after clearing N bytes" instruction like x86 does

Some advantages of "callee clears stack":

* Most functions are called more than once, so you'll have fewer overall instruction bytes
* The callee can optimize exactly where the stack adjustment occurs, whereas the caller likely has fewer options of exactly where that instruction is placed
> **Comments:**
> **username_10** (2023-07-09): I wonder, do any languages switch between these? E.g., use caller-clears for cold functions and callee-clears for ones where it makes more sense?  
> **username_11** (2023-07-09): @RydwolfPrograms Languages like C using the Windows calling conventions can make a choice as to which convention to use on a function by function level (__stdcall, __cdecl, etc).  It would be hard to do more dynamically unless the language doesn't support libraries - the library would have to have every possible convention.  Doing it at runtime (JIT) would be expensive, because you would have to re-compile all of the caller functions to match the new convention.  
> **username_12** (2023-07-09): But wouldn't the callee have to discover how many variadic arguments there are, *in order to use them productively*, anyway?  
> **username_7** (2023-07-10): @KarlKnechtel, the callee would see `[return-address][size-of-arguments][arguments]` starting at the stack-pointer address, and knowing the type-size of the arguments, it can calculate the number of variadic arguments.  The callee would adjust the stack pointer only when calling another function.  
> **username_13** (2023-07-10): @KarlKnechtel Not necessarily. See, for example, C's `printf`: I can write `printf("hello %d\n", a, b, c);` and `printf` only needs know it's been passed >1 int-sized argument. (Test-case: `printf '#include <stdio.h>\nint main(int c){printf("hello %%d\\n",c,12,16,20);return 0;}' | tcc -run - a b c`)  
> **username_14** (2023-07-28): @CortAmmon: An 8051 compiler I used would use linker names that matched function names when using the calling convention associated with non-prototyped calls, but use an underscore when defining or invoking prototyped functions that would use an incompatible convention.  A good convept, IMHO, and one which should have been employed on a wider range of platforms.  
---
### Answer by username_8 on 2023-07-09. Score: 6
Consider interrupts.

An interrupt can happen at any point of the program. The caller is not the one calling the interrupt - outside events cause the CPU to autonomously call the interrupt function with no action from the running program.

If the caller is responsible for saving and restoring state then correctly handling interrupts would be impossible since the program did not call the interrupt (also, most CPU designs will **not** save state for you with rare exceptions like Sun's Sparc register windows - even then, the hardware does not save all states).

You can of course design a runtime where the caller is responsible for saving and restoring state except for interrupt handlers - but this would require you to implement 2 types of functions: caller-save functions and callee-save functions. If you **must** implement callee-save functions why bother implement the caller-save mechanism?
> **Comments:**
> **username_4** (2023-07-09): ISR prologue and epilogue are usually different from normal function prologue and epilogue anyway, aren't they?  
---
