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