diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java index 9a2effe1669f4e..475b0c7044ac53 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java @@ -9,12 +9,16 @@ import io.quarkus.arc.ComponentsProvider; import io.quarkus.arc.InjectableBean; import io.quarkus.arc.processor.ResourceOutput.Resource; +import io.quarkus.gizmo.AssignableResultHandle; +import io.quarkus.gizmo.BytecodeCreator; +import io.quarkus.gizmo.CatchBlockCreator; import io.quarkus.gizmo.ClassCreator; import io.quarkus.gizmo.ClassOutput; import io.quarkus.gizmo.FieldDescriptor; import io.quarkus.gizmo.MethodCreator; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; +import io.quarkus.gizmo.TryBlock; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; @@ -120,8 +124,10 @@ Collection generate(String name, BeanDeployment beanDeployment, Map { private final ResultHandle removedBeansHandle; + private final ResultHandle typeCacheHandle; private final ClassOutput classOutput; private ResultHandle tccl; // Shared annotation literals for an individual addRemovedBeansX() method private final Map sharedQualifers; - // Shared java.lang.reflect.Type instances for an individual addRemovedBeansX() method - private final Map sharedTypes; + + private final MapTypeCache typeCache; public RemovedBeanAdder(ClassCreator componentsProvider, MethodCreator getComponentsMethod, - ResultHandle removedBeansHandle, ClassOutput classOutput) { + ResultHandle removedBeansHandle, ResultHandle typeCacheHandle, ClassOutput classOutput) { super(getComponentsMethod, componentsProvider); this.removedBeansHandle = removedBeansHandle; + this.typeCacheHandle = typeCacheHandle; this.classOutput = classOutput; this.sharedQualifers = new HashMap<>(); - this.sharedTypes = new HashMap<>(); + this.typeCache = new MapTypeCache(); } @Override MethodCreator newAddMethod() { // Clear the shared maps for each addRemovedBeansX() method sharedQualifers.clear(); - sharedTypes.clear(); - MethodCreator addMethod = componentsProvider.getMethodCreator(ADD_REMOVED_BEANS + group++, void.class, List.class) + // private void addRemovedBeans1(List removedBeans, List typeCache) + MethodCreator addMethod = componentsProvider + .getMethodCreator(ADD_REMOVED_BEANS + group++, void.class, List.class, Map.class) .setModifiers(ACC_PRIVATE); // Get the TCCL - we will use it later ResultHandle currentThread = addMethod .invokeStaticMethod(MethodDescriptors.THREAD_CURRENT_THREAD); tccl = addMethod.invokeVirtualMethod(MethodDescriptors.THREAD_GET_TCCL, currentThread); + + typeCache.initialize(addMethod); + return addMethod; } @@ -420,8 +433,8 @@ MethodCreator newAddMethod() { void invokeAddMethod() { getComponentsMethod.invokeVirtualMethod( MethodDescriptor.ofMethod(componentsProvider.getClassName(), - addMethod.getMethodDescriptor().getName(), void.class, List.class), - getComponentsMethod.getThis(), removedBeansHandle); + addMethod.getMethodDescriptor().getName(), void.class, List.class, Map.class), + getComponentsMethod.getThis(), removedBeansHandle, typeCacheHandle); } @Override @@ -436,14 +449,20 @@ void addComponentInternal(BeanInfo removedBean) { // Skip java.lang.Object continue; } - ResultHandle typeHandle; + + TryBlock tryBlock = addMethod.tryBlock(); + CatchBlockCreator catchBlock = tryBlock.addCatch(Throwable.class); + catchBlock.invokeStaticInterfaceMethod( + MethodDescriptors.COMPONENTS_PROVIDER_UNABLE_TO_LOAD_REMOVED_BEAN_TYPE, + catchBlock.load(type.toString()), catchBlock.getCaughtException()); + AssignableResultHandle typeHandle = tryBlock.createVariable(Object.class); try { - typeHandle = Types.getTypeHandle(addMethod, type, tccl, sharedTypes); + Types.getTypeHandle(typeHandle, tryBlock, type, tccl, typeCache); } catch (IllegalArgumentException e) { throw new IllegalStateException( "Unable to construct the type handle for " + removedBean + ": " + e.getMessage()); } - addMethod.invokeInterfaceMethod(MethodDescriptors.SET_ADD, typesHandle, typeHandle); + tryBlock.invokeInterfaceMethod(MethodDescriptors.SET_ADD, typesHandle, typeHandle); } // Qualifiers @@ -513,6 +532,27 @@ void addComponentInternal(BeanInfo removedBean) { } + static class MapTypeCache implements Types.TypeCache { + + private ResultHandle mapHandle; + + @Override + public void initialize(MethodCreator method) { + this.mapHandle = method.getMethodParam(1); + } + + @Override + public ResultHandle get(org.jboss.jandex.Type type, BytecodeCreator bytecode) { + return bytecode.invokeInterfaceMethod(MethodDescriptors.MAP_GET, mapHandle, bytecode.load(type.toString())); + } + + @Override + public void put(org.jboss.jandex.Type type, ResultHandle value, BytecodeCreator bytecode) { + bytecode.invokeInterfaceMethod(MethodDescriptors.MAP_PUT, mapHandle, bytecode.load(type.toString()), value); + } + + } + static class BeanAdder extends ComponentAdder { private final Set processedBeans; diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java index 06622c2f085a3d..b1f8dfad9edaee 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java @@ -3,6 +3,7 @@ import io.quarkus.arc.Arc; import io.quarkus.arc.ArcContainer; import io.quarkus.arc.ClientProxy; +import io.quarkus.arc.ComponentsProvider; import io.quarkus.arc.InjectableBean; import io.quarkus.arc.InjectableBean.Kind; import io.quarkus.arc.InjectableContext; @@ -80,6 +81,8 @@ public final class MethodDescriptors { public static final MethodDescriptor LIST_ADD = MethodDescriptor.ofMethod(List.class, "add", boolean.class, Object.class); + public static final MethodDescriptor LIST_GET = MethodDescriptor.ofMethod(List.class, "get", Object.class, int.class); + public static final MethodDescriptor OBJECT_EQUALS = MethodDescriptor.ofMethod(Object.class, "equals", boolean.class, Object.class); @@ -265,6 +268,10 @@ public final class MethodDescriptors { .ofMethod(Instances.class, "listOfHandles", List.class, InjectableBean.class, Type.class, Type.class, Set.class, CreationalContextImpl.class, Set.class, Member.class, int.class); + public static final MethodDescriptor COMPONENTS_PROVIDER_UNABLE_TO_LOAD_REMOVED_BEAN_TYPE = MethodDescriptor.ofMethod( + ComponentsProvider.class, "unableToLoadRemovedBeanType", + void.class, String.class, Throwable.class); + private MethodDescriptors() { } diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java index 28284991d4edc7..ebcbc9f42543ee 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java @@ -6,7 +6,10 @@ import io.quarkus.arc.impl.ParameterizedTypeImpl; import io.quarkus.arc.impl.TypeVariableImpl; import io.quarkus.arc.impl.WildcardTypeImpl; +import io.quarkus.gizmo.AssignableResultHandle; +import io.quarkus.gizmo.BranchResult; import io.quarkus.gizmo.BytecodeCreator; +import io.quarkus.gizmo.MethodCreator; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; import java.util.ArrayList; @@ -76,24 +79,26 @@ public static ResultHandle getTypeHandle(BytecodeCreator creator, Type type) { } public static ResultHandle getTypeHandle(BytecodeCreator creator, Type type, ResultHandle tccl) { - return getTypeHandle(creator, type, tccl, null); + AssignableResultHandle result = creator.createVariable(Object.class); + getTypeHandle(result, creator, type, tccl, null); + return result; } - static ResultHandle getTypeHandle(BytecodeCreator creator, Type type, ResultHandle tccl, - Map sharedTypes) { - if (sharedTypes != null) { - ResultHandle sharedType = sharedTypes.get(type); - if (sharedType != null) { - return sharedType; - } + static void getTypeHandle(AssignableResultHandle variable, BytecodeCreator creator, Type type, ResultHandle tccl, + TypeCache cache) { + if (cache != null) { + ResultHandle cachedType = cache.get(type, creator); + BranchResult cachedNull = creator.ifNull(cachedType); + cachedNull.falseBranch().assign(variable, cachedType); + creator = cachedNull.trueBranch(); } if (Kind.CLASS.equals(type.kind())) { String className = type.asClassType().name().toString(); ResultHandle classHandle = doLoadClass(creator, className, tccl); - if (sharedTypes != null) { - sharedTypes.put(type, classHandle); + if (cache != null) { + cache.put(type, classHandle, creator); } - return classHandle; + creator.assign(variable, classHandle); } else if (Kind.TYPE_VARIABLE.equals(type.kind())) { // E.g. T -> new TypeVariableImpl("T") TypeVariable typeVariable = type.asTypeVariable(); @@ -104,69 +109,85 @@ static ResultHandle getTypeHandle(BytecodeCreator creator, Type type, ResultHand } else { boundsHandle = creator.newArray(java.lang.reflect.Type.class, creator.load(bounds.size())); for (int i = 0; i < bounds.size(); i++) { - creator.writeArrayValue(boundsHandle, i, getTypeHandle(creator, bounds.get(i), tccl, sharedTypes)); + AssignableResultHandle boundHandle = creator.createVariable(Object.class); + getTypeHandle(boundHandle, creator, bounds.get(i), tccl, cache); + creator.writeArrayValue(boundsHandle, i, boundHandle); } } ResultHandle typeVariableHandle = creator.newInstance( MethodDescriptor.ofConstructor(TypeVariableImpl.class, String.class, java.lang.reflect.Type[].class), creator.load(typeVariable.identifier()), boundsHandle); - if (sharedTypes != null) { - sharedTypes.put(typeVariable, typeVariableHandle); + if (cache != null) { + cache.put(typeVariable, typeVariableHandle, creator); } - return typeVariableHandle; + creator.assign(variable, typeVariableHandle); } else if (Kind.PARAMETERIZED_TYPE.equals(type.kind())) { // E.g. List -> new ParameterizedTypeImpl(List.class, String.class) - return getParameterizedType(creator, tccl, type.asParameterizedType(), sharedTypes); + getParameterizedType(variable, creator, tccl, type.asParameterizedType(), cache); } else if (Kind.ARRAY.equals(type.kind())) { Type componentType = type.asArrayType().component(); // E.g. String[] -> new GenericArrayTypeImpl(String.class) + AssignableResultHandle componentTypeHandle = creator.createVariable(Object.class); + getTypeHandle(componentTypeHandle, creator, componentType, tccl, cache); ResultHandle arrayHandle = creator.newInstance( MethodDescriptor.ofConstructor(GenericArrayTypeImpl.class, java.lang.reflect.Type.class), - getTypeHandle(creator, componentType, tccl, sharedTypes)); - if (sharedTypes != null) { - sharedTypes.put(type, arrayHandle); + componentTypeHandle); + if (cache != null) { + cache.put(type, arrayHandle, creator); } - return arrayHandle; + creator.assign(variable, arrayHandle); } else if (Kind.WILDCARD_TYPE.equals(type.kind())) { // E.g. ? extends Number -> WildcardTypeImpl.withUpperBound(Number.class) WildcardType wildcardType = type.asWildcardType(); ResultHandle wildcardHandle; if (wildcardType.superBound() == null) { + AssignableResultHandle extendsBoundHandle = creator.createVariable(Object.class); + getTypeHandle(extendsBoundHandle, creator, wildcardType.extendsBound(), tccl, cache); wildcardHandle = creator.invokeStaticMethod( MethodDescriptor.ofMethod(WildcardTypeImpl.class, "withUpperBound", java.lang.reflect.WildcardType.class, java.lang.reflect.Type.class), - getTypeHandle(creator, wildcardType.extendsBound(), tccl, sharedTypes)); + extendsBoundHandle); } else { + AssignableResultHandle superBoundHandle = creator.createVariable(Object.class); + getTypeHandle(superBoundHandle, creator, wildcardType.superBound(), tccl, cache); wildcardHandle = creator.invokeStaticMethod( MethodDescriptor.ofMethod(WildcardTypeImpl.class, "withLowerBound", java.lang.reflect.WildcardType.class, java.lang.reflect.Type.class), - getTypeHandle(creator, wildcardType.superBound(), tccl, sharedTypes)); + superBoundHandle); } - if (sharedTypes != null) { - sharedTypes.put(wildcardType, wildcardHandle); + if (cache != null) { + cache.put(wildcardType, wildcardHandle, creator); } - return wildcardHandle; + creator.assign(variable, wildcardHandle); } else if (Kind.PRIMITIVE.equals(type.kind())) { switch (type.asPrimitiveType().primitive()) { case INT: - return creator.loadClassFromTCCL(int.class); + creator.assign(variable, creator.loadClassFromTCCL(int.class)); + break; case LONG: - return creator.loadClassFromTCCL(long.class); + creator.assign(variable, creator.loadClassFromTCCL(long.class)); + break; case BOOLEAN: - return creator.loadClassFromTCCL(boolean.class); + creator.assign(variable, creator.loadClassFromTCCL(boolean.class)); + break; case BYTE: - return creator.loadClassFromTCCL(byte.class); + creator.assign(variable, creator.loadClassFromTCCL(byte.class)); + break; case CHAR: - return creator.loadClassFromTCCL(char.class); + creator.assign(variable, creator.loadClassFromTCCL(char.class)); + break; case DOUBLE: - return creator.loadClassFromTCCL(double.class); + creator.assign(variable, creator.loadClassFromTCCL(double.class)); + break; case FLOAT: - return creator.loadClassFromTCCL(float.class); + creator.assign(variable, creator.loadClassFromTCCL(float.class)); + break; case SHORT: - return creator.loadClassFromTCCL(short.class); + creator.assign(variable, creator.loadClassFromTCCL(short.class)); + break; default: throw new IllegalArgumentException("Unsupported primitive type: " + type); } @@ -175,37 +196,39 @@ static ResultHandle getTypeHandle(BytecodeCreator creator, Type type, ResultHand } } - static ResultHandle getParameterizedType(BytecodeCreator creator, ResultHandle tccl, - ParameterizedType parameterizedType, Map sharedTypes) { + static void getParameterizedType(AssignableResultHandle variable, BytecodeCreator creator, ResultHandle tccl, + ParameterizedType parameterizedType, TypeCache cache) { List arguments = parameterizedType.arguments(); ResultHandle typeArgsHandle = creator.newArray(java.lang.reflect.Type.class, creator.load(arguments.size())); for (int i = 0; i < arguments.size(); i++) { - creator.writeArrayValue(typeArgsHandle, i, getTypeHandle(creator, arguments.get(i), tccl, sharedTypes)); + AssignableResultHandle argumentHandle = creator.createVariable(Object.class); + getTypeHandle(argumentHandle, creator, arguments.get(i), tccl, cache); + creator.writeArrayValue(typeArgsHandle, i, argumentHandle); } Type rawType = Type.create(parameterizedType.name(), Kind.CLASS); ResultHandle rawTypeHandle = null; - if (sharedTypes != null) { - rawTypeHandle = sharedTypes.get(rawType); + if (cache != null) { + rawTypeHandle = cache.get(rawType, creator); } if (rawTypeHandle == null) { rawTypeHandle = doLoadClass(creator, parameterizedType.name().toString(), tccl); - if (sharedTypes != null) { - sharedTypes.put(rawType, rawTypeHandle); + if (cache != null) { + cache.put(rawType, rawTypeHandle, creator); } } ResultHandle parameterizedTypeHandle = creator.newInstance( MethodDescriptor.ofConstructor(ParameterizedTypeImpl.class, java.lang.reflect.Type.class, java.lang.reflect.Type[].class), rawTypeHandle, typeArgsHandle); - if (sharedTypes != null) { - sharedTypes.put(parameterizedType, parameterizedTypeHandle); + if (cache != null) { + cache.put(parameterizedType, parameterizedTypeHandle, creator); } - return parameterizedTypeHandle; + creator.assign(variable, parameterizedTypeHandle); } - public static ResultHandle getParameterizedType(BytecodeCreator creator, ResultHandle tccl, + public static void getParameterizedType(AssignableResultHandle variable, BytecodeCreator creator, ResultHandle tccl, ParameterizedType parameterizedType) { - return getParameterizedType(creator, tccl, parameterizedType, null); + getParameterizedType(variable, creator, tccl, parameterizedType, null); } private static ResultHandle doLoadClass(BytecodeCreator creator, String className, ResultHandle tccl) { @@ -546,4 +569,26 @@ static boolean containsTypeVariable(Type type) { return false; } + interface TypeCache { + + void initialize(MethodCreator method); + + /** + * + * @param type + * @param bytecode + * @return the cached value or {@code null} + */ + ResultHandle get(Type type, BytecodeCreator bytecode); + + /** + * + * @param type + * @param value + * @param bytecode + */ + void put(Type type, ResultHandle value, BytecodeCreator bytecode); + + } + } diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java index af2f893e65705a..6ef91d6baa22fb 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java @@ -1,10 +1,18 @@ package io.quarkus.arc; +import org.jboss.logging.Logger; + /** * Service provider interface used to colllect the runtime components. */ public interface ComponentsProvider { + static Logger LOG = Logger.getLogger(ComponentsProvider.class); + Components getComponents(); + static void unableToLoadRemovedBeanType(String type, Throwable problem) { + LOG.warnf("Unable to load removed bean type [%s]: %s", type, problem.toString()); + } + } \ No newline at end of file