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 var testingAssertE2T2GC bool 233 234 // The compiler ensures that r is non-nil. 235 func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool { 236 if testingAssertE2T2GC { 237 GC() 238 } 239 ep := (*eface)(unsafe.Pointer(&e)) 240 if ep._type != t { 241 memclr(r, uintptr(t.size)) 242 return false 243 } 244 if isDirectIface(t) { 245 writebarrierptr((*uintptr)(r), uintptr(ep.data)) 246 } else { 247 typedmemmove(t, r, ep.data) 248 } 249 return true 250 } 251 252 func convI2E(i fInterface) (r interface{}) { 253 ip := (*iface)(unsafe.Pointer(&i)) 254 tab := ip.tab 255 if tab == nil { 256 return 257 } 258 rp := (*eface)(unsafe.Pointer(&r)) 259 rp._type = tab._type 260 rp.data = ip.data 261 return 262 } 263 264 func assertI2E(inter *interfacetype, i fInterface, r *interface{}) { 265 ip := (*iface)(unsafe.Pointer(&i)) 266 tab := ip.tab 267 if tab == nil { 268 // explicit conversions require non-nil interface value. 269 panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) 270 } 271 rp := (*eface)(unsafe.Pointer(r)) 272 rp._type = tab._type 273 rp.data = ip.data 274 return 275 } 276 277 // The compiler ensures that r is non-nil. 278 func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool { 279 ip := (*iface)(unsafe.Pointer(&i)) 280 tab := ip.tab 281 if tab == nil { 282 return false 283 } 284 rp := (*eface)(unsafe.Pointer(r)) 285 rp._type = tab._type 286 rp.data = ip.data 287 return true 288 } 289 290 func convI2I(inter *interfacetype, i fInterface) (r fInterface) { 291 ip := (*iface)(unsafe.Pointer(&i)) 292 tab := ip.tab 293 if tab == nil { 294 return 295 } 296 rp := (*iface)(unsafe.Pointer(&r)) 297 if tab.inter == inter { 298 rp.tab = tab 299 rp.data = ip.data 300 return 301 } 302 rp.tab = getitab(inter, tab._type, false) 303 rp.data = ip.data 304 return 305 } 306 307 func assertI2I(inter *interfacetype, i fInterface, r *fInterface) { 308 ip := (*iface)(unsafe.Pointer(&i)) 309 tab := ip.tab 310 if tab == nil { 311 // explicit conversions require non-nil interface value. 312 panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) 313 } 314 rp := (*iface)(unsafe.Pointer(r)) 315 if tab.inter == inter { 316 rp.tab = tab 317 rp.data = ip.data 318 return 319 } 320 rp.tab = getitab(inter, tab._type, false) 321 rp.data = ip.data 322 } 323 324 func assertI2I2(inter *interfacetype, i fInterface, r *fInterface) bool { 325 ip := (*iface)(unsafe.Pointer(&i)) 326 tab := ip.tab 327 if tab == nil { 328 if r != nil { 329 *r = nil 330 } 331 return false 332 } 333 if tab.inter != inter { 334 tab = getitab(inter, tab._type, true) 335 if tab == nil { 336 if r != nil { 337 *r = nil 338 } 339 return false 340 } 341 } 342 if r != nil { 343 rp := (*iface)(unsafe.Pointer(r)) 344 rp.tab = tab 345 rp.data = ip.data 346 } 347 return true 348 } 349 350 func assertE2I(inter *interfacetype, e interface{}, r *fInterface) { 351 ep := (*eface)(unsafe.Pointer(&e)) 352 t := ep._type 353 if t == nil { 354 // explicit conversions require non-nil interface value. 355 panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) 356 } 357 rp := (*iface)(unsafe.Pointer(r)) 358 rp.tab = getitab(inter, t, false) 359 rp.data = ep.data 360 } 361 362 var testingAssertE2I2GC bool 363 364 func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool { 365 if testingAssertE2I2GC { 366 GC() 367 } 368 ep := (*eface)(unsafe.Pointer(&e)) 369 t := ep._type 370 if t == nil { 371 if r != nil { 372 *r = nil 373 } 374 return false 375 } 376 tab := getitab(inter, t, true) 377 if tab == nil { 378 if r != nil { 379 *r = nil 380 } 381 return false 382 } 383 if r != nil { 384 rp := (*iface)(unsafe.Pointer(r)) 385 rp.tab = tab 386 rp.data = ep.data 387 } 388 return true 389 } 390 391 //go:linkname reflect_ifaceE2I reflect.ifaceE2I 392 func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) { 393 assertE2I(inter, e, dst) 394 } 395 396 func assertE2E(inter *interfacetype, e interface{}, r *interface{}) { 397 ep := (*eface)(unsafe.Pointer(&e)) 398 if ep._type == nil { 399 // explicit conversions require non-nil interface value. 400 panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) 401 } 402 *r = e 403 } 404 405 // The compiler ensures that r is non-nil. 406 func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool { 407 ep := (*eface)(unsafe.Pointer(&e)) 408 if ep._type == nil { 409 *r = nil 410 return false 411 } 412 *r = e 413 return true 414 } 415 416 func ifacethash(i fInterface) uint32 { 417 ip := (*iface)(unsafe.Pointer(&i)) 418 tab := ip.tab 419 if tab == nil { 420 return 0 421 } 422 return tab._type.hash 423 } 424 425 func efacethash(e interface{}) uint32 { 426 ep := (*eface)(unsafe.Pointer(&e)) 427 t := ep._type 428 if t == nil { 429 return 0 430 } 431 return t.hash 432 } 433 434 func iterate_itabs(fn func(*itab)) { 435 for _, h := range &hash { 436 for ; h != nil; h = h.link { 437 fn(h) 438 } 439 } 440 } 441