考虑以下情况:
type CustomUnmarshaler interface {
CustomUnmarshal([]byte) error
}
type MyMessage struct{}
func (m *MyMessage) Unmarshal(b []byte) error {
if u, ok := (interface{})(m).(CustomUnmarshaler); ok {
return u.CustomUnmarshal(b)
}
return nil
}
在这种情况下,编译器知道 MyMessage
类型没有 CustomUnmarshal
方法,因此类型Assert不可能成功。在这种情况下,if语句的条件可以静态确定,并且可以认为代码块是死代码。
然而,一个提示构建的编译器仍然会为Assert发出代码。
0x0021 00033 (/tmp/main.go:10) LEAQ type."".CustomUnmarshaler(SB), AX
0x0028 00040 (/tmp/main.go:10) MOVQ AX, (SP)
0x002c 00044 (/tmp/main.go:10) LEAQ type.*"".Foo(SB), AX
0x0033 00051 (/tmp/main.go:10) MOVQ AX, 8(SP)
0x0038 00056 (/tmp/main.go:9) MOVQ "".f+64(SP), AX
0x003d 00061 (/tmp/main.go:10) MOVQ AX, 16(SP)
0x0042 00066 (/tmp/main.go:10) PCDATA $0, $1
0x0042 00066 (/tmp/main.go:10) CALL runtime.assertE2I2(SB)
0x0047 00071 (/tmp/main.go:10) MOVQ 24(SP), AX
0x004c 00076 (/tmp/main.go:10) MOVQ 32(SP), CX
0x0051 00081 (/tmp/main.go:10) LEAQ 40(SP), DX
0x0056 00086 (/tmp/main.go:10) CMPB (DX), $0
0x0059 00089 (/tmp/main.go:10) JEQ 161
0x005b 00091 (/tmp/main.go:11) MOVQ 24(AX), AX
0x005f 00095 (/tmp/main.go:11) MOVQ "".b+72(SP), DX
0x0064 00100 (/tmp/main.go:11) MOVQ DX, 8(SP)
0x0069 00105 (/tmp/main.go:11) MOVQ "".b+80(SP), DX
0x006e 00110 (/tmp/main.go:11) MOVQ DX, 16(SP)
0x0073 00115 (/tmp/main.go:11) MOVQ "".b+88(SP), DX
0x0078 00120 (/tmp/main.go:11) MOVQ DX, 24(SP)
0x007d 00125 (/tmp/main.go:11) MOVQ CX, (SP)
0x0081 00129 (/tmp/main.go:11) PCDATA $0, $2
0x0081 00129 (/tmp/main.go:11) CALL AX
0x0083 00131 (/tmp/main.go:11) MOVQ 32(SP), AX
0x0088 00136 (/tmp/main.go:11) MOVQ 40(SP), CX
0x008d 00141 (/tmp/main.go:11) MOVQ AX, "".~r1+96(SP)
0x0092 00146 (/tmp/main.go:11) MOVQ CX, "".~r1+104(SP)
0x0097 00151 (/tmp/main.go:11) MOVQ 48(SP), BP
0x009c 00156 (/tmp/main.go:11) ADDQ $56, SP
0x00a0 00160 (/tmp/main.go:11) RET
5条答案
按热度按时间lpwwtiir1#
我假设这些事情发生在内联过程中(随着我们对内联的更激进,它们将变得越来越常见)。
在构建SSA到运行时调用的过程中,类型转换会被降低。我已经尝试编写一些代码来延迟在类似情况下降低,但我找不到一个好的方法来布局运行时函数调用(例如:堆栈插槽)。这超出了我的能力范围。
如果有人更熟悉编译器,能提出一些实用工具,在SSA传递过程中添加一个函数调用,那将对我非常有帮助,以便开始努力延迟运行时调用的降低,利用高级语义带来的优化机会。
qlzsbp2j2#
这些不可能的Assert在实际代码中到底有多少作用?(即优化可能产生的影响是什么?)
我假设这种情况主要发生在生成的代码中,但如果是这样的话,为了提高编译时间,避免一开始就发出多余的Assert不是更好吗?
k3bvogb13#
@bcmills 和 @rasky 关于内联导致这种情况发生的观点,我认为可能是今天这些事件的主要来源。例如,查看 https://godbolt.org/g/GzDvaU 或 https://godbolt.org/g/N5W6Ua(在这两种情况下,对
f()
的调用都被内联了,但类型Assert仍然存在)。(此外,但这在一个讨论的背景下是一个重要性较小的论点,要求代码生成器如此智能会大大复杂化它们)
uz75evzq4#
跟踪接口背后的具体类型也将有助于#19361,从而降低调用开销,如果方法被调用,并且可能通过不让调用参数逃逸来降低GC开销。
ukdjmx9f5#
我认为,关于内联,我们处于一种进退两难的境地:内联似乎并没有带来太大帮助,因为我们在优化器中并不擅长利用这些机会;而添加这样的优化可能会对工具速度产生影响,但收益不大,因为我们没有内联到应有的程度。