Skip to content

Commit c1fa608

Browse files
authored
Merge pull request quarkusio#35742 from mkouba/gizmo-transformer-api
Bump gizmo to 1.7.0 and leverage the ClassTransformer API in ArC
2 parents 2c25d2f + b9f7aed commit c1fa608

File tree

8 files changed

+84
-226
lines changed

8 files changed

+84
-226
lines changed

bom/application/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
<maven-toolchain.version>3.0-alpha-2</maven-toolchain.version>
9292
<plexus-component-annotations.version>2.1.0</plexus-component-annotations.version>
9393
<graal-sdk.version>23.0.1</graal-sdk.version>
94-
<gizmo.version>1.6.1.Final</gizmo.version>
94+
<gizmo.version>1.7.0</gizmo.version>
9595
<jackson-bom.version>2.15.2</jackson-bom.version>
9696
<commons-logging-jboss-logging.version>1.0.0.Final</commons-logging-jboss-logging.version>
9797
<commons-lang3.version>3.12.0</commons-lang3.version>

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/staticmethods/InterceptedStaticMethodsProcessor.java

+26-81
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
import org.jboss.jandex.Type;
3434
import org.jboss.logging.Logger;
3535
import org.objectweb.asm.ClassVisitor;
36-
import org.objectweb.asm.MethodVisitor;
37-
import org.objectweb.asm.Opcodes;
3836

3937
import io.quarkus.arc.InjectableInterceptor;
4038
import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem;
@@ -61,13 +59,12 @@
6159
import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem;
6260
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
6361
import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
64-
import io.quarkus.deployment.util.AsmUtil;
6562
import io.quarkus.gizmo.BytecodeCreator;
6663
import io.quarkus.gizmo.ClassCreator;
6764
import io.quarkus.gizmo.ClassOutput;
65+
import io.quarkus.gizmo.ClassTransformer;
6866
import io.quarkus.gizmo.DescriptorUtils;
6967
import io.quarkus.gizmo.FunctionCreator;
70-
import io.quarkus.gizmo.Gizmo;
7168
import io.quarkus.gizmo.MethodCreator;
7269
import io.quarkus.gizmo.MethodDescriptor;
7370
import io.quarkus.gizmo.ResultHandle;
@@ -445,85 +442,33 @@ public InterceptedStaticMethodsEnhancer(String initializerClassName, List<Interc
445442

446443
@Override
447444
public ClassVisitor apply(String className, ClassVisitor outputClassVisitor) {
448-
return new InterceptedStaticMethodsClassVisitor(initializerClassName, outputClassVisitor, methods);
449-
}
450-
451-
}
452-
453-
static class InterceptedStaticMethodsClassVisitor extends ClassVisitor {
454-
455-
private final String initializerClassName;
456-
private final List<InterceptedStaticMethodBuildItem> methods;
457-
458-
public InterceptedStaticMethodsClassVisitor(String initializerClassName, ClassVisitor outputClassVisitor,
459-
List<InterceptedStaticMethodBuildItem> methods) {
460-
super(Gizmo.ASM_API_VERSION, outputClassVisitor);
461-
this.methods = methods;
462-
this.initializerClassName = initializerClassName;
463-
}
464-
465-
@Override
466-
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
467-
InterceptedStaticMethodBuildItem method = findMatchingMethod(access, name, descriptor);
468-
if (method != null) {
469-
MethodVisitor copy = super.visitMethod(access,
470-
name + ORIGINAL_METHOD_COPY_SUFFIX,
471-
descriptor,
472-
signature,
473-
exceptions);
474-
MethodVisitor superVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
475-
return new InterceptedStaticMethodsMethodVisitor(superVisitor, copy, initializerClassName, method);
476-
} else {
477-
return super.visitMethod(access, name, descriptor, signature, exceptions);
478-
}
479-
}
480-
481-
private InterceptedStaticMethodBuildItem findMatchingMethod(int access, String name, String descriptor) {
482-
if (Modifier.isStatic(access)) {
483-
for (InterceptedStaticMethodBuildItem method : methods) {
484-
if (method.getMethod().name().equals(name)
485-
&& MethodDescriptor.of(method.getMethod()).getDescriptor().equals(descriptor)) {
486-
return method;
487-
}
445+
ClassTransformer transformer = new ClassTransformer(className);
446+
for (InterceptedStaticMethodBuildItem interceptedStaticMethod : methods) {
447+
MethodInfo interceptedMethod = interceptedStaticMethod.getMethod();
448+
MethodDescriptor originalDescriptor = MethodDescriptor.of(interceptedMethod);
449+
// Rename the intercepted method
450+
transformer.modifyMethod(originalDescriptor)
451+
.rename(interceptedMethod.name() + ORIGINAL_METHOD_COPY_SUFFIX);
452+
453+
// Add the intercepted method again - invoke the initializer in the body, e.g. Foo_InterceptorInitializer.hash("ping")
454+
MethodCreator newMethod = transformer.addMethod(originalDescriptor)
455+
.setModifiers(interceptedMethod.flags())
456+
.setSignature(interceptedMethod.genericSignatureIfRequired());
457+
for (Type exceptionType : interceptedMethod.exceptions()) {
458+
newMethod.addException(exceptionType.name().toString());
488459
}
460+
ResultHandle[] args = new ResultHandle[interceptedMethod.parametersCount()];
461+
for (int i = 0; i < interceptedMethod.parametersCount(); ++i) {
462+
args[i] = newMethod.getMethodParam(i);
463+
}
464+
ResultHandle ret = newMethod.invokeStaticMethod(MethodDescriptor.ofMethod(initializerClassName,
465+
interceptedStaticMethod.getForwardingMethodName(),
466+
interceptedMethod.returnType().descriptor(),
467+
interceptedMethod.parameterTypes().stream().map(Type::descriptor).toArray()),
468+
args);
469+
newMethod.returnValue(ret);
489470
}
490-
return null;
491-
}
492-
493-
}
494-
495-
static class InterceptedStaticMethodsMethodVisitor extends MethodVisitor {
496-
497-
private final String initializerClassName;
498-
private final InterceptedStaticMethodBuildItem interceptedStaticMethod;
499-
private final MethodVisitor superVisitor;
500-
501-
public InterceptedStaticMethodsMethodVisitor(MethodVisitor superVisitor, MethodVisitor copyVisitor,
502-
String initializerClassName, InterceptedStaticMethodBuildItem interceptedStaticMethod) {
503-
super(Gizmo.ASM_API_VERSION, copyVisitor);
504-
this.superVisitor = superVisitor;
505-
this.initializerClassName = initializerClassName;
506-
this.interceptedStaticMethod = interceptedStaticMethod;
507-
}
508-
509-
@Override
510-
public void visitEnd() {
511-
// Invoke the initializer, i.e. Foo_InterceptorInitializer.hash("ping")
512-
MethodDescriptor descriptor = MethodDescriptor.of(interceptedStaticMethod.getMethod());
513-
int paramSlot = 0;
514-
for (Type paramType : interceptedStaticMethod.getMethod().parameterTypes()) {
515-
superVisitor.visitIntInsn(AsmUtil.getLoadOpcode(paramType), paramSlot);
516-
paramSlot += AsmUtil.getParameterSize(paramType);
517-
}
518-
superVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
519-
initializerClassName.replace('.', '/'), interceptedStaticMethod.getForwardingMethodName(),
520-
descriptor.getDescriptor().toString(),
521-
false);
522-
superVisitor.visitInsn(AsmUtil.getReturnInstruction(interceptedStaticMethod.getMethod().returnType()));
523-
superVisitor.visitMaxs(0, 0);
524-
superVisitor.visitEnd();
525-
526-
super.visitEnd();
471+
return transformer.applyTo(outputClassVisitor);
527472
}
528473

529474
}

independent-projects/arc/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<version.jpa>3.1.0</version.jpa>
4848
<version.jta>2.0.1</version.jta>
4949
<!-- main versions -->
50-
<version.gizmo>1.6.1.Final</version.gizmo>
50+
<version.gizmo>1.7.0</version.gizmo>
5151
<version.jandex>3.1.3</version.jandex>
5252
<version.jboss-logging>3.5.3.Final</version.jboss-logging>
5353
<version.mutiny>2.2.0</version.mutiny>

independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java

+31-73
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@
3434
import org.jboss.jandex.Type.Kind;
3535
import org.jboss.logging.Logger;
3636
import org.objectweb.asm.ClassVisitor;
37-
import org.objectweb.asm.FieldVisitor;
38-
import org.objectweb.asm.MethodVisitor;
3937
import org.objectweb.asm.Opcodes;
4038

4139
import io.quarkus.arc.processor.InjectionPointInfo.TypeAndQualifiers;
42-
import io.quarkus.gizmo.Gizmo;
40+
import io.quarkus.gizmo.ClassTransformer;
41+
import io.quarkus.gizmo.FieldDescriptor;
42+
import io.quarkus.gizmo.MethodCreator;
43+
import io.quarkus.gizmo.MethodDescriptor;
4344

4445
public final class Beans {
4546

@@ -696,7 +697,7 @@ static void validateInterceptorDecorator(BeanInfo bean, List<Throwable> errors,
696697
if (injection.isField() && Modifier.isPrivate(injection.getTarget().asField().flags())) {
697698
bytecodeTransformerConsumer
698699
.accept(new BytecodeTransformer(bean.getTarget().get().asClass().name().toString(),
699-
new PrivateInjectedFieldTransformFunction(injection.getTarget().asField().name())));
700+
new PrivateInjectedFieldTransformFunction(injection.getTarget().asField())));
700701
}
701702
}
702703
}
@@ -791,7 +792,7 @@ static void validateBean(BeanInfo bean, List<Throwable> errors, Consumer<Bytecod
791792
for (Injection injection : bean.getInjections()) {
792793
if (injection.isField() && Modifier.isPrivate(injection.getTarget().asField().flags())) {
793794
bytecodeTransformerConsumer.accept(new BytecodeTransformer(beanClass.name().toString(),
794-
new PrivateInjectedFieldTransformFunction(injection.getTarget().asField().name())));
795+
new PrivateInjectedFieldTransformFunction(injection.getTarget().asField())));
795796
}
796797
}
797798
}
@@ -1046,8 +1047,7 @@ private static Integer initAlternativePriority(AnnotationTarget target, Integer
10461047
Integer computedPriority = deployment.computeAlternativePriority(target, stereotypes);
10471048
if (computedPriority != null) {
10481049
if (alternativePriority != null) {
1049-
LOGGER.infof(
1050-
"Computed priority [%s] overrides the priority [%s] declared via @Priority",
1050+
LOGGER.infof("Computed priority [%s] overrides the priority [%s] declared via @Priority",
10511051
computedPriority, alternativePriority);
10521052
}
10531053
alternativePriority = computedPriority;
@@ -1059,17 +1059,10 @@ static class FinalClassTransformFunction implements BiFunction<String, ClassVisi
10591059

10601060
@Override
10611061
public ClassVisitor apply(String className, ClassVisitor classVisitor) {
1062-
return new ClassVisitor(Gizmo.ASM_API_VERSION, classVisitor) {
1063-
1064-
@Override
1065-
public void visit(int version, int access, String name, String signature,
1066-
String superName,
1067-
String[] interfaces) {
1068-
LOGGER.debugf("Final flag removed from bean class %s", className);
1069-
super.visit(version, access = access & (~Opcodes.ACC_FINAL), name, signature,
1070-
superName, interfaces);
1071-
}
1072-
};
1062+
ClassTransformer transformer = new ClassTransformer(className);
1063+
transformer.removeModifiers(Opcodes.ACC_FINAL);
1064+
LOGGER.debugf("Final flag removed from bean class %s", className);
1065+
return transformer.applyTo(classVisitor);
10731066
}
10741067
}
10751068

@@ -1083,26 +1076,13 @@ public NoArgConstructorTransformFunction(String superClassName) {
10831076

10841077
@Override
10851078
public ClassVisitor apply(String className, ClassVisitor classVisitor) {
1086-
return new ClassVisitor(Gizmo.ASM_API_VERSION, classVisitor) {
1087-
1088-
@Override
1089-
public void visit(int version, int access, String name, String signature,
1090-
String superName,
1091-
String[] interfaces) {
1092-
super.visit(version, access, name, signature, superName, interfaces);
1093-
MethodVisitor mv = visitMethod(Modifier.PUBLIC | Opcodes.ACC_SYNTHETIC, Methods.INIT, "()V", null,
1094-
null);
1095-
mv.visitCode();
1096-
mv.visitVarInsn(Opcodes.ALOAD, 0);
1097-
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassName, Methods.INIT, "()V",
1098-
false);
1099-
// NOTE: it seems that we do not need to handle final fields?
1100-
mv.visitInsn(Opcodes.RETURN);
1101-
mv.visitMaxs(1, 1);
1102-
mv.visitEnd();
1103-
LOGGER.debugf("Added a no-args constructor to bean class: %s", className);
1104-
}
1105-
};
1079+
ClassTransformer transformer = new ClassTransformer(className);
1080+
MethodCreator constructor = transformer.addMethod(MethodDescriptor.ofConstructor(className));
1081+
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(superClassName), constructor.getThis());
1082+
// NOTE: it seems that we do not need to handle final fields
1083+
constructor.returnVoid();
1084+
LOGGER.debugf("Added a no-args constructor to bean class: %s", className);
1085+
return transformer.applyTo(classVisitor);
11061086
}
11071087

11081088
}
@@ -1111,53 +1091,31 @@ static class PrivateNoArgsConstructorTransformFunction implements BiFunction<Str
11111091

11121092
@Override
11131093
public ClassVisitor apply(String className, ClassVisitor classVisitor) {
1114-
return new ClassVisitor(Gizmo.ASM_API_VERSION, classVisitor) {
1115-
1116-
@Override
1117-
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
1118-
String[] exceptions) {
1119-
if (name.equals(Methods.INIT)) {
1120-
access = access & (~Opcodes.ACC_PRIVATE);
1121-
LOGGER.debugf(
1122-
"Changed visibility of a private no-args constructor to package-private: %s",
1123-
className);
1124-
}
1125-
return super.visitMethod(access, name, descriptor, signature, exceptions);
1126-
}
1127-
};
1094+
ClassTransformer transformer = new ClassTransformer(className);
1095+
transformer.modifyMethod(MethodDescriptor.ofConstructor(className)).removeModifiers(Opcodes.ACC_PRIVATE);
1096+
LOGGER.debugf("Changed visibility of a private no-args constructor to package-private: %s",
1097+
className);
1098+
return transformer.applyTo(classVisitor);
11281099
}
11291100

11301101
}
11311102

11321103
// alters an injected field modifier from private to package private
11331104
static class PrivateInjectedFieldTransformFunction implements BiFunction<String, ClassVisitor, ClassVisitor> {
11341105

1135-
public PrivateInjectedFieldTransformFunction(String fieldName) {
1136-
this.fieldName = fieldName;
1106+
public PrivateInjectedFieldTransformFunction(FieldInfo field) {
1107+
this.field = field;
11371108
}
11381109

1139-
private String fieldName;
1110+
private FieldInfo field;
11401111

11411112
@Override
11421113
public ClassVisitor apply(String className, ClassVisitor classVisitor) {
1143-
return new ClassVisitor(Gizmo.ASM_API_VERSION, classVisitor) {
1144-
1145-
@Override
1146-
public FieldVisitor visitField(
1147-
int access,
1148-
String name,
1149-
String descriptor,
1150-
String signature,
1151-
Object value) {
1152-
if (name.equals(fieldName)) {
1153-
access = access & (~Opcodes.ACC_PRIVATE);
1154-
LOGGER.debugf(
1155-
"Changed visibility of an injected private field to package-private. Field name: %s in class: %s",
1156-
name, className);
1157-
}
1158-
return super.visitField(access, name, descriptor, signature, value);
1159-
}
1160-
};
1114+
ClassTransformer transformer = new ClassTransformer(className);
1115+
transformer.modifyField(FieldDescriptor.of(field)).removeModifiers(Opcodes.ACC_PRIVATE);
1116+
LOGGER.debugf("Changed visibility of an injected private field to package-private. Field name: %s in class: %s",
1117+
field.name(), className);
1118+
return transformer.applyTo(classVisitor);
11611119
}
11621120

11631121
}

independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.quarkus.arc.InjectableContext;
2929
import io.quarkus.arc.impl.Mockable;
3030
import io.quarkus.arc.processor.BeanGenerator.ProviderType;
31+
import io.quarkus.arc.processor.Methods.MethodKey;
3132
import io.quarkus.arc.processor.ResourceOutput.Resource;
3233
import io.quarkus.arc.processor.ResourceOutput.Resource.SpecialType;
3334
import io.quarkus.gizmo.BytecodeCreator;
@@ -332,18 +333,18 @@ Collection<MethodInfo> getDelegatingMethods(BeanInfo bean, Consumer<BytecodeTran
332333
IndexView index = bean.getDeployment().getBeanArchiveIndex();
333334

334335
if (bean.isClassBean()) {
335-
Map<String, Set<Methods.NameAndDescriptor>> methodsFromWhichToRemoveFinal = new HashMap<>();
336+
Map<String, Set<MethodKey>> methodsFromWhichToRemoveFinal = new HashMap<>();
336337
ClassInfo classInfo = bean.getTarget().get().asClass();
337338
addDelegatesAndTrasformIfNecessary(bytecodeTransformerConsumer, transformUnproxyableClasses, methods, index,
338339
methodsFromWhichToRemoveFinal, classInfo);
339340
} else if (bean.isProducerMethod()) {
340-
Map<String, Set<Methods.NameAndDescriptor>> methodsFromWhichToRemoveFinal = new HashMap<>();
341+
Map<String, Set<MethodKey>> methodsFromWhichToRemoveFinal = new HashMap<>();
341342
MethodInfo producerMethod = bean.getTarget().get().asMethod();
342343
ClassInfo returnTypeClass = getClassByName(index, producerMethod.returnType());
343344
addDelegatesAndTrasformIfNecessary(bytecodeTransformerConsumer, transformUnproxyableClasses, methods, index,
344345
methodsFromWhichToRemoveFinal, returnTypeClass);
345346
} else if (bean.isProducerField()) {
346-
Map<String, Set<Methods.NameAndDescriptor>> methodsFromWhichToRemoveFinal = new HashMap<>();
347+
Map<String, Set<MethodKey>> methodsFromWhichToRemoveFinal = new HashMap<>();
347348
FieldInfo producerField = bean.getTarget().get().asField();
348349
ClassInfo fieldClass = getClassByName(index, producerField.type());
349350
addDelegatesAndTrasformIfNecessary(bytecodeTransformerConsumer, transformUnproxyableClasses, methods, index,
@@ -359,15 +360,15 @@ Collection<MethodInfo> getDelegatingMethods(BeanInfo bean, Consumer<BytecodeTran
359360
private void addDelegatesAndTrasformIfNecessary(Consumer<BytecodeTransformer> bytecodeTransformerConsumer,
360361
boolean transformUnproxyableClasses,
361362
Map<Methods.MethodKey, MethodInfo> methods, IndexView index,
362-
Map<String, Set<Methods.NameAndDescriptor>> methodsFromWhichToRemoveFinal,
363+
Map<String, Set<MethodKey>> methodsFromWhichToRemoveFinal,
363364
ClassInfo fieldClass) {
364365
Methods.addDelegatingMethods(index, fieldClass, methods, methodsFromWhichToRemoveFinal,
365366
transformUnproxyableClasses);
366367
if (!methodsFromWhichToRemoveFinal.isEmpty()) {
367-
for (Map.Entry<String, Set<Methods.NameAndDescriptor>> entry : methodsFromWhichToRemoveFinal.entrySet()) {
368+
for (Map.Entry<String, Set<MethodKey>> entry : methodsFromWhichToRemoveFinal.entrySet()) {
368369
String className = entry.getKey();
369370
bytecodeTransformerConsumer.accept(new BytecodeTransformer(className,
370-
new Methods.RemoveFinalFromMethod(className, entry.getValue())));
371+
new Methods.RemoveFinalFromMethod(entry.getValue())));
371372
}
372373
}
373374
}

0 commit comments

Comments
 (0)