io.opentelemetry.javaagent.tooling.instrumentation.indy.PatchByteCodeVersionTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of opentelemetry-javaagent-tooling Show documentation
Show all versions of opentelemetry-javaagent-tooling Show documentation
Instrumentation of Java libraries using OpenTelemetry.
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.tooling.instrumentation.indy;
import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import java.security.ProtectionDomain;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.field.FieldList;
import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.pool.TypePool;
import net.bytebuddy.utility.JavaModule;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.JSRInlinerAdapter;
/**
* Patches the class file version to 51 (Java 7) in order to support injecting {@code INVOKEDYNAMIC}
* instructions via {@link Advice.WithCustomMapping#bootstrap} which is important for indy plugins.
*/
public class PatchByteCodeVersionTransformer implements AgentBuilder.Transformer {
private static boolean isAtLeastJava7(TypeDescription typeDescription) {
ClassFileVersion classFileVersion = typeDescription.getClassFileVersion();
return classFileVersion != null && classFileVersion.getJavaVersion() >= 7;
}
@Override
public DynamicType.Builder> transform(
DynamicType.Builder> builder,
TypeDescription typeDescription,
ClassLoader classLoader,
JavaModule javaModule,
ProtectionDomain protectionDomain) {
if (isAtLeastJava7(typeDescription)) {
// we can avoid the expensive stack frame re-computation if stack frames are already present
// in the bytecode.
return builder;
}
return builder.visit(
new AsmVisitorWrapper.AbstractBase() {
@Override
public ClassVisitor wrap(
TypeDescription typeDescription,
ClassVisitor classVisitor,
Implementation.Context context,
TypePool typePool,
FieldList fieldList,
MethodList> methodList,
int writerFlags,
int readerFlags) {
return new ClassVisitor(Opcodes.ASM7, classVisitor) {
@Override
public void visit(
int version,
int access,
String name,
String signature,
String superName,
String[] interfaces) {
super.visit(Opcodes.V1_7, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(
int access,
String name,
String descriptor,
String signature,
String[] exceptions) {
MethodVisitor methodVisitor =
super.visitMethod(access, name, descriptor, signature, exceptions);
return new JSRInlinerAdapter(
methodVisitor, access, name, descriptor, signature, exceptions);
}
};
}
@Override
public int mergeWriter(int flags) {
// class files with version < Java 7 don't require a stack frame map
// as we're patching the version to at least 7, we have to compute the frames
return flags | COMPUTE_FRAMES;
}
});
}
}