Source file
src/runtime/symtab_test.go
Documentation: runtime
1
2
3
4
5 package runtime_test
6
7 import (
8 "runtime"
9 "strings"
10 "testing"
11 "unsafe"
12 )
13
14 func TestCaller(t *testing.T) {
15 procs := runtime.GOMAXPROCS(-1)
16 c := make(chan bool, procs)
17 for p := 0; p < procs; p++ {
18 go func() {
19 for i := 0; i < 1000; i++ {
20 testCallerFoo(t)
21 }
22 c <- true
23 }()
24 defer func() {
25 <-c
26 }()
27 }
28 }
29
30
31
32
33
34 func testCallerFoo(t *testing.T) {
35 testCallerBar(t)
36 }
37
38
39 func testCallerBar(t *testing.T) {
40 for i := 0; i < 2; i++ {
41 pc, file, line, ok := runtime.Caller(i)
42 f := runtime.FuncForPC(pc)
43 if !ok ||
44 !strings.HasSuffix(file, "symtab_test.go") ||
45 (i == 0 && !strings.HasSuffix(f.Name(), "testCallerBar")) ||
46 (i == 1 && !strings.HasSuffix(f.Name(), "testCallerFoo")) ||
47 line < 5 || line > 1000 ||
48 f.Entry() >= pc {
49 t.Errorf("incorrect symbol info %d: %t %d %d %s %s %d",
50 i, ok, f.Entry(), pc, f.Name(), file, line)
51 }
52 }
53 }
54
55 func lineNumber() int {
56 _, _, line, _ := runtime.Caller(1)
57 return line
58 }
59
60
61 var firstLine = lineNumber()
62 var (
63 lineVar1 = lineNumber()
64 lineVar2a, lineVar2b = lineNumber(), lineNumber()
65 )
66 var compLit = []struct {
67 lineA, lineB int
68 }{
69 {
70 lineNumber(), lineNumber(),
71 },
72 {
73 lineNumber(),
74 lineNumber(),
75 },
76 {
77 lineB: lineNumber(),
78 lineA: lineNumber(),
79 },
80 }
81 var arrayLit = [...]int{lineNumber(),
82 lineNumber(), lineNumber(),
83 lineNumber(),
84 }
85 var sliceLit = []int{lineNumber(),
86 lineNumber(), lineNumber(),
87 lineNumber(),
88 }
89 var mapLit = map[int]int{
90 29: lineNumber(),
91 30: lineNumber(),
92 lineNumber(): 31,
93 lineNumber(): 32,
94 }
95 var intLit = lineNumber() +
96 lineNumber() +
97 lineNumber()
98 func trythis() {
99 recordLines(lineNumber(),
100 lineNumber(),
101 lineNumber())
102 }
103
104
105
106 var l38, l39, l40 int
107
108 func recordLines(a, b, c int) {
109 l38 = a
110 l39 = b
111 l40 = c
112 }
113
114 func TestLineNumber(t *testing.T) {
115 trythis()
116 for _, test := range []struct {
117 name string
118 val int
119 want int
120 }{
121 {"firstLine", firstLine, 0},
122 {"lineVar1", lineVar1, 2},
123 {"lineVar2a", lineVar2a, 3},
124 {"lineVar2b", lineVar2b, 3},
125 {"compLit[0].lineA", compLit[0].lineA, 9},
126 {"compLit[0].lineB", compLit[0].lineB, 9},
127 {"compLit[1].lineA", compLit[1].lineA, 12},
128 {"compLit[1].lineB", compLit[1].lineB, 13},
129 {"compLit[2].lineA", compLit[2].lineA, 17},
130 {"compLit[2].lineB", compLit[2].lineB, 16},
131
132 {"arrayLit[0]", arrayLit[0], 20},
133 {"arrayLit[1]", arrayLit[1], 21},
134 {"arrayLit[2]", arrayLit[2], 21},
135 {"arrayLit[3]", arrayLit[3], 22},
136
137 {"sliceLit[0]", sliceLit[0], 24},
138 {"sliceLit[1]", sliceLit[1], 25},
139 {"sliceLit[2]", sliceLit[2], 25},
140 {"sliceLit[3]", sliceLit[3], 26},
141
142 {"mapLit[29]", mapLit[29], 29},
143 {"mapLit[30]", mapLit[30], 30},
144 {"mapLit[31]", mapLit[31+firstLine] + firstLine, 31},
145 {"mapLit[32]", mapLit[32+firstLine] + firstLine, 32},
146
147 {"intLit", intLit - 2*firstLine, 34 + 35 + 36},
148
149 {"l38", l38, 38},
150 {"l39", l39, 39},
151 {"l40", l40, 40},
152 } {
153 if got := test.val - firstLine; got != test.want {
154 t.Errorf("%s on firstLine+%d want firstLine+%d (firstLine=%d, val=%d)",
155 test.name, got, test.want, firstLine, test.val)
156 }
157 }
158 }
159
160 func TestNilName(t *testing.T) {
161 defer func() {
162 if ex := recover(); ex != nil {
163 t.Fatalf("expected no nil panic, got=%v", ex)
164 }
165 }()
166 if got := (*runtime.Func)(nil).Name(); got != "" {
167 t.Errorf("Name() = %q, want %q", got, "")
168 }
169 }
170
171 var dummy int
172
173 func inlined() {
174
175 dummy = 42
176 }
177
178
179
180
181
182
183 func tracebackFunc(t *testing.T) uintptr {
184
185
186 inlined()
187 inlined()
188
189
190 pc, _, _, ok := runtime.Caller(0)
191 if !ok {
192 t.Fatalf("Caller(0) got ok false, want true")
193 }
194
195 return pc
196 }
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 func TestFunctionAlignmentTraceback(t *testing.T) {
221 pc := tracebackFunc(t)
222
223
224 f := runtime.FuncForPC(pc)
225 if !strings.HasSuffix(f.Name(), "tracebackFunc") {
226 t.Fatalf("Caller(0) = %+v, want tracebackFunc", f)
227 }
228
229
230
231 for runtime.FuncForPC(pc) == f {
232 pc++
233 }
234 pc--
235
236
237
238
239 if runtime.GOARCH == "amd64" {
240 code := *(*uint8)(unsafe.Pointer(pc))
241 if code != 0xcc {
242 t.Errorf("PC %v code got %#x want 0xcc", pc, code)
243 }
244 }
245
246
247
248 frames := runtime.CallersFrames([]uintptr{pc})
249 frame, _ := frames.Next()
250 if frame.Func != f {
251 t.Errorf("frames.Next() got %+v want %+v", frame.Func, f)
252 }
253 }
254
255 func BenchmarkFunc(b *testing.B) {
256 pc, _, _, ok := runtime.Caller(0)
257 if !ok {
258 b.Fatal("failed to look up PC")
259 }
260 f := runtime.FuncForPC(pc)
261 b.Run("Name", func(b *testing.B) {
262 for i := 0; i < b.N; i++ {
263 name := f.Name()
264 if name != "runtime_test.BenchmarkFunc" {
265 b.Fatalf("unexpected name %q", name)
266 }
267 }
268 })
269 b.Run("Entry", func(b *testing.B) {
270 for i := 0; i < b.N; i++ {
271 pc := f.Entry()
272 if pc == 0 {
273 b.Fatal("zero PC")
274 }
275 }
276 })
277 b.Run("FileLine", func(b *testing.B) {
278 for i := 0; i < b.N; i++ {
279 file, line := f.FileLine(pc)
280 if !strings.HasSuffix(file, "symtab_test.go") || line == 0 {
281 b.Fatalf("unexpected file/line %q:%d", file, line)
282 }
283 }
284 })
285 }
286
View as plain text