mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
go/types, types2: reduce locks held at once in resolveUnderlying
There is no need to hold locks for the entire chain of Named types in resolveUnderlying. This change moves the locking / unlocking right to where t.underlying is set. This change consolidates logic into resolveUnderlying where possible and makes minor stylistic / documentation adjustments. Change-Id: Ic5ec5a7e9a0da8bc34954bf456e4e23a28df296d Reviewed-on: https://go-review.googlesource.com/c/go/+/714403 Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Robert Griesemer <gri@google.com> Auto-Submit: Mark Freeman <markfreeman@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
24af441437
commit
b8aa1ee442
2 changed files with 32 additions and 34 deletions
|
|
@ -590,7 +590,7 @@ func (n *Named) Underlying() Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !n.stateHas(hasUnder) {
|
if !n.stateHas(hasUnder) { // minor performance optimization
|
||||||
n.resolveUnderlying()
|
n.resolveUnderlying()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -605,7 +605,8 @@ func (t *Named) String() string { return TypeString(t, nil) }
|
||||||
// TODO(rfindley): reorganize the loading and expansion methods under this
|
// TODO(rfindley): reorganize the loading and expansion methods under this
|
||||||
// heading.
|
// heading.
|
||||||
|
|
||||||
// resolveUnderlying computes the underlying type of n.
|
// resolveUnderlying computes the underlying type of n. If n already has an
|
||||||
|
// underlying type, nothing happens.
|
||||||
//
|
//
|
||||||
// It does so by following RHS type chains for alias and named types. If any
|
// It does so by following RHS type chains for alias and named types. If any
|
||||||
// other type T is found, each named type in the chain has its underlying
|
// other type T is found, each named type in the chain has its underlying
|
||||||
|
|
@ -636,14 +637,13 @@ func (n *Named) resolveUnderlying() {
|
||||||
path[j] = t.obj
|
path[j] = t.obj
|
||||||
}
|
}
|
||||||
path = path[i:]
|
path = path[i:]
|
||||||
// Note: This code may only be called during type checking,
|
// only called during type checking, hence n.check != nil
|
||||||
// hence n.check != nil.
|
|
||||||
n.check.cycleError(path, firstInSrc(path))
|
n.check.cycleError(path, firstInSrc(path))
|
||||||
u = Typ[Invalid]
|
u = Typ[Invalid]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid acquiring the lock if we can
|
// don't recalculate the underlying
|
||||||
if t.stateHas(hasUnder) {
|
if t.stateHas(hasUnder) {
|
||||||
u = t.underlying
|
u = t.underlying
|
||||||
break
|
break
|
||||||
|
|
@ -655,9 +655,6 @@ func (n *Named) resolveUnderlying() {
|
||||||
seen[t] = len(seen)
|
seen[t] = len(seen)
|
||||||
|
|
||||||
t.unpack()
|
t.unpack()
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
|
|
||||||
assert(t.rhs() != nil || t.allowNilRHS)
|
assert(t.rhs() != nil || t.allowNilRHS)
|
||||||
rhs = t.rhs()
|
rhs = t.rhs()
|
||||||
|
|
||||||
|
|
@ -666,17 +663,19 @@ func (n *Named) resolveUnderlying() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set underlying for all Named types in the chain
|
|
||||||
for t := range seen {
|
for t := range seen {
|
||||||
|
func() {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
// Careful, t.underlying has lock-free readers. Since we might be racing
|
// Careful, t.underlying has lock-free readers. Since we might be racing
|
||||||
// another call to resolveUnderlying, we have to avoid overwriting
|
// another call to resolveUnderlying, we have to avoid overwriting
|
||||||
// t.underlying. Otherwise, the race detector will be tripped.
|
// t.underlying. Otherwise, the race detector will be tripped.
|
||||||
if t.stateHas(hasUnder) {
|
if !t.stateHas(hasUnder) {
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.underlying = u
|
t.underlying = u
|
||||||
t.setState(hasUnder)
|
t.setState(hasUnder)
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
|
func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
|
||||||
|
|
|
||||||
|
|
@ -593,7 +593,7 @@ func (n *Named) Underlying() Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !n.stateHas(hasUnder) {
|
if !n.stateHas(hasUnder) { // minor performance optimization
|
||||||
n.resolveUnderlying()
|
n.resolveUnderlying()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -608,7 +608,8 @@ func (t *Named) String() string { return TypeString(t, nil) }
|
||||||
// TODO(rfindley): reorganize the loading and expansion methods under this
|
// TODO(rfindley): reorganize the loading and expansion methods under this
|
||||||
// heading.
|
// heading.
|
||||||
|
|
||||||
// resolveUnderlying computes the underlying type of n.
|
// resolveUnderlying computes the underlying type of n. If n already has an
|
||||||
|
// underlying type, nothing happens.
|
||||||
//
|
//
|
||||||
// It does so by following RHS type chains for alias and named types. If any
|
// It does so by following RHS type chains for alias and named types. If any
|
||||||
// other type T is found, each named type in the chain has its underlying
|
// other type T is found, each named type in the chain has its underlying
|
||||||
|
|
@ -639,14 +640,13 @@ func (n *Named) resolveUnderlying() {
|
||||||
path[j] = t.obj
|
path[j] = t.obj
|
||||||
}
|
}
|
||||||
path = path[i:]
|
path = path[i:]
|
||||||
// Note: This code may only be called during type checking,
|
// only called during type checking, hence n.check != nil
|
||||||
// hence n.check != nil.
|
|
||||||
n.check.cycleError(path, firstInSrc(path))
|
n.check.cycleError(path, firstInSrc(path))
|
||||||
u = Typ[Invalid]
|
u = Typ[Invalid]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid acquiring the lock if we can
|
// don't recalculate the underlying
|
||||||
if t.stateHas(hasUnder) {
|
if t.stateHas(hasUnder) {
|
||||||
u = t.underlying
|
u = t.underlying
|
||||||
break
|
break
|
||||||
|
|
@ -658,9 +658,6 @@ func (n *Named) resolveUnderlying() {
|
||||||
seen[t] = len(seen)
|
seen[t] = len(seen)
|
||||||
|
|
||||||
t.unpack()
|
t.unpack()
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
|
|
||||||
assert(t.rhs() != nil || t.allowNilRHS)
|
assert(t.rhs() != nil || t.allowNilRHS)
|
||||||
rhs = t.rhs()
|
rhs = t.rhs()
|
||||||
|
|
||||||
|
|
@ -669,17 +666,19 @@ func (n *Named) resolveUnderlying() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set underlying for all Named types in the chain
|
|
||||||
for t := range seen {
|
for t := range seen {
|
||||||
|
func() {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
// Careful, t.underlying has lock-free readers. Since we might be racing
|
// Careful, t.underlying has lock-free readers. Since we might be racing
|
||||||
// another call to resolveUnderlying, we have to avoid overwriting
|
// another call to resolveUnderlying, we have to avoid overwriting
|
||||||
// t.underlying. Otherwise, the race detector will be tripped.
|
// t.underlying. Otherwise, the race detector will be tripped.
|
||||||
if t.stateHas(hasUnder) {
|
if !t.stateHas(hasUnder) {
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.underlying = u
|
t.underlying = u
|
||||||
t.setState(hasUnder)
|
t.setState(hasUnder)
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
|
func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue