github.com/brownsys/tracing-framework-go@v0.0.0-20161210174012-0542a62412fe/go/darwin_amd64/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 func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool { 222 tab := i.tab 223 if tab == nil || tab._type != t { 224 if r != nil { 225 memclr(r, t.size) 226 } 227 return false 228 } 229 if r != nil { 230 if isDirectIface(t) { 231 writebarrierptr((*uintptr)(r), uintptr(i.data)) 232 } else { 233 typedmemmove(t, r, i.data) 234 } 235 } 236 return true 237 } 238 239 func assertE2T(t *_type, e eface, r unsafe.Pointer) { 240 if e._type == nil { 241 panic(&TypeAssertionError{"", "", t.string(), ""}) 242 } 243 if e._type != t { 244 panic(&TypeAssertionError{"", e._type.string(), t.string(), ""}) 245 } 246 if r != nil { 247 if isDirectIface(t) { 248 writebarrierptr((*uintptr)(r), uintptr(e.data)) 249 } else { 250 typedmemmove(t, r, e.data) 251 } 252 } 253 } 254 255 var testingAssertE2T2GC bool 256 257 // The compiler ensures that r is non-nil. 258 func assertE2T2(t *_type, e eface, r unsafe.Pointer) bool { 259 if testingAssertE2T2GC { 260 GC() 261 } 262 if e._type != t { 263 memclr(r, t.size) 264 return false 265 } 266 if isDirectIface(t) { 267 writebarrierptr((*uintptr)(r), uintptr(e.data)) 268 } else { 269 typedmemmove(t, r, e.data) 270 } 271 return true 272 } 273 274 func convI2E(i iface) (r eface) { 275 tab := i.tab 276 if tab == nil { 277 return 278 } 279 r._type = tab._type 280 r.data = i.data 281 return 282 } 283 284 func assertI2E(inter *interfacetype, i iface, r *eface) { 285 tab := i.tab 286 if tab == nil { 287 // explicit conversions require non-nil interface value. 288 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 289 } 290 r._type = tab._type 291 r.data = i.data 292 return 293 } 294 295 // The compiler ensures that r is non-nil. 296 func assertI2E2(inter *interfacetype, i iface, r *eface) bool { 297 tab := i.tab 298 if tab == nil { 299 return false 300 } 301 r._type = tab._type 302 r.data = i.data 303 return true 304 } 305 306 func convI2I(inter *interfacetype, i iface) (r iface) { 307 tab := i.tab 308 if tab == nil { 309 return 310 } 311 if tab.inter == inter { 312 r.tab = tab 313 r.data = i.data 314 return 315 } 316 r.tab = getitab(inter, tab._type, false) 317 r.data = i.data 318 return 319 } 320 321 func assertI2I(inter *interfacetype, i iface, r *iface) { 322 tab := i.tab 323 if tab == nil { 324 // explicit conversions require non-nil interface value. 325 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 326 } 327 if tab.inter == inter { 328 r.tab = tab 329 r.data = i.data 330 return 331 } 332 r.tab = getitab(inter, tab._type, false) 333 r.data = i.data 334 } 335 336 func assertI2I2(inter *interfacetype, i iface, r *iface) bool { 337 tab := i.tab 338 if tab == nil { 339 if r != nil { 340 *r = iface{} 341 } 342 return false 343 } 344 if tab.inter != inter { 345 tab = getitab(inter, tab._type, true) 346 if tab == nil { 347 if r != nil { 348 *r = iface{} 349 } 350 return false 351 } 352 } 353 if r != nil { 354 r.tab = tab 355 r.data = i.data 356 } 357 return true 358 } 359 360 func assertE2I(inter *interfacetype, e eface, r *iface) { 361 t := e._type 362 if t == nil { 363 // explicit conversions require non-nil interface value. 364 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 365 } 366 r.tab = getitab(inter, t, false) 367 r.data = e.data 368 } 369 370 var testingAssertE2I2GC bool 371 372 func assertE2I2(inter *interfacetype, e eface, r *iface) bool { 373 if testingAssertE2I2GC { 374 GC() 375 } 376 t := e._type 377 if t == nil { 378 if r != nil { 379 *r = iface{} 380 } 381 return false 382 } 383 tab := getitab(inter, t, true) 384 if tab == nil { 385 if r != nil { 386 *r = iface{} 387 } 388 return false 389 } 390 if r != nil { 391 r.tab = tab 392 r.data = e.data 393 } 394 return true 395 } 396 397 //go:linkname reflect_ifaceE2I reflect.ifaceE2I 398 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { 399 assertE2I(inter, e, dst) 400 } 401 402 func assertE2E(inter *interfacetype, e eface, r *eface) { 403 if e._type == nil { 404 // explicit conversions require non-nil interface value. 405 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 406 } 407 *r = e 408 } 409 410 // The compiler ensures that r is non-nil. 411 func assertE2E2(inter *interfacetype, e eface, r *eface) bool { 412 if e._type == nil { 413 *r = eface{} 414 return false 415 } 416 *r = e 417 return true 418 } 419 420 func iterate_itabs(fn func(*itab)) { 421 for _, h := range &hash { 422 for ; h != nil; h = h.link { 423 fn(h) 424 } 425 } 426 }