import (
"bufio"
+ "internal/goexperiment"
"internal/testenv"
"io"
"math/bits"
- "os/exec"
"regexp"
"runtime"
"strings"
"fastlog2",
"fastrand",
"float64bits",
- "getArgInfoFast",
+ "funcspdelta",
"getm",
"getMCache",
"isDirectIface",
"itabHashFunc",
+ "nextslicecap",
"noescape",
"pcvalueCacheKey",
"readUnaligned32",
"(*bmap).keys",
"(*bmap).overflow",
"(*waitq).enqueue",
+ "funcInfo.entry",
// GC-related ones
"cgoInRange",
"gclinkptr.ptr",
"guintptr.ptr",
- "heapBits.bits",
- "heapBits.isPointer",
- "heapBits.morePointers",
- "heapBits.next",
- "heapBitsForAddr",
+ "writeHeapBitsForAddr",
+ "heapBitsSlice",
"markBits.isMarked",
"muintptr.ptr",
"puintptr.ptr",
"spanOf",
"spanOfUnchecked",
+ "typePointers.nextFast",
"(*gcWork).putFast",
"(*gcWork).tryGetFast",
"(*guintptr).set",
"(*mspan).base",
"(*mspan).markBitsForBase",
"(*mspan).markBitsForIndex",
+ "(*mspan).writeUserArenaHeapBits",
"(*muintptr).set",
"(*puintptr).set",
+ "(*wbBuf).get1",
+ "(*wbBuf).get2",
},
"runtime/internal/sys": {},
"runtime/internal/math": {
"(*Buffer).UnreadByte",
"(*Buffer).tryGrowByReslice",
},
+ "internal/abi": {
+ "UseInterfaceSwitchCache",
+ },
"compress/flate": {
"byLiteral.Len",
"byLiteral.Less",
"FullRune",
"FullRuneInString",
"RuneLen",
+ "AppendRune",
"ValidRune",
},
+ "unicode/utf16": {
+ "Decode",
+ },
"reflect": {
+ "Value.Bool",
+ "Value.Bytes",
"Value.CanAddr",
- "Value.CanSet",
+ "Value.CanComplex",
+ "Value.CanFloat",
+ "Value.CanInt",
"Value.CanInterface",
+ "Value.CanSet",
+ "Value.CanUint",
+ "Value.Cap",
+ "Value.Complex",
+ "Value.Float",
+ "Value.Int",
+ "Value.Interface",
+ "Value.IsNil",
"Value.IsValid",
+ "Value.Kind",
+ "Value.Len",
+ "Value.MapRange",
+ "Value.OverflowComplex",
+ "Value.OverflowFloat",
+ "Value.OverflowInt",
+ "Value.OverflowUint",
+ "Value.String",
+ "Value.Type",
+ "Value.Uint",
+ "Value.UnsafeAddr",
"Value.pointer",
"add",
"align",
"net": {
"(*UDPConn).ReadFromUDP",
},
+ "sync": {
+ // Both OnceFunc and its returned closure need to be inlinable so
+ // that the returned closure can be inlined into the caller of OnceFunc.
+ "OnceFunc",
+ "OnceFunc.func2", // The returned closure.
+ // TODO(austin): It would be good to check OnceValue and OnceValues,
+ // too, but currently they aren't reported because they have type
+ // parameters and aren't instantiated in sync.
+ },
+ "sync/atomic": {
+ // (*Bool).CompareAndSwap handled below.
+ "(*Bool).Load",
+ "(*Bool).Store",
+ "(*Bool).Swap",
+ "(*Int32).Add",
+ "(*Int32).CompareAndSwap",
+ "(*Int32).Load",
+ "(*Int32).Store",
+ "(*Int32).Swap",
+ "(*Int64).Add",
+ "(*Int64).CompareAndSwap",
+ "(*Int64).Load",
+ "(*Int64).Store",
+ "(*Int64).Swap",
+ "(*Uint32).Add",
+ "(*Uint32).CompareAndSwap",
+ "(*Uint32).Load",
+ "(*Uint32).Store",
+ "(*Uint32).Swap",
+ "(*Uint64).Add",
+ "(*Uint64).CompareAndSwap",
+ "(*Uint64).Load",
+ "(*Uint64).Store",
+ "(*Uint64).Swap",
+ "(*Uintptr).Add",
+ "(*Uintptr).CompareAndSwap",
+ "(*Uintptr).Load",
+ "(*Uintptr).Store",
+ "(*Uintptr).Swap",
+ "(*Pointer[go.shape.int]).CompareAndSwap",
+ "(*Pointer[go.shape.int]).Load",
+ "(*Pointer[go.shape.int]).Store",
+ "(*Pointer[go.shape.int]).Swap",
+ },
}
- if runtime.GOARCH != "386" && runtime.GOARCH != "mips64" && runtime.GOARCH != "mips64le" && runtime.GOARCH != "riscv64" {
- // nextFreeFast calls sys.Ctz64, which on 386 is implemented in asm and is not inlinable.
+ if runtime.GOARCH != "386" && runtime.GOARCH != "loong64" && runtime.GOARCH != "mips64" && runtime.GOARCH != "mips64le" && runtime.GOARCH != "riscv64" {
+ // nextFreeFast calls sys.TrailingZeros64, which on 386 is implemented in asm and is not inlinable.
// We currently don't have midstack inlining so nextFreeFast is also not inlinable on 386.
- // On mips64x and riscv64, Ctz64 is not intrinsified and causes nextFreeFast too expensive
- // to inline (Issue 22239).
+ // On loong64, mips64x and riscv64, TrailingZeros64 is not intrinsified and causes nextFreeFast
+ // too expensive to inline (Issue 22239).
want["runtime"] = append(want["runtime"], "nextFreeFast")
+ // Same behavior for heapBits.nextFast.
+ want["runtime"] = append(want["runtime"], "heapBits.nextFast")
}
if runtime.GOARCH != "386" {
- // As explained above, Ctz64 and Ctz32 are not Go code on 386.
+ // As explained above, TrailingZeros64 and TrailingZeros32 are not Go code on 386.
// The same applies to Bswap32.
- want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Ctz64")
- want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Ctz32")
+ want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "TrailingZeros64")
+ want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "TrailingZeros32")
want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Bswap32")
}
if bits.UintSize == 64 {
// mix is only defined on 64-bit architectures
want["runtime"] = append(want["runtime"], "mix")
+ // (*Bool).CompareAndSwap is just over budget on 32-bit systems (386, arm).
+ want["sync/atomic"] = append(want["sync/atomic"], "(*Bool).CompareAndSwap")
}
switch runtime.GOARCH {
}
}
- args := append([]string{"build", "-a", "-gcflags=all=-m -m", "-tags=math_big_pure_go"}, pkgs...)
- cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), args...))
+ args := append([]string{"build", "-gcflags=-m -m", "-tags=math_big_pure_go"}, pkgs...)
+ cmd := testenv.CleanCmdEnv(testenv.Command(t, testenv.GoToolPath(t), args...))
pr, pw := io.Pipe()
cmd.Stdout = pw
cmd.Stderr = pw
t.Errorf("%s was not inlined: %s", fullName, reason)
}
}
+
+func collectInlCands(msgs string) map[string]struct{} {
+ rv := make(map[string]struct{})
+ lines := strings.Split(msgs, "\n")
+ re := regexp.MustCompile(`^\S+\s+can\s+inline\s+(\S+)`)
+ for _, line := range lines {
+ m := re.FindStringSubmatch(line)
+ if m != nil {
+ rv[m[1]] = struct{}{}
+ }
+ }
+ return rv
+}
+
+func TestIssue56044(t *testing.T) {
+ if testing.Short() {
+ t.Skipf("skipping test: too long for short mode")
+ }
+ if !goexperiment.CoverageRedesign {
+ t.Skipf("skipping new coverage tests (experiment not enabled)")
+ }
+
+ testenv.MustHaveGoBuild(t)
+
+ modes := []string{"-covermode=set", "-covermode=atomic"}
+
+ for _, mode := range modes {
+ // Build the Go runtime with "-m", capturing output.
+ args := []string{"build", "-gcflags=runtime=-m", "runtime"}
+ cmd := testenv.Command(t, testenv.GoToolPath(t), args...)
+ b, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failed (%v): %s", err, b)
+ }
+ mbase := collectInlCands(string(b))
+
+ // Redo the build with -cover, also with "-m".
+ args = []string{"build", "-gcflags=runtime=-m", mode, "runtime"}
+ cmd = testenv.Command(t, testenv.GoToolPath(t), args...)
+ b, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failed (%v): %s", err, b)
+ }
+ mcov := collectInlCands(string(b))
+
+ // Make sure that there aren't any functions that are marked
+ // as inline candidates at base but not with coverage.
+ for k := range mbase {
+ if _, ok := mcov[k]; !ok {
+ t.Errorf("error: did not find %s in coverage -m output", k)
+ }
+ }
+ }
+}