Skip to content

Commit 166e5ee

Browse files
committed
runtime: use inlineUnwinder
This converts all places in the runtime that perform inline expansion to use the new inlineUnwinder abstraction. For #54466. Change-Id: I48d996fb6263ed5225bd21d30914a27ae434528d Reviewed-on: https://go-review.googlesource.com/c/go/+/466099 Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent 59d0de1 commit 166e5ee

File tree

5 files changed

+121
-195
lines changed

5 files changed

+121
-195
lines changed

src/runtime/preempt.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -413,14 +413,9 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) {
413413
// except the ones that have funcFlag_SPWRITE set in f.flag.
414414
return false, 0
415415
}
416-
name := funcname(f)
417-
if inldata := funcdata(f, _FUNCDATA_InlTree); inldata != nil {
418-
inltree := (*[1 << 20]inlinedCall)(inldata)
419-
ix := pcdatavalue(f, _PCDATA_InlTreeIndex, pc, nil)
420-
if ix >= 0 {
421-
name = funcnameFromNameOff(f, inltree[ix].nameOff)
422-
}
423-
}
416+
// Check the inner-most name
417+
u, uf := newInlineUnwinder(f, pc, nil)
418+
name := u.srcFunc(uf).name()
424419
if hasPrefix(name, "runtime.") ||
425420
hasPrefix(name, "runtime/internal/") ||
426421
hasPrefix(name, "reflect.") {

src/runtime/race.go

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -171,39 +171,32 @@ func racecallback(cmd uintptr, ctx unsafe.Pointer) {
171171
func raceSymbolizeCode(ctx *symbolizeCodeContext) {
172172
pc := ctx.pc
173173
fi := findfunc(pc)
174-
f := fi._Func()
175-
if f != nil {
176-
file, line := f.FileLine(pc)
177-
if line != 0 {
178-
if inldata := funcdata(fi, _FUNCDATA_InlTree); inldata != nil {
179-
inltree := (*[1 << 20]inlinedCall)(inldata)
180-
for {
181-
ix := pcdatavalue(fi, _PCDATA_InlTreeIndex, pc, nil)
182-
if ix >= 0 {
183-
if inltree[ix].funcID == funcID_wrapper {
184-
// ignore wrappers
185-
// Back up to an instruction in the "caller".
186-
pc = f.Entry() + uintptr(inltree[ix].parentPc)
187-
continue
188-
}
189-
ctx.pc = f.Entry() + uintptr(inltree[ix].parentPc) // "caller" pc
190-
name := funcnameFromNameOff(fi, inltree[ix].nameOff)
191-
ctx.fn = &bytes(name)[0] // assume NUL-terminated
192-
ctx.line = uintptr(line)
193-
ctx.file = &bytes(file)[0] // assume NUL-terminated
194-
ctx.off = pc - f.Entry()
195-
ctx.res = 1
196-
return
197-
}
198-
break
199-
}
174+
if fi.valid() {
175+
u, uf := newInlineUnwinder(fi, pc, nil)
176+
for ; uf.valid(); uf = u.next(uf) {
177+
sf := u.srcFunc(uf)
178+
if sf.funcID == funcID_wrapper {
179+
// ignore wrappers
180+
continue
181+
}
182+
183+
name := sf.name()
184+
file, line := u.fileLine(uf)
185+
if line == 0 {
186+
// Failure to symbolize
187+
continue
200188
}
201-
name := funcname(fi)
202189
ctx.fn = &bytes(name)[0] // assume NUL-terminated
203190
ctx.line = uintptr(line)
204191
ctx.file = &bytes(file)[0] // assume NUL-terminated
205-
ctx.off = pc - f.Entry()
192+
ctx.off = pc - fi.entry()
206193
ctx.res = 1
194+
if u.isInlined(uf) {
195+
// Set ctx.pc to the "caller" so the race detector calls this again
196+
// to further unwind.
197+
uf = u.next(uf)
198+
ctx.pc = uf.pc
199+
}
207200
return
208201
}
209202
}

src/runtime/stubs.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,15 @@ func noescape(p unsafe.Pointer) unsafe.Pointer {
222222
return unsafe.Pointer(x ^ 0)
223223
}
224224

225+
// noEscapePtr hides a pointer from escape analysis. See noescape.
226+
// USE CAREFULLY!
227+
//
228+
//go:nosplit
229+
func noEscapePtr[T any](p *T) *T {
230+
x := uintptr(unsafe.Pointer(p))
231+
return (*T)(unsafe.Pointer(x ^ 0))
232+
}
233+
225234
// Not all cgocallback frames are actually cgocallback,
226235
// so not all have these arguments. Mark them uintptr so that the GC
227236
// does not misinterpret memory when the arguments are not present.

src/runtime/symtab.go

Lines changed: 40 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -116,28 +116,21 @@ func (ci *Frames) Next() (frame Frame, more bool) {
116116
// work correctly for entries in the result of runtime.Callers.
117117
pc--
118118
}
119-
name := funcname(funcInfo)
120-
startLine := f.startLine()
121-
if inldata := funcdata(funcInfo, _FUNCDATA_InlTree); inldata != nil {
122-
inltree := (*[1 << 20]inlinedCall)(inldata)
123-
// Non-strict as cgoTraceback may have added bogus PCs
124-
// with a valid funcInfo but invalid PCDATA.
125-
ix := pcdatavalue1(funcInfo, _PCDATA_InlTreeIndex, pc, nil, false)
126-
if ix >= 0 {
127-
// Note: entry is not modified. It always refers to a real frame, not an inlined one.
128-
f = nil
129-
ic := inltree[ix]
130-
name = funcnameFromNameOff(funcInfo, ic.nameOff)
131-
startLine = ic.startLine
132-
// File/line from funcline1 below are already correct.
133-
}
119+
// It's important that interpret pc non-strictly as cgoTraceback may
120+
// have added bogus PCs with a valid funcInfo but invalid PCDATA.
121+
u, uf := newInlineUnwinder(funcInfo, pc, nil)
122+
sf := u.srcFunc(uf)
123+
if u.isInlined(uf) {
124+
// Note: entry is not modified. It always refers to a real frame, not an inlined one.
125+
// File/line from funcline1 below are already correct.
126+
f = nil
134127
}
135128
ci.frames = append(ci.frames, Frame{
136129
PC: pc,
137130
Func: f,
138-
Function: name,
131+
Function: sf.name(),
139132
Entry: entry,
140-
startLine: int(startLine),
133+
startLine: int(sf.startLine),
141134
funcInfo: funcInfo,
142135
// Note: File,Line set below
143136
})
@@ -182,6 +175,8 @@ func runtime_FrameStartLine(f *Frame) int {
182175
//
183176
//go:linkname runtime_expandFinalInlineFrame runtime/pprof.runtime_expandFinalInlineFrame
184177
func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr {
178+
// TODO: It would be more efficient to report only physical PCs to pprof and
179+
// just expand the whole stack.
185180
if len(stk) == 0 {
186181
return stk
187182
}
@@ -194,46 +189,29 @@ func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr {
194189
return stk
195190
}
196191

197-
inldata := funcdata(f, _FUNCDATA_InlTree)
198-
if inldata == nil {
199-
// Nothing inline in f.
192+
var cache pcvalueCache
193+
u, uf := newInlineUnwinder(f, tracepc, &cache)
194+
if !u.isInlined(uf) {
195+
// Nothing inline at tracepc.
200196
return stk
201197
}
202198

203199
// Treat the previous func as normal. We haven't actually checked, but
204200
// since this pc was included in the stack, we know it shouldn't be
205201
// elided.
206-
lastFuncID := funcID_normal
202+
calleeID := funcID_normal
207203

208204
// Remove pc from stk; we'll re-add it below.
209205
stk = stk[:len(stk)-1]
210206

211-
// See inline expansion in gentraceback.
212-
var cache pcvalueCache
213-
inltree := (*[1 << 20]inlinedCall)(inldata)
214-
for {
215-
// Non-strict as cgoTraceback may have added bogus PCs
216-
// with a valid funcInfo but invalid PCDATA.
217-
ix := pcdatavalue1(f, _PCDATA_InlTreeIndex, tracepc, &cache, false)
218-
if ix < 0 {
219-
break
220-
}
221-
if inltree[ix].funcID == funcID_wrapper && elideWrapperCalling(lastFuncID) {
207+
for ; uf.valid(); uf = u.next(uf) {
208+
funcID := u.srcFunc(uf).funcID
209+
if funcID == funcID_wrapper && elideWrapperCalling(calleeID) {
222210
// ignore wrappers
223211
} else {
224-
stk = append(stk, pc)
212+
stk = append(stk, uf.pc+1)
225213
}
226-
lastFuncID = inltree[ix].funcID
227-
// Back up to an instruction in the "caller".
228-
tracepc = f.entry() + uintptr(inltree[ix].parentPc)
229-
pc = tracepc + 1
230-
}
231-
232-
// N.B. we want to keep the last parentPC which is not inline.
233-
if f.funcID == funcID_wrapper && elideWrapperCalling(lastFuncID) {
234-
// Ignore wrapper functions (except when they trigger panics).
235-
} else {
236-
stk = append(stk, pc)
214+
calleeID = funcID
237215
}
238216

239217
return stk
@@ -752,28 +730,25 @@ func FuncForPC(pc uintptr) *Func {
752730
if !f.valid() {
753731
return nil
754732
}
755-
if inldata := funcdata(f, _FUNCDATA_InlTree); inldata != nil {
756-
// Note: strict=false so bad PCs (those between functions) don't crash the runtime.
757-
// We just report the preceding function in that situation. See issue 29735.
758-
// TODO: Perhaps we should report no function at all in that case.
759-
// The runtime currently doesn't have function end info, alas.
760-
if ix := pcdatavalue1(f, _PCDATA_InlTreeIndex, pc, nil, false); ix >= 0 {
761-
inltree := (*[1 << 20]inlinedCall)(inldata)
762-
ic := inltree[ix]
763-
name := funcnameFromNameOff(f, ic.nameOff)
764-
file, line := funcline(f, pc)
765-
fi := &funcinl{
766-
ones: ^uint32(0),
767-
entry: f.entry(), // entry of the real (the outermost) function.
768-
name: name,
769-
file: file,
770-
line: line,
771-
startLine: ic.startLine,
772-
}
773-
return (*Func)(unsafe.Pointer(fi))
774-
}
733+
// This must interpret PC non-strictly so bad PCs (those between functions) don't crash the runtime.
734+
// We just report the preceding function in that situation. See issue 29735.
735+
// TODO: Perhaps we should report no function at all in that case.
736+
// The runtime currently doesn't have function end info, alas.
737+
u, uf := newInlineUnwinder(f, pc, nil)
738+
if !u.isInlined(uf) {
739+
return f._Func()
775740
}
776-
return f._Func()
741+
sf := u.srcFunc(uf)
742+
file, line := u.fileLine(uf)
743+
fi := &funcinl{
744+
ones: ^uint32(0),
745+
entry: f.entry(), // entry of the real (the outermost) function.
746+
name: sf.name(),
747+
file: file,
748+
line: int32(line),
749+
startLine: sf.startLine,
750+
}
751+
return (*Func)(unsafe.Pointer(fi))
777752
}
778753

779754
// Name returns the name of the function.
@@ -1059,13 +1034,6 @@ func funcpkgpath(f funcInfo) string {
10591034
return name[:i]
10601035
}
10611036

1062-
func funcnameFromNameOff(f funcInfo, nameOff int32) string {
1063-
if !f.valid() {
1064-
return ""
1065-
}
1066-
return f.datap.funcName(nameOff)
1067-
}
1068-
10691037
func funcfile(f funcInfo, fileno int32) string {
10701038
datap := f.datap
10711039
if !f.valid() {

0 commit comments

Comments
 (0)