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.
8 "runtime/internal/atomic"
18 ifaceLock mutex // lock for accessing hash
22 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
23 if len(inter.mhdr) == 0 {
24 throw("internal error - misuse of itab")
33 panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *inter.mhdr[0].name})
36 // compiler has provided some good hash codes for us.
39 // TODO(rsc): h += 23 * x.mhash ?
42 // look twice - once without lock, once with.
43 // common case will be no lock contention.
46 for locked = 0; locked < 2; locked++ {
50 for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
51 if m.inter == inter && m._type == typ {
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.
73 m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))
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).
85 for k := 0; k < ni; k++ {
92 if t.mtyp == itype && (t.name == iname || *t.name == *iname) && t.pkgpath == ipkgpath {
94 *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = t.ifn
104 panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname})
111 throw("invalid itab locking")
114 atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
122 func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
123 tab := getitab(inter, t, false)
124 atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
128 func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
130 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E))
133 msanread(elem, t.size)
135 if isDirectIface(t) {
137 typedmemmove(t, unsafe.Pointer(&e.data), elem)
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)
151 func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
153 raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2I))
156 msanread(elem, t.size)
158 tab := (*itab)(atomic.Loadp(unsafe.Pointer(cache)))
160 tab = getitab(inter, t, false)
161 atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
163 if isDirectIface(t) {
165 typedmemmove(t, unsafe.Pointer(&i.data), elem)
170 typedmemmove(t, x, elem)
177 func panicdottype(have, want, iface *_type) {
180 haveString = *have._string
182 panic(&TypeAssertionError{*iface._string, haveString, *want._string, ""})
185 func assertI2T(t *_type, i iface, r unsafe.Pointer) {
188 panic(&TypeAssertionError{"", "", *t._string, ""})
191 panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
194 if isDirectIface(t) {
195 writebarrierptr((*uintptr)(r), uintptr(i.data))
197 typedmemmove(t, r, i.data)
202 func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
204 if tab == nil || tab._type != t {
206 memclr(r, uintptr(t.size))
211 if isDirectIface(t) {
212 writebarrierptr((*uintptr)(r), uintptr(i.data))
214 typedmemmove(t, r, i.data)
220 func assertE2T(t *_type, e eface, r unsafe.Pointer) {
222 panic(&TypeAssertionError{"", "", *t._string, ""})
225 panic(&TypeAssertionError{"", *e._type._string, *t._string, ""})
228 if isDirectIface(t) {
229 writebarrierptr((*uintptr)(r), uintptr(e.data))
231 typedmemmove(t, r, e.data)
236 var testingAssertE2T2GC bool
238 // The compiler ensures that r is non-nil.
239 func assertE2T2(t *_type, e eface, r unsafe.Pointer) bool {
240 if testingAssertE2T2GC {
244 memclr(r, uintptr(t.size))
247 if isDirectIface(t) {
248 writebarrierptr((*uintptr)(r), uintptr(e.data))
250 typedmemmove(t, r, e.data)
255 func convI2E(i iface) (r eface) {
265 func assertI2E(inter *interfacetype, i iface, r *eface) {
268 // explicit conversions require non-nil interface value.
269 panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
276 // The compiler ensures that r is non-nil.
277 func assertI2E2(inter *interfacetype, i iface, r *eface) bool {
287 func convI2I(inter *interfacetype, i iface) (r iface) {
292 if tab.inter == inter {
297 r.tab = getitab(inter, tab._type, false)
302 func assertI2I(inter *interfacetype, i iface, r *iface) {
305 // explicit conversions require non-nil interface value.
306 panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
308 if tab.inter == inter {
313 r.tab = getitab(inter, tab._type, false)
317 func assertI2I2(inter *interfacetype, i iface, r *iface) bool {
325 if tab.inter != inter {
326 tab = getitab(inter, tab._type, true)
341 func assertE2I(inter *interfacetype, e eface, r *iface) {
344 // explicit conversions require non-nil interface value.
345 panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
347 r.tab = getitab(inter, t, false)
351 var testingAssertE2I2GC bool
353 func assertE2I2(inter *interfacetype, e eface, r *iface) bool {
354 if testingAssertE2I2GC {
364 tab := getitab(inter, t, true)
378 //go:linkname reflect_ifaceE2I reflect.ifaceE2I
379 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
380 assertE2I(inter, e, dst)
383 func assertE2E(inter *interfacetype, e eface, r *eface) {
385 // explicit conversions require non-nil interface value.
386 panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
391 // The compiler ensures that r is non-nil.
392 func assertE2E2(inter *interfacetype, e eface, r *eface) bool {
401 func ifacethash(i iface) uint32 {
406 return tab._type.hash
409 func efacethash(e eface) uint32 {
417 func iterate_itabs(fn func(*itab)) {
418 for _, h := range &hash {
419 for ; h != nil; h = h.link {