package com.foursquare.heapaudit;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
public class HeapClass extends HeapUtil implements ClassVisitor {
public HeapClass(ClassVisitor cv,
String classId,
boolean suppressAuditing,
boolean debugAuditing) {
this.cv = new ClassAdapter(cv);
this.id = classId;
this.suppressClass = suppressAuditing;
this.debugClass = debugAuditing;
log(debugClass,
"{ # CLASS " + id);
}
private final ClassAdapter cv;
private String source;
private final String id;
private boolean suppressClass;
private final boolean debugClass;
public void visit(int version,
int access,
String name,
String signature,
String superName,
String[] interfaces) {
log(debugClass,
"\tvisit()");
cv.visit(version,
access,
name,
signature,
superName,
interfaces);
}
public void visitSource(String source,
String debug) {
log(debugClass,
"\tvisitSource(" + source + ", " + debug + ")");
this.source = source;
cv.visitSource(source,
debug);
}
public void visitOuterClass(String owner,
String name,
String desc) {
log(debugClass,
"\tvisitOuterClass(" + owner + ", " + name + ", " + desc + ")");
cv.visitOuterClass(owner,
name,
desc);
}
public AnnotationVisitor visitAnnotation(String desc,
boolean visible) {
log(debugClass,
"\tvisitAnnotation(" + desc + ", " + visible + ")");
if (desc.equals("Lcom/foursquare/heapaudit/HeapRecorder$Suppress;")) {
suppressClass = true;
}
return cv.visitAnnotation(desc,
visible);
}
public void visitAttribute(Attribute attr) {
log(debugClass,
"\tvisitAttribute()");
cv.visitAttribute(attr);
}
public void visitInnerClass(String name,
String outerName,
String innerName,
int access) {
log(debugClass,
"\tvisitInnerClass(" + name + ", " + outerName + ", " + innerName + ", " + access + ")");
cv.visitInnerClass(name,
outerName,
innerName,
access);
}
public FieldVisitor visitField(int access,
String name,
String desc,
String signature,
Object value) {
log(debugClass,
"\tvisitField()");
return cv.visitField(access,
name,
desc,
signature,
value);
}
public MethodVisitor visitMethod(int access,
String name,
String desc,
String signature,
String[] exceptions) {
log(debugClass,
"\tvisitMethod()");
String method = name + desc;
boolean suppressAuditing = suppressClass ||
HeapSettings.shouldSuppressAuditing(id,
method);
boolean avoidAuditing = HeapSettings.shouldAvoidAuditing(id,
method);
boolean debugAuditing = HeapSettings.shouldDebugAuditing(id,
method);
boolean traceAuditing = HeapSettings.shouldTraceAuditing(id,
method);
boolean injectRecorder = HeapSettings.shouldInjectRecorder(id,
method);
boolean threadRecorder = HeapSettings.threaded &&
id.equals("java/lang/Thread") &&
name.equals("<init>");
if (!suppressAuditing &&
avoidAuditing &&
!injectRecorder &&
!threadRecorder) {
return cv.visitMethod(access,
name,
desc,
signature,
exceptions);
}
HeapMethod mv = new HeapMethod(cv.visitMethod(access,
name,
desc,
signature,
exceptions),
source,
id + '@' + method,
suppressAuditing,
debugAuditing,
traceAuditing,
injectRecorder);
// The following sets up the weird cyclic dependency whereby the
// HeapMethod implementation uses the HeapVariables class for injecting
// new local variables but the HeapVariables wraps the HeapMethod from
// the outside.
mv.lvs = new HeapVariables(access,
desc,
debugAuditing,
traceAuditing,
mv);
return mv.lvs.lvs;
}
public void visitEnd() {
log(debugClass,
"\tvisitEnd()\n}");
cv.visitEnd();
}
}