github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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 m := &firstmoduledata; m != nil; m = m.next { 152 for _, i := range m.itablinks { 153 additab(i, true, false) 154 } 155 } 156 unlock(&ifaceLock) 157 } 158 159 func convT2E(t *_type, elem unsafe.Pointer) (e eface) { 160 if raceenabled { 161 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E)) 162 } 163 if msanenabled { 164 msanread(elem, t.size) 165 } 166 if isDirectIface(t) { 167 throw("direct convT2E") 168 } 169 x := newobject(t) 170 // TODO: We allocate a zeroed object only to overwrite it with 171 // actual data. Figure out how to avoid zeroing. Also below in convT2I. 172 typedmemmove(t, x, elem) 173 e._type = t 174 e.data = x 175 return 176 } 177 178 func convT2I(tab *itab, elem unsafe.Pointer) (i iface) { 179 t := tab._type 180 if raceenabled { 181 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I)) 182 } 183 if msanenabled { 184 msanread(elem, t.size) 185 } 186 if isDirectIface(t) { 187 throw("direct convT2I") 188 } 189 x := newobject(t) 190 typedmemmove(t, x, elem) 191 i.tab = tab 192 i.data = x 193 return 194 } 195 196 func panicdottype(have, want, iface *_type) { 197 haveString := "" 198 if have != nil { 199 haveString = have.string() 200 } 201 panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""}) 202 } 203 204 func assertI2T(t *_type, i iface, r unsafe.Pointer) { 205 tab := i.tab 206 if tab == nil { 207 panic(&TypeAssertionError{"", "", t.string(), ""}) 208 } 209 if tab._type != t { 210 panic(&TypeAssertionError{tab.inter.typ.string(), tab._type.string(), t.string(), ""}) 211 } 212 if r != nil { 213 if isDirectIface(t) { 214 writebarrierptr((*uintptr)(r), uintptr(i.data)) 215 } else { 216 typedmemmove(t, r, i.data) 217 } 218 } 219 } 220 221 // The compiler ensures that r is non-nil. 222 func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool { 223 tab := i.tab 224 if tab == nil || tab._type != t { 225 typedmemclr(t, r) 226 return false 227 } 228 if isDirectIface(t) { 229 writebarrierptr((*uintptr)(r), uintptr(i.data)) 230 } else { 231 typedmemmove(t, r, i.data) 232 } 233 return true 234 } 235 236 func assertE2T(t *_type, e eface, r unsafe.Pointer) { 237 if e._type == nil { 238 panic(&TypeAssertionError{"", "", t.string(), ""}) 239 } 240 if e._type != t { 241 panic(&TypeAssertionError{"", e._type.string(), t.string(), ""}) 242 } 243 if r != nil { 244 if isDirectIface(t) { 245 writebarrierptr((*uintptr)(r), uintptr(e.data)) 246 } else { 247 typedmemmove(t, r, e.data) 248 } 249 } 250 } 251 252 var testingAssertE2T2GC bool 253 254 // The compiler ensures that r is non-nil. 255 func assertE2T2(t *_type, e eface, r unsafe.Pointer) bool { 256 if testingAssertE2T2GC { 257 GC() 258 } 259 if e._type != t { 260 typedmemclr(t, r) 261 return false 262 } 263 if isDirectIface(t) { 264 writebarrierptr((*uintptr)(r), uintptr(e.data)) 265 } else { 266 typedmemmove(t, r, e.data) 267 } 268 return true 269 } 270 271 func assertI2E(inter *interfacetype, i iface, r *eface) { 272 tab := i.tab 273 if tab == nil { 274 // explicit conversions require non-nil interface value. 275 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 276 } 277 r._type = tab._type 278 r.data = i.data 279 return 280 } 281 282 // The compiler ensures that r is non-nil. 283 func assertI2E2(inter *interfacetype, i iface, r *eface) bool { 284 tab := i.tab 285 if tab == nil { 286 return false 287 } 288 r._type = tab._type 289 r.data = i.data 290 return true 291 } 292 293 func convI2I(inter *interfacetype, i iface) (r iface) { 294 tab := i.tab 295 if tab == nil { 296 return 297 } 298 if tab.inter == inter { 299 r.tab = tab 300 r.data = i.data 301 return 302 } 303 r.tab = getitab(inter, tab._type, false) 304 r.data = i.data 305 return 306 } 307 308 func assertI2I(inter *interfacetype, i iface, r *iface) { 309 tab := i.tab 310 if tab == nil { 311 // explicit conversions require non-nil interface value. 312 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 313 } 314 if tab.inter == inter { 315 r.tab = tab 316 r.data = i.data 317 return 318 } 319 r.tab = getitab(inter, tab._type, false) 320 r.data = i.data 321 } 322 323 func assertI2I2(inter *interfacetype, i iface, r *iface) bool { 324 tab := i.tab 325 if tab == nil { 326 if r != nil { 327 *r = iface{} 328 } 329 return false 330 } 331 if tab.inter != inter { 332 tab = getitab(inter, tab._type, true) 333 if tab == nil { 334 if r != nil { 335 *r = iface{} 336 } 337 return false 338 } 339 } 340 if r != nil { 341 r.tab = tab 342 r.data = i.data 343 } 344 return true 345 } 346 347 func assertE2I(inter *interfacetype, e eface, r *iface) { 348 t := e._type 349 if t == nil { 350 // explicit conversions require non-nil interface value. 351 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 352 } 353 r.tab = getitab(inter, t, false) 354 r.data = e.data 355 } 356 357 var testingAssertE2I2GC bool 358 359 func assertE2I2(inter *interfacetype, e eface, r *iface) bool { 360 if testingAssertE2I2GC { 361 GC() 362 } 363 t := e._type 364 if t == nil { 365 if r != nil { 366 *r = iface{} 367 } 368 return false 369 } 370 tab := getitab(inter, t, true) 371 if tab == nil { 372 if r != nil { 373 *r = iface{} 374 } 375 return false 376 } 377 if r != nil { 378 r.tab = tab 379 r.data = e.data 380 } 381 return true 382 } 383 384 //go:linkname reflect_ifaceE2I reflect.ifaceE2I 385 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { 386 assertE2I(inter, e, dst) 387 } 388 389 func assertE2E(inter *interfacetype, e eface, r *eface) { 390 if e._type == nil { 391 // explicit conversions require non-nil interface value. 392 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 393 } 394 *r = e 395 } 396 397 // The compiler ensures that r is non-nil. 398 func assertE2E2(inter *interfacetype, e eface, r *eface) bool { 399 if e._type == nil { 400 *r = eface{} 401 return false 402 } 403 *r = e 404 return true 405 } 406 407 func iterate_itabs(fn func(*itab)) { 408 for _, h := range &hash { 409 for ; h != nil; h = h.link { 410 fn(h) 411 } 412 } 413 }