summaryrefslogtreecommitdiffstats
path: root/src/runtime/start_line_test.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /src/runtime/start_line_test.go
parentInitial commit. (diff)
downloadgolang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.tar.xz
golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.zip
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/runtime/start_line_test.go')
-rw-r--r--src/runtime/start_line_test.go138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/runtime/start_line_test.go b/src/runtime/start_line_test.go
new file mode 100644
index 0000000..6c4faa8
--- /dev/null
+++ b/src/runtime/start_line_test.go
@@ -0,0 +1,138 @@
+// Copyright 2022 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.
+
+package runtime_test
+
+import (
+ "fmt"
+ "internal/testenv"
+ "runtime"
+ "testing"
+)
+
+// The tests in this file test the function start line metadata included in
+// _func and inlinedCall. TestStartLine hard-codes the start lines of functions
+// in this file. If code moves, the test will need to be updated.
+//
+// The "start line" of a function should be the line containing the func
+// keyword.
+
+func normalFunc() int {
+ return callerStartLine(false)
+}
+
+func multilineDeclarationFunc() int {
+ return multilineDeclarationFunc1(0, 0, 0)
+}
+
+//go:noinline
+func multilineDeclarationFunc1(
+ a, b, c int) int {
+ return callerStartLine(false)
+}
+
+func blankLinesFunc() int {
+
+ // Some
+ // lines
+ // without
+ // code
+
+ return callerStartLine(false)
+}
+
+func inlineFunc() int {
+ return inlineFunc1()
+}
+
+func inlineFunc1() int {
+ return callerStartLine(true)
+}
+
+var closureFn func() int
+
+func normalClosure() int {
+ // Assign to global to ensure this isn't inlined.
+ closureFn = func() int {
+ return callerStartLine(false)
+ }
+ return closureFn()
+}
+
+func inlineClosure() int {
+ return func() int {
+ return callerStartLine(true)
+ }()
+}
+
+func TestStartLine(t *testing.T) {
+ // We test inlined vs non-inlined variants. We can't do that if
+ // optimizations are disabled.
+ testenv.SkipIfOptimizationOff(t)
+
+ testCases := []struct{
+ name string
+ fn func() int
+ want int
+ }{
+ {
+ name: "normal",
+ fn: normalFunc,
+ want: 21,
+ },
+ {
+ name: "multiline-declaration",
+ fn: multilineDeclarationFunc,
+ want: 30,
+ },
+ {
+ name: "blank-lines",
+ fn: blankLinesFunc,
+ want: 35,
+ },
+ {
+ name: "inline",
+ fn: inlineFunc,
+ want: 49,
+ },
+ {
+ name: "normal-closure",
+ fn: normalClosure,
+ want: 57,
+ },
+ {
+ name: "inline-closure",
+ fn: inlineClosure,
+ want: 64,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ got := tc.fn()
+ if got != tc.want {
+ t.Errorf("start line got %d want %d", got, tc.want)
+ }
+ })
+ }
+}
+
+//go:noinline
+func callerStartLine(wantInlined bool) int {
+ var pcs [1]uintptr
+ n := runtime.Callers(2, pcs[:])
+ if n != 1 {
+ panic(fmt.Sprintf("no caller of callerStartLine? n = %d", n))
+ }
+
+ frames := runtime.CallersFrames(pcs[:])
+ frame, _ := frames.Next()
+
+ inlined := frame.Func == nil // Func always set to nil for inlined frames
+ if wantInlined != inlined {
+ panic(fmt.Sprintf("caller %s inlined got %v want %v", frame.Function, inlined, wantInlined))
+ }
+
+ return runtime.FrameStartLine(&frame)
+}