aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2021-08-04 17:58:54 -0700
committerDan Scales <danscales@google.com>2021-08-05 17:53:59 +0000
commit5dcb5e2cea883b1bd69b543841b137a287aa7037 (patch)
tree234d6e77fd916fbb386a90a9dbcae34d103b07b7
parent3cdf8b429e7550c04ab986327bf9aed8de08d6fa (diff)
downloadgo-5dcb5e2cea883b1bd69b543841b137a287aa7037.tar.gz
go-5dcb5e2cea883b1bd69b543841b137a287aa7037.zip
[dev.typeparams] cmd/compile: dictionary/shape cleanup
- Removed gcshapeType - we're going with more granular shapes for now, and gradually coarsening later if needed. - Put in early return in getDictionarySym(), so the entire rest of the function can be un-indented by one level. - Removed some duplicated infoprint calls, and fixed one infoprint message in getGfInfo. Change-Id: I13acce8fdabdb21e903275b53ff78a1e6a378de2 Reviewed-on: https://go-review.googlesource.com/c/go/+/339901 Trust: Dan Scales <danscales@google.com> Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
-rw-r--r--src/cmd/compile/internal/noder/stencil.go443
1 files changed, 113 insertions, 330 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index b2677d5a77..7cc37f1154 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -8,7 +8,6 @@
package noder
import (
- "bytes"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
@@ -19,7 +18,6 @@ import (
"cmd/internal/src"
"fmt"
"go/constant"
- "strconv"
)
// Enable extra consistency checks.
@@ -536,220 +534,6 @@ func (g *irgen) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Nam
return dict, usingSubdict
}
-func addGcType(fl []*types.Field, t *types.Type) []*types.Field {
- return append(fl, types.NewField(base.Pos, typecheck.Lookup("F"+strconv.Itoa(len(fl))), t))
-}
-
-const INTTYPE = types.TINT64 // XX fix for 32-bit arch
-const UINTTYPE = types.TUINT64 // XX fix for 32-bit arch
-const INTSTRING = "i8" // XX fix for 32-bit arch
-const UINTSTRING = "u8" // XX fix for 32-bit arch
-
-// accumGcshape adds fields to fl resulting from the GCshape transformation of
-// type t. The string associated with the GCshape transformation of t is added to
-// buf. fieldSym is the sym of the field associated with type t, if it is in a
-// struct. fieldSym could be used to have special naming for blank fields, etc.
-func accumGcshape(fl []*types.Field, buf *bytes.Buffer, t *types.Type, fieldSym *types.Sym) []*types.Field {
- // t.Kind() is already the kind of the underlying type, so no need to
- // reference t.Underlying() to reference the underlying type.
- assert(t.Kind() == t.Underlying().Kind())
-
- switch t.Kind() {
- case types.TINT8:
- fl = addGcType(fl, types.Types[types.TINT8])
- buf.WriteString("i1")
-
- case types.TUINT8:
- fl = addGcType(fl, types.Types[types.TUINT8])
- buf.WriteString("u1")
-
- case types.TINT16:
- fl = addGcType(fl, types.Types[types.TINT16])
- buf.WriteString("i2")
-
- case types.TUINT16:
- fl = addGcType(fl, types.Types[types.TUINT16])
- buf.WriteString("u2")
-
- case types.TINT32:
- fl = addGcType(fl, types.Types[types.TINT32])
- buf.WriteString("i4")
-
- case types.TUINT32:
- fl = addGcType(fl, types.Types[types.TUINT32])
- buf.WriteString("u4")
-
- case types.TINT64:
- fl = addGcType(fl, types.Types[types.TINT64])
- buf.WriteString("i8")
-
- case types.TUINT64:
- fl = addGcType(fl, types.Types[types.TUINT64])
- buf.WriteString("u8")
-
- case types.TINT:
- fl = addGcType(fl, types.Types[INTTYPE])
- buf.WriteString(INTSTRING)
-
- case types.TUINT, types.TUINTPTR:
- fl = addGcType(fl, types.Types[UINTTYPE])
- buf.WriteString(UINTSTRING)
-
- case types.TCOMPLEX64:
- fl = addGcType(fl, types.Types[types.TFLOAT32])
- fl = addGcType(fl, types.Types[types.TFLOAT32])
- buf.WriteString("f4")
- buf.WriteString("f4")
-
- case types.TCOMPLEX128:
- fl = addGcType(fl, types.Types[types.TFLOAT64])
- fl = addGcType(fl, types.Types[types.TFLOAT64])
- buf.WriteString("f8")
- buf.WriteString("f8")
-
- case types.TFLOAT32:
- fl = addGcType(fl, types.Types[types.TFLOAT32])
- buf.WriteString("f4")
-
- case types.TFLOAT64:
- fl = addGcType(fl, types.Types[types.TFLOAT64])
- buf.WriteString("f8")
-
- case types.TBOOL:
- fl = addGcType(fl, types.Types[types.TINT8])
- buf.WriteString("i1")
-
- case types.TPTR:
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- buf.WriteString("p")
-
- case types.TFUNC:
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- buf.WriteString("p")
-
- case types.TSLICE:
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- fl = addGcType(fl, types.Types[INTTYPE])
- fl = addGcType(fl, types.Types[INTTYPE])
- buf.WriteString("p")
- buf.WriteString(INTSTRING)
- buf.WriteString(INTSTRING)
-
- case types.TARRAY:
- n := t.NumElem()
- if n == 1 {
- fl = accumGcshape(fl, buf, t.Elem(), nil)
- } else if n > 0 {
- // Represent an array with more than one element as its
- // unique type, since it must be treated differently for
- // regabi.
- fl = addGcType(fl, t)
- buf.WriteByte('[')
- buf.WriteString(strconv.Itoa(int(n)))
- buf.WriteString("](")
- var ignore []*types.Field
- // But to determine its gcshape name, we must call
- // accumGcShape() on t.Elem().
- accumGcshape(ignore, buf, t.Elem(), nil)
- buf.WriteByte(')')
- }
-
- case types.TSTRUCT:
- nfields := t.NumFields()
- for i, f := range t.Fields().Slice() {
- fl = accumGcshape(fl, buf, f.Type, f.Sym)
-
- // Check if we need to add an alignment field.
- var pad int64
- if i < nfields-1 {
- pad = t.Field(i+1).Offset - f.Offset - f.Type.Width
- } else {
- pad = t.Width - f.Offset - f.Type.Width
- }
- if pad > 0 {
- // There is padding between fields or at end of
- // struct. Add an alignment field.
- fl = addGcType(fl, types.NewArray(types.Types[types.TUINT8], pad))
- buf.WriteString("a")
- buf.WriteString(strconv.Itoa(int(pad)))
- }
- }
-
- case types.TCHAN:
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- buf.WriteString("p")
-
- case types.TMAP:
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- buf.WriteString("p")
-
- case types.TINTER:
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- buf.WriteString("pp")
-
- case types.TFORW, types.TANY:
- assert(false)
-
- case types.TSTRING:
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- fl = addGcType(fl, types.Types[INTTYPE])
- buf.WriteString("p")
- buf.WriteString(INTSTRING)
-
- case types.TUNSAFEPTR:
- fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
- buf.WriteString("p")
-
- default: // Everything TTYPEPARAM and below in list of Kinds
- assert(false)
- }
-
- return fl
-}
-
-// gcshapeType returns the GCshape type and name corresponding to type t.
-func gcshapeType(t *types.Type) (*types.Type, string) {
- var fl []*types.Field
- buf := bytes.NewBufferString("")
-
- // Call CallSize so type sizes and field offsets are available.
- types.CalcSize(t)
-
- instType := t.Sym() != nil && t.IsFullyInstantiated()
- if instType {
- // We distinguish the gcshape of all top-level instantiated type from
- // normal concrete types, even if they have the exact same underlying
- // "shape", because in a function instantiation, any method call on
- // this type arg will be a generic method call (requiring a
- // dictionary), rather than a direct method call on the underlying
- // type (no dictionary). So, we add the instshape prefix to the
- // normal gcshape name, and will make it a defined type with that
- // name below.
- buf.WriteString("instshape-")
- }
- fl = accumGcshape(fl, buf, t, nil)
-
- // TODO: Should gcshapes be in a global package, so we don't have to
- // duplicate in each package? Or at least in the specified source package
- // of a function/method instantiation?
- gcshape := types.NewStruct(types.LocalPkg, fl)
- gcname := buf.String()
- if instType {
- // Lookup or create type with name 'gcname' (with instshape prefix).
- newsym := t.Sym().Pkg.Lookup(gcname)
- if newsym.Def != nil {
- gcshape = newsym.Def.Type()
- } else {
- newt := typecheck.NewIncompleteNamedType(t.Pos(), newsym)
- newt.SetUnderlying(gcshape.Underlying())
- gcshape = newt
- }
- }
- assert(gcshape.Size() == t.Size())
- return gcshape, buf.String()
-}
-
// checkFetchBody checks if a generic body can be fetched, but hasn't been loaded
// yet. If so, it imports the body.
func checkFetchBody(nameNode *ir.Name) {
@@ -1521,131 +1305,135 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth)
// Initialize the dictionary, if we haven't yet already.
- if lsym := sym.Linksym(); len(lsym.P) == 0 {
- info := g.getGfInfo(gf)
-
- infoPrint("=== Creating dictionary %v\n", sym.Name)
- off := 0
- // Emit an entry for each targ (concrete type or gcshape).
- for _, t := range targs {
- infoPrint(" * %v\n", t)
- s := reflectdata.TypeLinksym(t)
- off = objw.SymPtr(lsym, off, s, 0)
- markTypeUsed(t, lsym)
- }
- subst := typecheck.Tsubster{
- Tparams: info.tparams,
- Targs: targs,
- }
- // Emit an entry for each derived type (after substituting targs)
- for _, t := range info.derivedTypes {
- ts := subst.Typ(t)
- infoPrint(" - %v\n", ts)
- s := reflectdata.TypeLinksym(ts)
- off = objw.SymPtr(lsym, off, s, 0)
- markTypeUsed(ts, lsym)
- }
- // Emit an entry for each subdictionary (after substituting targs)
- for _, n := range info.subDictCalls {
- var sym *types.Sym
- switch n.Op() {
- case ir.OCALL:
- call := n.(*ir.CallExpr)
- if call.X.Op() == ir.OXDOT {
- var nameNode *ir.Name
- se := call.X.(*ir.SelectorExpr)
- if types.IsInterfaceMethod(se.Selection.Type) {
- // This is a method call enabled by a type bound.
- tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel)
- tmpse = typecheck.AddImplicitDots(tmpse)
- tparam := tmpse.X.Type()
- assert(tparam.IsTypeParam())
- recvType := targs[tparam.Index()]
- if recvType.IsInterface() || len(recvType.RParams()) == 0 {
- // No sub-dictionary entry is
- // actually needed, since the
- // type arg is not an
- // instantiated type that
- // will have generic methods.
- break
- }
- // This is a method call for an
- // instantiated type, so we need a
- // sub-dictionary.
- targs := recvType.RParams()
- genRecvType := recvType.OrigSym.Def.Type()
- nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
- sym = g.getDictionarySym(nameNode, targs, true)
- } else {
- // This is the case of a normal
- // method call on a generic type.
- nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name)
- subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams()
- s2targs := make([]*types.Type, len(subtargs))
- for i, t := range subtargs {
- s2targs[i] = subst.Typ(t)
- }
- sym = g.getDictionarySym(nameNode, s2targs, true)
+ lsym := sym.Linksym()
+ if len(lsym.P) > 0 {
+ // We already started creating this dictionary and its lsym.
+ return sym
+ }
+
+ info := g.getGfInfo(gf)
+
+ infoPrint("=== Creating dictionary %v\n", sym.Name)
+ off := 0
+ // Emit an entry for each targ (concrete type or gcshape).
+ for _, t := range targs {
+ infoPrint(" * %v\n", t)
+ s := reflectdata.TypeLinksym(t)
+ off = objw.SymPtr(lsym, off, s, 0)
+ markTypeUsed(t, lsym)
+ }
+ subst := typecheck.Tsubster{
+ Tparams: info.tparams,
+ Targs: targs,
+ }
+ // Emit an entry for each derived type (after substituting targs)
+ for _, t := range info.derivedTypes {
+ ts := subst.Typ(t)
+ infoPrint(" - %v\n", ts)
+ s := reflectdata.TypeLinksym(ts)
+ off = objw.SymPtr(lsym, off, s, 0)
+ markTypeUsed(ts, lsym)
+ }
+ // Emit an entry for each subdictionary (after substituting targs)
+ for _, n := range info.subDictCalls {
+ var sym *types.Sym
+ switch n.Op() {
+ case ir.OCALL:
+ call := n.(*ir.CallExpr)
+ if call.X.Op() == ir.OXDOT {
+ var nameNode *ir.Name
+ se := call.X.(*ir.SelectorExpr)
+ if types.IsInterfaceMethod(se.Selection.Type) {
+ // This is a method call enabled by a type bound.
+ tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel)
+ tmpse = typecheck.AddImplicitDots(tmpse)
+ tparam := tmpse.X.Type()
+ assert(tparam.IsTypeParam())
+ recvType := targs[tparam.Index()]
+ if recvType.IsInterface() || len(recvType.RParams()) == 0 {
+ // No sub-dictionary entry is
+ // actually needed, since the
+ // type arg is not an
+ // instantiated type that
+ // will have generic methods.
+ break
}
+ // This is a method call for an
+ // instantiated type, so we need a
+ // sub-dictionary.
+ targs := recvType.RParams()
+ genRecvType := recvType.OrigSym.Def.Type()
+ nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
+ sym = g.getDictionarySym(nameNode, targs, true)
} else {
- inst := call.X.(*ir.InstExpr)
- var nameNode *ir.Name
- var meth *ir.SelectorExpr
- var isMeth bool
- if meth, isMeth = inst.X.(*ir.SelectorExpr); isMeth {
- nameNode = meth.Selection.Nname.(*ir.Name)
- } else {
- nameNode = inst.X.(*ir.Name)
- }
- subtargs := typecheck.TypesOf(inst.Targs)
+ // This is the case of a normal
+ // method call on a generic type.
+ nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name)
+ subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams()
+ s2targs := make([]*types.Type, len(subtargs))
for i, t := range subtargs {
- subtargs[i] = subst.Typ(t)
+ s2targs[i] = subst.Typ(t)
}
- sym = g.getDictionarySym(nameNode, subtargs, isMeth)
+ sym = g.getDictionarySym(nameNode, s2targs, true)
+ }
+ } else {
+ inst := call.X.(*ir.InstExpr)
+ var nameNode *ir.Name
+ var meth *ir.SelectorExpr
+ var isMeth bool
+ if meth, isMeth = inst.X.(*ir.SelectorExpr); isMeth {
+ nameNode = meth.Selection.Nname.(*ir.Name)
+ } else {
+ nameNode = inst.X.(*ir.Name)
}
-
- case ir.OFUNCINST:
- inst := n.(*ir.InstExpr)
- nameNode := inst.X.(*ir.Name)
subtargs := typecheck.TypesOf(inst.Targs)
for i, t := range subtargs {
subtargs[i] = subst.Typ(t)
}
- sym = g.getDictionarySym(nameNode, subtargs, false)
-
- case ir.OXDOT:
- selExpr := n.(*ir.SelectorExpr)
- subtargs := deref(selExpr.X.Type()).RParams()
- s2targs := make([]*types.Type, len(subtargs))
- for i, t := range subtargs {
- s2targs[i] = subst.Typ(t)
- }
- nameNode := selExpr.Selection.Nname.(*ir.Name)
- sym = g.getDictionarySym(nameNode, s2targs, true)
+ sym = g.getDictionarySym(nameNode, subtargs, isMeth)
+ }
- default:
- assert(false)
+ case ir.OFUNCINST:
+ inst := n.(*ir.InstExpr)
+ nameNode := inst.X.(*ir.Name)
+ subtargs := typecheck.TypesOf(inst.Targs)
+ for i, t := range subtargs {
+ subtargs[i] = subst.Typ(t)
}
+ sym = g.getDictionarySym(nameNode, subtargs, false)
- if sym == nil {
- // Unused sub-dictionary entry, just emit 0.
- off = objw.Uintptr(lsym, off, 0)
- infoPrint(" - Unused subdict entry\n")
- } else {
- off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
- infoPrint(" - Subdict %v\n", sym.Name)
+ case ir.OXDOT:
+ selExpr := n.(*ir.SelectorExpr)
+ subtargs := deref(selExpr.X.Type()).RParams()
+ s2targs := make([]*types.Type, len(subtargs))
+ for i, t := range subtargs {
+ s2targs[i] = subst.Typ(t)
}
+ nameNode := selExpr.Selection.Nname.(*ir.Name)
+ sym = g.getDictionarySym(nameNode, s2targs, true)
+
+ default:
+ assert(false)
}
- delay := &delayInfo{
- gf: gf,
- targs: targs,
- sym: sym,
- off: off,
+ if sym == nil {
+ // Unused sub-dictionary entry, just emit 0.
+ off = objw.Uintptr(lsym, off, 0)
+ infoPrint(" - Unused subdict entry\n")
+ } else {
+ off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
+ infoPrint(" - Subdict %v\n", sym.Name)
}
- g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay)
- g.instTypeList = append(g.instTypeList, subst.InstTypeList...)
}
+
+ delay := &delayInfo{
+ gf: gf,
+ targs: targs,
+ sym: sym,
+ off: off,
+ }
+ g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay)
+ g.instTypeList = append(g.instTypeList, subst.InstTypeList...)
return sym
}
@@ -1805,11 +1593,6 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
n.(*ir.SelectorExpr).Selection != nil &&
len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
- if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
- infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
- } else {
- infoPrint(" Closure&subdictionary required at generic meth value %v\n", n)
- }
if hasTParamTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) {
if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
@@ -1849,7 +1632,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
info.itabConvs = append(info.itabConvs, n)
}
if n.Op() == ir.OXDOT && n.(*ir.SelectorExpr).X.Type().IsTypeParam() {
- infoPrint(" Itab for interface conv: %v\n", n)
+ infoPrint(" Itab for bound call: %v\n", n)
info.itabConvs = append(info.itabConvs, n)
}
if (n.Op() == ir.ODOTTYPE || n.Op() == ir.ODOTTYPE2) && !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() {