United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-7034585 : Adjust fillInStackTrace filtering to assist 6998871

Details
Type:
Enhancement
Submit Date:
2011-04-07
Status:
Closed
Updated Date:
2011-07-29
Project Name:
JDK
Resolved Date:
2011-04-24
Component:
hotspot
OS:
generic
Sub-Component:
runtime
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
hs21
Fixed Versions:
hs21 (b09)

Related Reports
Backport:
Relates:

Sub Tasks

Description
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.

                                    

Comments
EVALUATION

http://hg.openjdk.java.net/jdk7/hotspot-rt/hotspot/rev/6a615eae2f34
                                     
2011-04-12
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.
                                     
2011-04-11
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;
       }
     }
                                     
2011-04-07
EVALUATION

See description
                                     
2011-04-07



Hardware and Software, Engineered to Work Together