github.com/fenixara/go@v0.0.0-20170127160404-96ea0918e670/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 }