Skip to content

Commit cc0eaf2

Browse files
committed
Merge branch 'master' of github.com:cch123/golang-notes
2 parents ca0c426 + 7bd52e1 commit cc0eaf2

File tree

2 files changed

+252
-27
lines changed

2 files changed

+252
-27
lines changed

1.14/defer.md

Lines changed: 251 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,266 @@
33
在 Go 1.14 中,增加了一种新的 defer 实现:open coded defer。当函数内 defer 不超过 8 个时,则会使用这种实现。
44

55
```go
6-
package main
6+
1 package main
7+
2
8+
3 import "fmt"
9+
4
10+
5 var i = 100
11+
6
12+
7 func main() {
13+
8 if i == 0 {
14+
9 defer fmt.Println("1")
15+
10 }
16+
11
17+
12 if i == 1 {
18+
13 defer fmt.Println("2")
19+
14 }
20+
15
21+
16 if i == 2 {
22+
17 defer fmt.Println("3")
23+
18 }
24+
19
25+
20 if i == 3 {
26+
21 defer fmt.Println("4")
27+
22 }
28+
23
29+
24 if i == 4 {
30+
25 defer fmt.Println("5")
31+
26 }
32+
27
33+
28 if i == 5 {
34+
29 defer fmt.Println("6")
35+
30 }
36+
31 }
37+
```
738

8-
import "fmt"
39+
可以分析上面的代码生成的汇编来理解这个新版的 open coded defer 到底是怎么实现的:
940

10-
var i = 100
41+
```
42+
"".main STEXT size=1125 args=0x0 locals=0x160
43+
if i == 0:
44+
0x0055 00085 (open-coded-defer.go:8) CMPQ "".i(SB), $0
45+
0x005d 00093 (open-coded-defer.go:8) JNE 1075 // 1075 是条废指令,其实本质是跳过这条 if 的 DEFER PREPARE BLOCK,去地址 188
1146
12-
func main() {
13-
if i == 0 {
14-
defer fmt.Println("1")
15-
}
47+
DEFER PREPARE BLOCK 1,主要工作是将 fmt.Println 的参数和函数地址搬运到栈上该 defer 对应的区域:
48+
0x0063 00099 (open-coded-defer.go:9) XORPS X0, X0
49+
0x0066 00102 (open-coded-defer.go:9) MOVUPS X0, ""..autotmp_3+72(SP)
50+
0x006b 00107 (open-coded-defer.go:9) LEAQ type.string(SB), AX
51+
0x0072 00114 (open-coded-defer.go:9) MOVQ AX, ""..autotmp_3+72(SP)
52+
0x0077 00119 (open-coded-defer.go:9) LEAQ ""..stmp_0(SB), CX
53+
0x007e 00126 (open-coded-defer.go:9) MOVQ CX, ""..autotmp_3+80(SP)
54+
0x0083 00131 (open-coded-defer.go:9) LEAQ fmt.Println·f(SB), CX
55+
0x008a 00138 (open-coded-defer.go:9) MOVQ CX, ""..autotmp_25+192(SP)
56+
0x0092 00146 (open-coded-defer.go:9) LEAQ ""..autotmp_3+72(SP), DX
57+
0x0097 00151 (open-coded-defer.go:9) MOVQ DX, ""..autotmp_26+320(SP)
58+
0x009f 00159 (open-coded-defer.go:9) MOVQ $1, ""..autotmp_26+328(SP)
59+
0x00ab 00171 (open-coded-defer.go:9) MOVQ $1, ""..autotmp_26+336(SP)
60+
0x00b7 00183 (open-coded-defer.go:9) MOVB $1, ""..autotmp_24+55(SP)
61+
62+
// 根据 zero flag 设置值,如果 zero flag = 1,那么 DI = 1,如果 zero flag = 0,那么 DI = 0
63+
// 详情参见 intel 手册的 sete/setz 指令
64+
// 也就是说,只要走了上面的 DEFER PREPARE BLOCK,那么这里就 DI = 1,否则 DI = 0
65+
0x00bc 00188 (open-coded-defer.go:8) SETEQ DL
1666
17-
if i == 1 {
18-
defer fmt.Println("2")
19-
}
67+
if i == 1:
68+
0x00bf 00191 (open-coded-defer.go:12) CMPQ "".i(SB), $1
69+
0x00c7 00199 (open-coded-defer.go:12) JNE 278
2070
21-
if i == 2 {
22-
defer fmt.Println("3")
23-
}
71+
DEFER PREPARE BLOCK 2, 和 BLOCK 1 工作差不多,是把第二个 defer 的参数和函数地址保存在栈上:
72+
0x00c9 00201 (open-coded-defer.go:13) XORPS X0, X0
73+
0x00cc 00204 (open-coded-defer.go:13) MOVUPS X0, ""..autotmp_7+56(SP)
74+
0x00d1 00209 (open-coded-defer.go:13) MOVQ AX, ""..autotmp_7+56(SP)
75+
0x00d6 00214 (open-coded-defer.go:13) LEAQ ""..stmp_1(SB), BX
76+
0x00dd 00221 (open-coded-defer.go:13) MOVQ BX, ""..autotmp_7+64(SP)
77+
0x00e2 00226 (open-coded-defer.go:13) MOVQ CX, ""..autotmp_27+184(SP)
78+
0x00ea 00234 (open-coded-defer.go:13) LEAQ ""..autotmp_7+56(SP), BX
79+
0x00ef 00239 (open-coded-defer.go:13) MOVQ BX, ""..autotmp_28+296(SP)
80+
0x00f7 00247 (open-coded-defer.go:13) MOVQ $1, ""..autotmp_28+304(SP)
81+
0x0103 00259 (open-coded-defer.go:13) MOVQ $1, ""..autotmp_28+312(SP)
2482
25-
if i == 3 {
26-
defer fmt.Println("4")
27-
}
83+
0x010f 00271 (open-coded-defer.go:13) ORL $2, DX // 设置 DX 的第二个标记位为 1
84+
0x0112 00274 (open-coded-defer.go:13) MOVB DL, ""..autotmp_24+55(SP) // TODO
2885
29-
if i == 4 {
30-
defer fmt.Println("5")
31-
}
86+
if i == 2:
87+
0x0116 00278 (open-coded-defer.go:16) CMPQ "".i(SB), $2
88+
0x011e 00286 (open-coded-defer.go:16) JNE 377
3289
33-
if i == 5 {
34-
defer fmt.Println("6")
35-
}
36-
}
90+
DEFER PREPARE BLOCK 3,和上面类似,就不解释了:
91+
0x0120 00288 (open-coded-defer.go:17) XORPS X0, X0
92+
0x0123 00291 (open-coded-defer.go:17) MOVUPS X0, ""..autotmp_11+136(SP)
93+
0x012b 00299 (open-coded-defer.go:17) MOVQ AX, ""..autotmp_11+136(SP)
94+
0x0133 00307 (open-coded-defer.go:17) LEAQ ""..stmp_2(SB), BX
95+
0x013a 00314 (open-coded-defer.go:17) MOVQ BX, ""..autotmp_11+144(SP)
96+
0x0142 00322 (open-coded-defer.go:17) MOVQ CX, ""..autotmp_29+176(SP)
97+
0x014a 00330 (open-coded-defer.go:17) LEAQ ""..autotmp_11+136(SP), BX
98+
0x0152 00338 (open-coded-defer.go:17) MOVQ BX, ""..autotmp_30+272(SP)
99+
0x015a 00346 (open-coded-defer.go:17) MOVQ $1, ""..autotmp_30+280(SP)
100+
0x0166 00358 (open-coded-defer.go:17) MOVQ $1, ""..autotmp_30+288(SP)
37101
38-
```
102+
0x0172 00370 (open-coded-defer.go:17) ORL $4, DX // 设置 DX 的第三个标记位为 1
103+
0x0175 00373 (open-coded-defer.go:17) MOVB DL, ""..autotmp_24+55(SP)
39104
40-
可以分析上面的代码生成的汇编来理解这个新版的 open coded defer 到底是怎么实现的:
105+
if i == 3
106+
0x0179 00377 (open-coded-defer.go:20) CMPQ "".i(SB), $3
107+
0x0181 00385 (open-coded-defer.go:20) JNE 467
41108
42-
```
109+
DEFER PREPARE BLOCK 4:
110+
0x0183 00387 (open-coded-defer.go:21) XORPS X0, X0
111+
0x0186 00390 (open-coded-defer.go:21) MOVUPS X0, ""..autotmp_15+120(SP)
112+
0x018b 00395 (open-coded-defer.go:21) MOVQ AX, ""..autotmp_15+120(SP)
113+
0x0190 00400 (open-coded-defer.go:21) LEAQ ""..stmp_3(SB), BX
114+
0x0197 00407 (open-coded-defer.go:21) MOVQ BX, ""..autotmp_15+128(SP)
115+
0x019f 00415 (open-coded-defer.go:21) MOVQ CX, ""..autotmp_31+168(SP)
116+
0x01a7 00423 (open-coded-defer.go:21) LEAQ ""..autotmp_15+120(SP), BX
117+
0x01ac 00428 (open-coded-defer.go:21) MOVQ BX, ""..autotmp_32+248(SP)
118+
0x01b4 00436 (open-coded-defer.go:21) MOVQ $1, ""..autotmp_32+256(SP)
119+
0x01c0 00448 (open-coded-defer.go:21) MOVQ $1, ""..autotmp_32+264(SP)
120+
121+
0x01cc 00460 (open-coded-defer.go:21) ORL $8, DX // 设置 DX 的第四个标记位为 1
122+
0x01cf 00463 (open-coded-defer.go:21) MOVB DL, ""..autotmp_24+55(SP)
123+
124+
if i == 4:
125+
0x01d3 00467 (open-coded-defer.go:24) CMPQ "".i(SB), $4
126+
0x01db 00475 (open-coded-defer.go:24) JNE 554
127+
128+
DEFER PREPARE BLOCK 5:
129+
0x01dd 00477 (open-coded-defer.go:25) XORPS X0, X0
130+
0x01e0 00480 (open-coded-defer.go:25) MOVUPS X0, ""..autotmp_19+104(SP)
131+
0x01e5 00485 (open-coded-defer.go:25) MOVQ AX, ""..autotmp_19+104(SP)
132+
0x01ea 00490 (open-coded-defer.go:25) LEAQ ""..stmp_4(SB), BX
133+
0x01f1 00497 (open-coded-defer.go:25) MOVQ BX, ""..autotmp_19+112(SP)
134+
0x01f6 00502 (open-coded-defer.go:25) MOVQ CX, ""..autotmp_33+160(SP)
135+
0x01fe 00510 (open-coded-defer.go:25) LEAQ ""..autotmp_19+104(SP), BX
136+
0x0203 00515 (open-coded-defer.go:25) MOVQ BX, ""..autotmp_34+224(SP)
137+
0x020b 00523 (open-coded-defer.go:25) MOVQ $1, ""..autotmp_34+232(SP)
138+
0x0217 00535 (open-coded-defer.go:25) MOVQ $1, ""..autotmp_34+240(SP)
139+
140+
0x0223 00547 (open-coded-defer.go:25) ORL $16, DX // 设置 DX 的第五个标记位为 1
141+
0x0226 00550 (open-coded-defer.go:25) MOVB DL, ""..autotmp_24+55(SP)
142+
143+
if i == 5:
144+
0x022a 00554 (open-coded-defer.go:28) CMPQ "".i(SB), $5
145+
0x0232 00562 (open-coded-defer.go:28) JNE 641
146+
147+
DEFER PREPARE BLOCK 6:
148+
0x0234 00564 (open-coded-defer.go:29) XORPS X0, X0
149+
0x0237 00567 (open-coded-defer.go:29) MOVUPS X0, ""..autotmp_23+88(SP)
150+
0x023c 00572 (open-coded-defer.go:29) MOVQ AX, ""..autotmp_23+88(SP)
151+
0x0241 00577 (open-coded-defer.go:29) LEAQ ""..stmp_5(SB), AX
152+
0x0248 00584 (open-coded-defer.go:29) MOVQ AX, ""..autotmp_23+96(SP)
153+
0x024d 00589 (open-coded-defer.go:29) MOVQ CX, ""..autotmp_35+152(SP)
154+
0x0255 00597 (open-coded-defer.go:29) LEAQ ""..autotmp_23+88(SP), AX
155+
0x025a 00602 (open-coded-defer.go:29) MOVQ AX, ""..autotmp_36+200(SP)
156+
0x0262 00610 (open-coded-defer.go:29) MOVQ $1, ""..autotmp_36+208(SP)
157+
0x026e 00622 (open-coded-defer.go:29) MOVQ $1, ""..autotmp_36+216(SP)
158+
159+
0x027a 00634 (open-coded-defer.go:29) ORL $32, DX // 设置 DX 的第六个标志位为 1
160+
0x027d 00637 (open-coded-defer.go:29) MOVB DL, ""..autotmp_24+55(SP)
161+
162+
FUNCTION END, FLAG CHECKS, 这里要检查上面设置的所有的 open coded defer bits 了,可以看到与 flag 的设置顺序是相反的:
163+
0x0281 00641 (open-coded-defer.go:31) TESTB $32, DL
164+
0x0284 00644 (open-coded-defer.go:31) JNE 1011
165+
0x028a 00650 (open-coded-defer.go:31) TESTB $16, DL
166+
0x028d 00653 (open-coded-defer.go:31) JNE 947
167+
0x0293 00659 (open-coded-defer.go:31) TESTB $8, DL
168+
0x0296 00662 (open-coded-defer.go:31) JNE 883
169+
0x029c 00668 (open-coded-defer.go:31) TESTB $4, DL
170+
0x029f 00671 (open-coded-defer.go:31) JNE 819
171+
0x02a5 00677 (open-coded-defer.go:31) TESTB $2, DL
172+
0x02a8 00680 (open-coded-defer.go:31) JNE 755
173+
0x02aa 00682 (open-coded-defer.go:31) TESTB $1, DL
174+
0x02ad 00685 (open-coded-defer.go:31) JNE 703
175+
0x02af 00687 (open-coded-defer.go:31) MOVQ 344(SP), BP
176+
0x02b7 00695 (open-coded-defer.go:31) ADDQ $352, SP
177+
0x02be 00702 (open-coded-defer.go:31) RET
178+
179+
DEFER 逻辑执行部分:
180+
0x02bf 00703 (open-coded-defer.go:31) ANDL $-2, DX
181+
0x02c2 00706 (open-coded-defer.go:31) MOVB DL, ""..autotmp_24+55(SP)
182+
0x02c6 00710 (open-coded-defer.go:31) MOVQ ""..autotmp_26+320(SP), AX
183+
0x02ce 00718 (open-coded-defer.go:31) MOVQ ""..autotmp_26+328(SP), CX
184+
0x02d6 00726 (open-coded-defer.go:31) MOVQ ""..autotmp_26+336(SP), DX
185+
0x02de 00734 (open-coded-defer.go:31) MOVQ AX, (SP)
186+
0x02e2 00738 (open-coded-defer.go:31) MOVQ CX, 8(SP)
187+
0x02e7 00743 (open-coded-defer.go:31) MOVQ DX, 16(SP)
188+
0x02ec 00748 (open-coded-defer.go:31) CALL fmt.Println(SB)
189+
0x02f1 00753 (open-coded-defer.go:31) JMP 687
190+
191+
0x02f3 00755 (open-coded-defer.go:31) ANDL $-3, DX
192+
0x02f6 00758 (open-coded-defer.go:31) MOVB DL, ""..autotmp_37+54(SP)
193+
0x02fa 00762 (open-coded-defer.go:31) MOVB DL, ""..autotmp_24+55(SP)
194+
0x02fe 00766 (open-coded-defer.go:31) MOVQ ""..autotmp_28+312(SP), AX
195+
0x0306 00774 (open-coded-defer.go:31) MOVQ ""..autotmp_28+304(SP), CX
196+
0x030e 00782 (open-coded-defer.go:31) MOVQ ""..autotmp_28+296(SP), BX
197+
0x0316 00790 (open-coded-defer.go:31) MOVQ BX, (SP)
198+
0x031a 00794 (open-coded-defer.go:31) MOVQ CX, 8(SP)
199+
0x031f 00799 (open-coded-defer.go:31) MOVQ AX, 16(SP)
200+
0x0324 00804 (open-coded-defer.go:31) CALL fmt.Println(SB)
201+
0x0329 00809 (open-coded-defer.go:31) MOVBLZX ""..autotmp_37+54(SP), DX
202+
0x032e 00814 (open-coded-defer.go:31) JMP 682
203+
204+
0x0333 00819 (open-coded-defer.go:31) ANDL $-5, DX
205+
0x0336 00822 (open-coded-defer.go:31) MOVB DL, ""..autotmp_37+54(SP)
206+
0x033a 00826 (open-coded-defer.go:31) MOVB DL, ""..autotmp_24+55(SP)
207+
0x033e 00830 (open-coded-defer.go:31) MOVQ ""..autotmp_30+288(SP), AX
208+
0x0346 00838 (open-coded-defer.go:31) MOVQ ""..autotmp_30+280(SP), CX
209+
0x034e 00846 (open-coded-defer.go:31) MOVQ ""..autotmp_30+272(SP), BX
210+
0x0356 00854 (open-coded-defer.go:31) MOVQ BX, (SP)
211+
0x035a 00858 (open-coded-defer.go:31) MOVQ CX, 8(SP)
212+
0x035f 00863 (open-coded-defer.go:31) MOVQ AX, 16(SP)
213+
0x0364 00868 (open-coded-defer.go:31) CALL fmt.Println(SB)
214+
0x0369 00873 (open-coded-defer.go:31) MOVBLZX ""..autotmp_37+54(SP), DX
215+
0x036e 00878 (open-coded-defer.go:31) JMP 677
216+
217+
0x0373 00883 (open-coded-defer.go:31) ANDL $-9, DX
218+
0x0376 00886 (open-coded-defer.go:31) MOVB DL, ""..autotmp_37+54(SP)
219+
0x037a 00890 (open-coded-defer.go:31) MOVB DL, ""..autotmp_24+55(SP)
220+
0x037e 00894 (open-coded-defer.go:31) MOVQ ""..autotmp_32+264(SP), AX
221+
0x0386 00902 (open-coded-defer.go:31) MOVQ ""..autotmp_32+256(SP), CX
222+
0x038e 00910 (open-coded-defer.go:31) MOVQ ""..autotmp_32+248(SP), BX
223+
0x0396 00918 (open-coded-defer.go:31) MOVQ BX, (SP)
224+
0x039a 00922 (open-coded-defer.go:31) MOVQ CX, 8(SP)
225+
0x039f 00927 (open-coded-defer.go:31) MOVQ AX, 16(SP)
226+
0x03a4 00932 (open-coded-defer.go:31) CALL fmt.Println(SB)
227+
0x03a9 00937 (open-coded-defer.go:31) MOVBLZX ""..autotmp_37+54(SP), DX
228+
0x03ae 00942 (open-coded-defer.go:31) JMP 668
229+
230+
0x03b3 00947 (open-coded-defer.go:31) ANDL $-17, DX
231+
0x03b6 00950 (open-coded-defer.go:31) MOVB DL, ""..autotmp_37+54(SP)
232+
0x03ba 00954 (open-coded-defer.go:31) MOVB DL, ""..autotmp_24+55(SP)
233+
0x03be 00958 (open-coded-defer.go:31) MOVQ ""..autotmp_34+224(SP), AX
234+
0x03c6 00966 (open-coded-defer.go:31) MOVQ ""..autotmp_34+240(SP), CX
235+
0x03ce 00974 (open-coded-defer.go:31) MOVQ ""..autotmp_34+232(SP), BX
236+
0x03d6 00982 (open-coded-defer.go:31) MOVQ AX, (SP)
237+
0x03da 00986 (open-coded-defer.go:31) MOVQ BX, 8(SP)
238+
0x03df 00991 (open-coded-defer.go:31) MOVQ CX, 16(SP)
239+
0x03e4 00996 (open-coded-defer.go:31) CALL fmt.Println(SB)
240+
0x03e9 01001 (open-coded-defer.go:31) MOVBLZX ""..autotmp_37+54(SP), DX
241+
0x03ee 01006 (open-coded-defer.go:31) JMP 659
242+
243+
0x03f3 01011 (open-coded-defer.go:31) ANDL $-33, DX
244+
0x03f6 01014 (open-coded-defer.go:31) MOVB DL, ""..autotmp_37+54(SP)
245+
0x03fa 01018 (open-coded-defer.go:31) MOVB DL, ""..autotmp_24+55(SP)
246+
0x03fe 01022 (open-coded-defer.go:31) MOVQ ""..autotmp_36+216(SP), AX
247+
0x0406 01030 (open-coded-defer.go:31) MOVQ ""..autotmp_36+200(SP), CX
248+
0x040e 01038 (open-coded-defer.go:31) MOVQ ""..autotmp_36+208(SP), BX
249+
0x0416 01046 (open-coded-defer.go:31) MOVQ CX, (SP)
250+
0x041a 01050 (open-coded-defer.go:31) MOVQ BX, 8(SP)
251+
0x041f 01055 (open-coded-defer.go:31) MOVQ AX, 16(SP)
252+
0x0424 01060 (open-coded-defer.go:31) CALL fmt.Println(SB)
253+
0x0429 01065 (open-coded-defer.go:31) MOVBLZX ""..autotmp_37+54(SP), DX
254+
0x042e 01070 (open-coded-defer.go:31) JMP 650
255+
256+
如果第一个 if 不满足,会跳到这里:
257+
0x0433 01075 (open-coded-defer.go:31) LEAQ type.string(SB), AX
258+
0x043a 01082 (open-coded-defer.go:31) LEAQ fmt.Println·f(SB), CX
259+
0x0441 01089 (open-coded-defer.go:8) JMP 188
260+
261+
0x0446 01094 (open-coded-defer.go:8) CALL runtime.deferreturn(SB)
262+
0x044b 01099 (open-coded-defer.go:8) MOVQ 344(SP), BP
263+
0x0453 01107 (open-coded-defer.go:8) ADDQ $352, SP
264+
0x045a 01114 (open-coded-defer.go:8) RET
265+
0x045b 01115 (open-coded-defer.go:8) NOP
266+
0x045b 01115 (open-coded-defer.go:7) CALL runtime.morestack_noctxt(SB)
267+
0x0460 01120 (open-coded-defer.go:7) JMP 0
43268
```

syscall.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ TEXT runtime·read(SB),NOSPLIT,$0-28
305305
RET
306306
```
307307

308-
下面是所有 runtime 另外定义的 syscall 列表:
308+
下面是所有 runtime 另外定义的 syscall 列表(不同架构的机器映射各不相同,linux 下具体可通过 ausyscall --dump 命令获取系统调用映射表进行查看):
309309

310310
```go
311311
#define SYS_read 0

0 commit comments

Comments
 (0)