From 49383d4eb8e72f142264d7f84664f524dafc4fd6 Mon Sep 17 00:00:00 2001 From: nikandfor Date: Sat, 11 Nov 2023 23:43:10 +0400 Subject: [PATCH] go1.21; fix go1.16 --- README.md | 2 +- name_file_line_go1.12.go | 9 ++--- name_file_line_go1.16.go | 60 +++++++++++++++++++++++++++++++ name_file_line_go1.20.go | 4 +-- name_file_line_go1.21.go | 78 ++++++++++++++++++++++++++++++++++++++++ unsafe_go1.13.go | 6 ++-- unsafe_go1.16.go | 10 ++++++ unsafe_go1.17.go | 10 ------ 8 files changed, 159 insertions(+), 20 deletions(-) create mode 100644 name_file_line_go1.16.go create mode 100644 name_file_line_go1.21.go create mode 100644 unsafe_go1.16.go delete mode 100644 unsafe_go1.17.go diff --git a/README.md b/README.md index 79127a7..28e7d6c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ It's a fast, alloc-free and convinient version of `runtime.Caller`. Performance benefits are available when using the `nikandfor_loc_unsafe` build tag. This relies on the internal runtime implementation, which means that older versions of the package may not compile with future versions of Go. Without the tag, it is safe to use with any version of Go. -It was born from [tlog](https://github.com/nikandfor/tlog). +It was born from [tlog](https://github.com/tlog-dev/tlog). ## What is similar diff --git a/name_file_line_go1.12.go b/name_file_line_go1.12.go index 41f3492..cf9f576 100644 --- a/name_file_line_go1.12.go +++ b/name_file_line_go1.12.go @@ -1,5 +1,5 @@ -//go:build nikandfor_loc_unsafe && !go1.17 -// +build nikandfor_loc_unsafe,!go1.17 +//go:build nikandfor_loc_unsafe && !go1.16 +// +build nikandfor_loc_unsafe,!go1.16 package loc @@ -24,8 +24,6 @@ func (l PC) nameFileLine() (name, file string, line int) { } name = funcname(funcInfo) - file, line32 := funcline1(funcInfo, l, false) - line = int(line32) if inldata := funcdata(funcInfo, _FUNCDATA_InlTree); inldata != nil { ix := pcdatavalue(funcInfo, _PCDATA_InlTreeIndex, l, nil) if ix >= 0 { @@ -37,6 +35,9 @@ func (l PC) nameFileLine() (name, file string, line int) { } } + file, line32 := funcline1(funcInfo, l, false) + line = int(line32) + return } diff --git a/name_file_line_go1.16.go b/name_file_line_go1.16.go new file mode 100644 index 0000000..1d1eb17 --- /dev/null +++ b/name_file_line_go1.16.go @@ -0,0 +1,60 @@ +//go:build nikandfor_loc_unsafe && go1.16 && !go1.17 +// +build nikandfor_loc_unsafe,go1.16,!go1.17 + +package loc + +import "unsafe" + +func (l PC) nameFileLine() (name, file string, line int) { + if l == 0 { + return + } + + funcInfo := findfunc(l) + if funcInfo.entry == nil { + return + } + + if uintptr(l) > *funcInfo.entry { + // We store the pc of the start of the instruction following + // the instruction in question (the call or the inline mark). + // This is done for historical reasons, and to make FuncForPC + // work correctly for entries in the result of runtime.Callers. + l-- + } + + name = funcname(funcInfo) + if inldata := funcdata(funcInfo, _FUNCDATA_InlTree); inldata != nil { + ix := pcdatavalue1(funcInfo, _PCDATA_InlTreeIndex, l, nil, false) + if ix >= 0 { + inltree := (*[1 << 20]inlinedCall)(inldata) + // Note: entry is not modified. It always refers to a real frame, not an inlined one. + name = funcnameFromNameoff(funcInfo, inltree[ix].func_) + // File/line is already correct. + // TODO: remove file/line from InlinedCall? + } + } + + file, line32 := funcline1(funcInfo, l, false) + line = int(line32) + + return +} + +//go:linkname findfunc runtime.findfunc +func findfunc(pc PC) funcInfo + +//go:linkname funcline1 runtime.funcline1 +func funcline1(f funcInfo, targetpc PC, strict bool) (file string, line int32) + +//go:linkname funcname runtime.funcname +func funcname(f funcInfo) string + +//go:linkname funcdata runtime.funcdata +func funcdata(f funcInfo, i uint8) unsafe.Pointer + +//go:linkname pcdatavalue1 runtime.pcdatavalue1 +func pcdatavalue1(f funcInfo, table int32, targetpc PC, cache unsafe.Pointer, strict bool) int32 + +//go:linkname funcnameFromNameoff runtime.funcnameFromNameoff +func funcnameFromNameoff(f funcInfo, nameoff int32) string diff --git a/name_file_line_go1.20.go b/name_file_line_go1.20.go index b1ed077..e7b9c09 100644 --- a/name_file_line_go1.20.go +++ b/name_file_line_go1.20.go @@ -1,5 +1,5 @@ -//go:build nikandfor_loc_unsafe && go1.20 -// +build nikandfor_loc_unsafe,go1.20 +//go:build nikandfor_loc_unsafe && go1.20 && !go1.21 +// +build nikandfor_loc_unsafe,go1.20,!go1.21 package loc diff --git a/name_file_line_go1.21.go b/name_file_line_go1.21.go new file mode 100644 index 0000000..846f5c6 --- /dev/null +++ b/name_file_line_go1.21.go @@ -0,0 +1,78 @@ +//go:build nikandfor_loc_unsafe && go1.21 +// +build nikandfor_loc_unsafe,go1.21 + +package loc + +import "unsafe" + +type ( + inlineUnwinder struct { + f funcInfo + cache *uintptr + inlTree *uintptr + } + + inlineFrame struct { + pc uintptr + index int32 + } + + srcFunc struct { + datap *uintptr + nameOff int32 + startLine int32 + funcID funcID + } +) + +func (l PC) nameFileLine() (name, file string, line int) { + funcInfo := findfunc(l) + if funcInfo._func == nil { + return + } + + entry := funcInfoEntry(funcInfo) + + if l > entry { + // We store the pc of the start of the instruction following + // the instruction in question (the call or the inline mark). + // This is done for historical reasons, and to make FuncForPC + // work correctly for entries in the result of runtime.Callers. + l-- + } + + // It's important that interpret pc non-strictly as cgoTraceback may + // have added bogus PCs with a valid funcInfo but invalid PCDATA. + u, uf := newInlineUnwinder(funcInfo, l, nil) + sf := inlineUnwinder_srcFunc(&u, uf) + + name = funcNameForPrint(srcFunc_name(sf)) + file, line32 := funcline1(funcInfo, l, false) + line = int(line32) + + return +} + +//go:linkname findfunc runtime.findfunc +func findfunc(pc PC) funcInfo + +//go:linkname funcInfoEntry runtime.funcInfo.entry +func funcInfoEntry(f funcInfo) PC + +//go:linkname newInlineUnwinder runtime.newInlineUnwinder +func newInlineUnwinder(f funcInfo, pc PC, cache unsafe.Pointer) (inlineUnwinder, inlineFrame) + +//go:linkname inlineUnwinder_srcFunc runtime.(*inlineUnwinder).srcFunc +func inlineUnwinder_srcFunc(*inlineUnwinder, inlineFrame) srcFunc + +//go:linkname inlineUnwinder_isInlined runtime.(*inlineUnwinder).isInlined +func inlineUnwinder_isInlined(*inlineUnwinder, inlineFrame) bool + +//go:linkname srcFunc_name runtime.srcFunc.name +func srcFunc_name(srcFunc) string + +//go:linkname funcNameForPrint runtime.funcNameForPrint +func funcNameForPrint(name string) string + +//go:linkname funcline1 runtime.funcline1 +func funcline1(f funcInfo, targetpc PC, strict bool) (file string, line int32) diff --git a/unsafe_go1.13.go b/unsafe_go1.13.go index e8034f8..e440f12 100644 --- a/unsafe_go1.13.go +++ b/unsafe_go1.13.go @@ -1,9 +1,9 @@ -//go:build nikandfor_loc_unsafe && go1.13 && !go1.17 -// +build nikandfor_loc_unsafe,go1.13,!go1.17 +//go:build nikandfor_loc_unsafe && go1.13 && !go1.16 +// +build nikandfor_loc_unsafe,go1.13,!go1.16 package loc -//nolint +// nolint const ( _PCDATA_InlTreeIndex = 2 _FUNCDATA_InlTree = 4 diff --git a/unsafe_go1.16.go b/unsafe_go1.16.go new file mode 100644 index 0000000..4983eac --- /dev/null +++ b/unsafe_go1.16.go @@ -0,0 +1,10 @@ +//go:build nikandfor_loc_unsafe && go1.16 +// +build nikandfor_loc_unsafe,go1.16 + +package loc + +// nolint +const ( + _PCDATA_InlTreeIndex = 2 + _FUNCDATA_InlTree = 3 +) diff --git a/unsafe_go1.17.go b/unsafe_go1.17.go deleted file mode 100644 index 26d3122..0000000 --- a/unsafe_go1.17.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build nikandfor_loc_unsafe && go1.17 -// +build nikandfor_loc_unsafe,go1.17 - -package loc - -//nolint -const ( - _PCDATA_InlTreeIndex = 2 - _FUNCDATA_InlTree = 3 -)