/* NEST (New Scala Test)
* Copyright 2007-2013 LAMP/EPFL
* @author Grzegorz Kossakowski
*/
package scala.tools.partest.javaagent;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import scala.tools.asm.ClassReader;
import scala.tools.asm.ClassWriter;
public class ASMTransformer implements ClassFileTransformer {
private boolean shouldTransform(String className) {
return
// do not instrument instrumentation logic (in order to avoid infinite recursion)
!className.startsWith("scala/tools/partest/instrumented/") &&
!className.startsWith("scala/tools/partest/javaagent/") &&
// we instrument all classes from empty package
(!className.contains("/") ||
// we instrument all classes from scala package
className.startsWith("scala/") ||
// we instrument all classes from `instrumented` package
className.startsWith("instrumented/"));
}
public byte[] transform(final ClassLoader classLoader, final String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
if (shouldTransform(className)) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS) {
@Override protected String getCommonSuperClass(final String type1, final String type2) {
// Since we are not recomputing stack frame map, this should never be called we override this method because
// default implementation uses reflection for implementation and might try to load the class that we are
// currently processing. That leads to weird results like swallowed exceptions and classes being not
// transformed.
throw new RuntimeException("Unexpected call to getCommonSuperClass(" + type1 + ", " + type2 +
") while transforming " + className);
}
};
ProfilerVisitor visitor = new ProfilerVisitor(writer);
ClassReader reader = new ClassReader(classfileBuffer);
reader.accept(visitor, 0);
return writer.toByteArray();
} else {
return classfileBuffer;
}
}
}