Home | History | Annotate | Download | only in runtime
      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