Skip to content

Commit

Permalink
go/ssa: two minor cleanups
Browse files Browse the repository at this point in the history
1. inline sole uses of addMethod, createMethodSet.
2. simplify MethodValue call to LookupMethod in go/callgraph.

Change-Id: Ifa94d0dd7c2a522551c0d76341213dc9c8a73501
Reviewed-on: https://go-review.googlesource.com/c/tools/+/540216
Reviewed-by: Tim King <taking@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
  • Loading branch information
adonovan committed Nov 7, 2023
1 parent e7fb31a commit 51df92b
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 52 deletions.
2 changes: 1 addition & 1 deletion go/callgraph/rta/rta.go
Expand Up @@ -232,7 +232,7 @@ func (r *rta) visitDynCall(site ssa.CallInstruction) {
func (r *rta) addInvokeEdge(site ssa.CallInstruction, C types.Type) {
// Ascertain the concrete method of C to be called.
imethod := site.Common().Method
cmethod := r.prog.MethodValue(r.prog.MethodSets.MethodSet(C).Lookup(imethod.Pkg(), imethod.Name()))
cmethod := r.prog.LookupMethod(C, imethod.Pkg(), imethod.Name())
r.addEdge(site.Parent(), site, cmethod, true)
}

Expand Down
3 changes: 3 additions & 0 deletions go/callgraph/vta/vta.go
Expand Up @@ -154,6 +154,9 @@ func propFunc(p propType, c ssa.CallInstruction, cache methodCache) []*ssa.Funct
// ssa.Program.MethodSets and ssa.Program.MethodValue
// APIs. The cache is used to speed up querying of
// methods of a type as the mentioned APIs are expensive.
//
// TODO(adonovan): Program.MethodValue already does this kind of
// caching. Is this really necessary?
type methodCache map[types.Type]map[string][]*ssa.Function

// methods returns methods of a type `t` named `name`. First consults
Expand Down
84 changes: 33 additions & 51 deletions go/ssa/methods.go
Expand Up @@ -42,9 +42,39 @@ func (prog *Program) MethodValue(sel *types.Selection) *Function {

var cr creator

prog.methodsMu.Lock()
m := prog.addMethod(prog.createMethodSet(T), sel, &cr)
prog.methodsMu.Unlock()
m := func() *Function {
prog.methodsMu.Lock()
defer prog.methodsMu.Unlock()

// Get or create SSA method set.
mset, ok := prog.methodSets.At(T).(*methodSet)
if !ok {
mset = &methodSet{mapping: make(map[string]*Function)}
prog.methodSets.Set(T, mset)
}

// Get or create SSA method.
id := sel.Obj().Id()
fn, ok := mset.mapping[id]
if !ok {
obj := sel.Obj().(*types.Func)
_, ptrObj := deptr(recvType(obj))
_, ptrRecv := deptr(T)
needsPromotion := len(sel.Index()) > 1
needsIndirection := !ptrObj && ptrRecv
if needsPromotion || needsIndirection {
fn = createWrapper(prog, toSelection(sel), &cr)
} else {
fn = prog.objectMethod(obj, &cr)
}
if fn.Signature.Recv() == nil {
panic(fn)
}
mset.mapping[id] = fn
}

return fn
}()

b := builder{created: &cr}
b.iterate()
Expand Down Expand Up @@ -111,54 +141,6 @@ type methodSet struct {
mapping map[string]*Function // populated lazily
}

// Precondition: T is a concrete type, e.g. !isInterface(T) and not parameterized.
// Requires prog.methodsMu.
func (prog *Program) createMethodSet(T types.Type) *methodSet {
if prog.mode&SanityCheckFunctions != 0 {
if types.IsInterface(T) || prog.parameterized.isParameterized(T) {
panic("type is interface or parameterized")
}
}

mset, ok := prog.methodSets.At(T).(*methodSet)
if !ok {
mset = &methodSet{mapping: make(map[string]*Function)}
prog.methodSets.Set(T, mset)
}
return mset
}

// Adds any created functions to cr.
// Precondition: T is a concrete type, e.g. !isInterface(T) and not parameterized.
// Requires prog.methodsMu.
func (prog *Program) addMethod(mset *methodSet, sel *types.Selection, cr *creator) *Function {
if sel.Kind() == types.MethodExpr {
panic(sel)
}
id := sel.Obj().Id()
fn := mset.mapping[id]
if fn == nil {
sel := toSelection(sel)
obj := sel.obj.(*types.Func)

_, ptrObj := deptr(recvType(obj))
_, ptrRecv := deptr(sel.recv)

needsPromotion := len(sel.index) > 1
needsIndirection := !ptrObj && ptrRecv
if needsPromotion || needsIndirection {
fn = createWrapper(prog, sel, cr)
} else {
fn = prog.objectMethod(obj, cr)
}
if fn.Signature.Recv() == nil {
panic(fn) // missing receiver
}
mset.mapping[id] = fn
}
return fn
}

// RuntimeTypes returns a new unordered slice containing all types in
// the program for which a runtime type is required.
//
Expand Down

0 comments on commit 51df92b

Please sign in to comment.