JDK-7034585 : Adjust fillInStackTrace filtering to assist 6998871
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: hs21
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-04-07
  • Updated: 2011-07-29
  • Resolved: 2011-04-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 Other
7Fixed hs21Fixed
Related Reports
Relates :  
When an exception is created, fillInStacktrace is called to populate the backtrace information. This is done in java_lang_Throwable::fill_in_stack_trace in the VM. Because the interesting part of the stacktrace is from the location where the exception was created, and upwards, filtering is applied in fill_in_stack_trace to remove the entry for fillInStackTrace() itself, and the exception constructors.

The current filtering code only expects to find a single frame for the fillInStackTrace method, so if an exception class overrides fillInStackTrace (and invokes super.fillInStackTrace) this actually disables the filtering of the constructors. Eg we see:

Exception in thread "main" MyException
        at MyException.fillInStackTrace(MyException.java:3)
        at java.lang.Throwable.<init>(Throwable.java:260)
        at java.lang.Exception.<init>(Exception.java:54)
        at java.lang.RuntimeException.<init>(RuntimeException.java:51)
        at MyException.<init>(MyException.java:1)
        at MyException.main(MyException.java:7)

instead of:

Exception in thread "main" MyException
        at MyException.main(MyException.java:7)

The changes to Throwable.java for 6998871 effectively introduce an additional fillInStackTrace() frame and so this too disables the desired filtering of the backtrace.

The proposal is quite simple: to modify fill_in_stack_trace so that it expects one or more fillInStackTrace frames, followed by zero or more constructor frames. This addresses the needs of 6998871 as well as fixing any user-defined overriding of fillInStackTrace.

EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-rt/hotspot/rev/6a615eae2f34

EVALUATION Final solutions expects a stacktrace to consist of: a) 1 or more fillInStackTrace frames (with the name fillInStackTrace or fillInStackTrace0) defined in the current exception class hierarchy b) 0 or more <init> methods defined in the current exception class hierarchy c) rest of the stack Items (a) and (b) are elided from the backtrace that gets created. This provides some flexibility for changing the naming and/or structure of the Java code in Throwable.

SUGGESTED FIX --- a/src/share/vm/classfile/javaClasses.cpp +++ b/src/share/vm/classfile/javaClasses.cpp @@ -1462,23 +1462,31 @@ void java_lang_Throwable::fill_in_stack_ st_method = st.method(); } #endif + + // the format of the stacktrace will be: + // 1 or more fillInstackTrace frames (skipped) + // 0 or more <init> methods for the exception class (skipped) + // rest of the stack + if (!skip_fillInStackTrace_check) { - // check "fillInStackTrace" only once, so we negate the flag - // after the first time check. - skip_fillInStackTrace_check = true; if (method->name() == vmSymbols::fillInStackTrace_name()) { - continue; + continue; + } + else { + skip_fillInStackTrace_check = true; // gone past them all } } - // skip <init> methods of the exceptions klass. If there is <init> methods - // that belongs to a superclass of the exception we are going to skipping - // them in stack trace. This is simlar to classic VM. if (!skip_throwableInit_check) { + assert(skip_fillInStackTrace_check, "logic error in backtrace filtering"); + + // skip the chain of exception constructors (<init> methods) + // This is simlar to classic VM. if (method->name() == vmSymbols::object_initializer_name() && throwable->is_a(method->method_holder())) { continue; } else { - // if no "Throwable.init()" method found, we stop checking it next time. + // there are none or we've seen them all - either way stop checking skip_throwableInit_check = true; } }

EVALUATION See description