reflect: do not escape Value.Type

Types are either static (for compiler-created types) or heap
allocated and always reachable (for reflection-created types, held
in the central map). So there is no need to escape types.

With CL 408826 reflect.Value does not always escape. Some functions
that escapes Value.typ would make the Value escape without this CL.

Had to add a special case for the inliner to keep (*Value).Type
still inlineable.

Change-Id: I7c14d35fd26328347b509a06eb5bd1534d40775f
Reviewed-on: https://go-review.googlesource.com/c/go/+/413474
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Cherry Mui 2022-06-17 13:06:16 -04:00
parent 0ac72f8b96
commit be4fe08b57
7 changed files with 170 additions and 122 deletions

View file

@ -483,6 +483,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
// because getcaller{pc,sp} expect a pointer to the caller's first argument.
//
// runtime.throw is a "cheap call" like panic in normal code.
var cheap bool
if n.X.Op() == ir.ONAME {
name := n.X.(*ir.Name)
if name.Class == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
@ -496,6 +497,14 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
break
}
}
// Special case for reflect.noescpae. It does just type
// conversions to appease the escape analysis, and doesn't
// generate code.
if name.Class == ir.PFUNC && types.IsReflectPkg(name.Sym().Pkg) {
if name.Sym().Name == "noescape" {
cheap = true
}
}
// Special case for coverage counter updates; although
// these correspond to real operations, we treat them as
// zero cost for the moment. This is due to the existence
@ -514,7 +523,6 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
if meth := ir.MethodExprName(n.X); meth != nil {
if fn := meth.Func; fn != nil {
s := fn.Sym()
var cheap bool
if types.IsRuntimePkg(s.Pkg) && s.Name == "heapBits.nextArena" {
// Special case: explicitly allow mid-stack inlining of
// runtime.heapBits.next even though it calls slow-path
@ -536,12 +544,12 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
cheap = true
}
}
if cheap {
break // treat like any other node, that is, cost of 1
}
}
}
}
if cheap {
break // treat like any other node, that is, cost of 1
}
// Determine if the callee edge is for an inlinable hot callee or not.
if v.profile != nil && v.curFunc != nil {
@ -642,7 +650,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
// This doesn't produce code, but the children might.
v.budget++ // undo default cost
case ir.ODCLCONST, ir.OFALL:
case ir.ODCLCONST, ir.OFALL, ir.OTYPE:
// These nodes don't produce code; omit from inlining budget.
return false