github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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 "internal/abi" 9 "internal/goarch" 10 "runtime/internal/atomic" 11 "unsafe" 12 ) 13 14 const itabInitSize = 512 15 16 var ( 17 itabLock mutex // lock for accessing itab table 18 itabTable = &itabTableInit // pointer to current table 19 itabTableInit = itabTableType{size: itabInitSize} // starter table 20 ) 21 22 // Note: change the formula in the mallocgc call in itabAdd if you change these fields. 23 type itabTableType struct { 24 size uintptr // length of entries array. Always a power of 2. 25 count uintptr // current number of filled entries. 26 entries [itabInitSize]*itab // really [size] large 27 } 28 29 func itabHashFunc(inter *interfacetype, typ *_type) uintptr { 30 // compiler has provided some good hash codes for us. 31 return uintptr(inter.Type.Hash ^ typ.Hash) 32 } 33 34 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { 35 if len(inter.Methods) == 0 { 36 throw("internal error - misuse of itab") 37 } 38 39 // easy case 40 if typ.TFlag&abi.TFlagUncommon == 0 { 41 if canfail { 42 return nil 43 } 44 name := toRType(&inter.Type).nameOff(inter.Methods[0].Name) 45 panic(&TypeAssertionError{nil, typ, &inter.Type, name.Name()}) 46 } 47 48 var m *itab 49 50 // First, look in the existing table to see if we can find the itab we need. 51 // This is by far the most common case, so do it without locks. 52 // Use atomic to ensure we see any previous writes done by the thread 53 // that updates the itabTable field (with atomic.Storep in itabAdd). 54 t := (*itabTableType)(atomic.Loadp(unsafe.Pointer(&itabTable))) 55 if m = t.find(inter, typ); m != nil { 56 goto finish 57 } 58 59 // Not found. Grab the lock and try again. 60 lock(&itabLock) 61 if m = itabTable.find(inter, typ); m != nil { 62 unlock(&itabLock) 63 goto finish 64 } 65 66 // Entry doesn't exist yet. Make a new entry & add it. 67 m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.Methods)-1)*goarch.PtrSize, 0, &memstats.other_sys)) 68 m.inter = inter 69 m._type = typ 70 // The hash is used in type switches. However, compiler statically generates itab's 71 // for all interface/type pairs used in switches (which are added to itabTable 72 // in itabsinit). The dynamically-generated itab's never participate in type switches, 73 // and thus the hash is irrelevant. 74 // Note: m.hash is _not_ the hash used for the runtime itabTable hash table. 75 m.hash = 0 76 m.init() 77 itabAdd(m) 78 unlock(&itabLock) 79 finish: 80 if m.fun[0] != 0 { 81 return m 82 } 83 if canfail { 84 return nil 85 } 86 // this can only happen if the conversion 87 // was already done once using the , ok form 88 // and we have a cached negative result. 89 // The cached result doesn't record which 90 // interface function was missing, so initialize 91 // the itab again to get the missing function name. 92 panic(&TypeAssertionError{concrete: typ, asserted: &inter.Type, missingMethod: m.init()}) 93 } 94 95 // find finds the given interface/type pair in t. 96 // Returns nil if the given interface/type pair isn't present. 97 func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab { 98 // Implemented using quadratic probing. 99 // Probe sequence is h(i) = h0 + i*(i+1)/2 mod 2^k. 100 // We're guaranteed to hit all table entries using this probe sequence. 101 mask := t.size - 1 102 h := itabHashFunc(inter, typ) & mask 103 for i := uintptr(1); ; i++ { 104 p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) 105 // Use atomic read here so if we see m != nil, we also see 106 // the initializations of the fields of m. 107 // m := *p 108 m := (*itab)(atomic.Loadp(unsafe.Pointer(p))) 109 if m == nil { 110 return nil 111 } 112 if m.inter == inter && m._type == typ { 113 return m 114 } 115 h += i 116 h &= mask 117 } 118 } 119 120 // itabAdd adds the given itab to the itab hash table. 121 // itabLock must be held. 122 func itabAdd(m *itab) { 123 // Bugs can lead to calling this while mallocing is set, 124 // typically because this is called while panicing. 125 // Crash reliably, rather than only when we need to grow 126 // the hash table. 127 if getg().m.mallocing != 0 { 128 throw("malloc deadlock") 129 } 130 131 t := itabTable 132 if t.count >= 3*(t.size/4) { // 75% load factor 133 // Grow hash table. 134 // t2 = new(itabTableType) + some additional entries 135 // We lie and tell malloc we want pointer-free memory because 136 // all the pointed-to values are not in the heap. 137 t2 := (*itabTableType)(mallocgc((2+2*t.size)*goarch.PtrSize, nil, true)) 138 t2.size = t.size * 2 139 140 // Copy over entries. 141 // Note: while copying, other threads may look for an itab and 142 // fail to find it. That's ok, they will then try to get the itab lock 143 // and as a consequence wait until this copying is complete. 144 iterate_itabs(t2.add) 145 if t2.count != t.count { 146 throw("mismatched count during itab table copy") 147 } 148 // Publish new hash table. Use an atomic write: see comment in getitab. 149 atomicstorep(unsafe.Pointer(&itabTable), unsafe.Pointer(t2)) 150 // Adopt the new table as our own. 151 t = itabTable 152 // Note: the old table can be GC'ed here. 153 } 154 t.add(m) 155 } 156 157 // add adds the given itab to itab table t. 158 // itabLock must be held. 159 func (t *itabTableType) add(m *itab) { 160 // See comment in find about the probe sequence. 161 // Insert new itab in the first empty spot in the probe sequence. 162 mask := t.size - 1 163 h := itabHashFunc(m.inter, m._type) & mask 164 for i := uintptr(1); ; i++ { 165 p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) 166 m2 := *p 167 if m2 == m { 168 // A given itab may be used in more than one module 169 // and thanks to the way global symbol resolution works, the 170 // pointed-to itab may already have been inserted into the 171 // global 'hash'. 172 return 173 } 174 if m2 == nil { 175 // Use atomic write here so if a reader sees m, it also 176 // sees the correctly initialized fields of m. 177 // NoWB is ok because m is not in heap memory. 178 // *p = m 179 atomic.StorepNoWB(unsafe.Pointer(p), unsafe.Pointer(m)) 180 t.count++ 181 return 182 } 183 h += i 184 h &= mask 185 } 186 } 187 188 // init fills in the m.fun array with all the code pointers for 189 // the m.inter/m._type pair. If the type does not implement the interface, 190 // it sets m.fun[0] to 0 and returns the name of an interface function that is missing. 191 // It is ok to call this multiple times on the same m, even concurrently. 192 func (m *itab) init() string { 193 inter := m.inter 194 typ := m._type 195 x := typ.Uncommon() 196 197 // both inter and typ have method sorted by name, 198 // and interface names are unique, 199 // so can iterate over both in lock step; 200 // the loop is O(ni+nt) not O(ni*nt). 201 ni := len(inter.Methods) 202 nt := int(x.Mcount) 203 xmhdr := (*[1 << 16]abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff)))[:nt:nt] 204 j := 0 205 methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni] 206 var fun0 unsafe.Pointer 207 imethods: 208 for k := 0; k < ni; k++ { 209 i := &inter.Methods[k] 210 itype := toRType(&inter.Type).typeOff(i.Typ) 211 name := toRType(&inter.Type).nameOff(i.Name) 212 iname := name.Name() 213 ipkg := pkgPath(name) 214 if ipkg == "" { 215 ipkg = inter.PkgPath.Name() 216 } 217 for ; j < nt; j++ { 218 t := &xmhdr[j] 219 rtyp := toRType(typ) 220 tname := rtyp.nameOff(t.Name) 221 if rtyp.typeOff(t.Mtyp) == itype && tname.Name() == iname { 222 pkgPath := pkgPath(tname) 223 if pkgPath == "" { 224 pkgPath = rtyp.nameOff(x.PkgPath).Name() 225 } 226 if tname.IsExported() || pkgPath == ipkg { 227 if m != nil { 228 ifn := rtyp.textOff(t.Ifn) 229 if k == 0 { 230 fun0 = ifn // we'll set m.fun[0] at the end 231 } else { 232 methods[k] = ifn 233 } 234 } 235 continue imethods 236 } 237 } 238 } 239 // didn't find method 240 m.fun[0] = 0 241 return iname 242 } 243 m.fun[0] = uintptr(fun0) 244 return "" 245 } 246 247 func itabsinit() { 248 lockInit(&itabLock, lockRankItab) 249 lock(&itabLock) 250 for _, md := range activeModules() { 251 for _, i := range md.itablinks { 252 itabAdd(i) 253 } 254 } 255 unlock(&itabLock) 256 } 257 258 // panicdottypeE is called when doing an e.(T) conversion and the conversion fails. 259 // have = the dynamic type we have. 260 // want = the static type we're trying to convert to. 261 // iface = the static type we're converting from. 262 func panicdottypeE(have, want, iface *_type) { 263 panic(&TypeAssertionError{iface, have, want, ""}) 264 } 265 266 // panicdottypeI is called when doing an i.(T) conversion and the conversion fails. 267 // Same args as panicdottypeE, but "have" is the dynamic itab we have. 268 func panicdottypeI(have *itab, want, iface *_type) { 269 var t *_type 270 if have != nil { 271 t = have._type 272 } 273 panicdottypeE(t, want, iface) 274 } 275 276 // panicnildottype is called when doing an i.(T) conversion and the interface i is nil. 277 // want = the static type we're trying to convert to. 278 func panicnildottype(want *_type) { 279 panic(&TypeAssertionError{nil, nil, want, ""}) 280 // TODO: Add the static type we're converting from as well. 281 // It might generate a better error message. 282 // Just to match other nil conversion errors, we don't for now. 283 } 284 285 // The specialized convTx routines need a type descriptor to use when calling mallocgc. 286 // We don't need the type to be exact, just to have the correct size, alignment, and pointer-ness. 287 // However, when debugging, it'd be nice to have some indication in mallocgc where the types came from, 288 // so we use named types here. 289 // We then construct interface values of these types, 290 // and then extract the type word to use as needed. 291 type ( 292 uint16InterfacePtr uint16 293 uint32InterfacePtr uint32 294 uint64InterfacePtr uint64 295 stringInterfacePtr string 296 sliceInterfacePtr []byte 297 ) 298 299 var ( 300 uint16Eface any = uint16InterfacePtr(0) 301 uint32Eface any = uint32InterfacePtr(0) 302 uint64Eface any = uint64InterfacePtr(0) 303 stringEface any = stringInterfacePtr("") 304 sliceEface any = sliceInterfacePtr(nil) 305 306 uint16Type *_type = efaceOf(&uint16Eface)._type 307 uint32Type *_type = efaceOf(&uint32Eface)._type 308 uint64Type *_type = efaceOf(&uint64Eface)._type 309 stringType *_type = efaceOf(&stringEface)._type 310 sliceType *_type = efaceOf(&sliceEface)._type 311 ) 312 313 // The conv and assert functions below do very similar things. 314 // The convXXX functions are guaranteed by the compiler to succeed. 315 // The assertXXX functions may fail (either panicking or returning false, 316 // depending on whether they are 1-result or 2-result). 317 // The convXXX functions succeed on a nil input, whereas the assertXXX 318 // functions fail on a nil input. 319 320 // convT converts a value of type t, which is pointed to by v, to a pointer that can 321 // be used as the second word of an interface value. 322 func convT(t *_type, v unsafe.Pointer) unsafe.Pointer { 323 if raceenabled { 324 raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convT)) 325 } 326 if msanenabled { 327 msanread(v, t.Size_) 328 } 329 if asanenabled { 330 asanread(v, t.Size_) 331 } 332 x := mallocgc(t.Size_, t, true) 333 typedmemmove(t, x, v) 334 return x 335 } 336 func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer { 337 // TODO: maybe take size instead of type? 338 if raceenabled { 339 raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convTnoptr)) 340 } 341 if msanenabled { 342 msanread(v, t.Size_) 343 } 344 if asanenabled { 345 asanread(v, t.Size_) 346 } 347 348 x := mallocgc(t.Size_, t, false) 349 memmove(x, v, t.Size_) 350 return x 351 } 352 353 func convT16(val uint16) (x unsafe.Pointer) { 354 if val < uint16(len(staticuint64s)) { 355 x = unsafe.Pointer(&staticuint64s[val]) 356 if goarch.BigEndian { 357 x = add(x, 6) 358 } 359 } else { 360 x = mallocgc(2, uint16Type, false) 361 *(*uint16)(x) = val 362 } 363 return 364 } 365 366 func convT32(val uint32) (x unsafe.Pointer) { 367 if val < uint32(len(staticuint64s)) { 368 x = unsafe.Pointer(&staticuint64s[val]) 369 if goarch.BigEndian { 370 x = add(x, 4) 371 } 372 } else { 373 x = mallocgc(4, uint32Type, false) 374 *(*uint32)(x) = val 375 } 376 return 377 } 378 379 func convT64(val uint64) (x unsafe.Pointer) { 380 if val < uint64(len(staticuint64s)) { 381 x = unsafe.Pointer(&staticuint64s[val]) 382 } else { 383 x = mallocgc(8, uint64Type, false) 384 *(*uint64)(x) = val 385 } 386 return 387 } 388 389 func convTstring(val string) (x unsafe.Pointer) { 390 if val == "" { 391 x = unsafe.Pointer(&zeroVal[0]) 392 } else { 393 x = mallocgc(unsafe.Sizeof(val), stringType, true) 394 *(*string)(x) = val 395 } 396 return 397 } 398 399 func convTslice(val []byte) (x unsafe.Pointer) { 400 // Note: this must work for any element type, not just byte. 401 if (*slice)(unsafe.Pointer(&val)).array == nil { 402 x = unsafe.Pointer(&zeroVal[0]) 403 } else { 404 x = mallocgc(unsafe.Sizeof(val), sliceType, true) 405 *(*[]byte)(x) = val 406 } 407 return 408 } 409 410 // convI2I returns the new itab to be used for the destination value 411 // when converting a value with itab src to the dst interface. 412 func convI2I(dst *interfacetype, src *itab) *itab { 413 if src == nil { 414 return nil 415 } 416 if src.inter == dst { 417 return src 418 } 419 return getitab(dst, src._type, false) 420 } 421 422 func assertI2I(inter *interfacetype, tab *itab) *itab { 423 if tab == nil { 424 // explicit conversions require non-nil interface value. 425 panic(&TypeAssertionError{nil, nil, &inter.Type, ""}) 426 } 427 if tab.inter == inter { 428 return tab 429 } 430 return getitab(inter, tab._type, false) 431 } 432 433 func assertI2I2(inter *interfacetype, i iface) (r iface) { 434 tab := i.tab 435 if tab == nil { 436 return 437 } 438 if tab.inter != inter { 439 tab = getitab(inter, tab._type, true) 440 if tab == nil { 441 return 442 } 443 } 444 r.tab = tab 445 r.data = i.data 446 return 447 } 448 449 func assertE2I(inter *interfacetype, t *_type) *itab { 450 if t == nil { 451 // explicit conversions require non-nil interface value. 452 panic(&TypeAssertionError{nil, nil, &inter.Type, ""}) 453 } 454 return getitab(inter, t, false) 455 } 456 457 func assertE2I2(inter *interfacetype, e eface) (r iface) { 458 t := e._type 459 if t == nil { 460 return 461 } 462 tab := getitab(inter, t, true) 463 if tab == nil { 464 return 465 } 466 r.tab = tab 467 r.data = e.data 468 return 469 } 470 471 //go:linkname reflect_ifaceE2I reflect.ifaceE2I 472 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { 473 *dst = iface{assertE2I(inter, e._type), e.data} 474 } 475 476 //go:linkname reflectlite_ifaceE2I internal/reflectlite.ifaceE2I 477 func reflectlite_ifaceE2I(inter *interfacetype, e eface, dst *iface) { 478 *dst = iface{assertE2I(inter, e._type), e.data} 479 } 480 481 func iterate_itabs(fn func(*itab)) { 482 // Note: only runs during stop the world or with itabLock held, 483 // so no other locks/atomics needed. 484 t := itabTable 485 for i := uintptr(0); i < t.size; i++ { 486 m := *(**itab)(add(unsafe.Pointer(&t.entries), i*goarch.PtrSize)) 487 if m != nil { 488 fn(m) 489 } 490 } 491 } 492 493 // staticuint64s is used to avoid allocating in convTx for small integer values. 494 var staticuint64s = [...]uint64{ 495 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 496 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 497 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 498 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 499 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 500 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 501 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 502 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 503 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 504 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 505 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 506 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 507 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 508 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 509 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 510 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 511 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 512 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 513 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 514 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 515 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 516 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 517 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 518 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 519 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 520 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 521 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 522 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 523 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 524 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 525 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 526 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 527 } 528 529 // The linker redirects a reference of a method that it determined 530 // unreachable to a reference to this function, so it will throw if 531 // ever called. 532 func unreachableMethod() { 533 throw("unreachable method called. linker bug?") 534 }