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