Commit 7043d2bb authored by Michel Lespinasse's avatar Michel Lespinasse

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/20900Reviewed-by: 's avatarKeith Randall <khr@golang.org>
Run-TryBot: Michel Lespinasse <walken@google.com>
parent deb83d06
...@@ -19,25 +19,28 @@ var ( ...@@ -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 { ...@@ -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 { ...@@ -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: ...@@ -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: ...@@ -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() { ...@@ -435,6 +435,7 @@ func schedinit() {
tracebackinit() tracebackinit()
moduledataverify() moduledataverify()
stackinit() stackinit()
itabsinit()
mallocinit() mallocinit()
mcommoninit(_g_.m) mcommoninit(_g_.m)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment