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