/******************************************************************************* | |
* 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; | |
} | |
} | |
} |