1 /*
   2  * Copyright 2004-2008 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *  
  23  */
  24 
  25 package sun.jvm.hotspot.utilities;
  26 
  27 import java.io.*;
  28 import sun.jvm.hotspot.debugger.*;
  29 import sun.jvm.hotspot.memory.*;
  30 import sun.jvm.hotspot.oops.*;
  31 import sun.jvm.hotspot.runtime.*;
  32 
  33 /**
  34  * This is abstract base class for heap graph writers. This class does
  35  * not assume any file format for the heap graph. It hides heap
  36  * iteration, object (fields) iteration mechanism from derived
  37  * classes. This class does not even accept OutputStream etc. so that
  38  * derived class can construct specific writer/filter from input
  39  * stream.
  40  */
  41 
  42 public abstract class AbstractHeapGraphWriter implements HeapGraphWriter {
  43     // the function iterates heap and calls Oop type specific writers
  44     protected void write() throws IOException {
  45         SymbolTable symTbl = VM.getVM().getSymbolTable();
  46         javaLangClass = symTbl.probe("java/lang/Class");
  47         javaLangString = symTbl.probe("java/lang/String");
  48         javaLangThread = symTbl.probe("java/lang/Thread");
  49         ObjectHeap heap = VM.getVM().getObjectHeap();
  50         try {
  51             heap.iterate(new DefaultHeapVisitor() {
  52                     public void prologue(long usedSize) {
  53                         try {
  54                             writeHeapHeader();
  55                         } catch (IOException exp) {
  56                             throw new RuntimeException(exp);
  57                         }
  58                     }
  59 
  60                     public boolean doObj(Oop oop) {
  61                         try {
  62                             if (oop instanceof TypeArray) {
  63                                 writePrimitiveArray((TypeArray)oop);
  64                             } else if (oop instanceof ObjArray) {
  65                                 Klass klass = oop.getKlass();
  66                                 ObjArrayKlass oak = (ObjArrayKlass) klass;
  67                                 Klass bottomType = oak.getBottomKlass();
  68                                 if (bottomType instanceof InstanceKlass ||
  69                                     bottomType instanceof TypeArrayKlass) {
  70                                     writeObjectArray((ObjArray)oop);
  71                                 } else {
  72                                     writeInternalObject(oop);
  73                                 }
  74                             } else if (oop instanceof Instance) {
  75                                 Instance instance = (Instance) oop;
  76                                 Klass klass = instance.getKlass();
  77                                 Symbol name = klass.getName();
  78                                 if (name.equals(javaLangString)) {
  79                                     writeString(instance);
  80                                 } else if (name.equals(javaLangClass)) {
  81                                     writeClass(instance);
  82                                 } else if (name.equals(javaLangThread)) {
  83                                     writeThread(instance);      
  84                                 } else {
  85                                     klass = klass.getSuper();
  86                                     while (klass != null) {
  87                                         name = klass.getName();
  88                                         if (name.equals(javaLangThread)) {
  89                                             writeThread(instance);
  90                                             return false;
  91                                         }
  92                                         klass = klass.getSuper();
  93                                     }
  94                                     writeInstance(instance);
  95                                 }
  96                             } else {
  97                                 // not-a-Java-visible oop
  98                                 writeInternalObject(oop);
  99                             }
 100                         } catch (IOException exp) {
 101                             throw new RuntimeException(exp);
 102                         }
 103                         return false;
 104                     }
 105                     
 106                     public void epilogue() {
 107                         try {
 108                             writeHeapFooter();
 109                         } catch (IOException exp) {
 110                             throw new RuntimeException(exp);
 111                         }
 112                     }
 113                 }); 
 114 
 115                 // write JavaThreads 
 116                 writeJavaThreads();
 117 
 118                 // write JNI global handles
 119                 writeGlobalJNIHandles();
 120  
 121         } catch (RuntimeException re) {
 122             handleRuntimeException(re);
 123         }
 124     }
 125 
 126     protected void writeJavaThreads() throws IOException {
 127         Threads threads = VM.getVM().getThreads();
 128         JavaThread jt = threads.first();
 129         int index = 1;
 130         while (jt != null) {
 131             if (jt.getThreadObj() != null) {
 132                 // Note that the thread serial number range is 1-to-N
 133                 writeJavaThread(jt, index);
 134                 index++;
 135             }
 136             jt = jt.next();
 137         }
 138     }
 139 
 140     protected void writeJavaThread(JavaThread jt, int index) 
 141                             throws IOException {
 142     }
 143 
 144     protected void writeGlobalJNIHandles() throws IOException {
 145         JNIHandles handles = VM.getVM().getJNIHandles();
 146         JNIHandleBlock blk = handles.globalHandles();
 147         if (blk != null) {
 148             try {
 149                 blk.oopsDo(new AddressVisitor() {
 150                           public void visitAddress(Address handleAddr) {
 151                               try {
 152                                   if (handleAddr != null) {
 153                                       writeGlobalJNIHandle(handleAddr);
 154                                   }
 155                               } catch (IOException exp) {
 156                                   throw new RuntimeException(exp);
 157                               }
 158                           }
 159                               public void visitCompOopAddress(Address handleAddr) {
 160                              throw new RuntimeException("Should not reach here. JNIHandles are not compressed");
 161                           }
 162                        });
 163             } catch (RuntimeException re) {
 164                 handleRuntimeException(re);
 165             }
 166         }
 167     }
 168 
 169     protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
 170     }
 171 
 172     protected void writeHeapHeader() throws IOException {
 173     }
 174 
 175     // write non-Java-visible (hotspot internal) object
 176     protected void writeInternalObject(Oop oop) throws IOException {        
 177     }
 178 
 179     // write Java primitive array
 180     protected void writePrimitiveArray(TypeArray array) throws IOException {
 181         writeObject(array);
 182     }
 183 
 184     // write Java object array
 185     protected void writeObjectArray(ObjArray array) throws IOException {
 186         writeObject(array);
 187     }
 188 
 189     protected void writeInstance(Instance instance) throws IOException {
 190         writeObject(instance);
 191     }
 192 
 193     protected void writeString(Instance instance) throws IOException {
 194         writeInstance(instance);
 195     }
 196 
 197     protected void writeClass(Instance instance) throws IOException {
 198         writeInstance(instance);
 199     }
 200 
 201     protected void writeThread(Instance instance) throws IOException {
 202         writeInstance(instance);
 203     }
 204 
 205     protected void writeObject(Oop oop) throws IOException {
 206         writeObjectHeader(oop);
 207         writeObjectFields(oop);
 208         writeObjectFooter(oop);
 209     }
 210 
 211     protected void writeObjectHeader(Oop oop) throws IOException {
 212     }
 213 
 214     // write instance fields of given object
 215     protected void writeObjectFields(final Oop oop) throws IOException {
 216         try {
 217             oop.iterate(new DefaultOopVisitor() {               
 218                     public void doOop(OopField field, boolean isVMField) {
 219                         try {
 220                             Oop ref = field.getValue(oop);
 221                             if (ref instanceof TypeArray ||
 222                                 ref instanceof ObjArray  ||
 223                                 ref instanceof Instance) {
 224                                 writeReferenceField(oop, field);
 225                             } else {
 226                                 writeInternalReferenceField(oop, field);
 227                             }
 228                         } catch (IOException exp) {
 229                             throw new RuntimeException(exp);
 230                         }
 231                     }
 232 
 233                     public void doByte(ByteField field, boolean isVMField) {   
 234                         try {
 235                             writeByteField(oop, field);
 236                         } catch (IOException exp) {
 237                             throw new RuntimeException(exp);
 238                         }
 239                     }
 240 
 241                     public void doChar(CharField field, boolean isVMField) {
 242                         try {
 243                             writeCharField(oop, field);
 244                         } catch (IOException exp) {
 245                             throw new RuntimeException(exp);
 246                         }
 247                     }
 248                     
 249                     public void doBoolean(BooleanField field, boolean vField) {
 250                         try {
 251                             writeBooleanField(oop, field);
 252                         } catch (IOException exp) {
 253                             throw new RuntimeException(exp);
 254                         }
 255                     }
 256 
 257                     public void doShort(ShortField field, boolean isVMField) {
 258                         try {
 259                             writeShortField(oop, field);
 260                         } catch (IOException exp) {
 261                             throw new RuntimeException(exp);
 262                         }
 263                     }
 264 
 265                     public void doInt(IntField field, boolean isVMField) {
 266                         try {
 267                             writeIntField(oop, field);
 268                         } catch (IOException exp) {
 269                             throw new RuntimeException(exp);
 270                         }
 271                     }
 272 
 273                     public void doLong(LongField field, boolean isVMField) {
 274                         try {
 275                             writeLongField(oop, field);
 276                         } catch (IOException exp) {
 277                             throw new RuntimeException(exp);
 278                         }
 279                     }
 280 
 281                     public void doFloat(FloatField field, boolean isVMField) {
 282                         try {
 283                             writeFloatField(oop, field);
 284                         } catch (IOException exp) {
 285                             throw new RuntimeException(exp);
 286                         }
 287                     }
 288 
 289                     public void doDouble(DoubleField field, boolean vField) {
 290                         try {
 291                             writeDoubleField(oop, field);
 292                         } catch (IOException exp) {
 293                             throw new RuntimeException(exp);
 294                         }
 295                     }
 296                 }, false);
 297         } catch (RuntimeException re) {
 298             handleRuntimeException(re);
 299         }
 300     }
 301 
 302     // object field writers
 303     protected void writeInternalReferenceField(Oop oop, OopField field) 
 304         throws IOException {
 305     }
 306 
 307     protected void writeReferenceField(Oop oop, OopField field)
 308         throws IOException {
 309     }
 310 
 311     protected void writeByteField(Oop oop, ByteField field) 
 312         throws IOException {
 313     }
 314 
 315     protected void writeCharField(Oop oop, CharField field) 
 316         throws IOException {
 317     }
 318 
 319     protected void writeBooleanField(Oop oop, BooleanField field) 
 320         throws IOException {
 321     }
 322 
 323     protected void writeShortField(Oop oop, ShortField field) 
 324         throws IOException {
 325     }
 326 
 327     protected void writeIntField(Oop oop, IntField field) 
 328         throws IOException {
 329     }
 330 
 331     protected void writeLongField(Oop oop, LongField field) 
 332         throws IOException {
 333     }
 334 
 335     protected void writeFloatField(Oop oop, FloatField field) 
 336         throws IOException {
 337     }
 338 
 339     protected void writeDoubleField(Oop oop, DoubleField field) 
 340         throws IOException {
 341     }
 342 
 343     protected void writeObjectFooter(Oop oop) throws IOException {
 344     }
 345 
 346     protected void writeHeapFooter() throws IOException {
 347     }
 348       
 349     // HeapVisitor, OopVisitor methods can't throw any non-runtime
 350     // exception. But, derived class write methods (which are called
 351     // from visitor callbacks) may throw IOException. Hence, we throw
 352     // RuntimeException with origianal IOException as cause from the
 353     // visitor methods. This method gets back the original IOException
 354     // (if any) and re-throws the same.
 355     protected void handleRuntimeException(RuntimeException re) 
 356         throws IOException {
 357         Throwable cause = re.getCause();
 358         if (cause != null && cause instanceof IOException) {
 359             throw (IOException) cause;
 360         } else {
 361             // some other RuntimeException, just re-throw
 362             throw re;
 363         }
 364     }
 365 
 366     // whether a given oop is Java visible or hotspot internal?
 367     protected boolean isJavaVisible(Oop oop) {
 368         if (oop instanceof Instance || oop instanceof TypeArray) {
 369             return true;
 370         } else if (oop instanceof ObjArray) {
 371             ObjArrayKlass oak = (ObjArrayKlass) oop.getKlass();
 372             Klass bottomKlass = oak.getBottomKlass();
 373             return bottomKlass instanceof InstanceKlass ||
 374                    bottomKlass instanceof TypeArrayKlass;
 375         } else {
 376             return false;
 377         }
 378     }
 379 
 380     protected Symbol javaLangClass;
 381     protected Symbol javaLangString;
 382     protected Symbol javaLangThread;
 383 }