1
2
3
4
5
6
7
8 package devirtualize
9
10 import (
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/typecheck"
14 "cmd/compile/internal/types"
15 )
16
17
18 func Func(fn *ir.Func) {
19 ir.CurFunc = fn
20 ir.VisitList(fn.Body, func(n ir.Node) {
21 if call, ok := n.(*ir.CallExpr); ok {
22 Call(call)
23 }
24 })
25 }
26
27
28 func Call(call *ir.CallExpr) {
29 if call.Op() != ir.OCALLINTER {
30 return
31 }
32 sel := call.X.(*ir.SelectorExpr)
33 r := ir.StaticValue(sel.X)
34 if r.Op() != ir.OCONVIFACE {
35 return
36 }
37 recv := r.(*ir.ConvExpr)
38
39 typ := recv.X.Type()
40 if typ.IsInterface() {
41 return
42 }
43
44 dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
45 dt.SetType(typ)
46 x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
47 switch x.Op() {
48 case ir.ODOTMETH:
49 x := x.(*ir.SelectorExpr)
50 if base.Flag.LowerM != 0 {
51 base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
52 }
53 call.SetOp(ir.OCALLMETH)
54 call.X = x
55 case ir.ODOTINTER:
56
57 x := x.(*ir.SelectorExpr)
58 if base.Flag.LowerM != 0 {
59 base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
60 }
61 call.SetOp(ir.OCALLINTER)
62 call.X = x
63 default:
64
65 if base.Flag.LowerM != 0 {
66 base.WarnfAt(call.Pos(), "failed to devirtualize %v (%v)", x, x.Op())
67 }
68 return
69 }
70
71
72
73
74
75
76
77 types.CheckSize(x.Type())
78 switch ft := x.Type(); ft.NumResults() {
79 case 0:
80 case 1:
81 call.SetType(ft.Results().Field(0).Type)
82 default:
83 call.SetType(ft.Results())
84 }
85 }
86
View as plain text