Merge pull request #28679 from sttts/sttts-deepcopy-pointer-in
Automatic merge from submit-queue Deepcopy: avoid struct copies and reflection Call - make signature of generated deepcopy methods symmetric with `in *type, out *type`, avoiding copies of big structs on the stack - switch to `in interface{}, out interface{}` which allows us to call them with without `reflect.Call` The first change reduces runtime of BenchmarkPodCopy-4 from `> 3500ns` to around `2300ns`. The second change reduces runtime to around `1900ns`.
This commit is contained in:
@@ -204,6 +204,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
|
||||
const (
|
||||
apiPackagePath = "k8s.io/kubernetes/pkg/api"
|
||||
conversionPackagePath = "k8s.io/kubernetes/pkg/conversion"
|
||||
runtimePackagePath = "k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// genDeepCopy produces a file with autogenerated deep-copy functions.
|
||||
@@ -384,8 +385,10 @@ func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error {
|
||||
sw.Do("if err := $.scheme|raw$.AddGeneratedDeepCopyFuncs(\n", map[string]interface{}{
|
||||
"scheme": scheme,
|
||||
})
|
||||
reflect := c.Universe.Type(types.Name{Package: "reflect", Name: "TypeOf"})
|
||||
for _, t := range g.typesForInit {
|
||||
sw.Do(fmt.Sprintf("%s,\n", g.funcNameTmpl(t)), argsFromType(t))
|
||||
g.imports.AddType(reflect)
|
||||
sw.Do(fmt.Sprintf("conversion.GeneratedDeepCopyFunc{Fn: %s, InType: reflect.TypeOf(func() *$.type|raw$ {var x *$.type|raw$; return x}())},\n", g.funcNameTmpl(t)), argsFromType(t))
|
||||
}
|
||||
sw.Do("); err != nil {\n", nil)
|
||||
sw.Do("// if one of the deep copy functions is malformed, detect it immediately.\n", nil)
|
||||
@@ -425,10 +428,11 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri
|
||||
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
funcName := g.funcNameTmpl(t)
|
||||
sw.Do(fmt.Sprintf("func %s(in $.type|raw$, out *$.type|raw$, c *$.Cloner|raw$) error {\n", funcName), g.withGlobals(argsFromType(t)))
|
||||
sw.Do(fmt.Sprintf("func %s(in interface{}, out interface{}, c *$.Cloner|raw$) error {{\n", funcName), g.withGlobals(argsFromType(t)))
|
||||
sw.Do("in := in.(*$.type|raw$)\nout := out.(*$.type|raw$)\n", g.withGlobals(argsFromType(t)))
|
||||
g.generateFor(t, sw)
|
||||
sw.Do("return nil\n", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
sw.Do("}}\n\n", nil)
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
@@ -459,7 +463,7 @@ func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
|
||||
sw.Do("*out = in\n", nil)
|
||||
sw.Do("*out = *in\n", nil)
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
|
||||
@@ -467,63 +471,63 @@ func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
|
||||
if t.Key.IsAssignable() {
|
||||
switch {
|
||||
case hasDeepCopyMethod(t.Elem):
|
||||
sw.Do("for key, val := range in {\n", nil)
|
||||
sw.Do("for key, val := range *in {\n", nil)
|
||||
sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
case t.Elem.IsAnonymousStruct():
|
||||
sw.Do("for key := range in {\n", nil)
|
||||
sw.Do("for key := range *in {\n", nil)
|
||||
sw.Do("(*out)[key] = struct{}{}\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
case t.Elem.IsAssignable():
|
||||
sw.Do("for key, val := range in {\n", nil)
|
||||
sw.Do("for key, val := range *in {\n", nil)
|
||||
sw.Do("(*out)[key] = val\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
default:
|
||||
sw.Do("for key, val := range in {\n", nil)
|
||||
sw.Do("for key, val := range *in {\n", nil)
|
||||
if g.copyableAndInBounds(t.Elem) {
|
||||
sw.Do("newVal := new($.|raw$)\n", t.Elem)
|
||||
funcName := g.funcNameTmpl(t.Elem)
|
||||
sw.Do(fmt.Sprintf("if err := %s(val, newVal, c); err != nil {\n", funcName), argsFromType(t.Elem))
|
||||
sw.Do(fmt.Sprintf("if err := %s(&val, newVal, c); err != nil {\n", funcName), argsFromType(t.Elem))
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
sw.Do("(*out)[key] = *newVal\n", nil)
|
||||
} else {
|
||||
sw.Do("if newVal, err := c.DeepCopy(val); err != nil {\n", nil)
|
||||
sw.Do("if newVal, err := c.DeepCopy(&val); err != nil {\n", nil)
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("} else {\n", nil)
|
||||
sw.Do("(*out)[key] = newVal.($.|raw$)\n", t.Elem)
|
||||
sw.Do("(*out)[key] = *newVal.(*$.|raw$)\n", t.Elem)
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
} else {
|
||||
// TODO: Implement it when necessary.
|
||||
sw.Do("for range in {\n", nil)
|
||||
sw.Do("for range *in {\n", nil)
|
||||
sw.Do("// FIXME: Copying unassignable keys unsupported $.|raw$\n", t.Key)
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
|
||||
sw.Do("*out = make($.|raw$, len(in))\n", t)
|
||||
sw.Do("*out = make($.|raw$, len(*in))\n", t)
|
||||
if t.Elem.Kind == types.Builtin {
|
||||
sw.Do("copy(*out, in)\n", nil)
|
||||
sw.Do("copy(*out, *in)\n", nil)
|
||||
} else {
|
||||
sw.Do("for i := range in {\n", nil)
|
||||
sw.Do("for i := range *in {\n", nil)
|
||||
if hasDeepCopyMethod(t.Elem) {
|
||||
sw.Do("(*out)[i] = in[i].DeepCopy()\n", nil)
|
||||
sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil)
|
||||
} else if t.Elem.IsAssignable() {
|
||||
sw.Do("(*out)[i] = in[i]\n", nil)
|
||||
sw.Do("(*out)[i] = (*in)[i]\n", nil)
|
||||
} else if g.copyableAndInBounds(t.Elem) {
|
||||
funcName := g.funcNameTmpl(t.Elem)
|
||||
sw.Do(fmt.Sprintf("if err := %s(in[i], &(*out)[i], c); err != nil {\n", funcName), argsFromType(t.Elem))
|
||||
sw.Do(fmt.Sprintf("if err := %s(&(*in)[i], &(*out)[i], c); err != nil {\n", funcName), argsFromType(t.Elem))
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
} else {
|
||||
sw.Do("if newVal, err := c.DeepCopy(in[i]); err != nil {\n", nil)
|
||||
sw.Do("if newVal, err := c.DeepCopy(&(*in)[i]); err != nil {\n", nil)
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("} else {\n", nil)
|
||||
sw.Do("(*out)[i] = newVal.($.|raw$)\n", t.Elem)
|
||||
sw.Do("(*out)[i] = *newVal.(*$.|raw$)\n", t.Elem)
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
sw.Do("}\n", nil)
|
||||
@@ -531,6 +535,10 @@ func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
|
||||
if len(t.Members) == 0 {
|
||||
// at least do something with in/out to avoid "declared and not used" errors
|
||||
sw.Do("_ = in\n_ = out\n", nil)
|
||||
}
|
||||
for _, m := range t.Members {
|
||||
t := m.Type
|
||||
if t.Kind == types.Alias {
|
||||
@@ -547,7 +555,7 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
|
||||
sw.Do("out.$.name$ = in.$.name$\n", args)
|
||||
case types.Map, types.Slice, types.Pointer:
|
||||
sw.Do("if in.$.name$ != nil {\n", args)
|
||||
sw.Do("in, out := in.$.name$, &out.$.name$\n", args)
|
||||
sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
|
||||
g.generateFor(t, sw)
|
||||
sw.Do("} else {\n", nil)
|
||||
sw.Do("out.$.name$ = nil\n", args)
|
||||
@@ -559,23 +567,23 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
|
||||
sw.Do("out.$.name$ = in.$.name$\n", args)
|
||||
} else if g.copyableAndInBounds(t) {
|
||||
funcName := g.funcNameTmpl(t)
|
||||
sw.Do(fmt.Sprintf("if err := %s(in.$.name$, &out.$.name$, c); err != nil {\n", funcName), args)
|
||||
sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, c); err != nil {\n", funcName), args)
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
} else {
|
||||
sw.Do("if newVal, err := c.DeepCopy(in.$.name$); err != nil {\n", args)
|
||||
sw.Do("if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args)
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("} else {\n", nil)
|
||||
sw.Do("out.$.name$ = newVal.($.type|raw$)\n", args)
|
||||
sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args)
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
default:
|
||||
sw.Do("if in.$.name$ == nil {\n", args)
|
||||
sw.Do("out.$.name$ = nil\n", args)
|
||||
sw.Do("} else if newVal, err := c.DeepCopy(in.$.name$); err != nil {\n", args)
|
||||
sw.Do("} else if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args)
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("} else {\n", nil)
|
||||
sw.Do("out.$.name$ = newVal.($.type|raw$)\n", args)
|
||||
sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args)
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
}
|
||||
@@ -587,13 +595,15 @@ func (g *genDeepCopy) doInterface(t *types.Type, sw *generator.SnippetWriter) {
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
|
||||
sw.Do("*out = new($.Elem|raw$)\n", t)
|
||||
if hasDeepCopyMethod(t.Elem) {
|
||||
sw.Do("**out = in.DeepCopy()\n", nil)
|
||||
sw.Do("*out = new($.Elem|raw$)\n", t)
|
||||
sw.Do("**out = (*in).DeepCopy()\n", nil)
|
||||
} else if t.Elem.IsAssignable() {
|
||||
sw.Do("**out = *in", nil)
|
||||
sw.Do("*out = new($.Elem|raw$)\n", t)
|
||||
sw.Do("**out = **in", nil)
|
||||
} else if g.copyableAndInBounds(t.Elem) {
|
||||
funcName := g.funcNameTmpl(t.Elem)
|
||||
sw.Do("*out = new($.Elem|raw$)\n", t)
|
||||
sw.Do(fmt.Sprintf("if err := %s(*in, *out, c); err != nil {\n", funcName), argsFromType(t.Elem))
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
@@ -601,7 +611,7 @@ func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
|
||||
sw.Do("if newVal, err := c.DeepCopy(*in); err != nil {\n", nil)
|
||||
sw.Do("return err\n", nil)
|
||||
sw.Do("} else {\n", nil)
|
||||
sw.Do("**out = newVal.($.|raw$)\n", t.Elem)
|
||||
sw.Do("*out = newVal.($.|raw$)\n", t.Elem)
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user