United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 7191786 retransformClasses() does not pass in LocalVariableTypeTable of a method
7191786 : retransformClasses() does not pass in LocalVariableTypeTable of a method

Details
Type:
Bug
Submit Date:
2012-08-15
Status:
Resolved
Updated Date:
2013-04-30
Project Name:
JDK
Resolved Date:
2012-11-01
Component:
hotspot
OS:
generic
Sub-Component:
jvmti
CPU:
generic
Priority:
P4
Resolution:
Fixed
Affected Versions:
hs24
Fixed Versions:
hs24

Related Reports
Backport:
Backport:
Relates:
Relates:

Sub Tasks

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.
                                     
2012-11-01
EVALUATION

http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/1cb8583c3da8
                                     
2012-09-19
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);
                                     
2012-08-16
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.
                                     
2012-08-16



Hardware and Software, Engineered to Work Together