mirror of https://github.com/golang/go.git
go/ssa: Put type canonicalization on own mutex.
Put Program level type canonicalization on its own Mutex. With generics, canonical types are requested whenever instantiating a type. This simplifies when canonical types can be requested at the cost of maintaining two typeutil.Hashers. Updates golang/go#48525 Change-Id: I2376a43e43f410d10a6d87158816e728aba746ca Reviewed-on: https://go-review.googlesource.com/c/tools/+/386315 Reviewed-by: Robert Findley <rfindley@google.com> Run-TryBot: Tim King <taking@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Trust: Tim King <taking@google.com>
This commit is contained in:
parent
afc5fce285
commit
6a6eb596e7
|
|
@ -34,7 +34,6 @@ func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
|
|||
|
||||
h := typeutil.MakeHasher() // protected by methodsMu, in effect
|
||||
prog.methodSets.SetHasher(h)
|
||||
prog.canon.SetHasher(h)
|
||||
|
||||
return prog
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,11 @@ type Program struct {
|
|||
mode BuilderMode // set of mode bits for SSA construction
|
||||
MethodSets typeutil.MethodSetCache // cache of type-checker's method-sets
|
||||
|
||||
canon canonizer // type canonicalization map
|
||||
|
||||
methodsMu sync.Mutex // guards the following maps:
|
||||
methodSets typeutil.Map // maps type to its concrete methodSet
|
||||
runtimeTypes typeutil.Map // types for which rtypes are needed
|
||||
canon typeutil.Map // type canonicalization map
|
||||
bounds map[*types.Func]*Function // bounds for curried x.Method closures
|
||||
thunks map[selectionKey]*Function // thunks for T.Method expressions
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,22 @@ import (
|
|||
"go/types"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
)
|
||||
|
||||
//// Sanity checking utilities
|
||||
|
||||
// assert panics with the mesage msg if p is false.
|
||||
// Avoid combining with expensive string formatting.
|
||||
func assert(p bool, msg string) {
|
||||
if !p {
|
||||
panic(msg)
|
||||
}
|
||||
}
|
||||
|
||||
//// AST utilities
|
||||
|
||||
func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
|
||||
|
|
@ -87,3 +99,36 @@ func makeLen(T types.Type) *Builtin {
|
|||
sig: types.NewSignature(nil, lenParams, lenResults, false),
|
||||
}
|
||||
}
|
||||
|
||||
// Mapping of a type T to a canonical instance C s.t. types.Indentical(T, C).
|
||||
// Thread-safe.
|
||||
type canonizer struct {
|
||||
mu sync.Mutex
|
||||
canon typeutil.Map // map from type to a canonical instance
|
||||
}
|
||||
|
||||
// Tuple returns a canonical representative of a Tuple of types.
|
||||
// Representative of the empty Tuple is nil.
|
||||
func (c *canonizer) Tuple(ts []types.Type) *types.Tuple {
|
||||
if len(ts) == 0 {
|
||||
return nil
|
||||
}
|
||||
vars := make([]*types.Var, len(ts))
|
||||
for i, t := range ts {
|
||||
vars[i] = anonVar(t)
|
||||
}
|
||||
tuple := types.NewTuple(vars...)
|
||||
return c.Type(tuple).(*types.Tuple)
|
||||
}
|
||||
|
||||
// Type returns a canonical representative of type T.
|
||||
func (c *canonizer) Type(T types.Type) types.Type {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if r := c.canon.At(T); r != nil {
|
||||
return r.(types.Type)
|
||||
}
|
||||
c.canon.Set(T, T)
|
||||
return T
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,9 +246,11 @@ func makeThunk(prog *Program, sel *types.Selection) *Function {
|
|||
panic(sel)
|
||||
}
|
||||
|
||||
// Canonicalize sel.Recv() to avoid constructing duplicate thunks.
|
||||
canonRecv := prog.canon.Type(sel.Recv())
|
||||
key := selectionKey{
|
||||
kind: sel.Kind(),
|
||||
recv: sel.Recv(),
|
||||
recv: canonRecv,
|
||||
obj: sel.Obj(),
|
||||
index: fmt.Sprint(sel.Index()),
|
||||
indirect: sel.Indirect(),
|
||||
|
|
@ -257,14 +259,6 @@ func makeThunk(prog *Program, sel *types.Selection) *Function {
|
|||
prog.methodsMu.Lock()
|
||||
defer prog.methodsMu.Unlock()
|
||||
|
||||
// Canonicalize key.recv to avoid constructing duplicate thunks.
|
||||
canonRecv, ok := prog.canon.At(key.recv).(types.Type)
|
||||
if !ok {
|
||||
canonRecv = key.recv
|
||||
prog.canon.Set(key.recv, canonRecv)
|
||||
}
|
||||
key.recv = canonRecv
|
||||
|
||||
fn, ok := prog.thunks[key]
|
||||
if !ok {
|
||||
fn = makeWrapper(prog, sel)
|
||||
|
|
|
|||
Loading…
Reference in New Issue