You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I propose that we switch the Go internal ABI (used between Go functions) from stack-based to register-based argument and result passing for Go 1.16 1.17.
I lay out the details of our proposal and the work required in this document.
This was previously proposed in #18597, where @dr2chase did some excellent prototyping work that our new proposal builds on. With multiple ABI support, we’re now in a much better position to execute on this without breaking compatibility with the existing body of Go assembly code. I’ve opened this new issue to focus on discussion of our new proposal.
replace defer reflectcall with a direct closure call (CL)
cmd/internal/obj: reject splittable ABIInternal functions without morestack spill info (e.g., asm functions) because we can't generate a correct morestack path (CL)
cmd/asm: don't reference args_stackmap in ABIInternal functions (because it's for ABI0) (CL)
Port performance-critical assembly to ABIInternal (see CL 296372 for valuable functions) (CL 308931, CL 310184)
math: fix overhead of assembly->Go calls CL 310331
Release notes
Mention undocumented behavior we've observed applications depending on that may have changed.
Using reflect.ValueOf(fn).Pointer() to get the PC of an assembly function will now return the PC of the ABI wrapper
Performance surprise: calling from assembly to Go is slightly more expensive.
Performance surprise: calling an assembly function via a closure is slightly more expensive.
Traceback format is much improved
Enabling steps
Enable regabiwrappers by default on amd64 (Linux, Windows, and Darwin)
Static call, closure call, method call, interface call, reflect.{ValueOf(target),MakeFunc(x, target),Method(x)}.{Call,Interface}, called from defer, called from go, called as a finalizer
{Big,Small} {argument,result} in {memory,registers} and {not addressed,addressed and not leaked to heap,addressed and leaked to heap}
Use defer in a test function (check arguments, modify results)
Pass pointers-to-stack and pointers-to-heap
Cause result to move to heap
runtime: add MoveStackOnNextCall, assertions for pointer-to-stack/pointer-to-heap, assertions for live/dead (@aclements, CL)
simplify go/defer paths to assume zero args/results
simplify special _defer allocator and remove special _defer cases from mallocgc (because _defer records will be fixed size).
cmd/vet: add syntax and checks for register arguments and results in assembly like x+0(FP)
cmd/vet: check argument size for ABIInternal functions and fix runtime asm declarations
Cleanup (can be done later)
runtime: port all assembly -> Go calls to ABIInternal?
Eliminate ABIAlias support from cmd/compile, cmd/link, and object format
remove now-redundant fields from ssa.AuxCall
rationalize use of LocalsOffset/FrameOffset (for registers that use a link register, e.g. arm64, powerppc).
cmd/compile: revisit abiutils.go and clean up the API (also reduce ABIConfig copying)
cmd/internal/obj: generate stack maps in obj so we can better compact the morestack/body maps and reduce subtlety?
cmd/compile,runtime: re-enable passing arguments to go in runtime (context)
cmd/compile: always attach ir.Func to function ir.Names (context)
cmd/compile: support ABIInternal for tail calls (context)
cmd/compile: once wrapping of defers is on for all arch/OS combinations, it should be possible to simplify or remove some of the openDefer processing in ssagen (notablly we could get rid of openDeferSave()
[ ] runtime: think about an ABI-insensitive debugCall Delve uses DWARF information
I propose that we switch the Go internal ABI (used between Go functions) from stack-based to register-based argument and result passing for Go
1.161.17.I lay out the details of our proposal and the work required in this document.
The ABI specification can be found here.
This was previously proposed in #18597, where @dr2chase did some excellent prototyping work that our new proposal builds on. With multiple ABI support, we’re now in a much better position to execute on this without breaking compatibility with the existing body of Go assembly code. I’ve opened this new issue to focus on discussion of our new proposal.
/cc @dr2chase @danscales @thanm @cherrymui @mknyszek @prattmic @randall77
An incomplete and evolving list of tasks:
defer recover()(@cherrymui, CL)RegEntryTmpregisters in prologue (@mknyszek, CL)WriteFuncMap) (@dr2chase, CL)cgo_unsafe_argsgenerate an ABI0 function (or an ABIInternal-with-no-registers function) (@cherrymui, CL)High-priority non-critical path
funcPCalways return the "native" PC of a function (maybe also introduceABIOther) (@cherrymui, CL)funcPCis in[ ] cmd/compile: add a DWARF vendor attribute with function argument frame size (context)args_stackmapin ABIInternal functions (because it's for ABI0) (CL)reflect.ValueOf(fn).Pointer()to get the PC of an assembly function will now return the PC of the ABI wrapperEnabling steps
Testing
reflect.{ValueOf(target),MakeFunc(x, target),Method(x)}.{Call,Interface}, called fromdefer, called fromgo, called as a finalizerdeferin a test function (check arguments, modify results)MoveStackOnNextCall, assertions for pointer-to-stack/pointer-to-heap, assertions for live/dead (@aclements, CL)Post-MVP
[ ] Should this be X0 for more compact instruction encoding?[ ] porting guideCleanup (can be done later)
goin runtime (context)ir.Functo functionir.Names (context)[ ] runtime: think about an ABI-insensitive debugCallDelve uses DWARF informationfirstposinssa.go– sometimes it's late.