rsc.io/go@v0.0.0-20150416155037-e040fd465409/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 "unsafe" 9 ) 10 11 const ( 12 hashSize = 1009 13 ) 14 15 var ( 16 ifaceLock mutex // lock for accessing hash 17 hash [hashSize]*itab 18 ) 19 20 // fInterface is our standard non-empty interface. We use it instead 21 // of interface{f()} in function prototypes because gofmt insists on 22 // putting lots of newlines in the otherwise concise interface{f()}. 23 type fInterface interface { 24 f() 25 } 26 27 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { 28 if len(inter.mhdr) == 0 { 29 throw("internal error - misuse of itab") 30 } 31 32 // easy case 33 x := typ.x 34 if x == nil { 35 if canfail { 36 return nil 37 } 38 panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *inter.mhdr[0].name}) 39 } 40 41 // compiler has provided some good hash codes for us. 42 h := inter.typ.hash 43 h += 17 * typ.hash 44 // TODO(rsc): h += 23 * x.mhash ? 45 h %= hashSize 46 47 // look twice - once without lock, once with. 48 // common case will be no lock contention. 49 var m *itab 50 var locked int 51 for locked = 0; locked < 2; locked++ { 52 if locked != 0 { 53 lock(&ifaceLock) 54 } 55 for m = (*itab)(atomicloadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link { 56 if m.inter == inter && m._type == typ { 57 if m.bad != 0 { 58 m = nil 59 if !canfail { 60 // this can only happen if the conversion 61 // was already done once using the , ok form 62 // and we have a cached negative result. 63 // the cached result doesn't record which 64 // interface function was missing, so jump 65 // down to the interface check, which will 66 // do more work but give a better error. 67 goto search 68 } 69 } 70 if locked != 0 { 71 unlock(&ifaceLock) 72 } 73 return m 74 } 75 } 76 } 77 78 m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*ptrSize, 0, &memstats.other_sys)) 79 m.inter = inter 80 m._type = typ 81 82 search: 83 // both inter and typ have method sorted by name, 84 // and interface names are unique, 85 // so can iterate over both in lock step; 86 // the loop is O(ni+nt) not O(ni*nt). 87 ni := len(inter.mhdr) 88 nt := len(x.mhdr) 89 j := 0 90 for k := 0; k < ni; k++ { 91 i := &inter.mhdr[k] 92 iname := i.name 93 ipkgpath := i.pkgpath 94 itype := i._type 95 for ; j < nt; j++ { 96 t := &x.mhdr[j] 97 if t.mtyp == itype && (t.name == iname || *t.name == *iname) && t.pkgpath == ipkgpath { 98 if m != nil { 99 *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*ptrSize)) = t.ifn 100 } 101 goto nextimethod 102 } 103 } 104 // didn't find method 105 if !canfail { 106 if locked != 0 { 107 unlock(&ifaceLock) 108 } 109 panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname}) 110 } 111 m.bad = 1 112 break 113 nextimethod: 114 } 115 if locked == 0 { 116 throw("invalid itab locking") 117 } 118 m.link = hash[h] 119 atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m)) 120 unlock(&ifaceLock) 121 if m.bad != 0 { 122 return nil 123 } 124 return m 125 } 126 127 func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab { 128 tab := getitab(inter, t, false) 129 atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab)) 130 return tab 131 } 132 133 func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e interface{}) { 134 ep := (*eface)(unsafe.Pointer(&e)) 135 if isDirectIface(t) { 136 ep._type = t 137 typedmemmove(t, unsafe.Pointer(&ep.data), elem) 138 } else { 139 if x == nil { 140 x = newobject(t) 141 } 142 // TODO: We allocate a zeroed object only to overwrite it with 143 // actual data. Figure out how to avoid zeroing. Also below in convT2I. 144 typedmemmove(t, x, elem) 145 ep._type = t 146 ep.data = x 147 } 148 return 149 } 150 151 func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i fInterface) { 152 tab := (*itab)(atomicloadp(unsafe.Pointer(cache))) 153 if tab == nil { 154 tab = getitab(inter, t, false) 155 atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab)) 156 } 157 pi := (*iface)(unsafe.Pointer(&i)) 158 if isDirectIface(t) { 159 pi.tab = tab 160 typedmemmove(t, unsafe.Pointer(&pi.data), elem) 161 } else { 162 if x == nil { 163 x = newobject(t) 164 } 165 typedmemmove(t, x, elem) 166 pi.tab = tab 167 pi.data = x 168 } 169 return 170 } 171 172 func panicdottype(have, want, iface *_type) { 173 haveString := "" 174 if have != nil { 175 haveString = *have._string 176 } 177 panic(&TypeAssertionError{*iface._string, haveString, *want._string, ""}) 178 } 179 180 func assertI2T(t *_type, i fInterface, r unsafe.Pointer) { 181 ip := (*iface)(unsafe.Pointer(&i)) 182 tab := ip.tab 183 if tab == nil { 184 panic(&TypeAssertionError{"", "", *t._string, ""}) 185 } 186 if tab._type != t { 187 panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""}) 188 } 189 if r != nil { 190 if isDirectIface(t) { 191 writebarrierptr((*uintptr)(r), uintptr(ip.data)) 192 } else { 193 typedmemmove(t, r, ip.data) 194 } 195 } 196 } 197 198 func assertI2T2(t *_type, i fInterface, r unsafe.Pointer) bool { 199 ip := (*iface)(unsafe.Pointer(&i)) 200 tab := ip.tab 201 if tab == nil || tab._type != t { 202 if r != nil { 203 memclr(r, uintptr(t.size)) 204 } 205 return false 206 } 207 if r != nil { 208 if isDirectIface(t) { 209 writebarrierptr((*uintptr)(r), uintptr(ip.data)) 210 } else { 211 typedmemmove(t, r, ip.data) 212 } 213 } 214 return true 215 } 216 217 func assertE2T(t *_type, e interface{}, r unsafe.Pointer) { 218 ep := (*eface)(unsafe.Pointer(&e)) 219 if ep._type == nil { 220 panic(&TypeAssertionError{"", "", *t._string, ""}) 221 } 222 if ep._type != t { 223 panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""}) 224 } 225 if r != nil { 226 if isDirectIface(t) { 227 writebarrierptr((*uintptr)(r), uintptr(ep.data)) 228 } else { 229 typedmemmove(t, r, ep.data) 230 } 231 } 232 } 233 234 // The compiler ensures that r is non-nil. 235 func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool { 236 ep := (*eface)(unsafe.Pointer(&e)) 237 if ep._type != t { 238 memclr(r, uintptr(t.size)) 239 return false 240 } 241 if isDirectIface(t) { 242 writebarrierptr((*uintptr)(r), uintptr(ep.data)) 243 } else { 244 typedmemmove(t, r, ep.data) 245 } 246 return true 247 } 248 249 func convI2E(i fInterface) (r interface{}) { 250 ip := (*iface)(unsafe.Pointer(&i)) 251 tab := ip.tab 252 if tab == nil { 253 return 254 } 255 rp := (*eface)(unsafe.Pointer(&r)) 256 rp._type = tab._type 257 rp.data = ip.data 258 return 259 } 260 261 func assertI2E(inter *interfacetype, i fInterface, r *interface{}) { 262 ip := (*iface)(unsafe.Pointer(&i)) 263 tab := ip.tab 264 if tab == nil { 265 // explicit conversions require non-nil interface value. 266 panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) 267 } 268 rp := (*eface)(unsafe.Pointer(r)) 269 rp._type = tab._type 270 rp.data = ip.data 271 return 272 } 273 274 // The compiler ensures that r is non-nil. 275 func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool { 276 ip := (*iface)(unsafe.Pointer(&i)) 277 tab := ip.tab 278 if tab == nil { 279 return false 280 } 281 rp := (*eface)(unsafe.Pointer(r)) 282 rp._type = tab._type 283 rp.data = ip.data 284 return true 285 } 286 287 func convI2I(inter *interfacetype, i fInterface) (r fInterface) { 288 ip := (*iface)(unsafe.Pointer(&i)) 289 tab := ip.tab 290 if tab == nil { 291 return 292 } 293 rp := (*iface)(unsafe.Pointer(&r)) 294 if tab.inter == inter { 295 rp.tab = tab 296 rp.data = ip.data 297 return 298 } 299 rp.tab = getitab(inter, tab._type, false) 300 rp.data = ip.data 301 return 302 } 303 304 func assertI2I(inter *interfacetype, i fInterface, r *fInterface) { 305 ip := (*iface)(unsafe.Pointer(&i)) 306 tab := ip.tab 307 if tab == nil { 308 // explicit conversions require non-nil interface value. 309 panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) 310 } 311 rp := (*iface)(unsafe.Pointer(r)) 312 if tab.inter == inter { 313 rp.tab = tab 314 rp.data = ip.data 315 return 316 } 317 rp.tab = getitab(inter, tab._type, false) 318 rp.data = ip.data 319 } 320 321 func assertI2I2(inter *interfacetype, i fInterface, r *fInterface) bool { 322 ip := (*iface)(unsafe.Pointer(&i)) 323 tab := ip.tab 324 if tab == nil { 325 if r != nil { 326 *r = nil 327 } 328 return false 329 } 330 if tab.inter != inter { 331 tab = getitab(inter, tab._type, true) 332 if tab == nil { 333 if r != nil { 334 *r = nil 335 } 336 return false 337 } 338 } 339 if r != nil { 340 rp := (*iface)(unsafe.Pointer(r)) 341 rp.tab = tab 342 rp.data = ip.data 343 } 344 return true 345 } 346 347 func assertE2I(inter *interfacetype, e interface{}, r *fInterface) { 348 ep := (*eface)(unsafe.Pointer(&e)) 349 t := ep._type 350 if t == nil { 351 // explicit conversions require non-nil interface value. 352 panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) 353 } 354 rp := (*iface)(unsafe.Pointer(r)) 355 rp.tab = getitab(inter, t, false) 356 rp.data = ep.data 357 } 358 359 func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool { 360 ep := (*eface)(unsafe.Pointer(&e)) 361 t := ep._type 362 if t == nil { 363 if r != nil { 364 *r = nil 365 } 366 return false 367 } 368 tab := getitab(inter, t, true) 369 if tab == nil { 370 if r != nil { 371 *r = nil 372 } 373 return false 374 } 375 if r != nil { 376 rp := (*iface)(unsafe.Pointer(r)) 377 rp.tab = tab 378 rp.data = ep.data 379 } 380 return true 381 } 382 383 //go:linkname reflect_ifaceE2I reflect.ifaceE2I 384 func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) { 385 assertE2I(inter, e, dst) 386 } 387 388 func assertE2E(inter *interfacetype, e interface{}, r *interface{}) { 389 ep := (*eface)(unsafe.Pointer(&e)) 390 if ep._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 interface{}, r *interface{}) bool { 399 ep := (*eface)(unsafe.Pointer(&e)) 400 if ep._type == nil { 401 *r = nil 402 return false 403 } 404 *r = e 405 return true 406 } 407 408 func ifacethash(i fInterface) uint32 { 409 ip := (*iface)(unsafe.Pointer(&i)) 410 tab := ip.tab 411 if tab == nil { 412 return 0 413 } 414 return tab._type.hash 415 } 416 417 func efacethash(e interface{}) uint32 { 418 ep := (*eface)(unsafe.Pointer(&e)) 419 t := ep._type 420 if t == nil { 421 return 0 422 } 423 return t.hash 424 } 425 426 func iterate_itabs(fn func(*itab)) { 427 for _, h := range &hash { 428 for ; h != nil; h = h.link { 429 fn(h) 430 } 431 } 432 }