mirror of
https://github.com/golang/go
synced 2024-11-13 15:10:22 -07:00
runtime: insert itabs into hash table during init
See #14874 This change makes the runtime register all compiler generated itabs (as obtained from the moduledata) during init. Change-Id: I9969a0985b99b8bda820a631f7fe4c78f1174cdf Reviewed-on: https://go-review.googlesource.com/20900 Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Michel Lespinasse <walken@google.com>
This commit is contained in:
parent
deb83d0639
commit
7043d2bb5e
@ -19,25 +19,28 @@ var (
|
|||||||
hash [hashSize]*itab
|
hash [hashSize]*itab
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func itabhash(inter *interfacetype, typ *_type) uint32 {
|
||||||
|
// compiler has provided some good hash codes for us.
|
||||||
|
h := inter.typ.hash
|
||||||
|
h += 17 * typ.hash
|
||||||
|
// TODO(rsc): h += 23 * x.mhash ?
|
||||||
|
return h % hashSize
|
||||||
|
}
|
||||||
|
|
||||||
func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
|
func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
|
||||||
if len(inter.mhdr) == 0 {
|
if len(inter.mhdr) == 0 {
|
||||||
throw("internal error - misuse of itab")
|
throw("internal error - misuse of itab")
|
||||||
}
|
}
|
||||||
|
|
||||||
// easy case
|
// easy case
|
||||||
x := typ.uncommon()
|
if typ.tflag&tflagUncommon == 0 {
|
||||||
if x == nil {
|
|
||||||
if canfail {
|
if canfail {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
panic(&TypeAssertionError{"", typ._string, inter.typ._string, inter.mhdr[0].name.name()})
|
panic(&TypeAssertionError{"", typ._string, inter.typ._string, inter.mhdr[0].name.name()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// compiler has provided some good hash codes for us.
|
h := itabhash(inter, typ)
|
||||||
h := inter.typ.hash
|
|
||||||
h += 17 * typ.hash
|
|
||||||
// TODO(rsc): h += 23 * x.mhash ?
|
|
||||||
h %= hashSize
|
|
||||||
|
|
||||||
// look twice - once without lock, once with.
|
// look twice - once without lock, once with.
|
||||||
// common case will be no lock contention.
|
// common case will be no lock contention.
|
||||||
@ -56,10 +59,9 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
|
|||||||
// was already done once using the , ok form
|
// was already done once using the , ok form
|
||||||
// and we have a cached negative result.
|
// and we have a cached negative result.
|
||||||
// the cached result doesn't record which
|
// the cached result doesn't record which
|
||||||
// interface function was missing, so jump
|
// interface function was missing, so try
|
||||||
// down to the interface check, which will
|
// adding the itab again, which will throw an error.
|
||||||
// do more work but give a better error.
|
additab(m, locked != 0, false)
|
||||||
goto search
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if locked != 0 {
|
if locked != 0 {
|
||||||
@ -73,8 +75,19 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
|
|||||||
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))
|
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))
|
||||||
m.inter = inter
|
m.inter = inter
|
||||||
m._type = typ
|
m._type = typ
|
||||||
|
additab(m, true, canfail)
|
||||||
|
unlock(&ifaceLock)
|
||||||
|
if m.bad != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func additab(m *itab, locked, canfail bool) {
|
||||||
|
inter := m.inter
|
||||||
|
typ := m._type
|
||||||
|
x := typ.uncommon()
|
||||||
|
|
||||||
search:
|
|
||||||
// both inter and typ have method sorted by name,
|
// both inter and typ have method sorted by name,
|
||||||
// and interface names are unique,
|
// and interface names are unique,
|
||||||
// so can iterate over both in lock step;
|
// so can iterate over both in lock step;
|
||||||
@ -107,7 +120,7 @@ search:
|
|||||||
}
|
}
|
||||||
// didn't find method
|
// didn't find method
|
||||||
if !canfail {
|
if !canfail {
|
||||||
if locked != 0 {
|
if locked {
|
||||||
unlock(&ifaceLock)
|
unlock(&ifaceLock)
|
||||||
}
|
}
|
||||||
panic(&TypeAssertionError{"", typ._string, inter.typ._string, iname})
|
panic(&TypeAssertionError{"", typ._string, inter.typ._string, iname})
|
||||||
@ -116,16 +129,22 @@ search:
|
|||||||
break
|
break
|
||||||
nextimethod:
|
nextimethod:
|
||||||
}
|
}
|
||||||
if locked == 0 {
|
if !locked {
|
||||||
throw("invalid itab locking")
|
throw("invalid itab locking")
|
||||||
}
|
}
|
||||||
|
h := itabhash(inter, typ)
|
||||||
m.link = hash[h]
|
m.link = hash[h]
|
||||||
atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
|
atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
|
||||||
unlock(&ifaceLock)
|
}
|
||||||
if m.bad != 0 {
|
|
||||||
return nil
|
func itabsinit() {
|
||||||
|
lock(&ifaceLock)
|
||||||
|
for m := &firstmoduledata; m != nil; m = m.next {
|
||||||
|
for _, i := range m.itablinks {
|
||||||
|
additab(i, true, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return m
|
unlock(&ifaceLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
|
func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
|
||||||
|
@ -435,6 +435,7 @@ func schedinit() {
|
|||||||
tracebackinit()
|
tracebackinit()
|
||||||
moduledataverify()
|
moduledataverify()
|
||||||
stackinit()
|
stackinit()
|
||||||
|
itabsinit()
|
||||||
mallocinit()
|
mallocinit()
|
||||||
mcommoninit(_g_.m)
|
mcommoninit(_g_.m)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user