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 {
|
||||
fun *ir.Func // The instantiated function (with body)
|
||||
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
|
||||
gfInfo *gfInfo
|
||||
|
|
|
@ -105,21 +105,15 @@ func (g *irgen) stencil() {
|
|||
// instantiation.
|
||||
call := n.(*ir.CallExpr)
|
||||
inst := call.X.(*ir.InstExpr)
|
||||
st, dict := g.getInstantiationForNode(inst)
|
||||
dictkind := "Main dictionary"
|
||||
if declInfo != nil {
|
||||
// Get the dictionary arg via sub-dictionary reference
|
||||
entry, ok := declInfo.dictEntryMap[n]
|
||||
// If the entry is not found, it must be that
|
||||
// this node was 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)
|
||||
nameNode, isMeth := g.getInstNameNode(inst)
|
||||
targs := typecheck.TypesOf(inst.Targs)
|
||||
st := g.getInstantiation(nameNode, targs, isMeth)
|
||||
dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, nameNode, targs, isMeth)
|
||||
if infoPrintMode {
|
||||
dictkind := "Main dictionary"
|
||||
if usingSubdict {
|
||||
dictkind = "Sub-dictionary"
|
||||
}
|
||||
}
|
||||
if infoPrintMode {
|
||||
if inst.X.Op() == ir.OMETHVALUE {
|
||||
fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call)
|
||||
} else {
|
||||
|
@ -137,7 +131,7 @@ func (g *irgen) stencil() {
|
|||
call.Args.Prepend(inst.X.(*ir.SelectorExpr).X)
|
||||
}
|
||||
// Add dictionary to argument list.
|
||||
call.Args.Prepend(dict)
|
||||
call.Args.Prepend(dictValue)
|
||||
// Transform the Call now, which changes OCALL
|
||||
// to OCALLFUNC and does typecheckaste/assignconvfn.
|
||||
transformCall(call)
|
||||
|
@ -162,21 +156,18 @@ func (g *irgen) stencil() {
|
|||
}
|
||||
}
|
||||
|
||||
st, dict := g.getInstantiation(gf, targs, true)
|
||||
entry, ok := declInfo.dictEntryMap[n]
|
||||
// TODO: Not creating sub-dictionary entry for
|
||||
st := g.getInstantiation(gf, targs, true)
|
||||
dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true)
|
||||
_ = usingSubdict
|
||||
// TODO: We should do assert(usingSubdict) here, but
|
||||
// not creating sub-dictionary entry for
|
||||
// absDifference in absdiff.go yet. Unusual case,
|
||||
// where there are different generic method
|
||||
// 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.X = st.Nname
|
||||
call.Args.Prepend(dict, meth.X)
|
||||
call.Args.Prepend(dictValue, meth.X)
|
||||
// Transform the Call now, which changes OCALL
|
||||
// to OCALLFUNC and does typecheckaste/assignconvfn.
|
||||
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
|
||||
// as its first two arguments.
|
||||
// dictValue is the value to use for the dictionary argument.
|
||||
target, dictValue = g.getInstantiation(gf, targs, rcvrValue != nil)
|
||||
dictkind := "Main dictionary"
|
||||
if outerInfo != nil {
|
||||
entry, ok := outerInfo.dictEntryMap[x]
|
||||
if ok {
|
||||
dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen)
|
||||
dictkind = "Sub-dictionary"
|
||||
usingSubdict = true
|
||||
}
|
||||
}
|
||||
target = g.getInstantiation(gf, targs, rcvrValue != nil)
|
||||
dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, rcvrValue != nil)
|
||||
if infoPrintMode {
|
||||
dictkind := "Main dictionary"
|
||||
if usingSubdict {
|
||||
dictkind = "Sub-dictionary"
|
||||
}
|
||||
if rcvrValue == nil {
|
||||
fmt.Printf("%s in %v for generic function value %v\n", dictkind, outer, inst.X)
|
||||
} else {
|
||||
|
@ -308,17 +295,13 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
break
|
||||
}
|
||||
}
|
||||
target, dictValue = g.getInstantiation(gf, targs, true)
|
||||
dictkind := "Main dictionary"
|
||||
if outerInfo != nil {
|
||||
entry, ok := outerInfo.dictEntryMap[x]
|
||||
if ok {
|
||||
dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen)
|
||||
dictkind = "Sub-dictionary"
|
||||
usingSubdict = true
|
||||
}
|
||||
}
|
||||
target = g.getInstantiation(gf, targs, true)
|
||||
dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, true)
|
||||
if infoPrintMode {
|
||||
dictkind := "Main dictionary"
|
||||
if usingSubdict {
|
||||
dictkind = "Sub-dictionary"
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
// instantiateMethods instantiates all the methods of all fully-instantiated
|
||||
// generic types that have been added to g.instTypeList.
|
||||
// instantiateMethods instantiates all the methods (and associated dictionaries) of
|
||||
// all fully-instantiated generic types that have been added to g.instTypeList.
|
||||
func (g *irgen) instantiateMethods() {
|
||||
for i := 0; i < len(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.
|
||||
// Indirect method calls use wrappers generated in reflectcall. Those wrappers
|
||||
// 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
|
||||
|
||||
}
|
||||
|
||||
// getInstantiationForNode returns the function/method instantiation and
|
||||
// dictionary value for a InstExpr node inst.
|
||||
func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) (*ir.Func, ir.Node) {
|
||||
// getInstNameNode returns the name node for the method or function being instantiated, and a bool which is true if a method is being instantiated.
|
||||
func (g *irgen) getInstNameNode(inst *ir.InstExpr) (*ir.Name, bool) {
|
||||
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 {
|
||||
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 {
|
||||
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
|
||||
// with the type arguments targs. If the instantiated function is not already
|
||||
// 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 there is no body yet but Func.Inl exists, then we can can
|
||||
// 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.
|
||||
st := g.genericSubst(sym, nameNode, targs, isMeth, info)
|
||||
info.fun = st
|
||||
info.dictAddr = g.getDictionaryValue(nameNode, targs, isMeth)
|
||||
g.instInfoMap[sym] = info
|
||||
// This ensures that the linker drops duplicates of this instantiation.
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
return info.fun, info.dictAddr
|
||||
return info.fun
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
info := g.getGfInfo(gf)
|
||||
|
||||
// Get a symbol representing the dictionary.
|
||||
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).
|
||||
|
|
Loading…
Reference in a new issue