mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00:00
[dev.typeparams] cmd/compile: separate out creating instantiations from creating dictionaries
We often need to create a function/method instantiation, but not a dictionary, because the call to the instantiation will be using a sub-dictionary. Also, main dictionaries are only need for concrete, non-gcshape types, whereas instantiations will be for gcshape types (or concrete types, for strict stenciling). Created a helper function getDictOrSubdict() to reduce duplicated code. Also, moved gfGetGfInfo() call in getDictionarySym() inside conditional where it is needed, to avoid extra work when dictionary has already been created. Change-Id: I06587cb2ddc77de2f991e9f9eaf462d2c5a5d45e Reviewed-on: https://go-review.googlesource.com/c/go/+/332550 Trust: Dan Scales <danscales@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
6dec18cc75
commit
b994cc69e0
|
@ -111,11 +111,6 @@ type gfInfo struct {
|
||||||
type instInfo struct {
|
type instInfo struct {
|
||||||
fun *ir.Func // The instantiated function (with body)
|
fun *ir.Func // The instantiated function (with body)
|
||||||
dictParam *ir.Name // The node inside fun that refers to the dictionary param
|
dictParam *ir.Name // The node inside fun that refers to the dictionary param
|
||||||
// Addr of static dictionary associated with this instantiation. This is the
|
|
||||||
// dictionary you should pass if all the type args are concreate. Soon to be
|
|
||||||
// removed, when creating static dictionary and instantiated function are
|
|
||||||
// separated.
|
|
||||||
dictAddr ir.Node
|
|
||||||
|
|
||||||
gf *ir.Name // The associated generic function
|
gf *ir.Name // The associated generic function
|
||||||
gfInfo *gfInfo
|
gfInfo *gfInfo
|
||||||
|
|
|
@ -105,21 +105,15 @@ func (g *irgen) stencil() {
|
||||||
// instantiation.
|
// instantiation.
|
||||||
call := n.(*ir.CallExpr)
|
call := n.(*ir.CallExpr)
|
||||||
inst := call.X.(*ir.InstExpr)
|
inst := call.X.(*ir.InstExpr)
|
||||||
st, dict := g.getInstantiationForNode(inst)
|
nameNode, isMeth := g.getInstNameNode(inst)
|
||||||
dictkind := "Main dictionary"
|
targs := typecheck.TypesOf(inst.Targs)
|
||||||
if declInfo != nil {
|
st := g.getInstantiation(nameNode, targs, isMeth)
|
||||||
// Get the dictionary arg via sub-dictionary reference
|
dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, nameNode, targs, isMeth)
|
||||||
entry, ok := declInfo.dictEntryMap[n]
|
if infoPrintMode {
|
||||||
// If the entry is not found, it must be that
|
dictkind := "Main dictionary"
|
||||||
// this node was did not have any type args
|
if usingSubdict {
|
||||||
// that depend on type params, so we need a
|
|
||||||
// main dictionary, not a sub-dictionary.
|
|
||||||
if ok {
|
|
||||||
dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen)
|
|
||||||
dictkind = "Sub-dictionary"
|
dictkind = "Sub-dictionary"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if infoPrintMode {
|
|
||||||
if inst.X.Op() == ir.OMETHVALUE {
|
if inst.X.Op() == ir.OMETHVALUE {
|
||||||
fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call)
|
fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call)
|
||||||
} else {
|
} else {
|
||||||
|
@ -137,7 +131,7 @@ func (g *irgen) stencil() {
|
||||||
call.Args.Prepend(inst.X.(*ir.SelectorExpr).X)
|
call.Args.Prepend(inst.X.(*ir.SelectorExpr).X)
|
||||||
}
|
}
|
||||||
// Add dictionary to argument list.
|
// Add dictionary to argument list.
|
||||||
call.Args.Prepend(dict)
|
call.Args.Prepend(dictValue)
|
||||||
// Transform the Call now, which changes OCALL
|
// Transform the Call now, which changes OCALL
|
||||||
// to OCALLFUNC and does typecheckaste/assignconvfn.
|
// to OCALLFUNC and does typecheckaste/assignconvfn.
|
||||||
transformCall(call)
|
transformCall(call)
|
||||||
|
@ -162,21 +156,18 @@ func (g *irgen) stencil() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
st, dict := g.getInstantiation(gf, targs, true)
|
st := g.getInstantiation(gf, targs, true)
|
||||||
entry, ok := declInfo.dictEntryMap[n]
|
dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true)
|
||||||
// TODO: Not creating sub-dictionary entry for
|
_ = usingSubdict
|
||||||
|
// TODO: We should do assert(usingSubdict) here, but
|
||||||
|
// not creating sub-dictionary entry for
|
||||||
// absDifference in absdiff.go yet. Unusual case,
|
// absDifference in absdiff.go yet. Unusual case,
|
||||||
// where there are different generic method
|
// where there are different generic method
|
||||||
// implementations of Abs in absDifference.
|
// implementations of Abs in absDifference.
|
||||||
if ok {
|
|
||||||
if infoPrintMode {
|
|
||||||
fmt.Printf("Sub-dictionary in %v at generic method call: %v\n", decl, call)
|
|
||||||
}
|
|
||||||
dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen)
|
|
||||||
}
|
|
||||||
call.SetOp(ir.OCALL)
|
call.SetOp(ir.OCALL)
|
||||||
call.X = st.Nname
|
call.X = st.Nname
|
||||||
call.Args.Prepend(dict, meth.X)
|
call.Args.Prepend(dictValue, meth.X)
|
||||||
// Transform the Call now, which changes OCALL
|
// Transform the Call now, which changes OCALL
|
||||||
// to OCALLFUNC and does typecheckaste/assignconvfn.
|
// to OCALLFUNC and does typecheckaste/assignconvfn.
|
||||||
transformCall(call)
|
transformCall(call)
|
||||||
|
@ -263,17 +254,13 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
||||||
// For method values, the target expects a dictionary and the receiver
|
// For method values, the target expects a dictionary and the receiver
|
||||||
// as its first two arguments.
|
// as its first two arguments.
|
||||||
// dictValue is the value to use for the dictionary argument.
|
// dictValue is the value to use for the dictionary argument.
|
||||||
target, dictValue = g.getInstantiation(gf, targs, rcvrValue != nil)
|
target = g.getInstantiation(gf, targs, rcvrValue != nil)
|
||||||
dictkind := "Main dictionary"
|
dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, rcvrValue != nil)
|
||||||
if outerInfo != nil {
|
|
||||||
entry, ok := outerInfo.dictEntryMap[x]
|
|
||||||
if ok {
|
|
||||||
dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen)
|
|
||||||
dictkind = "Sub-dictionary"
|
|
||||||
usingSubdict = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if infoPrintMode {
|
if infoPrintMode {
|
||||||
|
dictkind := "Main dictionary"
|
||||||
|
if usingSubdict {
|
||||||
|
dictkind = "Sub-dictionary"
|
||||||
|
}
|
||||||
if rcvrValue == nil {
|
if rcvrValue == nil {
|
||||||
fmt.Printf("%s in %v for generic function value %v\n", dictkind, outer, inst.X)
|
fmt.Printf("%s in %v for generic function value %v\n", dictkind, outer, inst.X)
|
||||||
} else {
|
} else {
|
||||||
|
@ -308,17 +295,13 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target, dictValue = g.getInstantiation(gf, targs, true)
|
target = g.getInstantiation(gf, targs, true)
|
||||||
dictkind := "Main dictionary"
|
dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, true)
|
||||||
if outerInfo != nil {
|
|
||||||
entry, ok := outerInfo.dictEntryMap[x]
|
|
||||||
if ok {
|
|
||||||
dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen)
|
|
||||||
dictkind = "Sub-dictionary"
|
|
||||||
usingSubdict = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if infoPrintMode {
|
if infoPrintMode {
|
||||||
|
dictkind := "Main dictionary"
|
||||||
|
if usingSubdict {
|
||||||
|
dictkind = "Sub-dictionary"
|
||||||
|
}
|
||||||
fmt.Printf("%s in %v for method expression %v\n", dictkind, outer, x)
|
fmt.Printf("%s in %v for method expression %v\n", dictkind, outer, x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,8 +480,8 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
||||||
return ir.InitExpr(init, c)
|
return ir.InitExpr(init, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// instantiateMethods instantiates all the methods of all fully-instantiated
|
// instantiateMethods instantiates all the methods (and associated dictionaries) of
|
||||||
// generic types that have been added to g.instTypeList.
|
// all fully-instantiated generic types that have been added to g.instTypeList.
|
||||||
func (g *irgen) instantiateMethods() {
|
func (g *irgen) instantiateMethods() {
|
||||||
for i := 0; i < len(g.instTypeList); i++ {
|
for i := 0; i < len(g.instTypeList); i++ {
|
||||||
typ := g.instTypeList[i]
|
typ := g.instTypeList[i]
|
||||||
|
@ -521,23 +504,48 @@ func (g *irgen) instantiateMethods() {
|
||||||
// Direct method calls go directly to the instantiations, implemented above.
|
// Direct method calls go directly to the instantiations, implemented above.
|
||||||
// Indirect method calls use wrappers generated in reflectcall. Those wrappers
|
// Indirect method calls use wrappers generated in reflectcall. Those wrappers
|
||||||
// will use these instantiations if they are needed (for interface tables or reflection).
|
// will use these instantiations if they are needed (for interface tables or reflection).
|
||||||
_, _ = g.getInstantiation(baseNname, typ.RParams(), true)
|
_ = g.getInstantiation(baseNname, typ.RParams(), true)
|
||||||
|
_ = g.getDictionarySym(baseNname, typ.RParams(), true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.instTypeList = nil
|
g.instTypeList = nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getInstantiationForNode returns the function/method instantiation and
|
// getInstNameNode returns the name node for the method or function being instantiated, and a bool which is true if a method is being instantiated.
|
||||||
// dictionary value for a InstExpr node inst.
|
func (g *irgen) getInstNameNode(inst *ir.InstExpr) (*ir.Name, bool) {
|
||||||
func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) (*ir.Func, ir.Node) {
|
|
||||||
if meth, ok := inst.X.(*ir.SelectorExpr); ok {
|
if meth, ok := inst.X.(*ir.SelectorExpr); ok {
|
||||||
return g.getInstantiation(meth.Selection.Nname.(*ir.Name), typecheck.TypesOf(inst.Targs), true)
|
return meth.Selection.Nname.(*ir.Name), true
|
||||||
} else {
|
} else {
|
||||||
return g.getInstantiation(inst.X.(*ir.Name), typecheck.TypesOf(inst.Targs), false)
|
return inst.X.(*ir.Name), false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getDictOrSubdict returns, for a method/function call or reference (node n) in an
|
||||||
|
// instantiation (described by instInfo), a node which is accessing a sub-dictionary
|
||||||
|
// or main/static dictionary, as needed, and also returns a boolean indicating if a
|
||||||
|
// sub-dictionary was accessed. nameNode is the particular function or method being
|
||||||
|
// called/referenced, and targs are the type arguments.
|
||||||
|
func (g *irgen) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Name, targs []*types.Type, isMeth bool) (ir.Node, bool) {
|
||||||
|
var dict ir.Node
|
||||||
|
usingSubdict := false
|
||||||
|
if declInfo != nil {
|
||||||
|
// Get the dictionary arg via sub-dictionary reference
|
||||||
|
entry, ok := declInfo.dictEntryMap[n]
|
||||||
|
// If the entry is not found, it may be that this node did not have
|
||||||
|
// any type args that depend on type params, so we need a main
|
||||||
|
// dictionary, not a sub-dictionary.
|
||||||
|
if ok {
|
||||||
|
dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen)
|
||||||
|
usingSubdict = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !usingSubdict {
|
||||||
|
dict = g.getDictionaryValue(nameNode, targs, isMeth)
|
||||||
|
}
|
||||||
|
return dict, usingSubdict
|
||||||
|
}
|
||||||
|
|
||||||
func addGcType(fl []*types.Field, t *types.Type) []*types.Field {
|
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))
|
return append(fl, types.NewField(base.Pos, typecheck.Lookup("F"+strconv.Itoa(len(fl))), t))
|
||||||
}
|
}
|
||||||
|
@ -730,7 +738,7 @@ func gcshapeType(t *types.Type) (*types.Type, string) {
|
||||||
// getInstantiation gets the instantiantion and dictionary of the function or method nameNode
|
// getInstantiation gets the instantiantion and dictionary of the function or method nameNode
|
||||||
// with the type arguments targs. If the instantiated function is not already
|
// with the type arguments targs. If the instantiated function is not already
|
||||||
// cached, then it calls genericSubst to create the new instantiation.
|
// cached, then it calls genericSubst to create the new instantiation.
|
||||||
func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) (*ir.Func, ir.Node) {
|
func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func {
|
||||||
if nameNode.Func.Body == nil && nameNode.Func.Inl != nil {
|
if nameNode.Func.Body == nil && nameNode.Func.Inl != nil {
|
||||||
// If there is no body yet but Func.Inl exists, then we can can
|
// If there is no body yet but Func.Inl exists, then we can can
|
||||||
// import the whole generic body.
|
// import the whole generic body.
|
||||||
|
@ -763,7 +771,6 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth
|
||||||
// genericSubst fills in info.dictParam and info.dictEntryMap.
|
// genericSubst fills in info.dictParam and info.dictEntryMap.
|
||||||
st := g.genericSubst(sym, nameNode, targs, isMeth, info)
|
st := g.genericSubst(sym, nameNode, targs, isMeth, info)
|
||||||
info.fun = st
|
info.fun = st
|
||||||
info.dictAddr = g.getDictionaryValue(nameNode, targs, isMeth)
|
|
||||||
g.instInfoMap[sym] = info
|
g.instInfoMap[sym] = info
|
||||||
// This ensures that the linker drops duplicates of this instantiation.
|
// This ensures that the linker drops duplicates of this instantiation.
|
||||||
// All just works!
|
// All just works!
|
||||||
|
@ -773,7 +780,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth
|
||||||
ir.Dump(fmt.Sprintf("\nstenciled %v", st), st)
|
ir.Dump(fmt.Sprintf("\nstenciled %v", st), st)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return info.fun, info.dictAddr
|
return info.fun
|
||||||
}
|
}
|
||||||
|
|
||||||
// Struct containing info needed for doing the substitution as we create the
|
// Struct containing info needed for doing the substitution as we create the
|
||||||
|
@ -1352,13 +1359,13 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
||||||
base.Fatalf("%s should have type arguments", gf.Sym().Name)
|
base.Fatalf("%s should have type arguments", gf.Sym().Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
info := g.getGfInfo(gf)
|
|
||||||
|
|
||||||
// Get a symbol representing the dictionary.
|
// Get a symbol representing the dictionary.
|
||||||
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 {
|
if lsym := sym.Linksym(); len(lsym.P) == 0 {
|
||||||
|
info := g.getGfInfo(gf)
|
||||||
|
|
||||||
infoPrint("=== Creating dictionary %v\n", sym.Name)
|
infoPrint("=== Creating dictionary %v\n", sym.Name)
|
||||||
off := 0
|
off := 0
|
||||||
// Emit an entry for each targ (concrete type or gcshape).
|
// Emit an entry for each targ (concrete type or gcshape).
|
||||||
|
|
Loading…
Reference in a new issue