Skip to content

Commit

Permalink
cmd/compile: allowing inlining of functions with OCALLPART
Browse files Browse the repository at this point in the history
OCALLPART is exported in its original form, which is as an OXDOT.

The body of the method value wrapper created in makepartialcall() was
not being typechecked, and that was causing a problem during escape
analysis, so I added code to typecheck the body.

The go executable got slightly bigger with this change (13598111 ->
13598905), because of extra exported methods with OCALLPART (I
believe), while the text size got slightly smaller (9686964 ->
9686643).

This is mainly part of the work to make sure all function bodies can
be exported (for purposes of generics), but might as well fix the
OCALLPART inlining bug as well.

Fixes #18493

Change-Id: If7aa055ff78ed7a6330c6a1e22f836ec567d04fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/263620
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
  • Loading branch information
danscales committed Oct 20, 2020
1 parent 2754d91 commit 8fe372c
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 5 deletions.
6 changes: 6 additions & 0 deletions src/cmd/compile/internal/gc/closure.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ func typecheckpartialcall(fn *Node, sym *types.Sym) {
fn.Type = xfunc.Type
}

// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
// for partial calls.
func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
rcvrtype := fn.Left.Type
sym := methodSymSuffix(rcvrtype, meth, "-fm")
Expand Down Expand Up @@ -500,6 +502,10 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
funcbody()

xfunc = typecheck(xfunc, ctxStmt)
// Need to typecheck the body of the just-generated wrapper.
// typecheckslice() requires that Curfn is set when processing an ORETURN.
Curfn = xfunc
typecheckslice(xfunc.Nbody.Slice(), ctxStmt)
sym.Def = asTypesNode(xfunc)
xtop = append(xtop, xfunc)
Curfn = savecurfn
Expand Down
9 changes: 7 additions & 2 deletions src/cmd/compile/internal/gc/iexport.go
Original file line number Diff line number Diff line change
Expand Up @@ -1266,8 +1266,13 @@ func (w *exportWriter) expr(n *Node) {
// case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList

// case OCALLPART:
// unimplemented - handled by default case
case OCALLPART:
// An OCALLPART is an OXDOT before type checking.
w.op(OXDOT)
w.pos(n.Pos)
w.expr(n.Left)
// Right node should be ONAME
w.selector(n.Right.Sym)

case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
w.op(OXDOT)
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/gc/iimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ func (r *importReader) node() *Node {
// unreachable - handled in case OSTRUCTLIT by elemList

// case OCALLPART:
// unimplemented
// unreachable - mapped to case OXDOT below by exporter

// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
// unreachable - mapped to case OXDOT below by exporter
Expand Down
6 changes: 4 additions & 2 deletions src/cmd/compile/internal/gc/inl.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,10 @@ func (v *hairyVisitor) visit(n *Node) bool {
v.reason = "call to recover"
return true

case OCALLPART:
// OCALLPART is inlineable, but no extra cost to the budget

case OCLOSURE,
OCALLPART,
ORANGE,
OSELECT,
OTYPESW,
Expand Down Expand Up @@ -454,7 +456,7 @@ func inlcopy(n *Node) *Node {
}

m := n.copy()
if m.Func != nil {
if n.Op != OCALLPART && m.Func != nil {
Fatalf("unexpected Func: %v", m)
}
m.Left = inlcopy(n.Left)
Expand Down
17 changes: 17 additions & 0 deletions test/inline.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,20 @@ Loop:
}
}
}

// Issue #18493 - make sure we can do inlining of functions with a method value
type T1 struct{}

func (a T1) meth(val int) int { // ERROR "can inline T1.meth" "inlining call to T1.meth"
return val + 5
}

func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth"
return t1.meth // ERROR "t1.meth escapes to heap"
}

func ii() { // ERROR "can inline ii"
var t1 T1
f := getMeth(t1) // ERROR "inlining call to getMeth" "t1.meth does not escape"
_ = f(3)
}

0 comments on commit 8fe372c

Please sign in to comment.