1
0
mirror of https://github.com/golang/go synced 2024-11-17 19:34:50 -07:00

[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>
This commit is contained in:
Dan Scales 2021-08-04 17:58:54 -07:00
parent 3cdf8b429e
commit 5dcb5e2cea

View File

@ -8,7 +8,6 @@
package noder package noder
import ( import (
"bytes"
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/objw" "cmd/compile/internal/objw"
@ -19,7 +18,6 @@ import (
"cmd/internal/src" "cmd/internal/src"
"fmt" "fmt"
"go/constant" "go/constant"
"strconv"
) )
// Enable extra consistency checks. // Enable extra consistency checks.
@ -536,220 +534,6 @@ func (g *irgen) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Nam
return dict, usingSubdict 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 // checkFetchBody checks if a generic body can be fetched, but hasn't been loaded
// yet. If so, it imports the body. // yet. If so, it imports the body.
func checkFetchBody(nameNode *ir.Name) { func checkFetchBody(nameNode *ir.Name) {
@ -1521,7 +1305,12 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth) sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth)
// Initialize the dictionary, if we haven't yet already. // Initialize the dictionary, if we haven't yet already.
if lsym := sym.Linksym(); len(lsym.P) == 0 { lsym := sym.Linksym()
if len(lsym.P) > 0 {
// We already started creating this dictionary and its lsym.
return sym
}
info := g.getGfInfo(gf) info := g.getGfInfo(gf)
infoPrint("=== Creating dictionary %v\n", sym.Name) infoPrint("=== Creating dictionary %v\n", sym.Name)
@ -1645,7 +1434,6 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
} }
g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay) g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay)
g.instTypeList = append(g.instTypeList, subst.InstTypeList...) g.instTypeList = append(g.instTypeList, subst.InstTypeList...)
}
return sym return sym
} }
@ -1805,11 +1593,6 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() && } else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
n.(*ir.SelectorExpr).Selection != nil && n.(*ir.SelectorExpr).Selection != nil &&
len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 { 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 hasTParamTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) {
if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) 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) info.itabConvs = append(info.itabConvs, n)
} }
if n.Op() == ir.OXDOT && n.(*ir.SelectorExpr).X.Type().IsTypeParam() { 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) 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() { if (n.Op() == ir.ODOTTYPE || n.Op() == ir.ODOTTYPE2) && !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() {