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