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