1
0
mirror of https://github.com/golang/go synced 2024-11-20 06:54:42 -07:00
go/src/runtime/iface.go
Keith Randall 1dd0163ce3 runtime: remove trailing empty arrays in structs
The ones at the end of M and G are just used to compute
their size for use in assembly.  Generate the size explicitly.
The one at the end of itab is variable-sized, and at least one.
The ones at the end of interfacetype and uncommontype are not
needed, as the preceding slice references them (the slice was
originally added for use by reflect?).
The one at the end of stackmap is already accessed correctly,
and the runtime never allocates one.

Update #9401

Change-Id: Ia75e3aaee38425f038c506868a17105bd64c712f
Reviewed-on: https://go-review.googlesource.com/2420
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2015-01-07 16:05:16 +00:00

428 lines
9.2 KiB
Go

// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import (
"unsafe"
)
const (
hashSize = 1009
)
var (
ifaceLock mutex // lock for accessing hash
hash [hashSize]*itab
)
// fInterface is our standard non-empty interface. We use it instead
// of interface{f()} in function prototypes because gofmt insists on
// putting lots of newlines in the otherwise concise interface{f()}.
type fInterface interface {
f()
}
func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
if len(inter.mhdr) == 0 {
throw("internal error - misuse of itab")
}
// easy case
x := typ.x
if x == nil {
if canfail {
return nil
}
panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *inter.mhdr[0].name})
}
// compiler has provided some good hash codes for us.
h := inter.typ.hash
h += 17 * typ.hash
// TODO(rsc): h += 23 * x.mhash ?
h %= hashSize
// look twice - once without lock, once with.
// common case will be no lock contention.
var m *itab
var locked int
for locked = 0; locked < 2; locked++ {
if locked != 0 {
lock(&ifaceLock)
}
for m = (*itab)(atomicloadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
if m.inter == inter && m._type == typ {
if m.bad != 0 {
m = nil
if !canfail {
// this can only happen if the conversion
// was already done once using the , ok form
// and we have a cached negative result.
// the cached result doesn't record which
// interface function was missing, so jump
// down to the interface check, which will
// do more work but give a better error.
goto search
}
}
if locked != 0 {
unlock(&ifaceLock)
}
return m
}
}
}
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*ptrSize, 0, &memstats.other_sys))
m.inter = inter
m._type = typ
search:
// both inter and typ have method sorted by name,
// and interface names are unique,
// so can iterate over both in lock step;
// the loop is O(ni+nt) not O(ni*nt).
ni := len(inter.mhdr)
nt := len(x.mhdr)
j := 0
for k := 0; k < ni; k++ {
i := &inter.mhdr[k]
iname := i.name
ipkgpath := i.pkgpath
itype := i._type
for ; j < nt; j++ {
t := &x.mhdr[j]
if t.mtyp == itype && t.name == iname && t.pkgpath == ipkgpath {
if m != nil {
*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*ptrSize)) = t.ifn
}
goto nextimethod
}
}
// didn't find method
if !canfail {
if locked != 0 {
unlock(&ifaceLock)
}
panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname})
}
m.bad = 1
break
nextimethod:
}
if locked == 0 {
throw("invalid itab locking")
}
m.link = hash[h]
atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
unlock(&ifaceLock)
if m.bad != 0 {
return nil
}
return m
}
func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
tab := getitab(inter, t, false)
atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
return tab
}
func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
ep := (*eface)(unsafe.Pointer(&e))
if isDirectIface(t) {
ep._type = t
typedmemmove(t, unsafe.Pointer(&ep.data), elem)
} else {
x := newobject(t)
// TODO: We allocate a zeroed object only to overwrite it with
// actual data. Figure out how to avoid zeroing. Also below in convT2I.
typedmemmove(t, x, elem)
ep._type = t
ep.data = x
}
return
}
func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) (i fInterface) {
tab := (*itab)(atomicloadp(unsafe.Pointer(cache)))
if tab == nil {
tab = getitab(inter, t, false)
atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
}
pi := (*iface)(unsafe.Pointer(&i))
if isDirectIface(t) {
pi.tab = tab
typedmemmove(t, unsafe.Pointer(&pi.data), elem)
} else {
x := newobject(t)
typedmemmove(t, x, elem)
pi.tab = tab
pi.data = x
}
return
}
func assertI2T(t *_type, i fInterface, r unsafe.Pointer) {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil {
panic(&TypeAssertionError{"", "", *t._string, ""})
}
if tab._type != t {
panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
}
if r != nil {
if isDirectIface(t) {
writebarrierptr((*uintptr)(r), uintptr(ip.data))
} else {
typedmemmove(t, r, ip.data)
}
}
}
func assertI2T2(t *_type, i fInterface, r unsafe.Pointer) bool {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil || tab._type != t {
if r != nil {
memclr(r, uintptr(t.size))
}
return false
}
if r != nil {
if isDirectIface(t) {
writebarrierptr((*uintptr)(r), uintptr(ip.data))
} else {
typedmemmove(t, r, ip.data)
}
}
return true
}
func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {
ep := (*eface)(unsafe.Pointer(&e))
if ep._type == nil {
panic(&TypeAssertionError{"", "", *t._string, ""})
}
if ep._type != t {
panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
}
if r != nil {
if isDirectIface(t) {
writebarrierptr((*uintptr)(r), uintptr(ep.data))
} else {
typedmemmove(t, r, ep.data)
}
}
}
func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
ep := (*eface)(unsafe.Pointer(&e))
if ep._type != t {
if r != nil {
memclr(r, uintptr(t.size))
}
return false
}
if r != nil {
if isDirectIface(t) {
writebarrierptr((*uintptr)(r), uintptr(ep.data))
} else {
typedmemmove(t, r, ep.data)
}
}
return true
}
func convI2E(i fInterface) (r interface{}) {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil {
return
}
rp := (*eface)(unsafe.Pointer(&r))
rp._type = tab._type
rp.data = ip.data
return
}
func assertI2E(inter *interfacetype, i fInterface, r *interface{}) {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil {
// explicit conversions require non-nil interface value.
panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
}
rp := (*eface)(unsafe.Pointer(r))
rp._type = tab._type
rp.data = ip.data
return
}
func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil {
return false
}
if r != nil {
rp := (*eface)(unsafe.Pointer(r))
rp._type = tab._type
rp.data = ip.data
}
return true
}
func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil {
return
}
rp := (*iface)(unsafe.Pointer(&r))
if tab.inter == inter {
rp.tab = tab
rp.data = ip.data
return
}
rp.tab = getitab(inter, tab._type, false)
rp.data = ip.data
return
}
func assertI2I(inter *interfacetype, i fInterface, r *fInterface) {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil {
// explicit conversions require non-nil interface value.
panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
}
rp := (*iface)(unsafe.Pointer(r))
if tab.inter == inter {
rp.tab = tab
rp.data = ip.data
return
}
rp.tab = getitab(inter, tab._type, false)
rp.data = ip.data
}
func assertI2I2(inter *interfacetype, i fInterface, r *fInterface) bool {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil {
if r != nil {
*r = nil
}
return false
}
if tab.inter != inter {
tab = getitab(inter, tab._type, true)
if tab == nil {
if r != nil {
*r = nil
}
return false
}
}
if r != nil {
rp := (*iface)(unsafe.Pointer(r))
rp.tab = tab
rp.data = ip.data
}
return true
}
func assertE2I(inter *interfacetype, e interface{}, r *fInterface) {
ep := (*eface)(unsafe.Pointer(&e))
t := ep._type
if t == nil {
// explicit conversions require non-nil interface value.
panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
}
rp := (*iface)(unsafe.Pointer(r))
rp.tab = getitab(inter, t, false)
rp.data = ep.data
}
func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool {
ep := (*eface)(unsafe.Pointer(&e))
t := ep._type
if t == nil {
if r != nil {
*r = nil
}
return false
}
tab := getitab(inter, t, true)
if tab == nil {
if r != nil {
*r = nil
}
return false
}
if r != nil {
rp := (*iface)(unsafe.Pointer(r))
rp.tab = tab
rp.data = ep.data
}
return true
}
//go:linkname reflect_ifaceE2I reflect.ifaceE2I
func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) {
assertE2I(inter, e, dst)
}
func assertE2E(inter *interfacetype, e interface{}, r *interface{}) {
ep := (*eface)(unsafe.Pointer(&e))
if ep._type == nil {
// explicit conversions require non-nil interface value.
panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
}
*r = e
}
func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool {
ep := (*eface)(unsafe.Pointer(&e))
if ep._type == nil {
if r != nil {
*r = nil
}
return false
}
if r != nil {
*r = e
}
return true
}
func ifacethash(i fInterface) uint32 {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
if tab == nil {
return 0
}
return tab._type.hash
}
func efacethash(e interface{}) uint32 {
ep := (*eface)(unsafe.Pointer(&e))
t := ep._type
if t == nil {
return 0
}
return t.hash
}
func iterate_itabs(fn func(*itab)) {
for _, h := range &hash {
for ; h != nil; h = h.link {
fn(h)
}
}
}