mirror of
https://github.com/golang/go.git
synced 2025-11-10 05:31:03 +00:00
The devirtualization code was only in inl.go because it reused some of the same helper functions as inlining (notably staticValue), but that code all ended up in package ir instead anyway. Beyond that minor commonality, it's entirely separate from inlining. It's definitely on the small side, but consistent with the new micropass-as-a-package approach we're trying. [git-generate] cd src/cmd/compile/internal/inline rf ' mv Devirtualize Func mv devirtualizeCall Call mv Func Call devirtualize.go mv devirtualize.go cmd/compile/internal/devirtualize ' Change-Id: Iff7b9fe486856660a8107d5391c54b7e8d238706 Reviewed-on: https://go-review.googlesource.com/c/go/+/280212 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
101 lines
2.9 KiB
Go
101 lines
2.9 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
//
|
|
// The inlining facility makes 2 passes: first caninl determines which
|
|
// functions are suitable for inlining, and for those that are it
|
|
// saves a copy of the body. Then inlcalls walks each function body to
|
|
// expand calls to inlinable functions.
|
|
//
|
|
// The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
|
|
// making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
|
|
// are not supported.
|
|
// 0: disabled
|
|
// 1: 80-nodes leaf functions, oneliners, panic, lazy typechecking (default)
|
|
// 2: (unassigned)
|
|
// 3: (unassigned)
|
|
// 4: allow non-leaf functions
|
|
//
|
|
// At some point this may get another default and become switch-offable with -N.
|
|
//
|
|
// The -d typcheckinl flag enables early typechecking of all imported bodies,
|
|
// which is useful to flush out bugs.
|
|
//
|
|
// The Debug.m flag enables diagnostic output. a single -m is useful for verifying
|
|
// which calls get inlined or not, more is for debugging, and may go away at any point.
|
|
|
|
package devirtualize
|
|
|
|
import (
|
|
"cmd/compile/internal/base"
|
|
"cmd/compile/internal/ir"
|
|
"cmd/compile/internal/typecheck"
|
|
"cmd/compile/internal/types"
|
|
)
|
|
|
|
// Devirtualize replaces interface method calls within fn with direct
|
|
// concrete-type method calls where applicable.
|
|
func Func(fn *ir.Func) {
|
|
ir.CurFunc = fn
|
|
ir.VisitList(fn.Body, func(n ir.Node) {
|
|
if n.Op() == ir.OCALLINTER {
|
|
Call(n.(*ir.CallExpr))
|
|
}
|
|
})
|
|
}
|
|
|
|
func Call(call *ir.CallExpr) {
|
|
sel := call.X.(*ir.SelectorExpr)
|
|
r := ir.StaticValue(sel.X)
|
|
if r.Op() != ir.OCONVIFACE {
|
|
return
|
|
}
|
|
recv := r.(*ir.ConvExpr)
|
|
|
|
typ := recv.X.Type()
|
|
if typ.IsInterface() {
|
|
return
|
|
}
|
|
|
|
dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
|
|
dt.SetType(typ)
|
|
x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
|
|
switch x.Op() {
|
|
case ir.ODOTMETH:
|
|
x := x.(*ir.SelectorExpr)
|
|
if base.Flag.LowerM != 0 {
|
|
base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
|
|
}
|
|
call.SetOp(ir.OCALLMETH)
|
|
call.X = x
|
|
case ir.ODOTINTER:
|
|
// Promoted method from embedded interface-typed field (#42279).
|
|
x := x.(*ir.SelectorExpr)
|
|
if base.Flag.LowerM != 0 {
|
|
base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
|
|
}
|
|
call.SetOp(ir.OCALLINTER)
|
|
call.X = x
|
|
default:
|
|
// TODO(mdempsky): Turn back into Fatalf after more testing.
|
|
if base.Flag.LowerM != 0 {
|
|
base.WarnfAt(call.Pos(), "failed to devirtualize %v (%v)", x, x.Op())
|
|
}
|
|
return
|
|
}
|
|
|
|
// Duplicated logic from typecheck for function call return
|
|
// value types.
|
|
//
|
|
// Receiver parameter size may have changed; need to update
|
|
// call.Type to get correct stack offsets for result
|
|
// parameters.
|
|
types.CheckSize(x.Type())
|
|
switch ft := x.Type(); ft.NumResults() {
|
|
case 0:
|
|
case 1:
|
|
call.SetType(ft.Results().Field(0).Type)
|
|
default:
|
|
call.SetType(ft.Results())
|
|
}
|
|
}
|