funcgetitab(inter *interfacetype, typ *_type, canfail bool)*itab {// ……// 根据 inter, typ 计算出 hash 值
h :=itabhash(inter, typ)// look twice - once without lock, once with.// common case will be no lock contention.var m *itab
var locked intfor locked =0; locked <2; locked++{if locked !=0{lock(&ifaceLock)}// 遍历哈希表的一个 slotfor m =(*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m !=nil; m = m.link {// 如果在 hash 表中已经找到了 itab(inter 和 typ 指针都相同)if m.inter == inter && m._type == typ {// ……if locked !=0{unlock(&ifaceLock)}return m
}}}// 在 hash 表中没有找到 itab,那么新生成一个 itab
m =(*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize,0,&memstats.other_sys))
m.inter = inter
m._type = typ
// 添加到全局的 hash 表中additab(m,true, canfail)unlock(&ifaceLock)if m.bad {returnnil}return m
}
查看additab 函数的代码
// 检查 _type 是否符合 interface_type 并且创建对应的 itab 结构体 将其放到 hash 表中funcadditab(m *itab, locked, canfail bool){
inter := m.inter
typ := m._type
x := typ.uncommon()// both inter and typ have method sorted by name,// and interface names are unique,// so can iterate over both in lock step;// the loop is O(ni+nt) not O(ni*nt).// // inter 和 typ 的方法都按方法名称进行了排序// 并且方法名都是唯一的。所以循环的次数是固定的// 只用循环 O(ni+nt),而非 O(ni*nt)
ni :=len(inter.mhdr)
nt :=int(x.mcount)
xmhdr :=(*[1<<16]method)(add(unsafe.Pointer(x),uintptr(x.moff)))[:nt:nt]
j :=0for k :=0; k < ni; k++{
i :=&inter.mhdr[k]
itype := inter.typ.typeOff(i.ityp)
name := inter.typ.nameOff(i.name)
iname := name.name()
ipkg := name.pkgPath()if ipkg ==""{
ipkg = inter.pkgpath.name()}for; j < nt; j++{
t :=&xmhdr[j]
tname := typ.nameOff(t.name)// 检查方法名字是否一致if typ.typeOff(t.mtyp)== itype && tname.name()== iname {
pkgPath := tname.pkgPath()if pkgPath ==""{
pkgPath = typ.nameOff(x.pkgpath).name()}if tname.isExported()|| pkgPath == ipkg {if m !=nil{// 获取函数地址,并加入到itab.fun数组中
ifn := typ.textOff(t.ifn)*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]),uintptr(k)*sys.PtrSize))= ifn
}goto nextimethod
}}}// ……
m.bad =truebreak
nextimethod:}if!locked {throw("invalid itab locking")}// 计算 hash 值
h :=itabhash(inter, typ)// 加到Hash Slot链表中
m.link = hash[h]
m.inhash =trueatomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))}