diff options
Diffstat (limited to 'src/cmd/compile/internal/noder')
| -rw-r--r-- | src/cmd/compile/internal/noder/unified.go | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index 59a3536000..5948cac58c 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -5,6 +5,7 @@ package noder import ( + "fmt" "internal/pkgbits" "io" "runtime" @@ -14,6 +15,7 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/inline" "cmd/compile/internal/ir" + "cmd/compile/internal/pgo" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/compile/internal/types2" @@ -25,6 +27,65 @@ import ( // later. var localPkgReader *pkgReader +// LookupMethodFunc returns the ir.Func for an arbitrary full symbol name if +// that function exists in the set of available export data. +// +// This allows lookup of arbitrary methods that aren't otherwise referenced by +// the local package and thus haven't been read yet. +// +// TODO(prattmic): Does not handle instantiation of generic types. Currently +// profiles don't contain the original type arguments, so we won't be able to +// create the runtime dictionaries. +// +// TODO(prattmic): Hit rate of this function is usually fairly low, and errors +// are only used when debug logging is enabled. Consider constructing cheaper +// errors by default. +func LookupMethodFunc(fullName string) (*ir.Func, error) { + pkgPath, symName, err := ir.ParseLinkFuncName(fullName) + if err != nil { + return nil, fmt.Errorf("error parsing symbol name %q: %v", fullName, err) + } + + pkg, ok := types.PkgMap()[pkgPath] + if !ok { + return nil, fmt.Errorf("pkg %s doesn't exist in %v", pkgPath, types.PkgMap()) + } + + // N.B. readPackage creates a Sym for every object in the package to + // initialize objReader and importBodyReader, even if the object isn't + // read. + // + // However, objReader is only initialized for top-level objects, so we + // must first lookup the type and use that to find the method rather + // than looking for the method directly. + typ, meth, err := ir.LookupMethodSelector(pkg, symName) + if err != nil { + return nil, fmt.Errorf("error looking up method symbol %q: %v", symName, err) + } + + pri, ok := objReader[typ] + if !ok { + return nil, fmt.Errorf("type sym %v missing objReader", typ) + } + + name := pri.pr.objIdx(pri.idx, nil, nil, false).(*ir.Name) + if name.Op() != ir.OTYPE { + return nil, fmt.Errorf("type sym %v refers to non-type name: %v", typ, name) + } + if name.Alias() { + return nil, fmt.Errorf("type sym %v refers to alias", typ) + } + + for _, m := range name.Type().Methods() { + if m.Sym == meth { + fn := m.Nname.(*ir.Name).Func + return fn, nil + } + } + + return nil, fmt.Errorf("method %s missing from method set of %v", symName, typ) +} + // unified constructs the local package's Internal Representation (IR) // from its syntax tree (AST). // @@ -69,6 +130,7 @@ var localPkgReader *pkgReader func unified(m posMap, noders []*noder) { inline.InlineCall = unifiedInlineCall typecheck.HaveInlineBody = unifiedHaveInlineBody + pgo.LookupMethodFunc = LookupMethodFunc data := writePkgStub(m, noders) |
