7177128: SA cannot get correct system properties after 7126277
authorminqi
Fri, 22 Jun 2012 15:39:16 -0700
changeset 13095 e963ab7b3a6f
parent 13094 110c9357d14b
child 13096 8a01a0702816
child 13097 c146b608d91f
7177128: SA cannot get correct system properties after 7126277 Summary: Bug fix of 7126277 changed hashing algorithm and also changed key as final field, this led SA unable to set correct value for key. Solution by reading key/value and insert them into the new table. Reviewed-by: dholmes, mikael Contributed-by: yumin.qi@oracle.com
hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ObjectReader.java
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ObjectReader.java	Fri Jun 22 15:35:30 2012 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ObjectReader.java	Fri Jun 22 15:39:16 2012 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -85,6 +85,21 @@
       this(new ProcImageClassLoader());
    }
 
+   static void debugPrintln(String msg) {
+      if (DEBUG) {
+         System.err.println("DEBUG>" + msg);
+      }
+   }
+
+   static void debugPrintStackTrace(Exception exp) {
+      if (DEBUG) {
+         StackTraceElement[] els = exp.getStackTrace();
+         for (int i = 0; i < els.length; i++) {
+            System.err.println("DEBUG>" + els[i].toString());
+         }
+      }
+   }
+
    public Object readObject(Oop oop) throws ClassNotFoundException {
       if (oop instanceof Instance) {
          return readInstance((Instance) oop);
@@ -120,13 +135,96 @@
    }
 
    protected Symbol javaLangString;
+   protected Symbol javaUtilHashtableEntry;
+   protected Symbol javaUtilHashtable;
+   protected Symbol javaUtilProperties;
+
+   protected Symbol getVMSymbol(String name) {
+      return VM.getVM().getSymbolTable().probe(name);
+   }
+
    protected Symbol javaLangString() {
       if (javaLangString == null) {
-         javaLangString = VM.getVM().getSymbolTable().probe("java/lang/String");
+         javaLangString = getVMSymbol("java/lang/String");
       }
       return javaLangString;
    }
 
+   protected Symbol javaUtilHashtableEntry() {
+      if (javaUtilHashtableEntry == null) {
+         javaUtilHashtableEntry = getVMSymbol("java/util/Hashtable$Entry");
+      }
+      return javaUtilHashtableEntry;
+   }
+
+   protected Symbol javaUtilHashtable() {
+      if (javaUtilHashtable == null) {
+         javaUtilHashtable = getVMSymbol("java/util/Hashtable");
+      }
+      return javaUtilHashtable;
+   }
+
+   protected Symbol javaUtilProperties() {
+      if (javaUtilProperties == null) {
+         javaUtilProperties = getVMSymbol("java/util/Properties");
+      }
+      return javaUtilProperties;
+   }
+
+   private void setHashtableEntry(java.util.Hashtable p, Oop oop) {
+      InstanceKlass ik = (InstanceKlass)oop.getKlass();
+      OopField keyField = (OopField)ik.findField("key", "Ljava/lang/Object;");
+      OopField valueField = (OopField)ik.findField("value", "Ljava/lang/Object;");
+      OopField nextField = (OopField)ik.findField("next", "Ljava/util/Hashtable$Entry;");
+      if (DEBUG) {
+         if (Assert.ASSERTS_ENABLED) {
+            Assert.that(ik.getName().equals(javaUtilHashtableEntry()), "Not a Hashtable$Entry?");
+            Assert.that(keyField != null && valueField != null && nextField != null, "Invalid fields!");
+         }
+      }
+
+      Object key = null;
+      Object value = null;
+      Oop next = null;
+      try {
+         key = readObject(keyField.getValue(oop));
+         value = readObject(valueField.getValue(oop));
+         next =  (Oop)nextField.getValue(oop);
+         // For Properties, should use setProperty(k, v). Since it only runs in SA
+         // using put(k, v) should be OK.
+         p.put(key, value);
+         if (next != null) {
+            setHashtableEntry(p, next);
+         }
+      } catch (ClassNotFoundException ce) {
+         if( DEBUG) {
+            debugPrintln("Class not found " + ce);
+            debugPrintStackTrace(ce);
+         }
+      }
+   }
+
+   protected Object getHashtable(Instance oop, boolean isProperties) {
+      InstanceKlass k = (InstanceKlass)oop.getKlass();
+      OopField tableField = (OopField)k.findField("table", "[Ljava/util/Hashtable$Entry;");
+      if (tableField == null) {
+         debugPrintln("Could not find field of [Ljava/util/Hashtable$Entry;");
+         return null;
+      }
+      java.util.Hashtable table = (isProperties) ? new java.util.Properties()
+                                                 : new java.util.Hashtable();
+      ObjArray kvs = (ObjArray)tableField.getValue(oop);
+      long size = kvs.getLength();
+      debugPrintln("Hashtable$Entry Size = " + size);
+      for (long i=0; i<size; i++) {
+         Oop entry = kvs.getObjAt(i);
+         if (entry != null && entry.isInstance()) {
+            setHashtableEntry(table, entry);
+         }
+      }
+      return table;
+   }
+
    public Object readInstance(Instance oop) throws ClassNotFoundException {
       Object result = getFromObjTable(oop);
       if (result == null) {
@@ -134,11 +232,21 @@
          // Handle java.lang.String instances differently. As part of JSR-133, fields of immutable
          // classes have been made final. The algorithm below will not be able to read Strings from
          // debuggee (can't use reflection to set final fields). But, need to read Strings is very
-         // important. FIXME: need a framework to handle many other special cases.
+         // important.
+         // Same for Hashtable, key and hash are final, could not be set in the algorithm too.
+         // FIXME: need a framework to handle many other special cases.
          if (kls.getName().equals(javaLangString())) {
             return OopUtilities.stringOopToString(oop);
          }
 
+         if (kls.getName().equals(javaUtilHashtable())) {
+            return getHashtable(oop, false);
+         }
+
+         if (kls.getName().equals(javaUtilProperties())) {
+            return getHashtable(oop, true);
+         }
+
          Class clz = readClass(kls);
          try {
             result = clz.newInstance();
@@ -164,8 +272,8 @@
                   break;
                } catch (Exception exp) {
                   if (DEBUG) {
-                     System.err.println("Can't create object using " + c);
-                     exp.printStackTrace();
+                     debugPrintln("Can't create object using " + c);
+                     debugPrintStackTrace(exp);
                   }
                }
             }
@@ -329,8 +437,8 @@
                                      arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj()));
                                   } catch (Exception e) {
                                      if (DEBUG) {
-                                        System.err.println("Array element set failed for " + ifd);
-                                        e.printStackTrace();
+                                        debugPrintln("Array element set failed for " + ifd);
+                                        debugPrintStackTrace(e);
                                      }
                                   }
                                }
@@ -348,8 +456,8 @@
 
       private void printFieldSetError(java.lang.reflect.Field f, Exception ex) {
          if (DEBUG) {
-            if (f != null) System.err.println("Field set failed for " + f);
-            ex.printStackTrace();
+            if (f != null) debugPrintln("Field set failed for " + f);
+            debugPrintStackTrace(ex);
          }
       }
 
@@ -601,7 +709,7 @@
             return Class.forName(className, true, cl);
          } catch (Exception e) {
             if (DEBUG) {
-               System.err.println("Can't load class " + className);
+               debugPrintln("Can't load class " + className);
             }
             throw new RuntimeException(e);
          }