From 8d08f0ad8532c63a9161bf7761dcd351fc2bb23b Mon Sep 17 00:00:00 2001 From: Martin Panzer Date: Tue, 30 Nov 2021 18:57:14 +0100 Subject: [PATCH] Avoid duplicate calls to getParameterTypes and getGenericParameterTypes Calling getParameterTypes or getGenericParameterTypes creates clones of the underlying arrays. Doing so during iterations is costly, so lets better not do that. --- .../ReflectiveMethodBuildItem.java | 10 ++++--- .../deployment/proxy/ProxyFactory.java | 8 ++++-- .../recording/BytecodeRecorderImpl.java | 28 +++++++++++++------ .../deployment/AmazonLambdaProcessor.java | 20 +++++++------ .../lambda/runtime/AmazonLambdaRecorder.java | 13 +++++---- .../funqy/runtime/FunctionInvoker.java | 9 ++++-- .../functions/QuarkusBackgroundFunction.java | 5 ++-- .../proxy/nonjaxrs/LRAParticipant.java | 9 +++--- .../io/quarkus/qute/MethodsCandidate.java | 3 +- .../startup/RuntimeResourceDeployment.java | 13 +++++---- .../quarkus/arquillian/InjectionEnricher.java | 4 +-- .../MethodParameterInjectionPoint.java | 5 ++-- .../test/junit/QuarkusTestExtension.java | 4 ++- 13 files changed, 79 insertions(+), 52 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveMethodBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveMethodBuildItem.java index a5a64d143e99d..1ce1c86d438ee 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveMethodBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveMethodBuildItem.java @@ -25,11 +25,13 @@ public ReflectiveMethodBuildItem(MethodInfo methodInfo) { } public ReflectiveMethodBuildItem(Method method) { - String[] params = new String[method.getParameterCount()]; - for (int i = 0; i < params.length; ++i) { - params[i] = method.getParameterTypes()[i].getName(); + this.params = new String[method.getParameterCount()]; + if (method.getParameterCount() > 0) { + Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < params.length; ++i) { + params[i] = parameterTypes[i].getName(); + } } - this.params = params; this.name = method.getName(); this.declaringClass = method.getDeclaringClass().getName(); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/proxy/ProxyFactory.java b/core/deployment/src/main/java/io/quarkus/deployment/proxy/ProxyFactory.java index 977bd86c6837f..54a5125d95132 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/proxy/ProxyFactory.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/proxy/ProxyFactory.java @@ -190,9 +190,10 @@ private void doDefineClass() { ctor.returnValue(null); } + Class[] parameterTypes = injectConstructor.getParameterTypes(); List> args = new ArrayList<>(); args.add(InvocationHandler.class); - args.addAll(Arrays.asList(injectConstructor.getParameterTypes())); + args.addAll(Arrays.asList(parameterTypes)); try (MethodCreator ctor = cc .getMethodCreator(MethodDescriptor.ofConstructor(proxyName, args.toArray(Class[]::new)))) { List params = new ArrayList<>(); @@ -201,7 +202,7 @@ private void doDefineClass() { } ctor.invokeSpecialMethod( MethodDescriptor.ofConstructor(injectConstructor.getDeclaringClass(), - injectConstructor.getParameterTypes()), + parameterTypes), ctor.getThis(), params.toArray(ResultHandle[]::new)); ctor.writeInstanceField(invocationHandlerField, ctor.getThis(), ctor.getMethodParam(0)); @@ -268,8 +269,9 @@ public T newInstance(InvocationHandler handler) throws IllegalAccessException, I defineClass(); Object[] args = new Object[constructor.getParameterCount()]; args[0] = handler; + Class[] parameterTypes = this.constructor.getParameterTypes(); for (int i = 1; i < constructor.getParameterCount(); ++i) { - Constructor ctor = this.constructor.getParameterTypes()[i].getConstructor(); + Constructor ctor = parameterTypes[i].getConstructor(); ctor.setAccessible(true); args[i] = ctor.newInstance(); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java index 3bce407441b75..5cfe0e6da3cde 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java @@ -4,6 +4,7 @@ import static io.quarkus.gizmo.MethodDescriptor.ofMethod; import java.io.Closeable; +import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -497,9 +498,11 @@ ResultHandle createValue(MethodContext context, MethodCreator method, ResultHand //for every parameter that was passed into the method we create a deferred value //this will allocate a space in the array, so the value can be deserialized correctly //even if the code for an invocation is split over several methods + Class[] parameterTypes = call.method.getParameterTypes(); + Annotation[][] parameterAnnotations = call.method.getParameterAnnotations(); for (int i = 0; i < call.parameters.length; ++i) { call.deferredParameters[i] = loadObjectInstance(call.parameters[i], parameterMap, - call.method.getParameterTypes()[i], Arrays.stream(call.method.getParameterAnnotations()[i]) + parameterTypes[i], Arrays.stream(parameterAnnotations[i]) .anyMatch(s -> s.annotationType() == RelaxedValidation.class)); } } catch (Exception e) { @@ -1148,10 +1151,11 @@ public void prepare(MethodContext context) { } int count = 0; nonDefaultConstructorHandles = new DeferredParameter[params.size()]; + Class[] parameterTypes = nonDefaultConstructorHolder.constructor.getParameterTypes(); for (int i = 0; i < params.size(); i++) { Object obj = params.get(i); nonDefaultConstructorHandles[i] = loadObjectInstance(obj, existing, - nonDefaultConstructorHolder.constructor.getParameterTypes()[count++], relaxedValidation); + parameterTypes[count++], relaxedValidation); } } else if (classesToUseRecorableConstructor.contains(param.getClass())) { Constructor current = null; @@ -1181,9 +1185,13 @@ public void prepare(MethodContext context) { if (ctor.isAnnotationPresent(RecordableConstructor.class)) { nonDefaultConstructorHolder = new NonDefaultConstructorHolder(ctor, null); nonDefaultConstructorHandles = new DeferredParameter[ctor.getParameterCount()]; - for (int i = 0; i < ctor.getParameterCount(); ++i) { - String name = ctor.getParameters()[i].getName(); - constructorParamNameMap.put(name, i); + + if (ctor.getParameterCount() > 0) { + Parameter[] ctorParameters = ctor.getParameters(); + for (int i = 0; i < ctor.getParameterCount(); ++i) { + String name = ctorParameters[i].getName(); + constructorParamNameMap.put(name, i); + } } break; } @@ -1323,10 +1331,12 @@ public void prepare(MethodContext context) { for (Method m : param.getClass().getMethods()) { if (m.getName().equals(i.getWriteMethod().getName())) { - if (m.getParameterCount() > 0 - && m.getParameterTypes()[0].isAssignableFrom(param.getClass())) { - propertyType = m.getParameterTypes()[0]; - break; + if (m.getParameterCount() > 0) { + Class[] parameterTypes = m.getParameterTypes(); + if (parameterTypes[0].isAssignableFrom(param.getClass())) { + propertyType = parameterTypes[0]; + break; + } } } diff --git a/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java b/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java index 7fd8e9c0d83cb..9d4532b451dbb 100644 --- a/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java +++ b/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java @@ -162,15 +162,17 @@ void processProvidedLambda(Optional provid // for reflection. Shouldn't have to do this. for (Method method : handlerClass.getMethods()) { if (method.getName().equals("handleRequest") - && method.getParameterCount() == 2 - && !method.getParameterTypes()[0].equals(Object.class)) { - reflectiveClassBuildItemBuildProducer - .produce(new ReflectiveClassBuildItem(true, true, true, method.getParameterTypes()[0].getName())); - reflectiveClassBuildItemBuildProducer - .produce(new ReflectiveClassBuildItem(true, true, true, method.getReturnType().getName())); - reflectiveClassBuildItemBuildProducer.produce(new ReflectiveClassBuildItem(true, true, true, - DateTime.class)); - break; + && method.getParameterCount() == 2) { + Class[] parameterTypes = method.getParameterTypes(); + if (!parameterTypes[0].equals(Object.class)) { + reflectiveClassBuildItemBuildProducer + .produce(new ReflectiveClassBuildItem(true, true, true, parameterTypes[0].getName())); + reflectiveClassBuildItemBuildProducer + .produce(new ReflectiveClassBuildItem(true, true, true, method.getReturnType().getName())); + reflectiveClassBuildItemBuildProducer.produce(new ReflectiveClassBuildItem(true, true, true, + DateTime.class)); + break; + } } } } diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java index 8da63b5289f8b..0de989ddc979b 100644 --- a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java @@ -52,10 +52,11 @@ public void setHandlerClass(Class> handler, BeanC beanContainer = container; ObjectMapper objectMapper = AmazonLambdaMapperRecorder.objectMapper; Method handlerMethod = discoverHandlerMethod(handlerClass); - if (handlerMethod.getParameterTypes()[0].equals(S3Event.class)) { + Class parameterType = handlerMethod.getParameterTypes()[0]; + if (parameterType.equals(S3Event.class)) { objectReader = new S3EventInputReader(objectMapper); } else { - objectReader = new JacksonInputReader(objectMapper.readerFor(handlerMethod.getParameterTypes()[0])); + objectReader = new JacksonInputReader(objectMapper.readerFor(parameterType)); } objectWriter = new JacksonOutputWriter(objectMapper.writerFor(handlerMethod.getReturnType())); } @@ -85,9 +86,11 @@ private Method discoverHandlerMethod(Class> handl Method method = null; for (int i = 0; i < methods.length && method == null; i++) { if (methods[i].getName().equals("handleRequest")) { - final Class[] types = methods[i].getParameterTypes(); - if (types.length == 2 && !types[0].equals(Object.class)) { - method = methods[i]; + if (methods[i].getParameterCount() == 2) { + final Class[] types = methods[i].getParameterTypes(); + if (!types[0].equals(Object.class)) { + method = methods[i]; + } } } } diff --git a/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionInvoker.java b/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionInvoker.java index f633eb47d64c5..aeff7760bf343 100644 --- a/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionInvoker.java +++ b/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionInvoker.java @@ -26,10 +26,13 @@ public FunctionInvoker(String name, Class targetClass, Method method) { this.method = method; if (method.getParameterCount() > 0) { parameterInjectors = new ArrayList<>(method.getParameterCount()); + Class[] parameterTypes = method.getParameterTypes(); + Type[] genericParameterTypes = method.getGenericParameterTypes(); + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int i = 0; i < method.getParameterCount(); i++) { - Type type = method.getGenericParameterTypes()[i]; - Class clz = method.getParameterTypes()[i]; - Annotation[] annotations = method.getParameterAnnotations()[i]; + Type type = genericParameterTypes[i]; + Class clz = parameterTypes[i]; + Annotation[] annotations = parameterAnnotations[i]; ValueInjector injector = ParameterInjector.createInjector(type, clz, annotations); if (injector instanceof InputValueInjector) { inputType = type; diff --git a/extensions/google-cloud-functions/runtime/src/main/java/io/quarkus/gcp/functions/QuarkusBackgroundFunction.java b/extensions/google-cloud-functions/runtime/src/main/java/io/quarkus/gcp/functions/QuarkusBackgroundFunction.java index e0c31dfd72951..7ff59809ec61a 100644 --- a/extensions/google-cloud-functions/runtime/src/main/java/io/quarkus/gcp/functions/QuarkusBackgroundFunction.java +++ b/extensions/google-cloud-functions/runtime/src/main/java/io/quarkus/gcp/functions/QuarkusBackgroundFunction.java @@ -60,8 +60,9 @@ static void setDelegates(String selectedDelegate, String selectedRawDelegate) { if (method.getName().equals("accept")) { // the first parameter of the accept method is the event, we need to register it's type to // be able to deserialize to it to mimic what a BackgroundFunction does - if (method.getParameterTypes()[0] != Object.class) {// FIXME we have two accept methods !!! - parameterType = method.getParameterTypes()[0]; + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes[0] != Object.class) {// FIXME we have two accept methods !!! + parameterType = parameterTypes[0]; } } } diff --git a/extensions/narayana-lra/runtime/src/main/java/io/narayana/lra/client/internal/proxy/nonjaxrs/LRAParticipant.java b/extensions/narayana-lra/runtime/src/main/java/io/narayana/lra/client/internal/proxy/nonjaxrs/LRAParticipant.java index 57792c68a79d9..25898d22859d7 100644 --- a/extensions/narayana-lra/runtime/src/main/java/io/narayana/lra/client/internal/proxy/nonjaxrs/LRAParticipant.java +++ b/extensions/narayana-lra/runtime/src/main/java/io/narayana/lra/client/internal/proxy/nonjaxrs/LRAParticipant.java @@ -117,13 +117,12 @@ private void processParticipantMethod(Method method) { verifyReturnType(method); - Class[] parameterTypes = method.getParameterTypes(); - - if (parameterTypes.length > 2) { + if (method.getParameterCount() > 2) { throw new IllegalStateException(String.format("%s: %s", method.toGenericString(), "Participant method cannot have more than 2 arguments")); } + Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length > 0 && !parameterTypes[0].equals(URI.class)) { throw new IllegalStateException(String.format("%s: %s", method.toGenericString(), "Invalid argument type in LRA participant method: " + parameterTypes[0])); @@ -146,12 +145,12 @@ private boolean setAfterLRAAnnotation(Method method) { method.toGenericString(), "Invalid return type for @AfterLRA method: " + method.getReturnType())); } - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length > 2) { + if (method.getParameterCount() > 2) { throw new IllegalStateException(String.format("%s: %s", method.toGenericString(), "@AfterLRA method cannot have more than 2 arguments")); } + Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length > 0 && !parameterTypes[0].equals(URI.class)) { throw new IllegalStateException(String.format("%s: %s", method.toGenericString(), "Invalid first argument of @AfterLRA method: " + parameterTypes[0])); diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodsCandidate.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodsCandidate.java index 7c8482feda3ca..4691f11f78dd3 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodsCandidate.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodsCandidate.java @@ -31,10 +31,11 @@ public CompletionStage getValue(Object instance) { for (Method method : methods) { try { if (params.parameterTypesMatch(method.isVarArgs(), method.getParameterTypes())) { + Class[] parameterTypes = method.getParameterTypes(); Object[] args = new Object[method.getParameterCount()]; for (int i = 0; i < args.length; i++) { if (method.isVarArgs() && (i == args.length - 1)) { - Class lastParam = method.getParameterTypes()[i]; + Class lastParam = parameterTypes[i]; args[i] = params.getVarargsResults(method.getParameterCount(), lastParam.getComponentType()); } else { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java index 635f696abe394..50ccafa72b257 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java @@ -290,14 +290,15 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, Method javaMethod = lazyMethod.getMethod(); // Workaround our lack of support for generic params by not doing this init if there are not runtime // param converter providers - converter.init(paramConverterProviders, javaMethod.getParameterTypes()[i], - javaMethod.getGenericParameterTypes()[i], - javaMethod.getParameterAnnotations()[i]); + Class[] parameterTypes = javaMethod.getParameterTypes(); + Type[] genericParameterTypes = javaMethod.getGenericParameterTypes(); + Annotation[][] parameterAnnotations = javaMethod.getParameterAnnotations(); + converter.init(paramConverterProviders, parameterTypes[i], genericParameterTypes[i], + parameterAnnotations[i]); // make sure we give the user provided resolvers the chance to convert converter = new RuntimeResolvedConverter(converter); - converter.init(paramConverterProviders, javaMethod.getParameterTypes()[i], - javaMethod.getGenericParameterTypes()[i], - javaMethod.getParameterAnnotations()[i]); + converter.init(paramConverterProviders, parameterTypes[i], genericParameterTypes[i], + parameterAnnotations[i]); } } diff --git a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/InjectionEnricher.java b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/InjectionEnricher.java index d1667ec4926d6..cf64dd40a206d 100644 --- a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/InjectionEnricher.java +++ b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/InjectionEnricher.java @@ -156,15 +156,15 @@ public Object[] apply(Method method, Object creationalContext) { if (beanManager == null) { return values; } + Class[] parameterTypes = method.getParameterTypes(); try { // obtain the same method definition but from the TCCL method = getClass().getClassLoader() .loadClass(method.getDeclaringClass().getName()) - .getMethod(method.getName(), convertToCL(method.getParameterTypes(), getClass().getClassLoader())); + .getMethod(method.getName(), convertToCL(parameterTypes, getClass().getClassLoader())); } catch (Throwable t) { throw new RuntimeException(t); } - Class[] parameterTypes = method.getParameterTypes(); for (int i = 0; i < parameterTypes.length; i++) { try { values[i] = getInstanceByType(beanManager, i, method, (CreationalContext) creationalContext); diff --git a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/MethodParameterInjectionPoint.java b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/MethodParameterInjectionPoint.java index 80e440589a323..82ac304c32d46 100644 --- a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/MethodParameterInjectionPoint.java +++ b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/MethodParameterInjectionPoint.java @@ -63,8 +63,9 @@ public Annotated getAnnotated() { } private Type findTypeOrGenericType() { - if (method.getGenericParameterTypes().length > 0) { - return method.getGenericParameterTypes()[position]; + Type[] genericParameterTypes = method.getGenericParameterTypes(); + if (genericParameterTypes.length > 0) { + return genericParameterTypes[position]; } return method.getParameterTypes()[position]; } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java index 71144ae873dce..b320ecc8f3c5c 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java @@ -9,6 +9,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.nio.file.Path; import java.time.Duration; import java.time.temporal.ChronoUnit; @@ -869,11 +870,12 @@ private Object runExtensionMethod(ReflectiveInvocationContext invocation //TODO: make this more pluggable List originalArguments = invocationContext.getArguments(); List argumentsFromTccl = new ArrayList<>(); + Parameter[] parameters = invocationContext.getExecutable().getParameters(); for (int i = 0; i < originalArguments.size(); i++) { Object arg = originalArguments.get(i); boolean cloneRequired = false; Object replacement = null; - Class argClass = invocationContext.getExecutable().getParameters()[i].getType(); + Class argClass = parameters[i].getType(); if (arg != null) { Class theclass = argClass; while (theclass.isArray()) {