aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/reflectdata/reflect.go
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2021-06-07 18:13:15 -0700
committerDan Scales <danscales@google.com>2021-06-24 20:11:51 +0000
commitddb09af1b85ee9ae278ef338df56c4d91c1acd0d (patch)
treebfcd2590114f576b13e4b15cddb54c34422d9a95 /src/cmd/compile/internal/reflectdata/reflect.go
parentdf00abc61b415eb05d4df9fd2bf3fdda1aaaaba3 (diff)
downloadgo-ddb09af1b85ee9ae278ef338df56c4d91c1acd0d.tar.gz
go-ddb09af1b85ee9ae278ef338df56c4d91c1acd0d.zip
[dev.typeparams] cmd/compile: add derived types and subdictionaries to dictionaries
This is code in progress to generate the two main other types of entries in dictionaries: - all types in the instantiated function derived from the type arguments (which are currently concrete, but will eventually be gcshapes) - pointers (i.e. mainly the unique name) to all needed sub-dictionaries In order to generate these entries, we now generate cached information gfInfo about generic functions/methods that can be used for creating the instantiated dictionaries. We use the type substituter to compute the right type args for instantiated sub-dictionaries. If infoPrintMode is changed to true, the code prints out all the information gathered about generic functions, and also the entries in all the dictionaries that are instantiated. The debug mode also prints out the locations where we need main dictionaries in non-instantiated functions. Other changes: - Moved the dictionary generation back to stencil.go from reflect.go, since we need to do extra analysis for the new dictionary entries. In the process, made getInstantiation generate both the function instantiation and the associated dictionary. - Put in small change for now in reflect.go, so that we don't try generate separate dictionaries for Value[T].get and the auto-generated (*Value[T]).get. The auto-generated wrapper shouldn't really need a dictionary. - Detected, but not handling yet, a new case which needs dictionaries - closures that have function params or captured variables whose types are derived from type arguments. - Added new tests in dictionaryCapture for use of method value/expressions in generic functions and for mutually recursive generic functions. Change-Id: If0cbde8805a9f673a23f5ec798769c85c9c5359b Reviewed-on: https://go-review.googlesource.com/c/go/+/327311 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>
Diffstat (limited to 'src/cmd/compile/internal/reflectdata/reflect.go')
-rw-r--r--src/cmd/compile/internal/reflectdata/reflect.go63
1 files changed, 29 insertions, 34 deletions
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 52534db70d..8378fab36d 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -1716,8 +1716,12 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
rcvr = rcvr.PtrTo()
}
generic := false
- if !rcvr.IsInterface() && len(rcvr.RParams()) > 0 || rcvr.IsPtr() && len(rcvr.Elem().RParams()) > 0 { // TODO: right detection?
- // TODO: check that we do the right thing when rcvr.IsInterface().
+ if !types.IsInterfaceMethod(method.Type) &&
+ (len(rcvr.RParams()) > 0 ||
+ rcvr.IsPtr() && len(rcvr.Elem().RParams()) > 0) { // TODO: right detection?
+ // Don't need dictionary if we are reaching a method (possibly via
+ // an embedded field) which is an interface method.
+ // TODO: check that we do the right thing when method is an interface method.
generic = true
}
if base.Debug.Unified != 0 {
@@ -1786,12 +1790,6 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
}
dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
- if generic && dot.X != nthis && dot.X.Type().IsInterface() {
- // We followed some embedded fields, and the last type was
- // actually an interface, so no need for a dictionary.
- generic = false
- }
-
// generate call
// It's not possible to use a tail call when dynamic linking on ppc64le. The
// bad scenario is when a local call is made to the wrapper: the wrapper will
@@ -1815,6 +1813,14 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
} else {
fn.SetWrapper(true) // ignore frame for panic+recover matching
var call *ir.CallExpr
+
+ if generic && dot.X != nthis {
+ // TODO: for now, we don't try to generate dictionary wrappers for
+ // any methods involving embedded fields, because we're not
+ // generating the needed dictionaries in instantiateMethods.
+ generic = false
+ }
+
if generic {
var args []ir.Node
var targs []*types.Type
@@ -1827,7 +1833,17 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
fmt.Printf("%s\n", ir.MethodSym(orig, method.Sym).Name)
panic("multiple .inst.")
}
- args = append(args, getDictionary(".inst."+ir.MethodSym(orig, method.Sym).Name, targs)) // TODO: remove .inst.
+ // Temporary fix: the wrapper for an auto-generated
+ // pointer/non-pointer receiver method should share the
+ // same dictionary as the corresponding original
+ // (user-written) method.
+ baseOrig := orig
+ if baseOrig.IsPtr() && !method.Type.Recv().Type.IsPtr() {
+ baseOrig = baseOrig.Elem()
+ } else if !baseOrig.IsPtr() && method.Type.Recv().Type.IsPtr() {
+ baseOrig = types.NewPtr(baseOrig)
+ }
+ args = append(args, getDictionary(".inst."+ir.MethodSym(baseOrig, method.Sym).Name, targs)) // TODO: remove .inst.
if indirect {
args = append(args, ir.NewStarExpr(base.Pos, dot.X))
} else if methodrcvr.IsPtr() && methodrcvr.Elem() == dot.X.Type() {
@@ -1852,6 +1868,9 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
}
target := ir.AsNode(sym.Def)
call = ir.NewCallExpr(base.Pos, ir.OCALL, target, args)
+ // Fill-in the generic method node that was not filled in
+ // in instantiateMethod.
+ method.Nname = fn.Nname
} else {
call = ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
call.Args = ir.ParamNames(tfn.Type())
@@ -1924,23 +1943,6 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
r.Type = objabi.R_USEIFACEMETHOD
}
-// getDictionaryForInstantiation returns the dictionary that should be used for invoking
-// the concrete instantiation described by inst.
-func GetDictionaryForInstantiation(inst *ir.InstExpr) ir.Node {
- targs := typecheck.TypesOf(inst.Targs)
- if meth, ok := inst.X.(*ir.SelectorExpr); ok {
- return GetDictionaryForMethod(meth.Selection.Nname.(*ir.Name), targs)
- }
- return GetDictionaryForFunc(inst.X.(*ir.Name), targs)
-}
-
-func GetDictionaryForFunc(fn *ir.Name, targs []*types.Type) ir.Node {
- return getDictionary(typecheck.MakeInstName(fn.Sym(), targs, false).Name, targs)
-}
-func GetDictionaryForMethod(meth *ir.Name, targs []*types.Type) ir.Node {
- return getDictionary(typecheck.MakeInstName(meth.Sym(), targs, true).Name, targs)
-}
-
// getDictionary returns the dictionary for the given named generic function
// or method, with the given type arguments.
// TODO: pass a reference to the generic function instead? We might need
@@ -1964,14 +1966,7 @@ func getDictionary(name string, targs []*types.Type) ir.Node {
// Initialize the dictionary, if we haven't yet already.
if lsym := sym.Linksym(); len(lsym.P) == 0 {
- off := 0
- // Emit an entry for each concrete type.
- for _, t := range targs {
- s := TypeLinksym(t)
- off = objw.SymPtr(lsym, off, s, 0)
- }
- // TODO: subdictionaries
- objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA)
+ base.Fatalf("Dictionary should have alredy been generated: %v", sym)
}
// Make a node referencing the dictionary symbol.