github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/src/runtime/iface.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime 6 7 import ( 8 "runtime/internal/atomic" 9 "runtime/internal/sys" 10 "unsafe" 11 ) 12 13 const ( 14 hashSize = 1009 15 ) 16 17 var ( 18 ifaceLock mutex // lock for accessing hash 19 hash [hashSize]*itab 20 ) 21 22 func itabhash(inter *interfacetype, typ *_type) uint32 { 23 // compiler has provided some good hash codes for us. 24 h := inter.typ.hash 25 h += 17 * typ.hash 26 // TODO(rsc): h += 23 * x.mhash ? 27 return h % hashSize 28 } 29 30 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { 31 if len(inter.mhdr) == 0 { 32 throw("internal error - misuse of itab") 33 } 34 35 // easy case 36 if typ.tflag&tflagUncommon == 0 { 37 if canfail { 38 return nil 39 } 40 name := inter.typ.nameOff(inter.mhdr[0].name) 41 panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), name.name()}) 42 } 43 44 h := itabhash(inter, typ) 45 46 // look twice - once without lock, once with. 47 // common case will be no lock contention. 48 var m *itab 49 var locked int 50 for locked = 0; locked < 2; locked++ { 51 if locked != 0 { 52 lock(&ifaceLock) 53 } 54 for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link { 55 if m.inter == inter && m._type == typ { 56 if m.bad != 0 { 57 if !canfail { 58 // this can only happen if the conversion 59 // was already done once using the , ok form 60 // and we have a cached negative result. 61 // the cached result doesn't record which 62 // interface function was missing, so try 63 // adding the itab again, which will throw an error. 64 additab(m, locked != 0, false) 65 } 66 m = nil 67 } 68 if locked != 0 { 69 unlock(&ifaceLock) 70 } 71 return m 72 } 73 } 74 } 75 76 m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys)) 77 m.inter = inter 78 m._type = typ 79 additab(m, true, canfail) 80 unlock(&ifaceLock) 81 if m.bad != 0 { 82 return nil 83 } 84 return m 85 } 86 87 func additab(m *itab, locked, canfail bool) { 88 inter := m.inter 89 typ := m._type 90 x := typ.uncommon() 91 92 // both inter and typ have method sorted by name, 93 // and interface names are unique, 94 // so can iterate over both in lock step; 95 // the loop is O(ni+nt) not O(ni*nt). 96 ni := len(inter.mhdr) 97 nt := int(x.mcount) 98 xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt] 99 j := 0 100 for k := 0; k < ni; k++ { 101 i := &inter.mhdr[k] 102 itype := inter.typ.typeOff(i.ityp) 103 name := inter.typ.nameOff(i.name) 104 iname := name.name() 105 ipkg := name.pkgPath() 106 if ipkg == "" { 107 ipkg = inter.pkgpath.name() 108 } 109 for ; j < nt; j++ { 110 t := &xmhdr[j] 111 tname := typ.nameOff(t.name) 112 if typ.typeOff(t.mtyp) == itype && tname.name() == iname { 113 pkgPath := tname.pkgPath() 114 if pkgPath == "" { 115 pkgPath = typ.nameOff(x.pkgpath).name() 116 } 117 if tname.isExported() || pkgPath == ipkg { 118 if m != nil { 119 ifn := typ.textOff(t.ifn) 120 *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn 121 } 122 goto nextimethod 123 } 124 } 125 } 126 // didn't find method 127 if !canfail { 128 if locked { 129 unlock(&ifaceLock) 130 } 131 panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname}) 132 } 133 m.bad = 1 134 break 135 nextimethod: 136 } 137 if !locked { 138 throw("invalid itab locking") 139 } 140 h := itabhash(inter, typ) 141 if m == hash[h] { 142 println("duplicate itab for", typ.string(), "and", inter.typ.string()) 143 throw("duplicate itabs") 144 } 145 m.link = hash[h] 146 atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m)) 147 } 148 149 func itabsinit() { 150 lock(&ifaceLock) 151 for _, md := range activeModules() { 152 for _, i := range md.itablinks { 153 additab(i, true, false) 154 } 155 } 156 unlock(&ifaceLock) 157 } 158 159 // panicdottype is called when doing an i.(T) conversion and the conversion fails. 160 // have = the dynamic type we have. 161 // want = the static type we're trying to convert to. 162 // iface = the static type we're converting from. 163 func panicdottype(have, want, iface *_type) { 164 haveString := "" 165 if have != nil { 166 haveString = have.string() 167 } 168 panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""}) 169 } 170 171 // panicnildottype is called when doing a i.(T) conversion and the interface i is nil. 172 // want = the static type we're trying to convert to. 173 func panicnildottype(want *_type) { 174 panic(&TypeAssertionError{"", "", want.string(), ""}) 175 // TODO: Add the static type we're converting from as well. 176 // It might generate a better error message. 177 // Just to match other nil conversion errors, we don't for now. 178 } 179 180 // The conv and assert functions below do very similar things. 181 // The convXXX functions are guaranteed by the compiler to succeed. 182 // The assertXXX functions may fail (either panicing or returning false, 183 // depending on whether they are 1-result or 2-result). 184 // The convXXX functions succeed on a nil input, whereas the assertXXX 185 // functions fail on a nil input. 186 187 func convT2E(t *_type, elem unsafe.Pointer) (e eface) { 188 if raceenabled { 189 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E)) 190 } 191 if msanenabled { 192 msanread(elem, t.size) 193 } 194 if isDirectIface(t) { 195 // This case is implemented directly by the compiler. 196 throw("direct convT2E") 197 } 198 x := newobject(t) 199 // TODO: We allocate a zeroed object only to overwrite it with 200 // actual data. Figure out how to avoid zeroing. Also below in convT2I. 201 typedmemmove(t, x, elem) 202 e._type = t 203 e.data = x 204 return 205 } 206 207 func convT2I(tab *itab, elem unsafe.Pointer) (i iface) { 208 t := tab._type 209 if raceenabled { 210 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I)) 211 } 212 if msanenabled { 213 msanread(elem, t.size) 214 } 215 if isDirectIface(t) { 216 // This case is implemented directly by the compiler. 217 throw("direct convT2I") 218 } 219 x := newobject(t) 220 typedmemmove(t, x, elem) 221 i.tab = tab 222 i.data = x 223 return 224 } 225 226 func convI2I(inter *interfacetype, i iface) (r iface) { 227 tab := i.tab 228 if tab == nil { 229 return 230 } 231 if tab.inter == inter { 232 r.tab = tab 233 r.data = i.data 234 return 235 } 236 r.tab = getitab(inter, tab._type, false) 237 r.data = i.data 238 return 239 } 240 241 func assertI2I(inter *interfacetype, i iface) (r iface) { 242 tab := i.tab 243 if tab == nil { 244 // explicit conversions require non-nil interface value. 245 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 246 } 247 if tab.inter == inter { 248 r.tab = tab 249 r.data = i.data 250 return 251 } 252 r.tab = getitab(inter, tab._type, false) 253 r.data = i.data 254 return 255 } 256 257 func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) { 258 tab := i.tab 259 if tab == nil { 260 return 261 } 262 if tab.inter != inter { 263 tab = getitab(inter, tab._type, true) 264 if tab == nil { 265 return 266 } 267 } 268 r.tab = tab 269 r.data = i.data 270 b = true 271 return 272 } 273 274 func assertE2I(inter *interfacetype, e eface) (r iface) { 275 t := e._type 276 if t == nil { 277 // explicit conversions require non-nil interface value. 278 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 279 } 280 r.tab = getitab(inter, t, false) 281 r.data = e.data 282 return 283 } 284 285 func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) { 286 t := e._type 287 if t == nil { 288 return 289 } 290 tab := getitab(inter, t, true) 291 if tab == nil { 292 return 293 } 294 r.tab = tab 295 r.data = e.data 296 b = true 297 return 298 } 299 300 //go:linkname reflect_ifaceE2I reflect.ifaceE2I 301 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { 302 *dst = assertE2I(inter, e) 303 } 304 305 func iterate_itabs(fn func(*itab)) { 306 for _, h := range &hash { 307 for ; h != nil; h = h.link { 308 fn(h) 309 } 310 } 311 }