use of com.newrelic.agent.util.asm.PatchedClassWriter in project newrelic-java-agent by newrelic.
the class InstrumentingClassLoader method transform.
@Override
protected byte[] transform(String className) throws Exception {
byte[] classBytes = WeaveUtils.getClassBytesFromClassLoaderResource(className, this);
if (classBytes == null) {
return null;
}
final InstrumentationContext context = new InstrumentationContext(classBytes, null, null);
new ClassReader(classBytes).accept(new ScalaTraitMatcher().newClassMatchVisitor(null, null, null, null, context), ClassReader.SKIP_FRAMES);
// weave
byte[] weaved = weave(className, classBytes, context.getSkipMethods(), new ClassWeavedListener() {
@Override
public void classWeaved(PackageWeaveResult weaveResult, ClassLoader classloader, ClassCache cache) {
if (weaveResult.weavedClass()) {
final String packageName = weaveResult.getValidationResult().getWeavePackage().getName();
for (String originalName : weaveResult.getWeavedMethods().keySet()) {
for (Method method : weaveResult.getWeavedMethods().get(originalName)) {
context.addWeavedMethod(method, packageName);
}
ClassWeaverService.addTraceInformation(InstrumentingClassLoader.this.tracedWeaveInstrumentationDetails, packageName, context, weaveResult.getComposite(), originalName);
}
try {
Map<String, byte[]> annotationProxyClasses = weaveResult.getAnnotationProxyClasses();
if (!annotationProxyClasses.isEmpty()) {
// Special case for annotation weaving in order to support dynamic annotation proxies. We
// need to add the dynamic proxy classes that we created to the current classloader here
NewClassAppender.appendClasses(classloader, annotationProxyClasses);
}
} catch (Exception e) {
Agent.LOG.log(Level.FINE, e, "Unable to add annotation proxy classes");
}
}
}
});
// trace
if (weaved != null) {
classBytes = weaved;
}
ClassReader reader = new ClassReader(classBytes);
if (weaved == null) {
// process trace annotations for non-weaved code
reader.accept(new SimpleTraceMatchVisitor(null, context), ClassReader.EXPAND_FRAMES);
}
if (!context.isTracerMatch()) {
if (weaved != null) {
// printClass(className, weaved);
return weaved;
}
return null;
}
NoticeSqlVisitor noticeSqlVisitor = new NoticeSqlVisitor(WeaveUtils.ASM_API_LEVEL);
// find the noticeSql calls
reader.accept(noticeSqlVisitor, ClassReader.SKIP_FRAMES);
String internalClassName = className.replace('.', '/');
ClassWriter writer = new PatchedClassWriter(ClassWriter.COMPUTE_FRAMES, context.getClassResolver(this));
ClassVisitor cv = writer;
cv = new TraceClassVisitor(cv, internalClassName, context, noticeSqlVisitor.getNoticeSqlMethods());
cv = new ClassVisitor(WeaveUtils.ASM_API_LEVEL, cv) {
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
if (version < 49 || version > 100) {
// Some weird Apache classes have really large versions.
version = WeaveUtils.RUNTIME_MAX_SUPPORTED_CLASS_VERSION;
}
super.visit(version, access, name, signature, superName, interfaces);
}
};
reader.accept(cv, ClassReader.EXPAND_FRAMES);
byte[] result = writer.toByteArray();
return result;
}
use of com.newrelic.agent.util.asm.PatchedClassWriter in project newrelic-java-agent by newrelic.
the class FinalClassTransformer method getFinalTransformation.
private byte[] getFinalTransformation(ClassLoader loader, String className, Class<?> classBeingRedefined, byte[] classfileBuffer, InstrumentationContext context) {
ClassReader reader = new ClassReader(classfileBuffer);
ClassWriter writer = new PatchedClassWriter(ClassWriter.COMPUTE_FRAMES, context.getClassResolver(loader));
ClassVisitor cv = writer;
if (!context.getWeavedMethods().isEmpty()) {
cv = new MarkWeaverMethodsVisitor(cv, context);
}
cv = addModifiedClassAnnotation(cv, context);
cv = addModifiedMethodAnnotation(cv, context, loader);
cv = new ClassVisitor(WeaveUtils.ASM_API_LEVEL, cv) {
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
if (version < 49 || version > 100) {
// Some weird Apache classes have really large versions.
int newVersion = WeaveUtils.RUNTIME_MAX_SUPPORTED_CLASS_VERSION;
if (CLASSES_TO_SKIP_VERSION_UPGRADE.contains(name)) {
newVersion = WeaveUtils.JAVA_6_CLASS_VERSION;
}
Agent.LOG.log(Level.FINEST, "Converting {0} from version {1} to {2}", name, version, newVersion);
version = newVersion;
}
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new JSRInlinerAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc, signature, exceptions);
}
};
cv = skipExistingAnnotations(cv);
cv = CurrentTransactionRewriter.rewriteCurrentTransactionReferences(cv, reader);
reader.accept(cv, ClassReader.SKIP_FRAMES);
byte[] classBytes = writer.toByteArray();
if (CLASS_CHECKER != null) {
CLASS_CHECKER.check(classBytes);
}
if (Agent.isDebugEnabled()) {
writeClassFiles(className, context, classBytes);
}
addSupportabilityMetrics(reader, className, context);
Agent.LOG.finer("Final transformation of class " + className);
return classBytes;
}
use of com.newrelic.agent.util.asm.PatchedClassWriter in project newrelic-java-agent by newrelic.
the class JVMClassTransformerTest method convertToClassBytes.
/**
* Converts an ASM {@link ClassNode} to a byte array. Us
*
* @param classNode class node to convert
* @param classloader the classloader used to create the {@link PatchedClassWriter}
* @return byte array representing the specified class node
*/
public static byte[] convertToClassBytes(ClassNode classNode, ClassLoader classloader) {
// ClassWriter cw = new PatchedClassWriter(ClassWriter.COMPUTE_FRAMES, classloader);
ClassWriter cw = new ClassWriter(WeaveUtils.ASM_API_LEVEL);
classNode.accept(cw);
return cw.toByteArray();
}
use of com.newrelic.agent.util.asm.PatchedClassWriter in project newrelic-java-agent by newrelic.
the class ExtensionRewriter method rewrite.
/**
* Given a jar file, return the bytes for a new jar in which all classes have been modified so that references to
* dependencies that we repackage in the agent are rewritten to reference the repackaged classes. If no such
* references are found, a null is returned.
*
* @return the bytes for a new jar file, or null if no new jar is needed
*/
public static byte[] rewrite(JarFile jar, ClassLoader classLoader) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
JarOutputStream jarOut = new JarOutputStream(out);
boolean modified = false;
try {
for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
JarEntry entry = e.nextElement();
JarEntry newEntry = new JarEntry(entry.getName());
InputStream inputStream = jar.getInputStream(entry);
try {
if (entry.getName().endsWith(".class")) {
ClassReader cr = new ClassReader(inputStream);
ClassWriter writer = new PatchedClassWriter(ClassWriter.COMPUTE_FRAMES, classLoader);
ClassVisitor cv = new ClassRemapper(writer, REMAPPER);
cr.accept(cv, ClassReader.SKIP_FRAMES);
if (!REMAPPER.getRemappings().isEmpty()) {
modified = true;
}
inputStream.close();
inputStream = new ByteArrayInputStream(writer.toByteArray());
}
jarOut.putNextEntry(newEntry);
Streams.copy(inputStream, jarOut, inputStream.available());
} finally {
jarOut.closeEntry();
inputStream.close();
}
}
} finally {
jarOut.close();
jar.close();
out.close();
}
return modified ? out.toByteArray() : null;
}
Aggregations