Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8340973

add ability to recognize and hide stack frames which compute nothing to the future of a computation

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • None
    • hotspot

      When debugging some highly factored code, such as streams or method handles, a backtrace shows a large number of active frames. Some of these frames are relatively unimportant, since they just transfer control from one bit of factored code to another.

      Some of the methods that do this are marked `@Hidden` in the JDK. That helps with some code. One problem with that is that a hidden stack frame might do some work that is important to know about, and then hand off control to another block of code, without returning. So only the most trivial "shim" methods should be marked hidden.

      In very many cases, some particular method finishes all of its work, except for a final call to a second method that then handles the future of the computation requested by the caller of the first method. For most purposes, it is as if the caller of the first method invokes the first method, and then invokes the second method as well, forgetting about the first method. But on the backtrace both the now-useless first method, and the second method are visible as active stack frames. In very many cases, it is equally informative to show just the second method, not the first, as if it were activated by the original caller of the first method.

      int callerm(int x) {
         int v = firstm(x, 42);
        ...
      }
      int firstm(int x, int y) {
         int w = foo(x); // work proper to firstm
        return secondm(y, w);
      }
      int foo(int x) {
         …this is a helper for firstm; its caller is firstm (and then callerm before)
      }
      int secondm(int y, int z) {
        … at this point, firstm will do no future computation
        … it would be reasonable to hide firstm and show callerm as previous frame
        … if the user needs more historical information, un-hiding will expose firstm
      }


      As a technical term, we say that firstm performs a "tail call" to secondm. After a tail call, the immediate caller has no more contribution to the computation, and can be safely ignored (unless additional historical information is desired). In some systems, tail calls actually delete the caller frame ("firstm" here), but the JVM is not able to do this. However, the JVM can hide such frames, with a modest pattern match on the fly.

      The pattern match would be as follows, by inspecting the code for the frame of some method M that is being considered for hiding ("firstm"), at the point (BCI) where the callee from M ("secondm") will return to. Call that point the "continuation point" or "CP" of that frame.

      1. If M has any exception handler for the CP, do not hide.
      2. If M is not in the same package as either its caller or callee, do not hide.
      3. If the CP is not a return instruction (of some type), do not hide.
      4. If the CP is a non-void return, and the called method is void, do not hide.

      All of these conditions can be evaluated easily during a stack walk. If none of them are true, the method M is logically (though not physically) a tail call, and can be hidden.

      Additional criteria might be developed, such as allowing the CP to perform very simple conversions, such as a single checkcast, before returning. For such purposes, the CP can be regarded as the instruction after the simple conversion, such as the checkcast instruction. The theory of this would be that the checkcast adds so little value to the computation (because it presumably never fails) that the invocation of M is "close enough" to a logical tail call. Such a checkcast is routine in generic code.

      The HotSpot -XX:+ShowHiddenFrames flag would show hidden tail-call frames as well as what it shows today, frames marked `@Hidden`. This annotation is not helpful in the case where the method (such as "firstm") performs useful work (like "foo") that merits mention in a stack trace, while the useful work is in progress.

            Unassigned Unassigned
            jrose John Rose
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: