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