itab结构实际上如何拥有函数指针列表?

huangapple go评论79阅读模式
英文:

How is the itab struct actually having a list of function pointers?

问题

在研究Go语言中的接口值时,我发现了一篇很棒的(可能有点过时)文章,作者是Russ Cox。根据这篇文章:

itable首先包含一些关于涉及的类型的元数据,然后变成一系列函数指针

这个itable的实现应该是来自src/runtime/runtime2.go的代码:

type itab struct {
	inter *interfacetype
	_type *_type
	hash  uint32 // _type.hash的副本。用于类型切换。
	_     [4]byte
	fun   [1]uintptr // 可变大小。fun[0]==0表示_type不实现inter。
}

第一个令人困惑的问题是,一个数组如何是可变大小的?
第二个问题是,假设我们在索引0处有一个满足接口的方法的函数指针,我们应该在哪里存储第二个/第三个/...函数指针?

英文:

Researching the interface value in go - I found a great (maybe outdated) article by Russ Cox.
According to it:
> The itable begins with some metadata about the types involved and then becomes a list of function pointers.

The implementation for this itable should be the one from src/runtime/runtime2.go:

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.
}

First confusing thing is - how is an array - variable sized?
Second, assuming that we have a function pointer at index 0 for a method that satisfies the interface, where could we store a second/third/... function pointer?

答案1

得分: 1

编译后的代码和运行时访问fun,就好像字段声明为fun [n]uintptr,其中n是接口中方法的数量。第二个方法存储在fun[1],第三个方法存储在fun[2],依此类推。Go语言没有像这样的可变大小数组功能,但是可以使用unsafe来模拟该功能。

下面是itab的分配方式

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

英文:

The compiled code and runtime access fun as if the field is declared fun [n]uintpr where n is the number of methods in the interface. The second method is stored at fun[1], the third at fun[2] and so on. The Go Language does not have a variable size array feature like this, but unsafe shenanigans can be used to simulate the feature.

Here's how itab is allocated:

m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*goarch.PtrSize, 0, &amp;memstats.other_sys))

The function persistentalloc allocates memory. The first argument to the function is the size to allocate. The expression inter.mhdr is the number of methods in the interface.

Here's code that creates a slice on the variable size array:

methods := (*[1 &lt;&lt; 16]unsafe.Pointer)(unsafe.Pointer(&amp;m.fun[0]))[:ni:ni]

The expression methods[i] refers to the same element as m.fun[i] in a hypothetical world where m.fun is a variable size array with length > i. Later code uses normal slice syntax with methods to access the variable size array m.fun.

huangapple
  • 本文由 发表于 2022年2月13日 01:06:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/71094037.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定