Request for review (#4) 7174978: NPG: Fix bactrace builder for class redefinition

Coleen Phillimore coleen.phillimore at oracle.com
Mon Jan 14 18:36:21 PST 2013


Summary: Remove Method* from backtrace but save version so redefine 
classes doesn't give inaccurate line numbers.  Removed old Merlin API 
with duplicate code.

Sorry, this is so long but I want to explain this change properly.

When exceptions are thrown, the VM saves a backtrace for each which may 
or may not be printed or saved for later.   For speed, the information 
that the VM saves are arrays 32 of Method* and bci. For permgen 
elimination we added an array of mirrors (instances of java_lang_Class), 
so that the class loader owning the Method* pointer doesn't get unloaded 
and deallocated.

The problem with redefine classes is that the method can be redefined 
and the Method* pointer can be deallocated even if the class loader 
owning the Method* is kept alive.    Printing or touching the backtrace 
later will crash the VM.

This is my 4th attempt at fixing this problem.   The first that was 
reviewed, saved a side structure for each backtrace created so that we 
can walk the Method* pointers and keep them from being deallocated.   
This change had an unfortunate side structure to manage, and had also a 
6.1% slowdown in javac.    The second attempt was to predigest the 
Method* into the data needed for java_lang_StackTraceElement into 
method_name, class_name, file_name, and line_number, so that the Method* 
doesn't need to be saved. This had a 18% slowdown in javac.

The 3rd attempt is to look for a way to have GC handle backtraces and 
mark methods as on_stack but adding a InstanceThrowableKlass and 
determining which closures needed special actions for the array of 
Method* pointers is a lot of additional special case code to the garbage 
collectors.  It's unclear how this would work actually, but we might 
have to revisit this idea for java_lang_invoke_MemberName.

The 4th attempt is to save the method_idnum, bci, version_number, and 
mirror.   From the method_idnum, we can get the Method*.   The version 
number is updated for redefine classes.   There was an unused field that 
I repurposed.   If the method's version doesn't match the backtrace, we 
do not return the source_file and line_number from the Method* because 
it's changed.   You get a backtrace of the form:

java.lang.RuntimeException: Test exception
         at RedefineMethodInBacktraceTarget.methodToRedefine(Unknown Source)
         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
         at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
         at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
         at java.lang.reflect.Method.invoke(Method.java:474)
         at 
RedefineMethodInBacktraceApp.getThrowableFromMethodToRedefine(RedefineMethodInBacktraceApp.java:60)
         at 
RedefineMethodInBacktraceApp.doMethodInBacktraceTest(RedefineMethodInBacktraceApp.java:44)

This fix for the Method* crash does not add to the footprint of the 
backtraces (idnum is short and bci and version number is packed into an 
int).  It does not degrade performance of javac (or refworkload).   The 
cost is to not support getting a source file and line number from a 
method that was redefined after being saved in a backtrace.  Note that 
this change does not return the wrong information.   A CR can be filed 
for somebody to someday lift this restriction if someday we don't care 
about performance or a new solution is found.

This might be hard to review as a diff because I refactored duplicated code.

The webrev:  http://cr.openjdk.java.net/~coleenp/7174978_5/
Bug link: http://bugs.sun.com/view_bug.do?bug_id=7174978

Tested with NSK quick testlist, runThese jck tests, JPRT, refworkload.

Thanks,
Coleen



More information about the hotspot-runtime-dev mailing list