]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.unified] cmd/compile: add method expressions to dictionaries
authorMatthew Dempsky <mdempsky@google.com>
Sun, 24 Jul 2022 06:54:15 +0000 (23:54 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 25 Jul 2022 18:32:18 +0000 (18:32 +0000)
This CL changes method expressions that use derived-type receiver
parameters to use dictionary lookups.

Change-Id: Iacd09b6d77a2d3000438ec8bc9b5af2a0b068aa7
Reviewed-on: https://go-review.googlesource.com/c/go/+/419455
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/noder/writer.go
src/internal/pkgbits/encoder.go

index fbbce7e80f4a2137efeb40179627ef8a399f4400..6b7ac5494f3037c0e4bb2a07f59d5dd658145130 100644 (file)
@@ -154,6 +154,8 @@ type readerDict struct {
        funcsObj []ir.Node
 
        itabs []itabInfo2
+
+       methodExprs []ir.Node
 }
 
 type itabInfo2 struct {
@@ -776,6 +778,14 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, ex
                dict.itabs[i] = itabInfo2{typ: typ, lsym: lsym}
        }
 
+       dict.methodExprs = make([]ir.Node, r.Len())
+       for i := range dict.methodExprs {
+               recv := pr.typIdx(typeInfo{idx: pkgbits.Index(r.Len()), derived: true}, &dict, true)
+               _, sym := r.selector()
+
+               dict.methodExprs[i] = typecheck.Expr(ir.NewSelectorExpr(src.NoXPos, ir.OXDOT, ir.TypeNode(recv), sym))
+       }
+
        return &dict
 }
 
@@ -1696,15 +1706,13 @@ func (r *reader) expr() (res ir.Node) {
        case exprSelector:
                var x ir.Node
                if r.Bool() { // MethodExpr
-                       x = r.exprType(false)
-
-                       // Method expression with derived receiver type.
-                       if x.Op() == ir.ODYNAMICTYPE {
-                               // TODO(mdempsky): Handle with runtime dictionary lookup.
-                               n := ir.TypeNode(x.Type())
-                               n.SetTypecheck(1)
-                               x = n
+                       if r.Bool() {
+                               return r.dict.methodExprs[r.Len()]
                        }
+
+                       n := ir.TypeNode(r.typ())
+                       n.SetTypecheck(1)
+                       x = n
                } else { // FieldVal, MethodVal
                        x = r.expr()
                }
index ac08022c34b0f12841a38a3111498546ca0eca70..93e81bdc821ca5fac4cf8fb5a8d0bdda10fba48b 100644 (file)
@@ -177,6 +177,10 @@ type writerDict struct {
        // itabs lists itabs that are needed for dynamic type assertions
        // (including type switches).
        itabs []itabInfo
+
+       // methodsExprs lists method expressions with derived-type receiver
+       // parameters.
+       methodExprs []methodExprInfo
 }
 
 // A derivedInfo represents a reference to an encoded generic Go type.
@@ -208,13 +212,26 @@ type objInfo struct {
 // An itabInfo represents a reference to an encoded itab entry (i.e.,
 // a non-empty interface type along with a concrete type that
 // implements that interface).
-//
-// itabInfo is only used for
 type itabInfo struct {
        typIdx pkgbits.Index // always a derived type index
        iface  typeInfo      // always a non-empty interface type
 }
 
+// A methodExprInfo represents a reference to an encoded method
+// expression, whose receiver parameter is a derived type.
+type methodExprInfo struct {
+       recvIdx    pkgbits.Index // always a derived type index
+       methodInfo selectorInfo
+}
+
+// A selectorInfo represents a reference to an encoded field or method
+// name (i.e., objects that can only be accessed using selector
+// expressions).
+type selectorInfo struct {
+       pkgIdx  pkgbits.Index
+       nameIdx pkgbits.Index
+}
+
 // anyDerived reports whether any of info's explicit type arguments
 // are derived types.
 func (info objInfo) anyDerived() bool {
@@ -296,8 +313,12 @@ func (pw *pkgWriter) posBaseIdx(b *syntax.PosBase) pkgbits.Index {
 
 // pkg writes a use of the given Package into the element bitstream.
 func (w *writer) pkg(pkg *types2.Package) {
+       w.pkgRef(w.p.pkgIdx(pkg))
+}
+
+func (w *writer) pkgRef(idx pkgbits.Index) {
        w.Sync(pkgbits.SyncPkg)
-       w.Reloc(pkgbits.RelocPkg, w.p.pkgIdx(pkg))
+       w.Reloc(pkgbits.RelocPkg, idx)
 }
 
 // pkgIdx returns the index for the given package, adding it to the
@@ -793,6 +814,12 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) {
                w.typInfo(itab.iface)
        }
 
+       w.Len(len(dict.methodExprs))
+       for _, methodExpr := range dict.methodExprs {
+               w.Len(int(methodExpr.recvIdx))
+               w.selectorInfo(methodExpr.methodInfo)
+       }
+
        assert(len(dict.derived) == nderived)
        assert(len(dict.funcs) == nfuncs)
 }
@@ -862,9 +889,19 @@ func (w *writer) localIdent(obj types2.Object) {
 // selector writes the name of a field or method (i.e., objects that
 // can only be accessed using selector expressions).
 func (w *writer) selector(obj types2.Object) {
+       w.selectorInfo(w.p.selectorIdx(obj))
+}
+
+func (w *writer) selectorInfo(info selectorInfo) {
        w.Sync(pkgbits.SyncSelector)
-       w.pkg(obj.Pkg())
-       w.String(obj.Name())
+       w.pkgRef(info.pkgIdx)
+       w.StringRef(info.nameIdx)
+}
+
+func (pw *pkgWriter) selectorIdx(obj types2.Object) selectorInfo {
+       pkgIdx := pw.pkgIdx(obj.Pkg())
+       nameIdx := pw.StringIdx(obj.Name())
+       return selectorInfo{pkgIdx: pkgIdx, nameIdx: nameIdx}
 }
 
 // @@@ Compiler extensions
@@ -1490,7 +1527,19 @@ func (w *writer) expr(expr syntax.Expr) {
 
                w.Code(exprSelector)
                if w.Bool(sel.Kind() == types2.MethodExpr) {
-                       w.exprType(nil, expr.X, false)
+                       tv, ok := w.p.info.Types[expr.X]
+                       assert(ok)
+                       assert(tv.IsType())
+
+                       typInfo := w.p.typIdx(tv.Type, w.dict)
+                       if w.Bool(typInfo.derived) {
+                               methodInfo := w.p.selectorIdx(sel.Obj())
+                               idx := w.dict.methodExprIdx(typInfo, methodInfo)
+                               w.Len(idx)
+                               break
+                       }
+
+                       w.typInfo(typInfo)
                } else {
                        w.expr(expr.X)
                }
@@ -1821,6 +1870,21 @@ func (w *writer) exprType(iface types2.Type, typ syntax.Expr, nilOK bool) {
        w.typInfo(info)
 }
 
+func (dict *writerDict) methodExprIdx(recvInfo typeInfo, methodInfo selectorInfo) int {
+       assert(recvInfo.derived)
+       newInfo := methodExprInfo{recvIdx: recvInfo.idx, methodInfo: methodInfo}
+
+       for idx, oldInfo := range dict.methodExprs {
+               if oldInfo == newInfo {
+                       return idx
+               }
+       }
+
+       idx := len(dict.methodExprs)
+       dict.methodExprs = append(dict.methodExprs, newInfo)
+       return idx
+}
+
 // isInterface reports whether typ is known to be an interface type.
 // If typ is a type parameter, then isInterface reports an internal
 // compiler error instead.
index c50c838caaecd10929f46975feba32f3ef25903f..c0f22529098ab40f17f6a98089080380b33f6e35 100644 (file)
@@ -316,8 +316,14 @@ func (w *Encoder) Code(c Code) {
 // section (if not already present), and then writing a relocation
 // into the element bitstream.
 func (w *Encoder) String(s string) {
+       w.StringRef(w.p.StringIdx(s))
+}
+
+// StringRef writes a reference to the given index, which must be a
+// previously encoded string value.
+func (w *Encoder) StringRef(idx Index) {
        w.Sync(SyncString)
-       w.Reloc(RelocString, w.p.StringIdx(s))
+       w.Reloc(RelocString, idx)
 }
 
 // Strings encodes and writes a variable-length slice of strings into