blob: 5dbf8984158347cb91286c24b0ade6a6b105f7fa [file] [log] [blame]
/*
* Copyright (c) 2004, 2013, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package sun.jvm.hotspot.utilities;
import java.io.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.memory.*;
import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
/**
* This is abstract base class for heap graph writers. This class does
* not assume any file format for the heap graph. It hides heap
* iteration, object (fields) iteration mechanism from derived
* classes. This class does not even accept OutputStream etc. so that
* derived class can construct specific writer/filter from input
* stream.
*/
public abstract class AbstractHeapGraphWriter implements HeapGraphWriter {
// the function iterates heap and calls Oop type specific writers
protected void write() throws IOException {
SymbolTable symTbl = VM.getVM().getSymbolTable();
javaLangClass = symTbl.probe("java/lang/Class");
javaLangString = symTbl.probe("java/lang/String");
javaLangThread = symTbl.probe("java/lang/Thread");
ObjectHeap heap = VM.getVM().getObjectHeap();
try {
heap.iterate(new DefaultHeapVisitor() {
public void prologue(long usedSize) {
try {
writeHeapHeader();
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public boolean doObj(Oop oop) {
try {
writeHeapRecordPrologue();
if (oop instanceof TypeArray) {
writePrimitiveArray((TypeArray)oop);
} else if (oop instanceof ObjArray) {
Klass klass = oop.getKlass();
ObjArrayKlass oak = (ObjArrayKlass) klass;
Klass bottomType = oak.getBottomKlass();
if (bottomType instanceof InstanceKlass ||
bottomType instanceof TypeArrayKlass) {
writeObjectArray((ObjArray)oop);
} else {
writeInternalObject(oop);
}
} else if (oop instanceof Instance) {
Instance instance = (Instance) oop;
Klass klass = instance.getKlass();
Symbol name = klass.getName();
if (name.equals(javaLangString)) {
writeString(instance);
} else if (name.equals(javaLangClass)) {
writeClass(instance);
} else if (name.equals(javaLangThread)) {
writeThread(instance);
} else {
klass = klass.getSuper();
while (klass != null) {
name = klass.getName();
if (name.equals(javaLangThread)) {
writeThread(instance);
return false;
}
klass = klass.getSuper();
}
writeInstance(instance);
}
} else {
// not-a-Java-visible oop
writeInternalObject(oop);
}
writeHeapRecordEpilogue();
} catch (IOException exp) {
throw new RuntimeException(exp);
}
return false;
}
public void epilogue() {
try {
writeHeapFooter();
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
});
// write JavaThreads
writeJavaThreads();
// write JNI global handles
writeGlobalJNIHandles();
} catch (RuntimeException re) {
handleRuntimeException(re);
}
}
protected void writeJavaThreads() throws IOException {
Threads threads = VM.getVM().getThreads();
JavaThread jt = threads.first();
int index = 1;
while (jt != null) {
if (jt.getThreadObj() != null) {
// Note that the thread serial number range is 1-to-N
writeJavaThread(jt, index);
index++;
}
jt = jt.next();
}
}
protected void writeJavaThread(JavaThread jt, int index)
throws IOException {
}
protected void writeGlobalJNIHandles() throws IOException {
JNIHandles handles = VM.getVM().getJNIHandles();
JNIHandleBlock blk = handles.globalHandles();
if (blk != null) {
try {
blk.oopsDo(new AddressVisitor() {
public void visitAddress(Address handleAddr) {
try {
if (handleAddr != null) {
writeGlobalJNIHandle(handleAddr);
}
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void visitCompOopAddress(Address handleAddr) {
throw new RuntimeException("Should not reach here. JNIHandles are not compressed");
}
});
} catch (RuntimeException re) {
handleRuntimeException(re);
}
}
}
protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
}
protected void writeHeapHeader() throws IOException {
}
// write non-Java-visible (hotspot internal) object
protected void writeInternalObject(Oop oop) throws IOException {
}
// write Java primitive array
protected void writePrimitiveArray(TypeArray array) throws IOException {
writeObject(array);
}
// write Java object array
protected void writeObjectArray(ObjArray array) throws IOException {
writeObject(array);
}
protected void writeInstance(Instance instance) throws IOException {
writeObject(instance);
}
protected void writeString(Instance instance) throws IOException {
writeInstance(instance);
}
protected void writeClass(Instance instance) throws IOException {
writeInstance(instance);
}
protected void writeThread(Instance instance) throws IOException {
writeInstance(instance);
}
protected void writeObject(Oop oop) throws IOException {
writeObjectHeader(oop);
writeObjectFields(oop);
writeObjectFooter(oop);
}
protected void writeObjectHeader(Oop oop) throws IOException {
}
// write instance fields of given object
protected void writeObjectFields(final Oop oop) throws IOException {
try {
oop.iterate(new DefaultOopVisitor() {
public void doOop(OopField field, boolean isVMField) {
try {
writeReferenceField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doByte(ByteField field, boolean isVMField) {
try {
writeByteField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doChar(CharField field, boolean isVMField) {
try {
writeCharField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doBoolean(BooleanField field, boolean vField) {
try {
writeBooleanField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doShort(ShortField field, boolean isVMField) {
try {
writeShortField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doInt(IntField field, boolean isVMField) {
try {
writeIntField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doLong(LongField field, boolean isVMField) {
try {
writeLongField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doFloat(FloatField field, boolean isVMField) {
try {
writeFloatField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doDouble(DoubleField field, boolean vField) {
try {
writeDoubleField(oop, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
}, false);
} catch (RuntimeException re) {
handleRuntimeException(re);
}
}
// write instance fields of given object
protected void writeObjectFields(final InstanceKlass oop) throws IOException {
try {
oop.iterateStaticFields(new DefaultOopVisitor() {
public void doOop(OopField field, boolean isVMField) {
try {
writeReferenceField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doByte(ByteField field, boolean isVMField) {
try {
writeByteField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doChar(CharField field, boolean isVMField) {
try {
writeCharField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doBoolean(BooleanField field, boolean vField) {
try {
writeBooleanField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doShort(ShortField field, boolean isVMField) {
try {
writeShortField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doInt(IntField field, boolean isVMField) {
try {
writeIntField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doLong(LongField field, boolean isVMField) {
try {
writeLongField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doFloat(FloatField field, boolean isVMField) {
try {
writeFloatField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
public void doDouble(DoubleField field, boolean vField) {
try {
writeDoubleField(null, field);
} catch (IOException exp) {
throw new RuntimeException(exp);
}
}
});
} catch (RuntimeException re) {
handleRuntimeException(re);
}
}
// object field writers
protected void writeReferenceField(Oop oop, OopField field)
throws IOException {
}
protected void writeByteField(Oop oop, ByteField field)
throws IOException {
}
protected void writeCharField(Oop oop, CharField field)
throws IOException {
}
protected void writeBooleanField(Oop oop, BooleanField field)
throws IOException {
}
protected void writeShortField(Oop oop, ShortField field)
throws IOException {
}
protected void writeIntField(Oop oop, IntField field)
throws IOException {
}
protected void writeLongField(Oop oop, LongField field)
throws IOException {
}
protected void writeFloatField(Oop oop, FloatField field)
throws IOException {
}
protected void writeDoubleField(Oop oop, DoubleField field)
throws IOException {
}
protected void writeObjectFooter(Oop oop) throws IOException {
}
protected void writeHeapFooter() throws IOException {
}
protected void writeHeapRecordPrologue() throws IOException {
}
protected void writeHeapRecordEpilogue() throws IOException {
}
// HeapVisitor, OopVisitor methods can't throw any non-runtime
// exception. But, derived class write methods (which are called
// from visitor callbacks) may throw IOException. Hence, we throw
// RuntimeException with origianal IOException as cause from the
// visitor methods. This method gets back the original IOException
// (if any) and re-throws the same.
protected void handleRuntimeException(RuntimeException re)
throws IOException {
Throwable cause = re.getCause();
if (cause != null && cause instanceof IOException) {
throw (IOException) cause;
} else {
// some other RuntimeException, just re-throw
throw re;
}
}
// whether a given oop is Java visible or hotspot internal?
protected boolean isJavaVisible(Oop oop) {
if (oop instanceof Instance || oop instanceof TypeArray) {
return true;
} else if (oop instanceof ObjArray) {
ObjArrayKlass oak = (ObjArrayKlass) oop.getKlass();
Klass bottomKlass = oak.getBottomKlass();
return bottomKlass instanceof InstanceKlass ||
bottomKlass instanceof TypeArrayKlass;
} else {
return false;
}
}
protected Symbol javaLangClass;
protected Symbol javaLangString;
protected Symbol javaLangThread;
}