Description
The are various changes we'd like to make (or explore making) to the Go ABI, such as changing to a register-based ABI (#18597), propagating register clobbers up the call graph to avoid unnecessary spills, and passing dynamic information about allocation scopes. However, every attempt we've made to modify the calling convention has encountered major hurdles with calling back and forth between Go and assembly code.
This proposal is not about a specific change to the ABI, but about how to get to a place where we have the freedom to change the ABI. It was in part inspired by how Rust handles this issue.
I propose:
- We make the default Go function calling convention officially unspecified.
- We provide a pragma for marking the rare functions that need a stable ABI (specifically, the current stack-based ABI). We officially document the stack ABI (including the need to participate in stack growth).
- For a release or two, we keep the unspecified ABI the same as the stack ABI.
- We define the CALL assembly instruction to call via the stack ABI and modify vet to check for ABI violations, where assembly code is CALLing a function using the undefined ABI. (We may also need a way to call via the unspecified ABI in the runtime for closure calls, though ideally I'd like to minimize this even in the runtime.)
- After a few releases, we have the freedom to modify the unspecified ABI. We move the ABI check into the linker itself.
This would involve supporting potentially two ABIs for the rest of time, but I believe that's actually a strength. This approach provides a stable ABI for the rare cases that need it, while simultaneously giving us as compiler writers the freedom to evolve the ABI in the vast majority of cases that don't need a stable ABI.