【golang代码反编译研究】switch 中的常量有助于生成跳转表代码
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
先说结论:一些比较小的循环,可以用 switch + 常量来展开,可以提升性能。因为编译器会为 switch 建立代码段的跳转表,从而不需要很多比较指令。
例如:
for i:= range s{
if s[i]=='\n'{
printf("found new line\n")
return
}
}
已知:字符串 s 最多 4 个字符。
代码可以优化如下:
switch len(s){
case 0:
return;
case 1:
if s[0]=='\n'{/*do something*/}
case 2:
if s[0]=='\n' || s[1]=='\n' {/*do something*/}
case 3:
if s[0]=='\n' || s[1]=='\n' || s[2]=='\n'{/*do something*/}
case 4:
if s[0]=='\n' || s[1]=='\n' || s[2]=='\n' || s[3]=='\n'{/*do something*/}
default:
panic("")
}
大量常量 + 代码展开,有助于提升性能。
下面是一个反汇编的例子:
package is_sorted
func switchTest(a int) int {
switch a {
case 1:
return 100
case 2:
return 103
case 3:
return 205
case 4:
return 309
case 5:
return 413
case 6:
return 517
case 7:
return 621
case 8:
return 725
case 9:
return 829
default:
return 933
}
}
对应的汇编代码如下:
TEXT command-line-arguments.switchTest(SB), NOSPLIT|NOFRAME|ABIInternal, $0-8
FUNCDATA $0, gclocals·FzY36IO2mY0y4dZ1+Izd/w==(SB)
FUNCDATA $1, gclocals·FzY36IO2mY0y4dZ1+Izd/w==(SB)
FUNCDATA $5, command-line-arguments.switchTest.arginfo1(SB)
FUNCDATA $6, command-line-arguments.switchTest.argliveinfo(SB)
PCDATA $3, $1
LEAQ -1(AX), CX
CMPQ CX, $8
JHI command-line-arguments_switchTest_pc75
LEAQ command-line-arguments.switchTest.jump3(SB), AX
JMP (AX)(CX*8)
MOVL $100, AX
RET
MOVL $103, AX
NOP
RET
MOVL $205, AX
RET
MOVL $309, AX
RET
MOVL $413, AX
RET
MOVL $517, AX
RET
MOVL $621, AX
RET
MOVL $725, AX
RET
MOVL $829, AX
RET
command-line-arguments_switchTest_pc75:
MOVL $933, AX
RET
command-line-arguments.switchTest.jump3(SB) 这里是一个编译器生成的跳转表。
以上代码在 https://godbolt.org/ 网站生成,非常方便。


浙公网安备 33010602011771号