JDK-7191786 : retransformClasses() does not pass in LocalVariableTypeTable of a method
  • Type: Bug
  • Component: hotspot
  • Sub-Component: jvmti
  • Affected Version: hs24
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2012-08-15
  • Updated: 2013-04-30
  • Resolved: 2012-11-01
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 8 Other
8Fixed hs24Fixed
Related Reports
Relates :  
Relates :  
Description
If java.lang.instrument.Instrumentation.retransformsClasses() is called on a class that had already been loaded, then the jvm doesnt seem to pass in the LocalVariableTypeTable for the methods of the class.
This prevents any instrumentation which needs local variable type table info.

Skipping the details as this issue is similar to the CR:
  7064927 retransformClasses() does not pass in LocalVariableTable of a method

The above CR is covered by the test CR:
  7191322 add test for 7064927 to java.lang.instrument

Comments
The issue has been fixed and already integrated.
01-11-2012

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/1cb8583c3da8
19-09-2012

SUGGESTED FIX I suggest the following patch for this issue: % hg diff diff -r 6d0436885201 src/share/vm/prims/jvmtiClassFileReconstituter.cpp --- a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Fri Aug 10 23:07:38 2012 -0700 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Thu Aug 16 14:37:35 2012 -0700 @@ -43,7 +43,7 @@ #ifdef TARGET_ARCH_ppc # include "bytes_ppc.hpp" #endif -// FIXME: add Deprecated, LVTT attributes +// FIXME: add Deprecated attribute // FIXME: fix Synthetic attribute // FIXME: per Serguei, add error return handling for constantPoolOopDesc::copy_cpool_bytes() @@ -137,6 +137,7 @@ u2 line_num_cnt = 0; int stackmap_len = 0; int local_variable_table_length = 0; + int local_variable_type_table_length = 0; // compute number and length of attributes int attr_count = 0; @@ -188,6 +189,30 @@ // u2 index; // } attr_size += 2 + 4 + 2 + local_variable_table_length * (2 + 2 + 2 + 2 + 2); + + // There can be local variables with generic signature (LVTT elements) + LocalVariableTableElement *elem = method->localvariable_table_start(); + for (int idx = 0; idx < local_variable_table_length; idx++) { + if (elem[idx].signature_cp_index > 0) { + local_variable_type_table_length++; + } + } + } + + if (local_variable_type_table_length != 0) { + // Compute the size of the local variable type table attribute (VM stores raw): + // LocalVariableTypeTable_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 local_variable_type_table_length; + // { + // u2 start_pc; + // u2 length; + // u2 name_index; + // u2 signature_index; + // u2 index; + // } + attr_size += 2 + 4 + 2 + local_variable_type_table_length * (2 + 2 + 2 + 2 + 2); } } @@ -225,6 +250,9 @@ if (local_variable_table_length != 0) { write_local_variable_table_attribute(method, local_variable_table_length); } + if (local_variable_type_table_length != 0) { + write_local_variable_type_table_attribute(method, local_variable_type_table_length); + } } // Write Exceptions attribute @@ -389,7 +417,7 @@ } } -// Write LineNumberTable attribute +// Write LocalVariableTable attribute // JVMSpec| LocalVariableTable_attribute { // JVMSpec| u2 attribute_name_index; // JVMSpec| u4 attribute_length; @@ -419,6 +447,40 @@ } } +// Write LocalVariableTypeTable attribute +// JVMSpec| LocalVariableTypeTable_attribute { +// JVMSpec| u2 attribute_name_index; +// JVMSpec| u4 attribute_length; +// JVMSpec| u2 local_variable_type_table_length; +// JVMSpec| { u2 start_pc; +// JVMSpec| u2 length; +// JVMSpec| u2 name_index; +// JVMSpec| u2 signature_index; +// JVMSpec| u2 index; +// JVMSpec| } local_variable_type_table[local_variable_type_table_length]; +// JVMSpec| } +void JvmtiClassFileReconstituter::write_local_variable_type_table_attribute(methodHandle method, u2 num_entries) { + write_attribute_name_index("LocalVariableTypeTable"); + write_u4(2 + num_entries * (2 + 2 + 2 + 2 + 2)); + write_u2(num_entries); + + LocalVariableTableElement *elem = method->localvariable_table_start(); + for (int j=0; j<method->localvariable_table_length(); j++) { + if (elem->signature_cp_index > 0) { + // Local variable has a generic signature - write LVTT attribute entry + write_u2(elem->start_bci); + write_u2(elem->length); + write_u2(elem->name_cp_index); + write_u2(elem->signature_cp_index); + write_u2(elem->slot); + num_entries--; + } + elem++; + } + assert(num_entries == 0, "just checking"); +} + + // Write stack map table attribute // JSR-202| StackMapTable_attribute { // JSR-202| u2 attribute_name_index; diff -r 6d0436885201 src/share/vm/prims/jvmtiClassFileReconstituter.hpp --- a/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Fri Aug 10 23:07:38 2012 -0700 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Thu Aug 16 14:37:35 2012 -0700 @@ -120,6 +120,7 @@ u2 line_number_table_entries(methodHandle method); void write_line_number_table_attribute(methodHandle method, u2 num_entries); void write_local_variable_table_attribute(methodHandle method, u2 num_entries); + void write_local_variable_type_table_attribute(methodHandle method, u2 num_entries); void write_stackmap_table_attribute(methodHandle method, int stackmap_table_len); u2 inner_classes_attribute_length(); void write_inner_classes_attribute(int length);
16-08-2012

EVALUATION Passing the LVTT is a little bit tricky. The classfile parser merges LVT and LVTT into one LocalVariableTable. The ClassFileReconstituter.cpp has to split it back to two different attributes. If the elem->signature_cp_index > 0 then the LVTT atribute entry must be generated for such element. I wonder if there are any jck tests covering LVTT correctness in class retransformation.
16-08-2012