blob: e8b97e05a45e186e255d3a7160f2615f0f202265 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009,2021 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.mat.dtfj;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.dtfj.DTFJIndexBuilder.RuntimeInfo;
import org.eclipse.mat.parser.IObjectReader;
import org.eclipse.mat.parser.model.AbstractObjectImpl;
import org.eclipse.mat.parser.model.ClassImpl;
import org.eclipse.mat.parser.model.ClassLoaderImpl;
import org.eclipse.mat.parser.model.InstanceImpl;
import org.eclipse.mat.parser.model.ObjectArrayImpl;
import org.eclipse.mat.parser.model.PrimitiveArrayImpl;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.SnapshotInfo;
import org.eclipse.mat.snapshot.model.Field;
import org.eclipse.mat.snapshot.model.IObject;
import org.eclipse.mat.snapshot.model.ObjectReference;
import org.eclipse.mat.util.VoidProgressListener;
import com.ibm.dtfj.image.CorruptData;
import com.ibm.dtfj.image.CorruptDataException;
import com.ibm.dtfj.image.DataUnavailable;
import com.ibm.dtfj.image.Image;
import com.ibm.dtfj.image.ImageAddressSpace;
import com.ibm.dtfj.image.ImageFactory;
import com.ibm.dtfj.image.ImagePointer;
import com.ibm.dtfj.image.ImageProcess;
import com.ibm.dtfj.image.MemoryAccessException;
import com.ibm.dtfj.java.JavaClass;
import com.ibm.dtfj.java.JavaClassLoader;
import com.ibm.dtfj.java.JavaField;
import com.ibm.dtfj.java.JavaHeap;
import com.ibm.dtfj.java.JavaLocation;
import com.ibm.dtfj.java.JavaMethod;
import com.ibm.dtfj.java.JavaMonitor;
import com.ibm.dtfj.java.JavaObject;
import com.ibm.dtfj.java.JavaRuntime;
import com.ibm.dtfj.java.JavaStackFrame;
import com.ibm.dtfj.java.JavaThread;
/**
* Reads details of an object from a DTFJ dump.
* @author ajohnson
*/
public class DTFJHeapObjectReader implements IObjectReader
{
/**
* Size above which we only return an array stub - the data is returned
* piecemeal later
*/
private static final int LARGE_ARRAY_SIZE = 1000;
/** Whether to use stack frames and methods as objects and classes */
private static final boolean getExtraInfo = true;
/** the file */
private File file;
/** All the key DTFJ data */
private RuntimeInfo dtfjInfo;
/** the snapshot */
private ISnapshot snapshot;
/**
* whether to give up and throw an exception if reading object data fails,
* or whether to carry on getting more data
*/
private static final boolean throwExceptions = true;
/*
* (non-Javadoc)
* @see org.eclipse.mat.parser.IObjectReader#close()
*/
public void close() throws IOException
{
// Close the dump
DTFJIndexBuilder.DumpCache.releaseDump(file, dtfjInfo, true);
snapshot = null;
}
/**
* Used as a proxy for org.eclipse.mat.parser to read objects
* via address.
*/
class ObjectAddressReference extends ObjectReference
{
private static final long serialVersionUID = 1L;
/**
* Constructor.
* The address will be filled in by {@link ObjectReference}.
*/
public ObjectAddressReference()
{
super(snapshot, 0);
}
/**
* Create an IObject from the address.
*/
public IObject getObject() throws SnapshotException
{
try
{
IObject o = DTFJHeapObjectReader.this.read(getObjectAddress(), -1, snapshot);
((AbstractObjectImpl)o).setSnapshot(snapshot);
return o;
}
catch (IOException e)
{
throw new SnapshotException(e);
}
}
}
/**
* Returns extra data to be provided by {@link ISnapshot#getSnapshotAddons(Class addon)}.
* Also can be returned via {@link org.eclipse.mat.query.annotations.Argument}.
* @see IObjectReader#getAddon(Class)
* @param addon the type of the extra data required from the dump
* Types supported by DTFJHeapObjectReader include
* <ul>
* <li>{@link com.ibm.dtfj.image.Image}</li>
* <li>{@link com.ibm.dtfj.image.ImageAddressSpace}</li>
* <li>{@link com.ibm.dtfj.image.ImageProcess}</li>
* <li>{@link com.ibm.dtfj.java.JavaRuntime}</li>
* <li>{@link com.ibm.dtfj.image.ImageFactory} since 1.1</li>
* </ul>
* @return the extra data
*/
public <A> A getAddon(Class<A> addon) throws SnapshotException
{
ImageFactory factory = dtfjInfo.getImageFactory();
Image image = dtfjInfo.getImage();
ImageAddressSpace addrSpace = dtfjInfo.getImageAddressSpace();
ImageProcess process = dtfjInfo.getImageProcess();
JavaRuntime jvm = dtfjInfo.getJavaRuntime();
if (image != null && addon.isAssignableFrom(image.getClass()))
{
return addon.cast(image);
}
else if (jvm != null && addon.isAssignableFrom(jvm.getClass()))
{
return addon.cast(jvm);
}
else if (addrSpace != null && addon.isAssignableFrom(addrSpace.getClass()))
{
return addon.cast(addrSpace);
}
else if (process != null && addon.isAssignableFrom(process.getClass()))
{
return addon.cast(process);
}
else if (factory != null && addon.isAssignableFrom(factory.getClass()))
{
return addon.cast(factory);
}
else if (addon.isAssignableFrom(ObjectAddressReference.class))
{
return addon.cast(new ObjectAddressReference());
}
else
{
return null;
}
}
/*
* (non-Javadoc)
* @see
* org.eclipse.mat.parser.IObjectReader#open(org.eclipse.mat.snapshot.ISnapshot
* )
*/
public void open(ISnapshot snapshot) throws IOException, SnapshotException
{
file = new File(snapshot.getSnapshotInfo().getPath());
this.snapshot = snapshot;
SnapshotInfo snapinfo = snapshot.getSnapshotInfo();
RuntimeInfo info = DTFJIndexBuilder.DumpCache.getDump(file, snapinfo.getProperty("$heapFormat")); //$NON-NLS-1$
Serializable runtimeId = snapinfo.getProperty(DTFJIndexBuilder.RUNTIME_ID_KEY);
// Find the JVM
dtfjInfo = DTFJIndexBuilder.getRuntime(info.getImageFactory(), info.getImage(), runtimeId, null);
}
/*
* (non-Javadoc)
* @see org.eclipse.mat.parser.IObjectReader#read(int,
* org.eclipse.mat.snapshot.ISnapshot)
*/
public IObject read(int objectId, ISnapshot snapshot) throws SnapshotException, IOException
{
long addr = snapshot.mapIdToAddress(objectId);
return read(addr, objectId, snapshot);
}
IObject read(long addr, int objectId, ISnapshot snapshot) throws SnapshotException, IOException
{
try
{
// DTFJ is not thread safe, but MAT is multi-threaded
synchronized (dtfjInfo.getImage())
{
if (getExtraInfo && objectId != -1)
{
// See if the class looks like a method
ClassImpl cls = (ClassImpl) snapshot.getClassOf(objectId);
if (cls.getName().contains(DTFJIndexBuilder.METHOD_NAME_SIG) || cls.getName().equals(DTFJIndexBuilder.STACK_FRAME))
{
// Get the special method/stack frame data
IObject ret = createObject2(snapshot, objectId, addr, cls);
if (ret != null)
return ret;
}
}
JavaObject jo = getJavaObjectByAddress0(addr);
IObject inst;
if (objectId == -1 ? jo.isArray() : snapshot.isArray(objectId))
{
inst = createArray(snapshot, objectId, addr, jo);
}
else
{
inst = createObject(snapshot, objectId, addr, jo);
}
return inst;
}
}
catch (MemoryAccessException e)
{
throw new SnapshotException(MessageFormat.format(Messages.DTFJHeapObjectReader_ErrorReadingObjectAtIndex,
objectId, format(addr)), e);
}
catch (CorruptDataException e)
{
throw new SnapshotException(MessageFormat.format(Messages.DTFJHeapObjectReader_ErrorReadingObjectAtIndex,
objectId, format(addr)), e);
}
catch (IllegalArgumentException e)
{
throw new SnapshotException(MessageFormat.format(Messages.DTFJHeapObjectReader_ErrorReadingObjectAtIndex,
objectId, format(addr)), e);
}
}
/**
* Create an MAT object for a stack frame special object
*
* @param snapshot
* @param objectId
* @param addr
* @param cls
* @return
*/
private IObject createObject2(ISnapshot snapshot, int objectId, long addr, ClassImpl cls)
{
// Use a search over every frame to find the right one
if (getExtraInfo)
{
long prevFrameAddress = 0;
for (Iterator<?> i = dtfjInfo.getJavaRuntime().getThreads(); i.hasNext();)
{
Object next = i.next();
if (next instanceof CorruptData)
{
continue;
}
JavaThread jt = (JavaThread) next;
int pointerSize = snapshot.getSnapshotInfo().getIdentifierSize() * 8;
// Count all the frames
int totalDepth = 0;
for (Iterator<?> j = jt.getStackFrames(); j.hasNext(); ++totalDepth)
{
j.next();
}
int depth = 0;
for (Iterator<?> j = jt.getStackFrames(); j.hasNext(); ++depth)
{
Object next2 = j.next();
if (next2 instanceof CorruptData)
{
continue;
}
JavaStackFrame jsf = (JavaStackFrame) next2;
long currAddr = DTFJIndexBuilder.getFrameAddress(jsf, prevFrameAddress, pointerSize);
prevFrameAddress = currAddr;
if (currAddr == addr)
{
// These fields should match those in the method
// class
List<Field> fields = new ArrayList<Field>();
if (!cls.getName().contains(DTFJIndexBuilder.METHOD_NAME_SIG))
{
try
{
JavaLocation jl = jsf.getLocation();
JavaMethod jm = jl.getMethod();
JavaClass jc = jm.getDeclaringClass();
String name = jc.getName().replace('/', '.');
String methodName = name
+ DTFJIndexBuilder.METHOD_NAME_PREFIX
+ DTFJIndexBuilder.getMethodName(jl.getMethod(),
new VoidProgressListener());
Field f = new Field(DTFJIndexBuilder.METHOD_NAME, IObject.Type.OBJECT, methodName);
fields.add(f);
}
catch (DataUnavailable e)
{}
catch (CorruptDataException e)
{}
}
try
{
JavaLocation jl = jsf.getLocation();
Field f = new Field(DTFJIndexBuilder.FILE_NAME, IObject.Type.OBJECT, jl.getFilename());
fields.add(f);
}
catch (DataUnavailable e)
{}
catch (CorruptDataException e)
{}
try
{
JavaLocation jl = jsf.getLocation();
Field f = new Field(DTFJIndexBuilder.LINE_NUMBER, IObject.Type.INT, Integer.valueOf(jl.getLineNumber()));
fields.add(f);
}
catch (DataUnavailable e)
{}
catch (CorruptDataException e)
{}
try
{
JavaLocation jl = jsf.getLocation();
Field f = new Field(DTFJIndexBuilder.COMPILATION_LEVEL, IObject.Type.INT, Integer.valueOf(jl.getCompilationLevel()));
fields.add(f);
}
catch (ClassCastException e)
{
// Sov problem
}
catch (CorruptDataException e)
{}
try
{
JavaLocation jl = jsf.getLocation();
Field f = new Field(DTFJIndexBuilder.LOCATION_ADDRESS, IObject.Type.LONG, Long.valueOf(jl.getAddress().getAddress()));
fields.add(f);
}
catch (ClassCastException e)
{
// Sov problem
}
catch (CorruptDataException e)
{}
Field f = new Field(DTFJIndexBuilder.FRAME_NUMBER, IObject.Type.INT, Integer.valueOf(depth));
fields.add(f);
f = new Field(DTFJIndexBuilder.STACK_DEPTH, IObject.Type.INT, Integer.valueOf(totalDepth - depth));
fields.add(f);
InstanceImpl inst = new InstanceImpl(objectId, addr, cls, fields);
return inst;
}
}
}
}
// Not found
return null;
}
/**
* Read a JavaObject using the general DTFJ method, if available
*
* @param addr
* the address of the Java object in the address space
* @return The Java Object at the given address
* @throws CorruptDataException
*/
private JavaObject getJavaObjectByAddress0(long addr) throws CorruptDataException, MemoryAccessException
{
ImagePointer ip = dtfjInfo.getImageAddressSpace().getPointer(addr);
try
{
// Previous versions of DTFJ might not have this method, so handle
// that possibility
JavaObject jo = dtfjInfo.getJavaRuntime().getObjectAtAddress(ip);
return jo;
}
catch (DataUnavailable e)
{
return getJavaObjectByAddress(addr);
}
catch (LinkageError e)
{
return getJavaObjectByAddress(addr);
}
}
/**
* Slow, but universal object finder. Scans over every object it can find.
*
* @param addr
* the address of the Java object in the address space
* @return The Java Object at the given address
* @throws CorruptDataException
*/
private JavaObject getJavaObjectByAddress(long addr)
{
// Now look for thread objects
for (Iterator<?> i = dtfjInfo.getJavaRuntime().getThreads(); i.hasNext();)
{
Object next = i.next();
if (next instanceof CorruptData)
{
continue;
}
JavaThread thrd = (JavaThread) next;
long thAddr = DTFJIndexBuilder.getThreadAddress(thrd, null);
if (addr == thAddr)
{
JavaObject jo;
try
{
jo = thrd.getObject();
}
catch (CorruptDataException e)
{
jo = null;
}
return jo;
}
}
// Now look for monitor objects
for (Iterator<?> i = dtfjInfo.getJavaRuntime().getMonitors(); i.hasNext();)
{
Object next = i.next();
if (next instanceof CorruptData)
{
continue;
}
JavaMonitor mon = (JavaMonitor) next;
JavaObject jo = mon.getObject();
if (jo != null && jo.getID().getAddress() == addr) { return jo; }
}
// Now look for class loader objects
for (Iterator<?> i = dtfjInfo.getJavaRuntime().getJavaClassLoaders(); i.hasNext();)
{
Object next = i.next();
if (next instanceof CorruptData)
{
continue;
}
JavaClassLoader ldr = (JavaClassLoader) next;
try
{
JavaObject jo = ldr.getObject();
if (jo != null && jo.getID().getAddress() == addr) { return jo; }
}
catch (CorruptDataException e)
{}
}
// Now look for ordinary objects on the heap
for (Iterator<?> i = dtfjInfo.getJavaRuntime().getHeaps(); i.hasNext();)
{
Object next = i.next();
if (next instanceof CorruptData)
{
continue;
}
JavaHeap jh = (JavaHeap) next;
for (Iterator<?> j = jh.getObjects(); j.hasNext();)
{
Object next2 = j.next();
if (next2 instanceof CorruptData)
{
continue;
}
JavaObject jo = (JavaObject) next2;
if (jo.getID().getAddress() == addr)
{
// System.out.println("At "+format(addr)+" found JavaObject
// "+jo+" by scanning entire heap");
return jo;
}
}
}
throw new IllegalArgumentException(MessageFormat.format(
Messages.DTFJHeapObjectReader_JavaObjectAtAddressNotFound, format(addr)));
}
/**
* @param snapshot
* @param objectId
* @param addr
* @param jo
* @return
* @throws CorruptDataException
* @throws SnapshotException
*/
private InstanceImpl createObject(ISnapshot snapshot, int objectId, long addr, JavaObject jo)
throws CorruptDataException, MemoryAccessException, SnapshotException
{
ClassImpl cls = findClass(snapshot, objectId, jo, addr);
/*
* Optimization - don't bother going to dump if there are no fields to
* be found, and find the number of fields in advance if we do.
*/
int nFields = 0;
for (ClassImpl cls2 = cls; cls2 != null; cls2 = cls2.getSuperClass())
{
nFields += cls2.getFieldDescriptors().size();
}
List<Field> fields = new ArrayList<Field>(nFields);
if (nFields > 0)
for (JavaClass jc = jo.getJavaClass(); jc != null; jc = getSuperclass(jc))
{
for (Iterator<?> ii = jc.getDeclaredFields(); ii.hasNext();)
{
Object next = ii.next();
if (next instanceof CorruptData)
continue;
JavaField jf = (JavaField) next;
if (!Modifier.isStatic(jf.getModifiers()))
{
Object val = null;
try
{
Object o = jf.get(jo);
if (o instanceof JavaObject)
{
JavaObject jo2 = (JavaObject) o;
long addr2 = jo2.getID().getAddress();
val = new ObjectReference(snapshot, addr2);
}
else
{
if (o instanceof Number || o instanceof Character || o instanceof Boolean || o == null)
{
val = o;
}
else
{
// Unexpected type
}
}
}
catch (CorruptDataException e)
{
logOrThrow(e);
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
Field f = new Field(jf.getName(), DTFJIndexBuilder.signatureToType(jf.getSignature()), val);
if (false)
System.out.println(jc.getName() + " New field " + f.getName() + " " //$NON-NLS-1$ //$NON-NLS-2$
+ f.getVerboseSignature() + " " + val); //$NON-NLS-1$
fields.add(f);
}
}
}
InstanceImpl inst;
if (snapshot.isClassLoader(objectId))
{
inst = new ClassLoaderImpl(objectId, addr, cls, fields);
}
else
{
inst = new InstanceImpl(objectId, addr, cls, fields);
}
// System.out.println("inst = "+inst);
return inst;
}
/**
* Find the {@link ClassImpl} which is the type of the object.
* @param snapshot the snapshot
* @param objectId for normal reads this is the object ID, -1 if unknown
* @param jo The DTFJ {@link JavaObject}
* @param addr the address of the object, for error messages
* @return the ClassImpl for the object, to allow the IOject to be constructed.
* @throws CorruptDataException
* @throws SnapshotException
*/
private ClassImpl findClass(ISnapshot snapshot, int objectId, JavaObject jo, long addr)
throws CorruptDataException, SnapshotException
{
ClassImpl cls;
if (objectId == -1)
{
JavaClass jc = jo.getJavaClass();
if (jc != null)
{
JavaObject jco = jc.getObject();
long caddr;
if (jco != null)
caddr = jco.getID().getAddress();
else
caddr = jc.getID().getAddress();
int clsId = snapshot.mapAddressToId(caddr);
IObject cls1 = snapshot.getObject(clsId);
if (cls1 instanceof ClassImpl)
cls = (ClassImpl) cls1;
else
throw new SnapshotException(MessageFormat.format(
Messages.DTFJHeapObjectReader_ErrorReadingObjectAtIndex, objectId, format(addr)));
}
else
{
throw new SnapshotException(MessageFormat.format(
Messages.DTFJHeapObjectReader_ErrorReadingObjectAtIndex, objectId, format(addr)));
}
}
else
{
cls = (ClassImpl) snapshot.getClassOf(objectId);
}
return cls;
}
/**
* Avoid problems with corrupt dumps
* @param jc
* @return
* @throws CorruptDataException
*/
private JavaClass getSuperclass(JavaClass jc) throws CorruptDataException
{
try
{
return jc.getSuperclass();
}
catch (CorruptDataException e)
{
// We have already logged this error on creating the indexes
if (false)
logOrThrow(e);
return null;
}
}
static class DeferredReadArray
{
// The MAT object ID
private int objectId;
// The MAT and DTFJ address
private long addr;
// The DTFJ object
private JavaObject jo;
public DeferredReadArray(int objectId, long addr, JavaObject jo)
{
setObjectId(objectId);
setAddr(addr);
setJo(jo);
}
private void setObjectId(int objectId)
{
this.objectId = objectId;
}
int getObjectId()
{
return objectId;
}
private void setAddr(long addr)
{
this.addr = addr;
}
long getAddr()
{
return addr;
}
private void setJo(JavaObject jo)
{
this.jo = jo;
}
JavaObject getJo()
{
return jo;
}
}
/**
* @param snapshot
* @param objectId
* @param addr
* @param jo
* @return
* @throws CorruptDataException
* @throws SnapshotException
*/
private IObject createArray(ISnapshot snapshot, int objectId, long addr, JavaObject jo)
throws CorruptDataException, MemoryAccessException, SnapshotException
{
ClassImpl cls = findClass(snapshot, objectId, jo, addr);
int offset = 0;
int length = jo.getArraySize();
// System.out.println("Array length "+length);
JavaClass arrayClass = jo.getJavaClass();
if (DTFJIndexBuilder.isPrimitiveArray(arrayClass))
{
String typeName = arrayClass.getName();
int type = getArrayType(typeName);
Object res;
if (length < LARGE_ARRAY_SIZE)
{
res = getPrimitiveData(jo, type, offset, length);
}
else
{
res = new DeferredReadArray(objectId, addr, jo);
}
// System.out.println("new "+type+" array["+length+"]");
// System.out.println("Byte Data "+Arrays.toString(res));
PrimitiveArrayImpl ret = new PrimitiveArrayImpl(objectId, addr, cls, length, type);
ret.setInfo(res);
return ret;
}
else
{
Object res;
// Performance optimization - for PHD files delay reading the refs until really needed.
// Often, we only need the array length.
Object format = snapshot.getSnapshotInfo().getProperty("$heapFormat"); //$NON-NLS-1$
if (!"DTFJ-PHD".equals(format) && length < LARGE_ARRAY_SIZE) //$NON-NLS-1$
{
res = getObjectData(jo, offset, length);
}
else
{
res = new DeferredReadArray(objectId, addr, jo);
}
// System.out.println("new object array["+length+"]");
// System.out.println("long Data "+Arrays.toString(res));
ObjectArrayImpl ret = new ObjectArrayImpl(objectId, addr, cls, length);
ret.setInfo(res);
return ret;
}
}
/**
* Extracts object data from a Java array
*
* @param jo
* @param offset
* @param length
* @return an array of addresses of the objects
* @throws CorruptDataException
*/
private long[] getObjectData(JavaObject jo, int offset, int length) throws CorruptDataException,
MemoryAccessException
{
JavaObject temp[] = new JavaObject[length];
try
{
jo.arraycopy(offset, temp, 0, length);
// System.out.println("Data "+Arrays.toString(temp));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
long res[] = new long[length];
for (int i = 0; i < length; ++i)
{
long addr2 = temp[i] == null ? 0 : temp[i].getID().getAddress();
res[i] = addr2;
}
return res;
}
/**
* Convert DTFJ array types to MAT types
*
* @param typeName
* @return
*/
private int getArrayType(String typeName)
{
int type;
if (typeName.equals("[Z") || typeName.equals("[boolean")) //$NON-NLS-1$ //$NON-NLS-2$
{
type = IObject.Type.BOOLEAN;
}
else if (typeName.equals("[B") || typeName.equals("[byte")) //$NON-NLS-1$ //$NON-NLS-2$
{
type = IObject.Type.BYTE;
}
else if (typeName.equals("[C") || typeName.equals("[char")) //$NON-NLS-1$ //$NON-NLS-2$
{
type = IObject.Type.CHAR;
}
else if (typeName.equals("[S") || typeName.equals("[short")) //$NON-NLS-1$ //$NON-NLS-2$
{
type = IObject.Type.SHORT;
}
else if (typeName.equals("[I") || typeName.equals("[int")) //$NON-NLS-1$ //$NON-NLS-2$
{
type = IObject.Type.INT;
}
else if (typeName.equals("[F") || typeName.equals("[float")) //$NON-NLS-1$ //$NON-NLS-2$
{
type = IObject.Type.FLOAT;
}
else if (typeName.equals("[J") || typeName.equals("[long")) //$NON-NLS-1$ //$NON-NLS-2$
{
type = IObject.Type.LONG;
}
else if (typeName.equals("[D") || typeName.equals("[double")) //$NON-NLS-1$ //$NON-NLS-2$
{
type = IObject.Type.DOUBLE;
}
else
{
// Should never occur
type = IObject.Type.BYTE;
throw new IllegalArgumentException(MessageFormat.format(Messages.DTFJHeapObjectReader_UnexpectedTypeName,
typeName));
}
return type;
}
/**
* Extract non-object data from a non-object array
*
* @param jo
* @param typeName
* @param offset
* in data items
* @param length
* @return
* @throws CorruptDataException
*/
private Object getPrimitiveData(JavaObject jo, int type, int offset, int length) throws CorruptDataException,
MemoryAccessException
{
Object res;
switch (type)
{
case IObject.Type.BOOLEAN:
res = new boolean[length];
try
{
jo.arraycopy(offset, res, 0, length);
// System.out.println("Data "+Arrays.toString(res));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
break;
case IObject.Type.BYTE:
res = new byte[length];
try
{
jo.arraycopy(offset, res, 0, length);
// System.out.println("Data "+Arrays.toString(res));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
break;
case IObject.Type.CHAR:
res = new char[length];
try
{
jo.arraycopy(offset, res, 0, length);
// System.out.println("Data "+Arrays.toString(res));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
break;
case IObject.Type.SHORT:
res = new short[length];
try
{
jo.arraycopy(offset, res, 0, length);
// System.out.println("Data "+Arrays.toString(temp));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
break;
case IObject.Type.INT:
res = new int[length];
try
{
jo.arraycopy(offset, res, 0, length);
// System.out.println("Data "+Arrays.toString(res));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
break;
case IObject.Type.FLOAT:
res = new float[length];
try
{
jo.arraycopy(offset, res, 0, length);
// System.out.println("Data "+Arrays.toString(res));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
break;
case IObject.Type.LONG:
res = new long[length];
try
{
jo.arraycopy(offset, res, 0, length);
// System.out.println("Data "+Arrays.toString(res));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
break;
case IObject.Type.DOUBLE:
res = new double[length];
try
{
jo.arraycopy(offset, res, 0, length);
// System.out.println("Data "+Arrays.toString(temp));
}
catch (MemoryAccessException e)
{
logOrThrow(e);
}
break;
default:
// Should never occur
// type = IObject.Type.BYTE;
// res = new byte[length * 8];
throw new IllegalArgumentException(MessageFormat.format(Messages.DTFJHeapObjectReader_UnexpectedType,
type));
}
return res;
}
/**
* Read some of the contents of an array
*
* @param array
* The MAT array to be read
* @param offset
* the offset into the array
* @param length
* the number of items to be read
* @return A primitive array holding the items
*/
public Object readPrimitiveArrayContent(PrimitiveArrayImpl array, int offset, int length) throws IOException,
SnapshotException
{
Object info = array.getInfo();
Object res;
if (info instanceof DeferredReadArray)
{
DeferredReadArray da = (DeferredReadArray) info;
try
{
// DTFJ is not thread safe, but MAT is multi-threaded
synchronized (dtfjInfo.getImage())
{
res = getPrimitiveData(da.getJo(), array.getType(), offset, length);
}
}
catch (CorruptDataException e)
{
IOException e1 = new IOException(MessageFormat.format(
Messages.DTFJHeapObjectReader_ErrorReadingPrimitiveArray, da.getObjectId(), format(da
.getAddr()), offset, length));
e1.initCause(e);
throw e1;
}
catch (MemoryAccessException e)
{
IOException e1 = new IOException(MessageFormat.format(
Messages.DTFJHeapObjectReader_ErrorReadingPrimitiveArray, da.getObjectId(), format(da
.getAddr()), offset, length));
e1.initCause(e);
throw e1;
}
}
else
{
res = Array.newInstance(info.getClass().getComponentType(), length);
System.arraycopy(info, offset, res, 0, length);
}
return res;
}
/**
* Read some of the contents of an array
*
* @param array
* The MAT array to be read
* @param offset
* the offset into the array
* @param length
* the number of items to be read
* @return A array of longs holding the addresses of the objects in the
* array
*/
public long[] readObjectArrayContent(ObjectArrayImpl array, int offset, int length) throws IOException,
SnapshotException
{
Object info = array.getInfo();
long res[];
if (info instanceof DeferredReadArray)
{
DeferredReadArray da = (DeferredReadArray) info;
try
{
// DTFJ is not thread safe, but MAT is multi-threaded
synchronized (dtfjInfo.getImage())
{
res = getObjectData(da.getJo(), offset, length);
}
}
catch (CorruptDataException e)
{
IOException e1 = new IOException(MessageFormat.format(
Messages.DTFJHeapObjectReader_ErrorReadingObjectArray, da.getObjectId(), format(da
.getAddr()), offset, length));
e1.initCause(e);
throw e1;
}
catch (MemoryAccessException e)
{
IOException e1 = new IOException(MessageFormat.format(
Messages.DTFJHeapObjectReader_ErrorReadingObjectArray, da.getObjectId(), format(da
.getAddr()), offset, length));
e1.initCause(e);
throw e1;
}
}
else
{
res = new long[length];
System.arraycopy(info, offset, res, 0, length);
}
return res;
}
/**
* Convert an address to a 0x hex number
*
* @param address
* @return A string representing the address
*/
private static String format(long address)
{
return "0x" + Long.toHexString(address); //$NON-NLS-1$
}
private void logOrThrow(MemoryAccessException e) throws MemoryAccessException
{
if (throwExceptions)
throw e;
e.printStackTrace();
}
private void logOrThrow(CorruptDataException e) throws CorruptDataException
{
if (throwExceptions)
throw e;
e.printStackTrace();
}
}