itab 结构实际上如何具有函数指针列表?
How is the itab struct actually having a list of function pointers?
研究 go 中的接口值 - 我发现了 Russ Cox 的一个很棒的(可能已经过时了)article。
根据它:
The itable begins with some metadata about the types involved and then becomes a list of function pointers.
这个 itable 的实现 应该是 来自 src/runtime/runtime2 的实现:
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
首先令人困惑的是 - 数组的大小如何变化?
其次,假设我们在索引 0 处有一个满足接口的方法的函数指针,我们可以在哪里存储 second/third/... 函数指针?
编译后的代码和运行时访问 fun
就好像声明了字段 fun [n]uintpr
其中 n
是接口中方法的数量。第二种方法存储在 fun[1]
,第三种存储在 fun[2]
,依此类推。 Go 语言没有像这样的可变大小数组特性,但是 unsafe 恶作剧可以用来模拟这个特性。
方法如下 itab is allocated:
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*goarch.PtrSize, 0, &memstats.other_sys))
函数persistentalloc
分配内存。该函数的第一个参数是要分配的大小。表达式inter.mhdr
是接口中的方法数。
这里 code 在可变大小数组上创建一个切片:
methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni]
表达式 methods[i]
与假设世界中的 m.fun[i]
指代相同的元素,其中 m.fun
是长度 > i
的可变大小数组。后面的代码使用带 methods
的普通切片语法来访问可变大小数组 m.fun
.
研究 go 中的接口值 - 我发现了 Russ Cox 的一个很棒的(可能已经过时了)article。 根据它:
The itable begins with some metadata about the types involved and then becomes a list of function pointers.
这个 itable 的实现 应该是 来自 src/runtime/runtime2 的实现:
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
首先令人困惑的是 - 数组的大小如何变化? 其次,假设我们在索引 0 处有一个满足接口的方法的函数指针,我们可以在哪里存储 second/third/... 函数指针?
编译后的代码和运行时访问 fun
就好像声明了字段 fun [n]uintpr
其中 n
是接口中方法的数量。第二种方法存储在 fun[1]
,第三种存储在 fun[2]
,依此类推。 Go 语言没有像这样的可变大小数组特性,但是 unsafe 恶作剧可以用来模拟这个特性。
方法如下 itab is allocated:
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*goarch.PtrSize, 0, &memstats.other_sys))
函数persistentalloc
分配内存。该函数的第一个参数是要分配的大小。表达式inter.mhdr
是接口中的方法数。
这里 code 在可变大小数组上创建一个切片:
methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni]
表达式 methods[i]
与假设世界中的 m.fun[i]
指代相同的元素,其中 m.fun
是长度 > i
的可变大小数组。后面的代码使用带 methods
的普通切片语法来访问可变大小数组 m.fun
.