blob: 7c6bc04611a63a497499e7333ab520fbf7ca0c85 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2018 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
* IBM Corporation - additional resolvers and fixes
*******************************************************************************/
package org.eclipse.mat.inspections;
import java.lang.reflect.Modifier;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.extension.IClassSpecificNameResolver;
import org.eclipse.mat.snapshot.extension.Subject;
import org.eclipse.mat.snapshot.extension.Subjects;
import org.eclipse.mat.snapshot.model.IClass;
import org.eclipse.mat.snapshot.model.IObject;
import org.eclipse.mat.snapshot.model.IObjectArray;
import org.eclipse.mat.snapshot.model.IPrimitiveArray;
import org.eclipse.mat.snapshot.model.PrettyPrinter;
import org.eclipse.mat.snapshot.registry.ClassSpecificNameResolverRegistry;
public class CommonNameResolver
{
@Subject("java.lang.String")
public static class StringResolver implements IClassSpecificNameResolver
{
public String resolve(IObject obj) throws SnapshotException
{
return PrettyPrinter.objectAsString(obj, 1024);
}
}
@Subjects( { "java.lang.StringBuffer", //
"java.lang.StringBuilder" })
public static class StringBufferResolver implements IClassSpecificNameResolver
{
public String resolve(IObject obj) throws SnapshotException
{
Integer count = (Integer) obj.resolveValue("count"); //$NON-NLS-1$
if (count == null)
return null;
if (count == 0)
return ""; //$NON-NLS-1$
IPrimitiveArray charArray = (IPrimitiveArray) obj.resolveValue("value"); //$NON-NLS-1$
if (charArray == null)
return null;
if (charArray.getType() == IObject.Type.BYTE)
{
// Java 9 compact strings
return PrettyPrinter.objectAsString(obj, 1024);
}
else
{
return PrettyPrinter.arrayAsString(charArray, 0, count, 1024);
}
}
}
@Subject("java.lang.Thread")
public static class ThreadResolver implements IClassSpecificNameResolver
{
public String resolve(IObject obj) throws SnapshotException
{
IObject name = (IObject) obj.resolveValue("name"); //$NON-NLS-1$
return name != null ? name.getClassSpecificName() : null;
}
}
@Subject("java.lang.ThreadGroup")
public static class ThreadGroupResolver implements IClassSpecificNameResolver
{
public String resolve(IObject object) throws SnapshotException
{
IObject nameString = (IObject) object.resolveValue("name"); //$NON-NLS-1$
if (nameString == null)
return null;
return nameString.getClassSpecificName();
}
}
@Subjects( { "java.lang.Byte", //
"java.lang.Character", //
"java.lang.Short", //
"java.lang.Integer", //
"java.lang.Long", //
"java.lang.Float", //
"java.lang.Double", //
"java.lang.Boolean", //
"java.util.concurrent.atomic.AtomicInteger", //
"java.util.concurrent.atomic.AtomicLong", //
})
public static class ValueResolver implements IClassSpecificNameResolver
{
public String resolve(IObject heapObject) throws SnapshotException
{
Object value = heapObject.resolveValue("value"); //$NON-NLS-1$
return value != null ? String.valueOf(value) : null;
}
}
/**
* For Oracle VMs for int.class, byte.class, void.class etc.
* These are just simple IObjects, not IClass objects.
* All other classes resolve via IClass.
*/
@Subjects("java.lang.Class")
public static class ClassTypeResolver implements IClassSpecificNameResolver
{
public String resolve(IObject object) throws SnapshotException
{
// Let normal IClass resolution happen if possible
if (object instanceof IClass)
return null;
IObject nameString = (IObject) object.resolveValue("name"); //$NON-NLS-1$
if (nameString == null)
return null;
return nameString.getClassSpecificName();
}
}
@Subjects("java.util.concurrent.atomic.AtomicBoolean")
public static class AtomicBooleanResolver implements IClassSpecificNameResolver
{
public String resolve(IObject heapObject) throws SnapshotException
{
Integer value = (Integer) heapObject.resolveValue("value"); //$NON-NLS-1$
return value != null ? Boolean.toString(value != 0) : null;
}
}
@Subjects("java.util.concurrent.atomic.AtomicReference")
public static class AtomicReferenceValueResolver implements IClassSpecificNameResolver
{
public String resolve(IObject heapObject) throws SnapshotException
{
IObject value = (IObject) heapObject.resolveValue("value"); //$NON-NLS-1$
return value != null ? ClassSpecificNameResolverRegistry.resolve(value) : null;
}
}
@Subjects("java.util.concurrent.atomic.AtomicStampedReference")
public static class AtomicStampedReferenceValueResolver implements IClassSpecificNameResolver
{
public String resolve(IObject heapObject) throws SnapshotException
{
IObject value = (IObject) heapObject.resolveValue("pair.reference"); //$NON-NLS-1$
return value != null ? ClassSpecificNameResolverRegistry.resolve(value) : null;
}
}
@Subject("char[]")
public static class CharArrayResolver implements IClassSpecificNameResolver
{
public String resolve(IObject heapObject) throws SnapshotException
{
IPrimitiveArray charArray = (IPrimitiveArray) heapObject;
return PrettyPrinter.arrayAsString(charArray, 0, charArray.getLength(), 1024);
}
}
@Subject("byte[]")
public static class ByteArrayResolver implements IClassSpecificNameResolver
{
public String resolve(IObject heapObject) throws SnapshotException
{
IPrimitiveArray arr = (IPrimitiveArray) heapObject;
byte[] value = (byte[]) arr.getValueArray(0, Math.min(arr.getLength(), 1024));
if (value == null)
return null;
// must not modify the original byte array
StringBuilder r = new StringBuilder(value.length);
for (int i = 0; i < value.length; i++)
{
// ASCII/Unicode 127 is not printable
if (value[i] < 32 || value[i] > 126)
r.append('.');
else
r.append((char) value[i]);
}
return r.toString();
}
}
/*
* Contributed in bug 273915
*/
@Subject("java.net.URL")
public static class URLResolver implements IClassSpecificNameResolver
{
public String resolve(IObject obj) throws SnapshotException
{
StringBuilder builder = new StringBuilder();
IObject protocol = (IObject) obj.resolveValue("protocol"); //$NON-NLS-1$
if (protocol != null)
{
builder.append(protocol.getClassSpecificName());
builder.append(":"); //$NON-NLS-1$
}
IObject authority = (IObject) obj.resolveValue("authority"); //$NON-NLS-1$
if (authority != null)
{
builder.append("//"); //$NON-NLS-1$
builder.append(authority.getClassSpecificName());
}
IObject path = (IObject) obj.resolveValue("path"); //$NON-NLS-1$
if (path != null)
builder.append(path.getClassSpecificName());
IObject query = (IObject) obj.resolveValue("query"); //$NON-NLS-1$
if (query != null)
{
builder.append("?"); //$NON-NLS-1$
builder.append(query.getClassSpecificName());
}
IObject ref = (IObject) obj.resolveValue("ref"); //$NON-NLS-1$
if (ref != null)
{
builder.append("#"); //$NON-NLS-1$
builder.append(ref.getClassSpecificName());
}
return builder.length() > 0 ? builder.toString() : null;
}
}
@Subject("java.lang.reflect.AccessibleObject")
public static class AccessibleObjectResolver implements IClassSpecificNameResolver
{
public String resolve(IObject obj) throws SnapshotException
{
// Important fields
// modifiers - not actually present, but present in all superclasses
// clazz - not actually present, but present in all superclasses
StringBuilder r = new StringBuilder();
ISnapshot snapshot = obj.getSnapshot();
IObject ref;
Object val = obj.resolveValue("modifiers"); //$NON-NLS-1$
if (val instanceof Integer)
{
r.append(Modifier.toString((Integer)val));
if (r.length() > 0) r.append(' ');
}
ref = (IObject) obj.resolveValue("clazz"); //$NON-NLS-1$
if (ref != null)
{
addClassName(snapshot, ref.getObjectAddress(), r);
}
else
{
return null;
}
return r.toString();
}
protected void addClassName(ISnapshot snapshot, long addr, StringBuilder r) throws SnapshotException
{
int id = snapshot.mapAddressToId(addr);
IObject ox = snapshot.getObject(id);
if (ox instanceof IClass)
{
IClass cls = (IClass) ox;
r.append(cls.getName());
}
}
}
@Subject("java.lang.reflect.Field")
public static class FieldResolver extends AccessibleObjectResolver
{
public String resolve(IObject obj) throws SnapshotException
{
// Important fields
// modifiers
// clazz
// name
// type
StringBuilder r = new StringBuilder();
ISnapshot snapshot = obj.getSnapshot();
IObject ref;
Object val = obj.resolveValue("modifiers"); //$NON-NLS-1$
if (val instanceof Integer)
{
r.append(Modifier.toString((Integer)val));
if (r.length() > 0) r.append(' ');
}
ref = (IObject) obj.resolveValue("type"); //$NON-NLS-1$
if (ref != null)
{
addClassName(snapshot, ref.getObjectAddress(), r);
r.append(' ');
}
ref = (IObject) obj.resolveValue("clazz"); //$NON-NLS-1$
if (ref != null)
{
addClassName(snapshot, ref.getObjectAddress(), r);
r.append('.');
}
ref = (IObject) obj.resolveValue("name"); //$NON-NLS-1$
if (ref != null)
{
r.append(ref.getClassSpecificName());
}
else
{
// No method name so give up
return null;
}
return r.toString();
}
}
@Subject("java.lang.reflect.Method")
public static class MethodResolver extends AccessibleObjectResolver
{
public String resolve(IObject obj) throws SnapshotException
{
// Important fields
// modifiers
// clazz
// name
// parameterTypes[]
// exceptionTypes[]
// returnType
StringBuilder r = new StringBuilder();
ISnapshot snapshot = obj.getSnapshot();
IObject ref;
Object val = obj.resolveValue("modifiers"); //$NON-NLS-1$
if (val instanceof Integer)
{
r.append(Modifier.toString((Integer)val));
if (r.length() > 0) r.append(' ');
}
ref = (IObject) obj.resolveValue("returnType"); //$NON-NLS-1$
if (ref != null)
{
addClassName(snapshot, ref.getObjectAddress(), r);
r.append(' ');
}
ref = (IObject) obj.resolveValue("clazz"); //$NON-NLS-1$
if (ref != null)
{
addClassName(snapshot, ref.getObjectAddress(), r);
r.append('.');
}
ref = (IObject) obj.resolveValue("name"); //$NON-NLS-1$
if (ref != null)
{
r.append(ref.getClassSpecificName());
}
else
{
// No method name so give up
return null;
}
r.append('(');
ref = (IObject) obj.resolveValue("parameterTypes"); //$NON-NLS-1$
if (ref instanceof IObjectArray)
{
IObjectArray orefa = (IObjectArray) ref;
long refs[] = orefa.getReferenceArray();
for (int i = 0; i < orefa.getLength(); ++i)
{
if (i > 0)
r.append(',');
long addr = refs[i];
addClassName(snapshot, addr, r);
}
}
r.append(')');
return r.toString();
}
}
@Subject("java.lang.reflect.Constructor")
public static class ConstructorResolver extends AccessibleObjectResolver
{
public String resolve(IObject obj) throws SnapshotException
{
// Important fields
// modifiers
// clazz
// parameterTypes[]
// exceptionTypes[]
StringBuilder r = new StringBuilder();
ISnapshot snapshot = obj.getSnapshot();
IObject ref;
Object val = obj.resolveValue("modifiers"); //$NON-NLS-1$
if (val instanceof Integer)
{
r.append(Modifier.toString((Integer)val));
if (r.length() > 0) r.append(' ');
}
ref = (IObject) obj.resolveValue("clazz"); //$NON-NLS-1$
if (ref != null)
{
addClassName(snapshot, ref.getObjectAddress(), r);
}
else
{
// No class name so give up
return null;
}
r.append('(');
ref = (IObject) obj.resolveValue("parameterTypes"); //$NON-NLS-1$
if (ref instanceof IObjectArray)
{
IObjectArray orefa = (IObjectArray) ref;
long refs[] = orefa.getReferenceArray();
for (int i = 0; i < orefa.getLength(); ++i)
{
if (i > 0)
r.append(',');
long addr = refs[i];
addClassName(snapshot, addr, r);
}
}
r.append(')');
return r.toString();
}
}
@Subject("java.lang.StackTraceElement")
public static class StackTraceElementResolver implements IClassSpecificNameResolver
{
public String resolve(IObject obj) throws SnapshotException
{
IObject cls = (IObject)obj.resolveValue("declaringClass");
IObject methodName = (IObject)obj.resolveValue("methodName");
if (cls == null || methodName == null)
return null;
int line = (Integer)obj.resolveValue("lineNumber");
IObject fn = (IObject)obj.resolveValue("fileName");
String ln;
if (line == -2)
ln = "(Compiled Code)";
else if (line == -3)
ln = "(Native Method)";
else if (line == -1)
ln = "";
else if (line == 0)
ln = "";
else
ln = Integer.toString(line);
String name;
if (fn == null)
if (line > 0)
name = cls.getClassSpecificName() + "." + methodName.getClassSpecificName() + "() " + ln;
else
name = cls.getClassSpecificName() + "." + methodName.getClassSpecificName() + "()";
else
if (line > 0)
name = cls.getClassSpecificName() + "." + methodName.getClassSpecificName() + "() ("
+ fn.getClassSpecificName() + ":" + ln + ")";
else
name = cls.getClassSpecificName() + "." + methodName.getClassSpecificName() + "() ("
+ fn.getClassSpecificName() + ")";
return name;
}
}
}