// ...... 00007 (+143) LEAQ type.func()(SB), AX // Load function type info 00009 (143) MOVQ AX, (SP) 00010 (143) CALL runtime.newobject(SB) // Call runtime.newobject to allocate the object 00012 (143) MOVQ 8(SP), DI // Save the address of the new object (SP+8) to DI 00014 (143) MOVQ DI, "".&f-144(SP) // Save the address the new object to local variable 00017 (143) CMPL runtime.writeBarrier(SB), $0 00018 (143) JEQ 20 00019 (143) JMP 144 00020 (143) LEAQ "".CheckFunctionInternal·f(SB), AX // Load address of CheckFunctionInternal to AX 00021 (143) MOVQ AX, (DI) // Save address of CheckFunctionInternal to the newly allocated object 00022 (143) JMP 23 // ......
// ... 00069 (+167) MOVQ "".&f-144(SP), AX // Load the address of the function pointer to AX 00071 (167) MOVQ (AX), DX // Load the function address to DX 00072 (167) MOVQ (DX), AX // Move the function address to AX 00074 (167) CALL AX // Call the actual function // ...
所以还真的是这么实现的。这里我们先不着急,等看完之后的Closure实现,我们就明白了~
5.2. 闭包(Closure)
那闭包呢?闭包应该会创建上下文(Context),所以一个指针应该表示不了了,我们也来试一试。
1 2
Var Type Address RootOffset LocalOffset Size cls func() 0x000000c000006068 0 0 8
居然还是8个字节!我们这就来看看是怎么回事,老办法,先写个小代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
funcCheckClosureInternal() { var i int = 1 var f func() = func() { i = 2 fmt.Printf("i = %v\n", i) } UpdateClosure(f) fmt.Printf("AfterReturn: Ptr = %p\n", &f) }
//go:noinline funcUpdateClosure(f func()) { var b bool = false f = func() { b = true fmt.Printf("i = %v\n", b) } fmt.Printf("AfterUpdate: Ptr = %p\n", &f) }
// ...... 00007 (+162) LEAQ type.int(SB), AX // Load int type info to AX 00009 (162) MOVQ AX, (SP) 00010 (162) CALL runtime.newobject(SB) // Create a int 00012 (162) MOVQ 8(SP), AX // Save the address of the int to AX 00014 (162) MOVQ AX, "".&i-152(SP) // Save the address of the int to stack SP+(&i-152) 00016 (162) MOVQ $1, (AX) // Set the value of the newly allocated int 00018 (+163) LEAQ type.func()(SB), AX // Load function func() type info to AX 00020 (163) MOVQ AX, (SP) 00021 (163) CALL runtime.newobject(SB) // Allocate the buffer for holding the func object 00023 (163) MOVQ 8(SP), AX 00026 (163) MOVQ AX, "".&f-144(SP) // Save the func address to SP+(&f-144) 00028 (163) LEAQ type.noalg.struct { F uintptr; "".i *int }(SB), AX // Load the closure context type info, which captures the pointer to the int. 00030 (163) MOVQ AX, (SP) 00031 (163) CALL runtime.newobject(SB) // Create the closure context 00033 (163) MOVQ 8(SP), AX 00035 (163) MOVQ AX, ""..autotmp_15-168(SP) // Save the closure context address to temp variable SP+(""..autotmp_15-168) 00036 (163) LEAQ "".CheckClosureInternal.func1(SB), CX // Load the annoymous function address 00038 (163) MOVQ CX, (AX) // Update the function address in closure context 00040 (163) MOVQ ""..autotmp_15-168(SP), AX 00041 (163) TESTB AX, (AX) 00044 (163) MOVQ "".&i-152(SP), CX // Load the address of the int 00046 (163) LEAQ 8(AX), DI // Load the address of the int pointer in the closure context 00049 (163) CMPL runtime.writeBarrier(SB), $0 00050 (163) JEQ 52 00051 (163) JMP 190 00052 (163) MOVQ CX, 8(AX) // Update the int pointer in the closure context to the int it created above 00053 (163) JMP 54 00056 (163) MOVQ "".&f-144(SP), DI // Load the function address back to DI 00059 (163) MOVQ ""..autotmp_15-168(SP), AX // Load the closure context address back to AX 00062 (163) CMPL runtime.writeBarrier(SB), $0 00063 (163) JEQ 65 00064 (163) JMP 188 00065 (163) MOVQ AX, (DI) // Save the closure context as the function address 00066 (163) JMP 67 // ......