Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

runtime.Callers and branch delay slot

738 views
Skip to first unread message

cherry

unread,
Sep 29, 2015, 6:50:24 PM9/29/15
to golan...@googlegroups.com, Ian Lance Taylor, minux
Hi Gophers,

The doc of runtime.Callers says
> Callers fills the slice pc with the return program counters
and also
> To look up the file and line number of the call itself, use pc[i]-1

The two points become conflict when the return pc is not right
following the CALL instruction, for example, with branch delay slot
between them on architectures like MIPS. CL 14990 brings up the
question.

In order to work with this circumstance, we could either return the
"return pc" (which breaks "pc-1" idiom), or return the pc right after
the CALL instruction, i.e. the delay slot, so "pc-1" still work (but
breaks "return pc" spec). Either way, it needs some adjustment of the
doc. Any suggestions?

Is the main purpose of this function to look up the file/line
information of the CALL instructions? If so, I would go with Ian's
suggestion, keeping the "pc-1" idiom.

BTW, runtime.Caller is fine, as it returns the pc of CALL instruction directly.

Thanks,
Cherry

Aram Hăvărneanu

unread,
Sep 29, 2015, 11:41:08 PM9/29/15
to cherry, golang-dev, Ian Lance Taylor, minux
SPARC has the same problem. I have no preference either way. I can see
advantages to preserving either property.

--
Aram Hăvărneanu

Ian Lance Taylor

unread,
Sep 30, 2015, 5:02:54 PM9/30/15
to cherry, golan...@googlegroups.com, minux
My opinion is that we should preserve the documented property, which
is: "To look up the file and line number of the call itself, use pc[i]-1."

Then we should define a new function, perhaps runtime.SkipCallDelaySlot,
which takes a PC value returned by runtime.Callers and returns the PC
value of the next instruction to be executed when the call returns.

Ian

Austin Clements

unread,
Sep 30, 2015, 5:28:06 PM9/30/15
to Ian Lance Taylor, cherry, golan...@googlegroups.com, minux, David Chase
If we're going to introduce a new API, I'd suggest that rather than baking in notions of delay slots and specific calculations to be done by the caller, it simply return an object that records both the call PC and the return PC. I think returning an object representing the frame would also put us on better ground to return information about inlined calls in the future.

Ian Lance Taylor

unread,
Sep 30, 2015, 6:49:00 PM9/30/15
to Austin Clements, cherry, golan...@googlegroups.com, minux, David Chase
That is a good point. runtime.Callers is definitely a thorn in the
side of gccgo.

Still, we have to decide what to do with runtime.Callers. Perhaps we
should just keep the pc[i]-1 property for mips, and postpone
considerations of a more complex API until somebody is ready to tackle
that.

Ian

David Chase

unread,
Sep 30, 2015, 10:19:34 PM9/30/15
to Ian Lance Taylor, Austin Clements, cherry, golan...@googlegroups.com, minux
And also, we need to break the 1-1 correspondence between PC and file+line.  If we ever do inlining that is not all the way to the leaves, we'll find ourselves with a PC that corresponds to "g() from G.go, line 1171, inlined at f() from F.go, line 635".  As long as we have an interface that can't express this we're going to have an annoying tension between inlining/optimization and ability to debug code.

I've done this before for a static Java compiler, I'd be happy to put it on my list or talk to someone else who wants to work on this.

Chris Hines

unread,
Oct 5, 2015, 11:55:23 AM10/5/15
to golang-dev, ia...@golang.org, aus...@google.com, luna...@gmail.com, mi...@golang.org
Since we're griping about runtime.Callers...

I have authored gopkg.in/stack.v1 (docs: https://godoc.org/gopkg.in/stack.v1), which attempts to simplify use of the runtime.Callers API.

One of the challenges the package faces is handling the documented exception:

To look up the file and line number of the call itself, use pc[i]-1. As an exception to this rule, if pc[i-1] corresponds to the function runtime.sigpanic, then pc[i] is the program counter of a faulting instruction and should be used without any subtraction.

It is unfortunate that code consuming this API must deal with a special case that involves an unexported function name. In addition to the leakage of internal details, checking the rule outside of the runtime package requires calling FuncForPC (fast) and Func.Name (slow). In my benchmarks, Func.Name takes roughly five times as long as FuncForPC. To eliminate the extra overhead, the above package caches the *runtime.Func for runtime.sigpanic during initialization (code: https://github.com/go-stack/stack/blob/v1.4.0/stack.go#L239). Using this hack allows stack.Caller to perform on par with runtime.Caller and improves the performance of stack.Trace by roughly 30% compared to calling Func.Name on each loop iteration.

It would be nice if any improvements made to the runtime.Caller and runtime.Func related APIs either eliminated this special case, or made it easier to check for.

I like Austin's suggestion for an API that explicitly provides the return PC. I believe that is what most external consumers actually want.

Chris

minux

unread,
Oct 26, 2015, 11:46:35 PM10/26/15
to cherry, golang-dev, Ian Lance Taylor
Given that Russ proposed that we disable instruction scheduling on MIPS,
we have yet another solution to the problem.

We can make liblink treat each CALL/JMP instruction as a special 8-byte
macro instruction that also contains the NOP delay slot.

Then pc[i]-1 will indeed point to the CALL instruction, and then all the existing
documentation will be correct as is.

What do you think?

Ian Lance Taylor

unread,
Oct 27, 2015, 9:01:15 PM10/27/15
to minux, cherry, golang-dev
Works for me for now.

Ian

cherry

unread,
Oct 28, 2015, 8:18:15 AM10/28/15
to Ian Lance Taylor, minux, golang-dev
I updated the CLs so that it always fills the delay slot with NOP.
Runtime.Caller does nothing special for MIPS now, since the NOP has
the same line number as the CALL instruction.
Thanks.
Reply all
Reply to author
Forward
0 new messages