github.com/euank/go@v0.0.0-20160829210321-495514729181/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 m.link = hash[h] 142 atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m)) 143 } 144 145 func itabsinit() { 146 lock(&ifaceLock) 147 for m := &firstmoduledata; m != nil; m = m.next { 148 for _, i := range m.itablinks { 149 additab(i, true, false) 150 } 151 } 152 unlock(&ifaceLock) 153 } 154 155 func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) { 156 if raceenabled { 157 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E)) 158 } 159 if msanenabled { 160 msanread(elem, t.size) 161 } 162 if isDirectIface(t) { 163 throw("direct convT2E") 164 } 165 if x == nil { 166 x = newobject(t) 167 // TODO: We allocate a zeroed object only to overwrite it with 168 // actual data. Figure out how to avoid zeroing. Also below in convT2I. 169 } 170 typedmemmove(t, x, elem) 171 e._type = t 172 e.data = x 173 return 174 } 175 176 func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) { 177 t := tab._type 178 if raceenabled { 179 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I)) 180 } 181 if msanenabled { 182 msanread(elem, t.size) 183 } 184 if isDirectIface(t) { 185 throw("direct convT2I") 186 } 187 if x == nil { 188 x = newobject(t) 189 } 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 memclr(r, t.size) 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 memclr(r, t.size) 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 convI2E(i iface) (r eface) { 272 tab := i.tab 273 if tab == nil { 274 return 275 } 276 r._type = tab._type 277 r.data = i.data 278 return 279 } 280 281 func assertI2E(inter *interfacetype, i iface, r *eface) { 282 tab := i.tab 283 if tab == nil { 284 // explicit conversions require non-nil interface value. 285 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 286 } 287 r._type = tab._type 288 r.data = i.data 289 return 290 } 291 292 // The compiler ensures that r is non-nil. 293 func assertI2E2(inter *interfacetype, i iface, r *eface) bool { 294 tab := i.tab 295 if tab == nil { 296 return false 297 } 298 r._type = tab._type 299 r.data = i.data 300 return true 301 } 302 303 func convI2I(inter *interfacetype, i iface) (r iface) { 304 tab := i.tab 305 if tab == nil { 306 return 307 } 308 if tab.inter == inter { 309 r.tab = tab 310 r.data = i.data 311 return 312 } 313 r.tab = getitab(inter, tab._type, false) 314 r.data = i.data 315 return 316 } 317 318 func assertI2I(inter *interfacetype, i iface, r *iface) { 319 tab := i.tab 320 if tab == nil { 321 // explicit conversions require non-nil interface value. 322 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 323 } 324 if tab.inter == inter { 325 r.tab = tab 326 r.data = i.data 327 return 328 } 329 r.tab = getitab(inter, tab._type, false) 330 r.data = i.data 331 } 332 333 func assertI2I2(inter *interfacetype, i iface, r *iface) bool { 334 tab := i.tab 335 if tab == nil { 336 if r != nil { 337 *r = iface{} 338 } 339 return false 340 } 341 if tab.inter != inter { 342 tab = getitab(inter, tab._type, true) 343 if tab == nil { 344 if r != nil { 345 *r = iface{} 346 } 347 return false 348 } 349 } 350 if r != nil { 351 r.tab = tab 352 r.data = i.data 353 } 354 return true 355 } 356 357 func assertE2I(inter *interfacetype, e eface, r *iface) { 358 t := e._type 359 if t == nil { 360 // explicit conversions require non-nil interface value. 361 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 362 } 363 r.tab = getitab(inter, t, false) 364 r.data = e.data 365 } 366 367 var testingAssertE2I2GC bool 368 369 func assertE2I2(inter *interfacetype, e eface, r *iface) bool { 370 if testingAssertE2I2GC { 371 GC() 372 } 373 t := e._type 374 if t == nil { 375 if r != nil { 376 *r = iface{} 377 } 378 return false 379 } 380 tab := getitab(inter, t, true) 381 if tab == nil { 382 if r != nil { 383 *r = iface{} 384 } 385 return false 386 } 387 if r != nil { 388 r.tab = tab 389 r.data = e.data 390 } 391 return true 392 } 393 394 //go:linkname reflect_ifaceE2I reflect.ifaceE2I 395 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { 396 assertE2I(inter, e, dst) 397 } 398 399 func assertE2E(inter *interfacetype, e eface, r *eface) { 400 if e._type == nil { 401 // explicit conversions require non-nil interface value. 402 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 403 } 404 *r = e 405 } 406 407 // The compiler ensures that r is non-nil. 408 func assertE2E2(inter *interfacetype, e eface, r *eface) bool { 409 if e._type == nil { 410 *r = eface{} 411 return false 412 } 413 *r = e 414 return true 415 } 416 417 func iterate_itabs(fn func(*itab)) { 418 for _, h := range &hash { 419 for ; h != nil; h = h.link { 420 fn(h) 421 } 422 } 423 }