Skip to content

Commit 1c44642

Browse files
committed
WIP: Use MethodByName only with constants
We would like to enable dead-code-elimination, as unblocked by https://go-review.googlesource.com/c/go/+/522436
1 parent f486a95 commit 1c44642

File tree

3 files changed

+65
-37
lines changed

3 files changed

+65
-37
lines changed

upup/pkg/fi/cloudup/gcetasks/subnet.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ type terraformSubnetRange struct {
299299
CIDR string `cty:"ip_cidr_range"`
300300
}
301301

302-
func (_ *Subnet) RenderSubnet(t *terraform.TerraformTarget, a, e, changes *Subnet) error {
302+
func (_ *Subnet) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *Subnet) error {
303303
shared := fi.ValueOf(e.Shared)
304304
if shared {
305305
// Not terraform owned / managed

upup/pkg/fi/context.go

+44-30
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"k8s.io/klog/v2"
2828
"k8s.io/kops/pkg/apis/kops"
2929
"k8s.io/kops/pkg/apis/nodeup"
30+
"k8s.io/kops/util/pkg/reflectutils"
3031
"k8s.io/kops/util/pkg/vfs"
3132
)
3233

@@ -136,7 +137,7 @@ func (c *Context[T]) RunTasks(options RunTasksOptions) error {
136137
// it is typically called after we have checked the existing state of the Task and determined that is different
137138
// from the desired state.
138139
func (c *Context[T]) Render(a, e, changes Task[T]) error {
139-
typeContextPtr := reflect.TypeOf((*Context[T])(nil))
140+
// typeContextPtr := reflect.TypeOf((*Context[T])(nil))
140141
var lifecycle Lifecycle
141142
if hl, ok := e.(HasLifecycle); ok {
142143
lifecycle = hl.GetLifecycle()
@@ -192,60 +193,73 @@ func (c *Context[T]) Render(a, e, changes Task[T]) error {
192193
}
193194

194195
v := reflect.ValueOf(e)
195-
vType := v.Type()
196+
// vType := v.Type()
196197

197-
targetType := reflect.ValueOf(c.Target).Type()
198+
// targetType := reflect.ValueOf(c.Target).Type()
198199

199-
var renderer *reflect.Method
200+
var renderer *reflect.Value
200201
var rendererArgs []reflect.Value
202+
rendererName := ""
201203

202-
for i := 0; i < vType.NumMethod(); i++ {
203-
method := vType.Method(i)
204-
if !strings.HasPrefix(method.Name, "Render") {
204+
renderMethodNames := []string{"Render"}
205+
206+
targetTypeName := fmt.Sprintf("%T", c.Target)
207+
switch targetTypeName {
208+
case "Foo":
209+
210+
default:
211+
panic(fmt.Sprintf("targetType %q is not recognized", targetTypeName))
212+
}
213+
for _, methodName := range renderMethodNames {
214+
method := reflectutils.GetMethodByName(v, methodName)
215+
if method.IsZero() {
205216
continue
206217
}
207218
match := true
208219

209-
var args []reflect.Value
210-
for j := 0; j < method.Type.NumIn(); j++ {
211-
arg := method.Type.In(j)
212-
if arg.ConvertibleTo(vType) {
213-
continue
214-
}
215-
if arg.ConvertibleTo(typeContextPtr) {
216-
args = append(args, reflect.ValueOf(c))
217-
continue
218-
}
219-
if arg.ConvertibleTo(targetType) {
220-
args = append(args, reflect.ValueOf(c.Target))
221-
continue
222-
}
223-
match = false
224-
break
225-
}
220+
// var args []reflect.Value
221+
// for j := 0; j < method.Type.NumIn(); j++ {
222+
// arg := method.Type.In(j)
223+
// if arg.ConvertibleTo(vType) {
224+
// continue
225+
// }
226+
// if arg.ConvertibleTo(typeContextPtr) {
227+
// args = append(args, reflect.ValueOf(c))
228+
// continue
229+
// }
230+
// if arg.ConvertibleTo(targetType) {
231+
// args = append(args, reflect.ValueOf(c.Target))
232+
// continue
233+
// }
234+
// match = false
235+
// break
236+
// }
226237
if match {
227238
if renderer != nil {
228-
if method.Name == "Render" {
239+
if methodName == "Render" {
229240
continue
230241
}
231-
if renderer.Name != "Render" {
242+
if rendererName != "Render" {
232243
return fmt.Errorf("found multiple Render methods that could be involved on %T", e)
233244
}
234245
}
235246
renderer = &method
236-
rendererArgs = args
247+
rendererName = methodName
248+
// rendererArgs = args
237249
}
238250

239251
}
240252
if renderer == nil {
241253
return fmt.Errorf("could not find Render method on type %T (target %T)", e, c.Target)
242254
}
255+
256+
rendererArgs = append(rendererArgs, reflect.ValueOf(c))
243257
rendererArgs = append(rendererArgs, reflect.ValueOf(a))
244258
rendererArgs = append(rendererArgs, reflect.ValueOf(e))
245259
rendererArgs = append(rendererArgs, reflect.ValueOf(changes))
246-
klog.V(11).Infof("Calling method %s on %T", renderer.Name, e)
247-
m := v.MethodByName(renderer.Name)
248-
rv := m.Call(rendererArgs)
260+
klog.V(11).Infof("Calling method %s on %T", rendererName, e)
261+
// m := v.MethodByName(renderer.Name)
262+
rv := (*renderer).Call(rendererArgs)
249263
var rvErr error
250264
if !rv[0].IsNil() {
251265
rvErr = rv[0].Interface().(error)

util/pkg/reflectutils/walk.go

+20-6
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,29 @@ func JSONMergeStruct(dest, src interface{}) {
5757
}
5858
}
5959

60+
// GetMethodByName implements a switch statement so that we can help the compiler with dead-code-elimination.
61+
// For background: https://github.com/golang/protobuf/issues/1561
62+
func GetMethodByName(reflectValue reflect.Value, methodName string) reflect.Value {
63+
switch methodName {
64+
case "CheckChanges":
65+
return reflectValue.MethodByName("CheckChanges")
66+
case "Find":
67+
return reflectValue.MethodByName("Find")
68+
case "ShouldCreate":
69+
return reflectValue.MethodByName("ShouldCreate")
70+
default:
71+
panic(fmt.Sprintf("need to add %q to getMethodByName helper", methodName))
72+
}
73+
}
74+
6075
// InvokeMethod calls the specified method by reflection
61-
func InvokeMethod(target interface{}, name string, args ...interface{}) ([]reflect.Value, error) {
76+
func InvokeMethod(target interface{}, methodName string, args ...interface{}) ([]reflect.Value, error) {
6277
v := reflect.ValueOf(target)
6378

64-
method, found := v.Type().MethodByName(name)
65-
if !found {
79+
m := GetMethodByName(v, methodName)
80+
if m.IsZero() {
6681
return nil, &MethodNotFoundError{
67-
Name: name,
82+
Name: methodName,
6883
Target: target,
6984
}
7085
}
@@ -73,8 +88,7 @@ func InvokeMethod(target interface{}, name string, args ...interface{}) ([]refle
7388
for _, a := range args {
7489
argValues = append(argValues, reflect.ValueOf(a))
7590
}
76-
klog.V(12).Infof("Calling method %s on %T", method.Name, target)
77-
m := v.MethodByName(method.Name)
91+
klog.V(12).Infof("Calling method %s on %T", methodName, target)
7892
rv := m.Call(argValues)
7993
return rv, nil
8094
}

0 commit comments

Comments
 (0)