github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/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 itabhash(inter *interfacetype, typ *_type) uint32 { 23 // compiler has provided some good hash codes for us. 24 h := inter.typ.hash 25 h += 17 * typ.hash 26 // TODO(rsc): h += 23 * x.mhash ? 27 return h % hashSize 28 } 29 30 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { 31 if len(inter.mhdr) == 0 { 32 throw("internal error - misuse of itab") 33 } 34 35 // easy case 36 if typ.tflag&tflagUncommon == 0 { 37 if canfail { 38 return nil 39 } 40 name := inter.typ.nameOff(inter.mhdr[0].name) 41 panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), name.name()}) 42 } 43 44 h := itabhash(inter, typ) 45 46 // look twice - once without lock, once with. 47 // common case will be no lock contention. 48 var m *itab 49 var locked int 50 for locked = 0; locked < 2; locked++ { 51 if locked != 0 { 52 lock(&ifaceLock) 53 } 54 for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link { 55 if m.inter == inter && m._type == typ { 56 if m.bad != 0 { 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 try 63 // adding the itab again, which will throw an error. 64 additab(m, locked != 0, false) 65 } 66 m = nil 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)*sys.PtrSize, 0, &memstats.other_sys)) 77 m.inter = inter 78 m._type = typ 79 additab(m, true, canfail) 80 unlock(&ifaceLock) 81 if m.bad != 0 { 82 return nil 83 } 84 return m 85 } 86 87 func additab(m *itab, locked, canfail bool) { 88 inter := m.inter 89 typ := m._type 90 x := typ.uncommon() 91 92 // both inter and typ have method sorted by name, 93 // and interface names are unique, 94 // so can iterate over both in lock step; 95 // the loop is O(ni+nt) not O(ni*nt). 96 ni := len(inter.mhdr) 97 nt := int(x.mcount) 98 xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt] 99 j := 0 100 for k := 0; k < ni; k++ { 101 i := &inter.mhdr[k] 102 itype := inter.typ.typeOff(i.ityp) 103 name := inter.typ.nameOff(i.name) 104 iname := name.name() 105 ipkg := name.pkgPath() 106 if ipkg == "" { 107 ipkg = inter.pkgpath.name() 108 } 109 for ; j < nt; j++ { 110 t := &xmhdr[j] 111 tname := typ.nameOff(t.name) 112 if typ.typeOff(t.mtyp) == itype && tname.name() == iname { 113 pkgPath := tname.pkgPath() 114 if pkgPath == "" { 115 pkgPath = typ.nameOff(x.pkgpath).name() 116 } 117 if tname.isExported() || pkgPath == ipkg { 118 if m != nil { 119 ifn := typ.textOff(t.ifn) 120 *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn 121 } 122 goto nextimethod 123 } 124 } 125 } 126 // didn't find method 127 if !canfail { 128 if locked { 129 unlock(&ifaceLock) 130 } 131 panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname}) 132 } 133 m.bad = 1 134 break 135 nextimethod: 136 } 137 if !locked { 138 throw("invalid itab locking") 139 } 140 h := itabhash(inter, typ) 141 m.link = hash[h] 142 m.inhash = 1 143 atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m)) 144 } 145 146 func itabsinit() { 147 lock(&ifaceLock) 148 for _, md := range activeModules() { 149 for _, i := range md.itablinks { 150 // itablinks is a slice of pointers to the itabs used in this 151 // module. A given itab may be used in more than one module 152 // and thanks to the way global symbol resolution works, the 153 // pointed-to itab may already have been inserted into the 154 // global 'hash'. 155 if i.inhash == 0 { 156 additab(i, true, false) 157 } 158 } 159 } 160 unlock(&ifaceLock) 161 } 162 163 // panicdottype is called when doing an i.(T) conversion and the conversion fails. 164 // have = the dynamic type we have. 165 // want = the static type we're trying to convert to. 166 // iface = the static type we're converting from. 167 func panicdottype(have, want, iface *_type) { 168 haveString := "" 169 if have != nil { 170 haveString = have.string() 171 } 172 panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""}) 173 } 174 175 // panicnildottype is called when doing a i.(T) conversion and the interface i is nil. 176 // want = the static type we're trying to convert to. 177 func panicnildottype(want *_type) { 178 panic(&TypeAssertionError{"", "", want.string(), ""}) 179 // TODO: Add the static type we're converting from as well. 180 // It might generate a better error message. 181 // Just to match other nil conversion errors, we don't for now. 182 } 183 184 // The conv and assert functions below do very similar things. 185 // The convXXX functions are guaranteed by the compiler to succeed. 186 // The assertXXX functions may fail (either panicking or returning false, 187 // depending on whether they are 1-result or 2-result). 188 // The convXXX functions succeed on a nil input, whereas the assertXXX 189 // functions fail on a nil input. 190 191 func convT2E(t *_type, elem unsafe.Pointer) (e eface) { 192 if raceenabled { 193 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E)) 194 } 195 if msanenabled { 196 msanread(elem, t.size) 197 } 198 if isDirectIface(t) { 199 // This case is implemented directly by the compiler. 200 throw("direct convT2E") 201 } 202 x := newobject(t) 203 // TODO: We allocate a zeroed object only to overwrite it with 204 // actual data. Figure out how to avoid zeroing. Also below in convT2I. 205 typedmemmove(t, x, elem) 206 e._type = t 207 e.data = x 208 return 209 } 210 211 func convT2I(tab *itab, elem unsafe.Pointer) (i iface) { 212 t := tab._type 213 if raceenabled { 214 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I)) 215 } 216 if msanenabled { 217 msanread(elem, t.size) 218 } 219 if isDirectIface(t) { 220 // This case is implemented directly by the compiler. 221 throw("direct convT2I") 222 } 223 x := newobject(t) 224 typedmemmove(t, x, elem) 225 i.tab = tab 226 i.data = x 227 return 228 } 229 230 func convI2I(inter *interfacetype, i iface) (r iface) { 231 tab := i.tab 232 if tab == nil { 233 return 234 } 235 if tab.inter == inter { 236 r.tab = tab 237 r.data = i.data 238 return 239 } 240 r.tab = getitab(inter, tab._type, false) 241 r.data = i.data 242 return 243 } 244 245 func assertI2I(inter *interfacetype, i iface) (r iface) { 246 tab := i.tab 247 if tab == nil { 248 // explicit conversions require non-nil interface value. 249 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 250 } 251 if tab.inter == inter { 252 r.tab = tab 253 r.data = i.data 254 return 255 } 256 r.tab = getitab(inter, tab._type, false) 257 r.data = i.data 258 return 259 } 260 261 func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) { 262 tab := i.tab 263 if tab == nil { 264 return 265 } 266 if tab.inter != inter { 267 tab = getitab(inter, tab._type, true) 268 if tab == nil { 269 return 270 } 271 } 272 r.tab = tab 273 r.data = i.data 274 b = true 275 return 276 } 277 278 func assertE2I(inter *interfacetype, e eface) (r iface) { 279 t := e._type 280 if t == nil { 281 // explicit conversions require non-nil interface value. 282 panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) 283 } 284 r.tab = getitab(inter, t, false) 285 r.data = e.data 286 return 287 } 288 289 func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) { 290 t := e._type 291 if t == nil { 292 return 293 } 294 tab := getitab(inter, t, true) 295 if tab == nil { 296 return 297 } 298 r.tab = tab 299 r.data = e.data 300 b = true 301 return 302 } 303 304 //go:linkname reflect_ifaceE2I reflect.ifaceE2I 305 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { 306 *dst = assertE2I(inter, e) 307 } 308 309 func iterate_itabs(fn func(*itab)) { 310 for _, h := range &hash { 311 for ; h != nil; h = h.link { 312 fn(h) 313 } 314 } 315 } 316 317 // staticbytes is used to avoid convT2E for byte-sized values. 318 var staticbytes = [...]byte{ 319 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 320 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 321 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 322 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 323 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 324 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 325 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 326 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 327 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 328 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 329 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 330 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 331 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 332 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 333 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 334 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 335 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 336 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 337 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 338 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 339 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 340 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 341 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 342 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 343 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 344 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 345 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 346 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 347 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 348 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 349 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 350 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 351 }