Using go1.11.2.
Consider the following snippet:
var sink []V
func main() {
sink = []V{
- (*tar.Reader)(nil),
+ VOf((*tar.Reader)(nil)),
}
}
type V = interface{}
func VOf(t interface{}) V { return t }
The VOf function is a trivially useless function does nothing. If VOf function is missing, the main function is 176 bytes long, but if it is present, the function is 188 bytes long.
The assembly output without use of VOf is:
"".main STEXT size=176 args=0x0 locals=0x18
(main.go:9) TEXT "".main(SB), $24-0
(main.go:9) MOVQ (TLS), CX
(main.go:9) CMPQ SP, 16(CX)
(main.go:9) JLS 166
(main.go:9) SUBQ $24, SP
(main.go:9) MOVQ BP, 16(SP)
(main.go:9) LEAQ 16(SP), BP
(main.go:9) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
(main.go:9) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
(main.go:9) FUNCDATA $3, gclocals·f6aec3988379d2bd21c69c093370a150(SB)
(main.go:10) LEAQ type.[1]interface {}(SB), AX
(main.go:10) MOVQ AX, (SP)
(main.go:10) CALL runtime.newobject(SB)
(main.go:10) MOVQ 8(SP), AX
(main.go:11) MOVQ "".statictmp_0(SB), CX
(main.go:11) LEAQ type.*archive/tar.Reader(SB), DX
(main.go:11) MOVQ DX, (AX)
(main.go:11) CMPL runtime.writeBarrier(SB), $0
(main.go:11) JNE 146
(main.go:11) MOVQ CX, 8(AX)
(main.go:10) MOVQ $1, "".sink+8(SB)
(main.go:10) MOVQ $1, "".sink+16(SB)
(main.go:10) CMPL runtime.writeBarrier(SB), $0
(main.go:10) JNE 132
(main.go:10) MOVQ AX, "".sink(SB)
(main.go:13) MOVQ 16(SP), BP
(main.go:13) ADDQ $24, SP
(main.go:13) RET
(main.go:10) LEAQ "".sink(SB), DI
(main.go:10) CALL runtime.gcWriteBarrier(SB)
(main.go:10) JMP 122
(main.go:11) LEAQ 8(AX), DI
(main.go:10) MOVQ AX, DX
(main.go:11) MOVQ CX, AX
(main.go:11) CALL runtime.gcWriteBarrier(SB)
(main.go:10) MOVQ DX, AX
(main.go:11) JMP 84
(main.go:11) NOP
(main.go:9) CALL runtime.morestack_noctxt(SB)
(main.go:9) JMP 0
However, calling VOf results in the generation of an autotmp variables.
"".main STEXT size=188 args=0x0 locals=0x20
(main.go:9) TEXT "".main(SB), $32-0
(main.go:9) MOVQ (TLS), CX
(main.go:9) CMPQ SP, 16(CX)
(main.go:9) JLS 178
(main.go:9) SUBQ $32, SP
(main.go:9) MOVQ BP, 24(SP)
(main.go:9) LEAQ 24(SP), BP
(main.go:9) FUNCDATA $0, gclocals·69c1753bd5f81501d95132d08af04464(SB)
(main.go:9) FUNCDATA $1, gclocals·9fb7f0986f647f17cb53dda1484e0f7a(SB)
(main.go:9) FUNCDATA $3, gclocals·ba192201ac73f95fb90b551d9176d705(SB)
(main.go:11) MOVQ "".statictmp_0(SB), AX
+ (main.go:11) MOVQ AX, ""..autotmp_9+16(SP)
(main.go:10) LEAQ type.[1]interface {}(SB), CX
(main.go:10) MOVQ CX, (SP)
(main.go:10) CALL runtime.newobject(SB)
(main.go:10) MOVQ 8(SP), AX
(main.go:10) LEAQ type.*archive/tar.Reader(SB), CX
(main.go:10) MOVQ CX, (AX)
(main.go:10) CMPL runtime.writeBarrier(SB), $0
(main.go:10) JNE 156
+ (main.go:10) MOVQ ""..autotmp_9+16(SP), CX
(main.go:10) MOVQ CX, 8(AX)
(main.go:10) MOVQ $1, "".sink+8(SB)
(main.go:10) MOVQ $1, "".sink+16(SB)
(main.go:10) CMPL runtime.writeBarrier(SB), $0
(main.go:10) JNE 142
(main.go:10) MOVQ AX, "".sink(SB)
(main.go:13) MOVQ 24(SP), BP
(main.go:13) ADDQ $32, SP
(main.go:13) RET
(main.go:10) LEAQ "".sink(SB), DI
(main.go:10) CALL runtime.gcWriteBarrier(SB)
(main.go:10) JMP 132
(main.go:10) LEAQ 8(AX), DI
(main.go:10) MOVQ AX, CX
+ (main.go:10) MOVQ ""..autotmp_9+16(SP), AX
(main.go:10) CALL runtime.gcWriteBarrier(SB)
(main.go:10) MOVQ CX, AX
(main.go:10) JMP 94
(main.go:10) NOP
(main.go:9) CALL runtime.morestack_noctxt(SB)
(main.go:9) JMP 0
An additional autotmp variable is added for every element in the slice, so large slice literals are noticeably more bloated with VOf than without.
Using
go1.11.2.Consider the following snippet:
var sink []V func main() { sink = []V{ - (*tar.Reader)(nil), + VOf((*tar.Reader)(nil)), } } type V = interface{} func VOf(t interface{}) V { return t }The
VOffunction is a trivially useless function does nothing. IfVOffunction is missing, the main function is 176 bytes long, but if it is present, the function is 188 bytes long.The assembly output without use of
VOfis:"".main STEXT size=176 args=0x0 locals=0x18 (main.go:9) TEXT "".main(SB), $24-0 (main.go:9) MOVQ (TLS), CX (main.go:9) CMPQ SP, 16(CX) (main.go:9) JLS 166 (main.go:9) SUBQ $24, SP (main.go:9) MOVQ BP, 16(SP) (main.go:9) LEAQ 16(SP), BP (main.go:9) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) (main.go:9) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) (main.go:9) FUNCDATA $3, gclocals·f6aec3988379d2bd21c69c093370a150(SB) (main.go:10) LEAQ type.[1]interface {}(SB), AX (main.go:10) MOVQ AX, (SP) (main.go:10) CALL runtime.newobject(SB) (main.go:10) MOVQ 8(SP), AX (main.go:11) MOVQ "".statictmp_0(SB), CX (main.go:11) LEAQ type.*archive/tar.Reader(SB), DX (main.go:11) MOVQ DX, (AX) (main.go:11) CMPL runtime.writeBarrier(SB), $0 (main.go:11) JNE 146 (main.go:11) MOVQ CX, 8(AX) (main.go:10) MOVQ $1, "".sink+8(SB) (main.go:10) MOVQ $1, "".sink+16(SB) (main.go:10) CMPL runtime.writeBarrier(SB), $0 (main.go:10) JNE 132 (main.go:10) MOVQ AX, "".sink(SB) (main.go:13) MOVQ 16(SP), BP (main.go:13) ADDQ $24, SP (main.go:13) RET (main.go:10) LEAQ "".sink(SB), DI (main.go:10) CALL runtime.gcWriteBarrier(SB) (main.go:10) JMP 122 (main.go:11) LEAQ 8(AX), DI (main.go:10) MOVQ AX, DX (main.go:11) MOVQ CX, AX (main.go:11) CALL runtime.gcWriteBarrier(SB) (main.go:10) MOVQ DX, AX (main.go:11) JMP 84 (main.go:11) NOP (main.go:9) CALL runtime.morestack_noctxt(SB) (main.go:9) JMP 0However, calling
VOfresults in the generation of anautotmpvariables.An additional
autotmpvariable is added for every element in the slice, so large slice literals are noticeably more bloated withVOfthan without.