Difference between JUMP and CALL
One correction to your thoughts: It is not only with tail recursion, but generally with tail calls, that we don't need the stack frame and hence simply could JMP there (provided the arguments have been set up correctly).
You're mostly right, if you are talking about CALL/JMP in x86 assembly or something similar. The main difference is:
- JMP performs a jump to a location, without doing anything else
- CALL pushes the current instruction pointer on the stack (rather: one after the current instruction), and then JMPs to the location. With a RET you can get back to where you were.
Usually, CALL is just a convenience function implemented using JMP. You could do something like
movl $afterJmp, -(%esp)
jmp location
afterJmp:
instead of a CALL.
You're exactly right about the difference between a jump and a call.
In the sample case of a single function with tail recursion, then the compiler may be able to reuse the existing stack frame. However, it can become more complicated with mutually recursive functions:
void ping() { printf("ping\n"); pong(); }
void pong() { printf("pong\n"); ping(); }
Consider the case where ping() and pong() are more complex functions that take different numbers of parameters. Mark Probst's paper talks about tail recursion implementation for GCC in great detail.
I think you've got the general idea.
It depends on the architecture, but in general, at the hardware level:
A jump instruction will change the program counter to continue execution at a different part of the program.
A call instruction will push the current program location (or current location + 1) to the call stack and jump to another part of a program. A return instruction will then pop the location off of the call stack and jump back to the original location (or orignal location + 1).
So, a jump instruction is close to a GOTO
, while a call instruction is close to a procedural/function call.
Also, for the reason that a call stack is used when making function calls, pushing too many return addresses to the call stack by recursion will cause a stack overflow.
When learning assembly, I find it easier when dealing with RISC processors than x86 processors, as it tends to have less instruction and simpler operations.