type eface struct { _type *_type data unsafe.Pointer }
// Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize, // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and // ../reflect/type.go:/^type.rtype. type _type struct { size uintptr//type size ptrdata uintptr// size of memory prefix holding all pointers hash uint32//hash of type;avoids computation in hash table tflag tflag align uint8 fieldalign uint8 kind uint8// type mask alg *typeAlg // gcdata stores the GC type data for the garbage collector. // If the KindGCProg bit is set in kind, gcdata is a GC program. // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. gcdata *byte str nameOff //string form ptrToThis typeOff // type for pointer to this type, may be zero }
type iface struct { tab *itab data unsafe.Pointer }
// layout of Itab known to compilers // allocated in non-garbage-collected memory // Needs to be in sync with // ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs. type itab struct { inter *interfacetype //interface type description _type *_type //origin type link *itab //hash表头指针 hash uint32// copy of _type.hash. Used for type switches. bad bool// type does not implement interface inhash bool// has this itab been added to hash? unused [2]byte fun [1]uintptr// variable sized }
type interfacetype struct { typ _type pkgpath name mhdr []imethod }
var x unsafe.Pointer if *(*uint64)(elem) == 0 { x = unsafe.Pointer(&zeroVal[0]) } else { x = mallocgc(8, t, false) //分配一个8字节的对象 *(*uint64)(x) = *(*uint64)(elem) } e._type = t e.data = x return }
形象一些的内存表示如下图:
iface
类似的,对于包含参数的接口转换,runtime包中给出的实现为:
1 2 3 4 5 6 7 8 9 10
funcconvT2I(tab *itab, elem unsafe.Pointer)(i iface) { t := tab._type ...
x := mallocgc(t.size, t, true) typedmemmove(t, x, elem) i.tab = tab i.data = x return }
funcgetitab(inter *interfacetype, typ *_type, canfail bool) *itab { iflen(inter.mhdr) == 0 { throw("internal error - misuse of itab") }
// easy case if typ.tflag&tflagUncommon == 0 { if canfail { returnnil } name := inter.typ.nameOff(inter.mhdr[0].name) panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), name.name()}) }
h := itabhash(inter, typ) //根据inter和itab的type计算hash值
// look twice - once without lock, once with. // common case will be no lock contention. var m *itab var locked int for locked = 0; locked < 2; locked++ { if locked != 0 { lock(&ifaceLock) } for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {//查询itab的hash表中是否已经包含itab和inter关联的itab记录 if m.inter == inter && m._type == typ {//找到记录 if m.bad { if !canfail { //异常处理 // this can only happen if the conversion // was already done once using the , ok form // and we have a cached negative result. // the cached result doesn't record which // interface function was missing, so try // adding the itab again, which will throw an error. additab(m, locked != 0, false) } m = nil } if locked != 0 { unlock(&ifaceLock) } return m //返回查找结果 } } }
//hash表中未找到记录 m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys)) //分配新的itab m.inter = inter m._type = typ additab(m, true, canfail) //加入itab的hash表 unlock(&ifaceLock) if m.bad { returnnil } return m }
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). ni := len(inter.mhdr) nt := int(x.mcount) xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt] j := 0 for k := 0; k < ni; k++ { //inter方法列表遍历 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++ { //typ方法列表遍历 t := &xmhdr[j] tname := typ.nameOff(t.name) if typ.typeOff(t.mtyp) == itype && tname.name() == iname {// find the method pkgPath := tname.pkgPath() if pkgPath == "" { pkgPath = typ.nameOff(x.pkgpath).name() } if tname.isExported() || pkgPath == ipkg { if m != nil { ifn := typ.textOff(t.ifn) *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn // 方法写入新生成的itab方法表 } goto nextimethod } } } // didn't find method if !canfail { if locked { unlock(&ifaceLock) } panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname}) } m.bad = true//不匹配的itab break nextimethod: } if !locked { throw("invalid itab locking") } h := itabhash(inter, typ) m.link = hash[h] m.inhash = true atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m)) }
iface的实现中,包含了一个所有itab实例的hash表:
1 2 3 4
var ( ifaceLock mutex // lock for accessing hash hash [hashSize]*itab )