]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: redo IsRuntimePkg/IsReflectPkg predicate
authorAustin Clements <austin@google.com>
Fri, 7 Jul 2023 20:16:30 +0000 (16:16 -0400)
committerAustin Clements <austin@google.com>
Tue, 22 Aug 2023 19:18:21 +0000 (19:18 +0000)
Currently, the types package has IsRuntimePkg and IsReflectPkg
predicates for testing if a Pkg is the runtime or reflect packages.
IsRuntimePkg returns "true" for any "CompilingRuntime" package, which
includes all of the packages imported by the runtime. This isn't
inherently wrong, except that all but one use of it is of the form "is
this Sym a specific runtime.X symbol?" for which we clearly only want
the package "runtime" itself. IsRuntimePkg was introduced (as
isRuntime) in CL 37538 as part of separating the real runtime package
from the compiler built-in fake runtime package. As of that CL, the
"runtime" package couldn't import any other packages, so this was
adequate at the time.

We could fix this by just changing the implementation of IsRuntimePkg,
but the meaning of this API is clearly somewhat ambiguous. Instead, we
replace it with a new RuntimeSymName function that returns the name of
a symbol if it's in package "runtime", or "" if not. This is what
every call site (except one) actually wants, which lets us simplify
the callers, and also more clearly addresses the ambiguity between
package "runtime" and the general concept of a runtime package.

IsReflectPkg doesn't have the same issue of ambiguity, but it
parallels IsRuntimePkg and is used in the same way, so we replace it
with a new ReflectSymName for consistency.

Change-Id: If3a81d7d11732a9ab2cac9488d17508415cfb597
Reviewed-on: https://go-review.googlesource.com/c/go/+/521696
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/noder/unified.go
src/cmd/compile/internal/ssagen/nowb.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/types/type.go
src/cmd/compile/internal/walk/builtin.go
src/cmd/compile/internal/walk/expr.go
test/nowritebarrier.go

index bb3d872d75d90941532be3993c3c8ea43e09c65a..739705aa8aa4ea9b922843bc8d6b34188aaf0f3d 100644 (file)
@@ -505,6 +505,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
        if n == nil {
                return false
        }
+opSwitch:
        switch n.Op() {
        // Call is okay if inlinable and we have the budget for the body.
        case ir.OCALLFUNC:
@@ -516,22 +517,19 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
                var cheap bool
                if n.X.Op() == ir.ONAME {
                        name := n.X.(*ir.Name)
-                       if name.Class == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
-                               fn := name.Sym().Name
-                               if fn == "getcallerpc" || fn == "getcallersp" {
+                       if name.Class == ir.PFUNC {
+                               switch fn := types.RuntimeSymName(name.Sym()); fn {
+                               case "getcallerpc", "getcallersp":
                                        v.reason = "call to " + fn
                                        return true
-                               }
-                               if fn == "throw" {
+                               case "throw":
                                        v.budget -= inlineExtraThrowCost
-                                       break
+                                       break opSwitch
                                }
-                       }
-                       // 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" {
+                               // Special case for reflect.noescape. It does just type
+                               // conversions to appease the escape analysis, and doesn't
+                               // generate code.
+                               if types.ReflectSymName(name.Sym()) == "noescape" {
                                        cheap = true
                                }
                        }
@@ -553,7 +551,7 @@ 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()
-                                       if types.IsRuntimePkg(s.Pkg) && s.Name == "heapBits.nextArena" {
+                                       if types.RuntimeSymName(s) == "heapBits.nextArena" {
                                                // Special case: explicitly allow mid-stack inlining of
                                                // runtime.heapBits.next even though it calls slow-path
                                                // runtime.heapBits.nextArena.
@@ -906,8 +904,11 @@ func inlnode(callerfn *ir.Func, n ir.Node, bigCaller bool, inlCalls *[]*ir.Inlin
                        // even when package reflect was compiled without it (#35073).
                        if meth := ir.MethodExprName(n.X); meth != nil {
                                s := meth.Sym()
-                               if base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
-                                       return n
+                               if base.Debug.Checkptr != 0 {
+                                       switch types.ReflectSymName(s) {
+                                       case "Value.UnsafeAddr", "Value.Pointer":
+                                               return n
+                                       }
                                }
                        }
                }
index 58d4e029373ae68e86e12524e7221e368b1c5965..e534f0b72569e5ad6b0f58a9de51ce3dda5dd0f7 100644 (file)
@@ -109,7 +109,7 @@ func unified(m posMap, noders []*noder) {
        // For functions originally came from package runtime,
        // mark as norace to prevent instrumenting, see issue #60439.
        for _, fn := range target.Funcs {
-               if !base.Flag.CompilingRuntime && types.IsRuntimePkg(fn.Sym().Pkg) {
+               if !base.Flag.CompilingRuntime && types.RuntimeSymName(fn.Sym()) != "" {
                        fn.Pragma |= ir.Norace
                }
        }
index 3ef0952eff0398721fcf97eb23798f8f206ad6b7..68da39f35266f64c88f489d01479f5b4701067a4 100644 (file)
@@ -82,7 +82,7 @@ func (c *nowritebarrierrecChecker) findExtraCalls(nn ir.Node) {
        if fn.Class != ir.PFUNC || fn.Defn == nil {
                return
        }
-       if !types.IsRuntimePkg(fn.Sym().Pkg) || fn.Sym().Name != "systemstack" {
+       if types.RuntimeSymName(fn.Sym()) != "systemstack" {
                return
        }
 
index 414dd17826fbce1ee57ba1b739108ccd1ae87caa..c4b053e690a0dfd34fa90e7c1bef83486cf7b700 100644 (file)
@@ -278,7 +278,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
                n.SetType(l.Type().Result(0).Type)
 
                if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME {
-                       if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" {
+                       if sym := n.X.(*ir.Name).Sym(); types.RuntimeSymName(sym) == "getg" {
                                // Emit code for runtime.getg() directly instead of calling function.
                                // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
                                // so that the ordering pass can make sure to preserve the semantics of the original code
index eafa3f3ef11beec52722d6a59c1da114a3b76e73..bd63f651a53bf171c2f14d8a173828d981ec6d3a 100644 (file)
@@ -1841,17 +1841,22 @@ func IsMethodApplicable(t *Type, m *Field) bool {
        return t.IsPtr() || !m.Type.Recv().Type.IsPtr() || IsInterfaceMethod(m.Type) || m.Embedded == 2
 }
 
-// IsRuntimePkg reports whether p is package runtime.
-func IsRuntimePkg(p *Pkg) bool {
-       if base.Flag.CompilingRuntime && p == LocalPkg {
-               return true
+// RuntimeSymName returns the name of s if it's in package "runtime"; otherwise
+// it returns "".
+func RuntimeSymName(s *Sym) string {
+       if s.Pkg.Path == "runtime" {
+               return s.Name
        }
-       return p.Path == "runtime"
+       return ""
 }
 
-// IsReflectPkg reports whether p is package reflect.
-func IsReflectPkg(p *Pkg) bool {
-       return p.Path == "reflect"
+// ReflectSymName returns the name of s if it's in package "reflect"; otherwise
+// it returns "".
+func ReflectSymName(s *Sym) string {
+       if s.Pkg.Path == "reflect" {
+               return s.Name
+       }
+       return ""
 }
 
 // IsNoInstrumentPkg reports whether p is a package that
index 11951179a5545472d329d013707a28c9a5780242..799ab5770d5091dedee8f7f6625c1208c6ddca37 100644 (file)
@@ -631,7 +631,7 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
                        on = typecheck.LookupRuntime("printslice")
                        on = typecheck.SubstArgTypes(on, n.Type()) // any-1
                case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
-                       if types.IsRuntimePkg(n.Type().Sym().Pkg) && n.Type().Sym().Name == "hex" {
+                       if types.RuntimeSymName(n.Type().Sym()) == "hex" {
                                on = typecheck.LookupRuntime("printhex")
                        } else {
                                on = typecheck.LookupRuntime("printuint")
index 85a6d1fc33dea046502cc1e3d0daa505723f3e4a..4b83773932562fdfd34217cc7201368429dbe2db 100644 (file)
@@ -993,7 +993,7 @@ func usemethod(n *ir.CallExpr) {
 
        // Check that first result type is "reflect.Method". Note that we have to check sym name and sym package
        // separately, as we can't check for exact string "reflect.Method" reliably (e.g., see #19028 and #38515).
-       if s := t.Result(0).Type.Sym(); s != nil && s.Name == "Method" && types.IsReflectPkg(s.Pkg) {
+       if s := t.Result(0).Type.Sym(); s != nil && types.ReflectSymName(s) == "Method" {
                ir.CurFunc.SetReflectMethod(true)
                // The LSym is initialized at this point. We need to set the attribute on the LSym.
                ir.CurFunc.LSym.Set(obj.AttrReflectMethod, true)
index 654f16d0d2468533b549978ceee91c1b41858ab7..d176e28b5ae3fd204398d703005f06f05fcbe43e 100644 (file)
@@ -1,12 +1,14 @@
-// errorcheck -+
+// errorcheck -+ -p=runtime
 
 // Copyright 2016 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.
 
 // Test go:nowritebarrier and related directives.
+// This must appear to be in package runtime so the compiler
+// recognizes "systemstack".
 
-package p
+package runtime
 
 type t struct {
        f *t