]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime: avoid repeated findmoduledatap calls
authorAustin Clements <austin@google.com>
Tue, 21 Feb 2017 03:37:07 +0000 (22:37 -0500)
committerAustin Clements <austin@google.com>
Mon, 6 Mar 2017 19:17:24 +0000 (19:17 +0000)
Currently almost every function that deals with a *_func has to first
look up the *moduledata for the module containing the function's entry
point. This means we almost always do at least two identical module
lookups whenever we deal with a *_func (one to get the *_func and
another to get something from its module data) and sometimes several
more.

Fix this by making findfunc return a new funcInfo type that embeds
*_func, but also includes the *moduledata, and making all of the
functions that currently take a *_func instead take a funcInfo and use
the already-found *moduledata.

This transformation is trivial for the most part, since the *_func
type is usually inferred. The annoying part is that we can no longer
use nil to indicate failure, so this introduces a funcInfo.valid()
method and replaces nil checks with calls to valid.

Change-Id: I9b8075ef1c31185c1943596d96dec45c7ab5100f
Reviewed-on: https://go-review.googlesource.com/37331
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
20 files changed:
src/runtime/extern.go
src/runtime/heapdump.go
src/runtime/mbitmap.go
src/runtime/os3_plan9.go
src/runtime/plugin.go
src/runtime/proc.go
src/runtime/race.go
src/runtime/runtime2.go
src/runtime/signal_386.go
src/runtime/signal_amd64x.go
src/runtime/signal_arm.go
src/runtime/signal_arm64.go
src/runtime/signal_linux_s390x.go
src/runtime/signal_mips64x.go
src/runtime/signal_mipsx.go
src/runtime/signal_ppc64x.go
src/runtime/stack.go
src/runtime/symtab.go
src/runtime/trace.go
src/runtime/traceback.go

index ddcb81fdc73244e3e3da5ecf3b7ab7e7313f63ce..896bfc4fcb366107419926fa6c22ffcf05677178 100644 (file)
@@ -174,7 +174,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
                return
        }
        f := findfunc(rpc[1])
-       if f == nil {
+       if !f.valid() {
                // TODO(rsc): Probably a bug?
                // The C version said "have retpc at least"
                // but actually returned pc=0.
@@ -187,7 +187,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
        // All architectures turn faults into apparent calls to sigpanic.
        // If we see a call to sigpanic, we do not back up the PC to find
        // the line number of the call instruction, because there is no call.
-       if xpc > f.entry && (g == nil || g.entry != funcPC(sigpanic)) {
+       if xpc > f.entry && (!g.valid() || g.entry != funcPC(sigpanic)) {
                xpc--
        }
        file, line32 := funcline(f, xpc)
index 32e393db2bd20e94fcd6dc2f44126348ccc4bfa3..35f6124643c86f2c9c22887723ad26fe060a96df 100644 (file)
@@ -565,7 +565,7 @@ func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs,
        for i := uintptr(0); i < nstk; i++ {
                pc := stk[i]
                f := findfunc(pc)
-               if f == nil {
+               if !f.valid() {
                        var buf [64]byte
                        n := len(buf)
                        n--
index 7bead96904bf64c1ee6bf87f5057c7ed34e8b58f..3e782f50da0f0a7f46becd19a52770b7285059a9 100644 (file)
@@ -1877,7 +1877,7 @@ func getgcmask(ep interface{}) (mask []byte) {
                frame.sp = uintptr(p)
                _g_ := getg()
                gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0)
-               if frame.fn != nil {
+               if frame.fn.valid() {
                        f := frame.fn
                        targetpc := frame.continpc
                        if targetpc == 0 {
index 5aa6b67a859e6e1d622e0e8804f71f5173f029ac..5d4b5a6698fac0c514bde81c070d63f183e391df 100644 (file)
@@ -62,7 +62,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
                // but we do recognize the top pointer on the stack as code,
                // then assume this was a call to non-code and treat like
                // pc == 0, to make unwinding show the context.
-               if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+               if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
                        pc = 0
                }
 
index ea246509ccbe7d949286f485909b26ce73a16bb3..682caacb21bdeec4eec96bc8b42e9ddfa7228477 100644 (file)
@@ -95,7 +95,7 @@ func pluginftabverify(md *moduledata) {
                        continue
                }
 
-               f := (*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff]))
+               f := funcInfo{(*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff])), md}
                name := funcname(f)
 
                // A common bug is f.entry has a relocation to a duplicate
@@ -104,7 +104,7 @@ func pluginftabverify(md *moduledata) {
                name2 := "none"
                entry2 := uintptr(0)
                f2 := findfunc(entry)
-               if f2 != nil {
+               if f2.valid() {
                        name2 = funcname(f2)
                        entry2 = f2.entry
                }
index 722bdf7b3954335011047d5399e29e2a25dd0d9d..c9c451351c77701003038a095d59a72aa39d92e5 100644 (file)
@@ -3336,7 +3336,7 @@ func sigprofNonGoPC(pc uintptr) {
 // or putting one on the stack at the right offset.
 func setsSP(pc uintptr) bool {
        f := findfunc(pc)
-       if f == nil {
+       if !f.valid() {
                // couldn't find the function for this PC,
                // so assume the worst and stop traceback
                return true
index 1034e35cebba563bff835e4af13539fe5ce751c4..49495cc78357bfccd449b06f283ae4150f273e8d 100644 (file)
@@ -98,7 +98,7 @@ func raceSymbolizeCode(ctx *symbolizeCodeContext) {
        if f != nil {
                file, line := f.FileLine(ctx.pc)
                if line != 0 {
-                       ctx.fn = cfuncname(f.raw())
+                       ctx.fn = cfuncname(f.funcInfo())
                        ctx.line = uintptr(line)
                        ctx.file = &bytes(file)[0] // assume NUL-terminated
                        ctx.off = ctx.pc - f.Entry()
index 7c1591994efefa82ab58aa21e1e879228bf5641f..8b6bddf456eb0f2aed52ee6591c7c0854eb742ee 100644 (file)
@@ -685,7 +685,7 @@ type _panic struct {
 
 // stack traces
 type stkframe struct {
-       fn       *_func     // function being run
+       fn       funcInfo   // function being run
        pc       uintptr    // program counter within fn
        continpc uintptr    // program counter where execution can continue, or 0 if not
        lr       uintptr    // program counter at caller aka link register
index 8807552da220833e96cc76832349adb476cd8414..416c7c2715dc630892231d46dc44dae503702df0 100644 (file)
@@ -60,7 +60,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        // but we do recognize the top pointer on the stack as code,
        // then assume this was a call to non-code and treat like
        // pc == 0, to make unwinding show the context.
-       if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+       if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
                pc = 0
        }
 
index c8a6513261d28d303b0be11dc7d845215c10a885..fad5fc0f8aed1993a5964b172f82b87a48ccfe18 100644 (file)
@@ -71,7 +71,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        // but we do recognize the top pointer on the stack as code,
        // then assume this was a call to non-code and treat like
        // pc == 0, to make unwinding show the context.
-       if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+       if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
                pc = 0
        }
 
index 9748544e0e2cf4183fdc3ad1fb1860fca5a3909d..d00b225ef65e3110eccdd664caaba11e9c34ba01 100644 (file)
@@ -57,7 +57,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        // but we do recognize the link register as code,
        // then assume this was a call to non-code and treat like
        // pc == 0, to make unwinding show the context.
-       if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
+       if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.lr())).valid() {
                pc = 0
        }
 
index 4c6df425d82dc9007f04072eb2043705e7057af2..1db052538c139841a429ad5e8ee81c942a9b8296 100644 (file)
@@ -73,7 +73,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        // but we do recognize the link register as code,
        // then assume this was a call to non-code and treat like
        // pc == 0, to make unwinding show the context.
-       if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
+       if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.lr())).valid() {
                pc = 0
        }
 
index de71ee950d3bb0e46991bf8444619689c05e3037..a31f4364117d7e5167006bca401feb8a6bf7d480 100644 (file)
@@ -103,7 +103,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        // but we do recognize the link register as code,
        // then assume this was a call to non-code and treat like
        // pc == 0, to make unwinding show the context.
-       if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+       if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
                pc = 0
        }
 
index 973ec2dc36335d96b1f56959d37e7a1810cfa154..9546a5af997bc49a7a52be35d8b00c420f97c21e 100644 (file)
@@ -77,7 +77,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        // but we do recognize the link register as code,
        // then assume this was a call to non-code and treat like
        // pc == 0, to make unwinding show the context.
-       if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+       if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
                pc = 0
        }
 
index 62df79caeb40374bfc1d5ef9b5b5ea633af63a06..1c545ec8cb9ab3917c356349c1b1d90293828fea 100644 (file)
@@ -74,7 +74,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        // but we do recognize the link register as code,
        // then assume this was a call to non-code and treat like
        // pc == 0, to make unwinding show the context.
-       if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+       if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
                pc = 0
        }
 
index f09f890aeee9030f147d7d8b801ac158914ffa42..03cb996f3fde4a8a0e76f8a756087c31c4050ad0 100644 (file)
@@ -78,7 +78,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        // but we do recognize the link register as code,
        // then assume this was a call to non-code and treat like
        // pc == 0, to make unwinding show the context.
-       if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+       if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
                pc = 0
        }
 
index d6a4e4ea801f9ffd32d61f28f9d08f16a9604bd9..92b8a2b921d49bbebd5e400450bcc058b564bf82 100644 (file)
@@ -569,7 +569,7 @@ func ptrbit(bv *gobitvector, i uintptr) uint8 {
 
 // bv describes the memory starting at address scanp.
 // Adjust any pointers contained therein.
-func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f *_func) {
+func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f funcInfo) {
        bv := gobv(*cbv)
        minp := adjinfo.old.lo
        maxp := adjinfo.old.hi
@@ -589,7 +589,7 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
                        pp := (*uintptr)(add(scanp, i*sys.PtrSize))
                retry:
                        p := *pp
-                       if f != nil && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
+                       if f.valid() && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
                                // Looks like a junk value in a pointer slot.
                                // Live analysis wrong?
                                getg().m.traceback = 2
@@ -713,7 +713,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
                if stackDebug >= 3 {
                        print("      args\n")
                }
-               adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, nil)
+               adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, funcInfo{})
        }
        return true
 }
index b16e5445bd1872a81ba9e48d3e2a5a07ac916dd9..a31cf55c29c3cc97fcbc8ff032aafdbba5e4e88e 100644 (file)
@@ -157,7 +157,8 @@ func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) {
 // NOTE: Func does not expose the actual unexported fields, because we return *Func
 // values to users, and we want to keep them from being able to overwrite the data
 // with (say) *f = Func{}.
-// All code operating on a *Func must call raw to get the *_func instead.
+// All code operating on a *Func must call raw() to get the *_func
+// or funcInfo() to get the funcInfo instead.
 
 // A Func represents a Go function in the running binary.
 type Func struct {
@@ -168,6 +169,11 @@ func (f *Func) raw() *_func {
        return (*_func)(unsafe.Pointer(f))
 }
 
+func (f *Func) funcInfo() funcInfo {
+       fn := f.raw()
+       return funcInfo{fn, findmoduledatap(fn.entry)}
+}
+
 // PCDATA and FUNCDATA table indexes.
 //
 // See funcdata.h and ../cmd/internal/obj/funcdata.go.
@@ -365,15 +371,15 @@ func moduledataverify1(datap *moduledata) {
        for i := 0; i < nftab; i++ {
                // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
                if datap.ftab[i].entry > datap.ftab[i+1].entry {
-                       f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
-                       f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
+                       f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
+                       f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
                        f2name := "end"
                        if i+1 < nftab {
                                f2name = funcname(f2)
                        }
                        println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
                        for j := 0; j <= i; j++ {
-                               print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
+                               print("\t", hex(datap.ftab[j].entry), " ", funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}), "\n")
                        }
                        throw("invalid runtime symbol table")
                }
@@ -386,10 +392,10 @@ func moduledataverify1(datap *moduledata) {
                        // But don't use the next PC if it corresponds to a foreign object chunk
                        // (no pcln table, f2.pcln == 0). That chunk might have an alignment
                        // more than 16 bytes.
-                       f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
+                       f := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
                        end := f.entry
                        if i+1 < nftab {
-                               f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
+                               f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
                                if f2.pcln != 0 {
                                        end = f2.entry - 16
                                        if end < f.entry {
@@ -419,12 +425,12 @@ func moduledataverify1(datap *moduledata) {
 // FuncForPC returns a *Func describing the function that contains the
 // given program counter address, or else nil.
 func FuncForPC(pc uintptr) *Func {
-       return (*Func)(unsafe.Pointer(findfunc(pc)))
+       return (*Func)(unsafe.Pointer(findfunc(pc)._func))
 }
 
 // Name returns the name of the function.
 func (f *Func) Name() string {
-       return funcname(f.raw())
+       return funcname(f.funcInfo())
 }
 
 // Entry returns the entry address of the function.
@@ -439,7 +445,7 @@ func (f *Func) Entry() uintptr {
 func (f *Func) FileLine(pc uintptr) (file string, line int) {
        // Pass strict=false here, because anyone can call this function,
        // and they might just be wrong about targetpc belonging to f.
-       file, line32 := funcline1(f.raw(), pc, false)
+       file, line32 := funcline1(f.funcInfo(), pc, false)
        return file, int(line32)
 }
 
@@ -452,10 +458,19 @@ func findmoduledatap(pc uintptr) *moduledata {
        return nil
 }
 
-func findfunc(pc uintptr) *_func {
+type funcInfo struct {
+       *_func
+       datap *moduledata
+}
+
+func (f funcInfo) valid() bool {
+       return f._func != nil
+}
+
+func findfunc(pc uintptr) funcInfo {
        datap := findmoduledatap(pc)
        if datap == nil {
-               return nil
+               return funcInfo{}
        }
        const nsub = uintptr(len(findfuncbucket{}.subbuckets))
 
@@ -491,7 +506,7 @@ func findfunc(pc uintptr) *_func {
                        idx++
                }
        }
-       return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
+       return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])), datap}
 }
 
 type pcvalueCache struct {
@@ -506,7 +521,7 @@ type pcvalueCacheEnt struct {
        val int32
 }
 
-func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
+func pcvalue(f funcInfo, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
        if off == 0 {
                return -1
        }
@@ -530,14 +545,14 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
                }
        }
 
-       datap := findmoduledatap(f.entry) // inefficient
-       if datap == nil {
+       if !f.valid() {
                if strict && panicking == 0 {
                        print("runtime: no module data for ", hex(f.entry), "\n")
                        throw("no module data")
                }
                return -1
        }
+       datap := f.datap
        p := datap.pclntable[off:]
        pc := f.entry
        val := int32(-1)
@@ -589,41 +604,37 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
        return -1
 }
 
-func cfuncname(f *_func) *byte {
-       if f == nil || f.nameoff == 0 {
-               return nil
-       }
-       datap := findmoduledatap(f.entry) // inefficient
-       if datap == nil {
+func cfuncname(f funcInfo) *byte {
+       if !f.valid() || f.nameoff == 0 {
                return nil
        }
-       return &datap.pclntable[f.nameoff]
+       return &f.datap.pclntable[f.nameoff]
 }
 
-func funcname(f *_func) string {
+func funcname(f funcInfo) string {
        return gostringnocopy(cfuncname(f))
 }
 
-func funcnameFromNameoff(f *_func, nameoff int32) string {
-       datap := findmoduledatap(f.entry) // inefficient
-       if datap == nil {
+func funcnameFromNameoff(f funcInfo, nameoff int32) string {
+       datap := f.datap
+       if !f.valid() {
                return ""
        }
        cstr := &datap.pclntable[nameoff]
        return gostringnocopy(cstr)
 }
 
-func funcfile(f *_func, fileno int32) string {
-       datap := findmoduledatap(f.entry) // inefficient
-       if datap == nil {
+func funcfile(f funcInfo, fileno int32) string {
+       datap := f.datap
+       if !f.valid() {
                return "?"
        }
        return gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
 }
 
-func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
-       datap := findmoduledatap(f.entry) // inefficient
-       if datap == nil {
+func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
+       datap := f.datap
+       if !f.valid() {
                return "?", 0
        }
        fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict))
@@ -636,11 +647,11 @@ func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32
        return
 }
 
-func funcline(f *_func, targetpc uintptr) (file string, line int32) {
+func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
        return funcline1(f, targetpc, true)
 }
 
-func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
+func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
        x := pcvalue(f, f.pcsp, targetpc, cache, true)
        if x&(sys.PtrSize-1) != 0 {
                print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
@@ -648,7 +659,7 @@ func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
        return x
 }
 
-func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
+func pcdatavalue(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
        if table < 0 || table >= f.npcdata {
                return -1
        }
@@ -656,14 +667,14 @@ func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) i
        return pcvalue(f, off, targetpc, cache, true)
 }
 
-func funcdata(f *_func, i int32) unsafe.Pointer {
+func funcdata(f funcInfo, i int32) unsafe.Pointer {
        if i < 0 || i >= f.nfuncdata {
                return nil
        }
        p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
        if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
-               if uintptr(unsafe.Pointer(f))&4 != 0 {
-                       println("runtime: misaligned func", f)
+               if uintptr(unsafe.Pointer(f._func))&4 != 0 {
+                       println("runtime: misaligned func", f._func)
                }
                p = add(p, 4)
        }
index 9f319cd5702c9eb83904dd85964ae503f83b0ce0..c29c162333b1d875a8dbc62e85a6d48276dd3c2d 100644 (file)
@@ -816,7 +816,7 @@ func traceFrameForPC(buf *traceBuf, frames map[uintptr]traceFrame, pc uintptr) (
 
        var frame traceFrame
        f := findfunc(pc)
-       if f == nil {
+       if !f.valid() {
                frames[pc] = frame
                return frame, buf
        }
index 39ef8a2a6408d682a917684501d2c9a89085ffb2..f72b068516aa19fc73271fcf23eb827b46741c65 100644 (file)
@@ -92,14 +92,14 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
                if fn == nil {
                        // Defer of nil function. Args don't matter.
                        frame.pc = 0
-                       frame.fn = nil
+                       frame.fn = funcInfo{}
                        frame.argp = 0
                        frame.arglen = 0
                        frame.argmap = nil
                } else {
                        frame.pc = fn.fn
                        f := findfunc(frame.pc)
-                       if f == nil {
+                       if !f.valid() {
                                print("runtime: unknown pc in defer ", hex(frame.pc), "\n")
                                throw("unknown pc")
                        }
@@ -186,7 +186,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
        }
 
        f := findfunc(frame.pc)
-       if f == nil {
+       if !f.valid() {
                if callback != nil {
                        print("runtime: unknown pc ", hex(frame.pc), "\n")
                        throw("unknown pc")
@@ -230,10 +230,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                                frame.fp += sys.RegSize
                        }
                }
-               var flr *_func
+               var flr funcInfo
                if topofstack(f) {
                        frame.lr = 0
-                       flr = nil
+                       flr = funcInfo{}
                } else if usesLR && f.entry == jmpdeferPC {
                        // jmpdefer modifies SP/LR/PC non-atomically.
                        // If a profiling interrupt arrives during jmpdefer,
@@ -259,7 +259,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                                }
                        }
                        flr = findfunc(frame.lr)
-                       if flr == nil {
+                       if !flr.valid() {
                                // This happens if you get a profiling interrupt at just the wrong time.
                                // In that context it is okay to stop early.
                                // But if callback is set, we're doing a garbage collection and must
@@ -403,7 +403,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                waspanic = f.entry == sigpanicPC
 
                // Do not unwind past the bottom of the stack.
-               if flr == nil {
+               if !flr.valid() {
                        break
                }
 
@@ -426,7 +426,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                        }
                        f = findfunc(frame.pc)
                        frame.fn = f
-                       if f == nil {
+                       if !f.valid() {
                                frame.pc = x
                        } else if funcspdelta(f, frame.pc, &cache) == 0 {
                                frame.lr = x
@@ -521,7 +521,7 @@ type reflectMethodValue struct {
 // call, ctxt must be nil (getArgInfo will retrieve what it needs from
 // the active stack frame). If this is a deferred call, ctxt must be
 // the function object that was deferred.
-func getArgInfo(frame *stkframe, f *_func, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
+func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
        arglen = uintptr(f.args)
        if needArgMap && f.args == _ArgsSizeUnknown {
                // Extract argument bitmaps for reflect stubs from the calls they made to reflect.
@@ -593,7 +593,7 @@ func printcreatedby(gp *g) {
        // Show what created goroutine, except main goroutine (goid 1).
        pc := gp.gopc
        f := findfunc(pc)
-       if f != nil && showframe(f, gp, false) && gp.goid != 1 {
+       if f.valid() && showframe(f, gp, false) && gp.goid != 1 {
                print("created by ", funcname(f), "\n")
                tracepc := pc // back up to CALL instruction for funcline.
                if pc > f.entry {
@@ -673,7 +673,7 @@ func gcallers(gp *g, skip int, pcbuf []uintptr) int {
        return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
 }
 
-func showframe(f *_func, gp *g, firstFrame bool) bool {
+func showframe(f funcInfo, gp *g, firstFrame bool) bool {
        g := getg()
        if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
                return true
@@ -690,7 +690,7 @@ func showframe(f *_func, gp *g, firstFrame bool) bool {
                return true
        }
 
-       return level > 1 || f != nil && contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
+       return level > 1 || f.valid() && contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
 }
 
 // isExportedRuntime reports whether name is an exported runtime function.
@@ -781,7 +781,7 @@ func tracebackothers(me *g) {
 }
 
 // Does f mark the top of a goroutine stack?
-func topofstack(f *_func) bool {
+func topofstack(f funcInfo) bool {
        pc := f.entry
        return pc == goexitPC ||
                pc == mstartPC ||