diff --git a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java index 5c82459d08232..33ca5cd68de84 100644 --- a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java +++ b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java @@ -71,6 +71,7 @@ import io.quarkus.gizmo.ClassOutput; import io.quarkus.gizmo.DescriptorUtils; import io.quarkus.gizmo.FunctionCreator; +import io.quarkus.gizmo.Gizmo; import io.quarkus.gizmo.MethodCreator; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; @@ -960,8 +961,7 @@ private void implementResolve(String defaultBundleImpl, ClassCreator bundleCreat ResultHandle ret = resolve.newInstance(MethodDescriptor.ofConstructor(CompletableFuture.class)); // First handle dynamic messages, i.e. the "message" virtual method - BytecodeCreator dynamicMessage = resolve.ifTrue(resolve.invokeVirtualMethod(Descriptors.EQUALS, - resolve.load(MESSAGE), name)) + BytecodeCreator dynamicMessage = resolve.ifTrue(Gizmo.equals(resolve, resolve.load(MESSAGE), name)) .trueBranch(); ResultHandle evaluatedMessageKey = dynamicMessage.invokeStaticMethod(Descriptors.EVALUATED_PARAMS_EVALUATE_MESSAGE_KEY, evalContext); @@ -988,8 +988,8 @@ private void implementResolve(String defaultBundleImpl, ClassCreator bundleCreat nameIsNull.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE, whenRet, resultNotFound); nameIsNull.returnValue(null); - BytecodeCreator nameNotFound = success.ifTrue(success.invokeVirtualMethod(Descriptors.EQUALS, - whenComplete.getMethodParam(0), resultNotFound)).trueBranch(); + BytecodeCreator nameNotFound = success.ifTrue(Gizmo.equals(success, whenComplete.getMethodParam(0), resultNotFound)) + .trueBranch(); nameNotFound.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE, whenRet, resultNotFound); nameNotFound.returnValue(null); @@ -1067,8 +1067,7 @@ private void addMessageMethod(MethodCreator resolve, String key, MethodInfo meth ResultHandle ret, String bundleClass) { List methodParams = method.parameterTypes(); - BytecodeCreator matched = resolve.ifTrue(resolve.invokeVirtualMethod(Descriptors.EQUALS, - resolve.load(key), name)) + BytecodeCreator matched = resolve.ifTrue(Gizmo.equals(resolve, resolve.load(key), name)) .trueBranch(); if (method.parameterTypes().isEmpty()) { matched.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE, ret, diff --git a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/Descriptors.java b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/Descriptors.java index b0826982da99e..57799bf42d767 100644 --- a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/Descriptors.java +++ b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/Descriptors.java @@ -27,8 +27,6 @@ private Descriptors() { boolean.class, Class.class); public static final MethodDescriptor GET_CLASS = MethodDescriptor.ofMethod(Object.class, "getClass", Class.class); public static final MethodDescriptor COLLECTION_SIZE = MethodDescriptor.ofMethod(Collection.class, "size", int.class); - public static final MethodDescriptor EQUALS = MethodDescriptor.ofMethod(Object.class, "equals", boolean.class, - Object.class); public static final MethodDescriptor GET_NAME = MethodDescriptor.ofMethod(EvalContext.class, "getName", String.class); public static final MethodDescriptor GET_BASE = MethodDescriptor.ofMethod(EvalContext.class, "getBase", Object.class); public static final MethodDescriptor GET_PARAMS = MethodDescriptor.ofMethod(EvalContext.class, "getParams", List.class); diff --git a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java index e6da69c6ca21f..145514ca1dd66 100644 --- a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java +++ b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java @@ -42,6 +42,7 @@ import io.quarkus.gizmo.ClassOutput; import io.quarkus.gizmo.FieldDescriptor; import io.quarkus.gizmo.FunctionCreator; +import io.quarkus.gizmo.Gizmo; import io.quarkus.gizmo.MethodCreator; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; @@ -393,14 +394,12 @@ private void implementAppliesTo(ClassCreator valueResolver, MethodInfo method, S // Any of the name matches BytecodeCreator namesMatch = appliesTo.createScope(); for (String match : matchNames) { - ResultHandle nameTest = namesMatch.invokeVirtualMethod(Descriptors.EQUALS, name, - namesMatch.load(match)); + ResultHandle nameTest = Gizmo.equals(namesMatch, name, namesMatch.load(match)); namesMatch.ifTrue(nameTest).trueBranch().breakScope(namesMatch); } namesMatch.returnValue(namesMatch.load(false)); } else { - ResultHandle nameTest = appliesTo.invokeVirtualMethod(Descriptors.EQUALS, name, - appliesTo.load(matchName)); + ResultHandle nameTest = Gizmo.equals(appliesTo, name, appliesTo.load(matchName)); BytecodeCreator nameNotMatched = appliesTo.ifFalse(nameTest).trueBranch(); nameNotMatched.returnValue(nameNotMatched.load(false)); } @@ -634,15 +633,12 @@ private BytecodeCreator createNamespaceExtensionMatchScope(BytecodeCreator bytec // Any of the name matches BytecodeCreator namesMatch = matchScope.createScope(); for (String match : matchNames) { - ResultHandle nameTest = namesMatch.invokeVirtualMethod(Descriptors.EQUALS, name, - namesMatch.load(match)); + ResultHandle nameTest = Gizmo.equals(namesMatch, name, namesMatch.load(match)); namesMatch.ifTrue(nameTest).trueBranch().breakScope(namesMatch); } namesMatch.breakScope(matchScope); } else { - matchScope.ifTrue(matchScope.invokeVirtualMethod(Descriptors.EQUALS, - matchScope.load(matchName), - name)) + matchScope.ifTrue(Gizmo.equals(matchScope, matchScope.load(matchName), name)) .falseBranch().breakScope(matchScope); } } diff --git a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ValueResolverGenerator.java b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ValueResolverGenerator.java index 8a2573b58ca7e..a07b3f30a1a92 100644 --- a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ValueResolverGenerator.java +++ b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ValueResolverGenerator.java @@ -44,6 +44,7 @@ import io.quarkus.gizmo.DescriptorUtils; import io.quarkus.gizmo.FieldDescriptor; import io.quarkus.gizmo.FunctionCreator; +import io.quarkus.gizmo.Gizmo; import io.quarkus.gizmo.MethodCreator; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; @@ -171,7 +172,7 @@ private void generate(DotName className, int priority) { AnnotationInstance templateData = nameToTemplateData.get(className); if (templateData == null) { // @TemplateData declared on the class - for (AnnotationInstance annotation : clazz.classAnnotations()) { + for (AnnotationInstance annotation : clazz.declaredAnnotations()) { if (annotation.name().equals(TEMPLATE_DATA)) { AnnotationValue targetValue = annotation.value(TARGET); if (targetValue == null || targetValue.asClass().name().equals(className)) { @@ -306,136 +307,136 @@ private boolean implementResolve(ClassCreator valueResolver, String clazzName, C fields.add(field); } } - if (!fields.isEmpty()) { - BytecodeCreator zeroParamsBranch = resolve.ifNonZero(paramsCount).falseBranch(); - for (FieldInfo field : fields) { - String getterName = fieldToGetterFun != null ? fieldToGetterFun.apply(field) : null; - if (getterName != null && noneMethodMatches(methods, getterName)) { - LOGGER.debugf("Forced getter added: %s", field); - BytecodeCreator getterMatch = zeroParamsBranch.createScope(); - // Match the getter name - BytecodeCreator notMatched = getterMatch.ifNonZero(getterMatch.invokeVirtualMethod(Descriptors.EQUALS, - getterMatch.load(getterName), - name)) - .falseBranch(); - // Match the property name - notMatched.ifNonZero(notMatched.invokeVirtualMethod(Descriptors.EQUALS, - notMatched.load(field.name()), - name)).falseBranch().breakScope(getterMatch); - ResultHandle value = getterMatch.invokeVirtualMethod( - MethodDescriptor.ofMethod(clazz.name().toString(), getterName, - DescriptorUtils.typeToString(field.type())), - base); - getterMatch.returnValue(getterMatch.invokeStaticMethod(Descriptors.COMPLETED_STAGE, value)); - } else { - LOGGER.debugf("Field added: %s", field); - // Match field name - BytecodeCreator fieldMatch = zeroParamsBranch - .ifNonZero( - zeroParamsBranch.invokeVirtualMethod(Descriptors.EQUALS, - resolve.load(field.name()), name)) - .trueBranch(); - ResultHandle value = fieldMatch - .readInstanceField(FieldDescriptor.of(clazzName, field.name(), field.type().name().toString()), - base); - fieldMatch.returnValue(fieldMatch.invokeStaticMethod(Descriptors.COMPLETED_STAGE, value)); - } - } - } if (methods.isEmpty() && fields.isEmpty()) { + // No members return false; } - if (!methods.isEmpty()) { - // name, number of params -> list of methods - Map> matches = new HashMap<>(); - Map> varargsMatches = new HashMap<>(); + // Collect methods + List noParamMethods = new ArrayList<>(); + // name, number of params -> list of methods + Map> matches = new HashMap<>(); + Map> varargsMatches = new HashMap<>(); - for (MethodKey methodKey : methods) { - MethodInfo method = methodKey.method; - List methodParams = method.parameterTypes(); - if (methodParams.isEmpty()) { - // No params - just invoke the method - LOGGER.debugf("Method added %s", method); - try (BytecodeCreator matchScope = createMatchScope(resolve, method.name(), 0, method.returnType(), name, - params, paramsCount)) { - ResultHandle ret; - boolean hasCompletionStage = !skipMemberType(method.returnType()) - && hasCompletionStageInTypeClosure(index.getClassByName(method.returnType().name()), index); - ResultHandle invokeRet; - if (Modifier.isInterface(clazz.flags())) { - invokeRet = matchScope.invokeInterfaceMethod(MethodDescriptor.of(method), base); - } else { - invokeRet = matchScope.invokeVirtualMethod(MethodDescriptor.of(method), base); - } - if (hasCompletionStage) { - ret = invokeRet; - } else { - ret = matchScope.invokeStaticMethod(Descriptors.COMPLETED_STAGE, invokeRet); - } - matchScope.returnValue(ret); - } - } else { - // Collect methods with params - Match match = new Match(method.name(), method.parametersCount()); - List methodMatches = matches.get(match); + for (MethodKey methodKey : methods) { + MethodInfo method = methodKey.method; + if (method.parametersCount() == 0) { + noParamMethods.add(methodKey); + } else { + Match match = new Match(method.name(), method.parametersCount()); + List methodMatches = matches.get(match); + if (methodMatches == null) { + methodMatches = new ArrayList<>(); + matches.put(match, methodMatches); + } + methodMatches.add(method); + + if (isVarArgs(method)) { + // The last argument is a sequence of arguments -> match name and min number of params + // getList(int age, String... names) -> "getList", 1 + match = new Match(method.name(), method.parametersCount() - 1); + methodMatches = varargsMatches.get(match); if (methodMatches == null) { methodMatches = new ArrayList<>(); - matches.put(match, methodMatches); + varargsMatches.put(match, methodMatches); } methodMatches.add(method); - - if (isVarArgs(method)) { - // The last argument is a sequence of arguments -> match name and min number of params - // getList(int age, String... names) -> "getList", 1 - match = new Match(method.name(), method.parametersCount() - 1); - methodMatches = varargsMatches.get(match); - if (methodMatches == null) { - methodMatches = new ArrayList<>(); - varargsMatches.put(match, methodMatches); - } - methodMatches.add(method); - } } } + } - // Match methods by name and number of params - for (Entry> entry : matches.entrySet()) { - Match match = entry.getKey(); - - // The set of matching methods is made up of the methods matching the name and number of params + varargs methods matching the name and minimal number of params - // For example both the methods getList(int age, String... names) and getList(int age) match "getList" and 1 param - Set methodMatches = new HashSet<>(entry.getValue()); - varargsMatches.entrySet().stream() - .filter(e -> e.getKey().name.equals(match.name) && e.getKey().paramsCount >= match.paramsCount) - .forEach(e -> methodMatches.addAll(e.getValue())); + BytecodeCreator zeroParamsBranch = resolve.ifZero(paramsCount).trueBranch(); + + for (FieldInfo field : fields) { + String getterName = fieldToGetterFun != null ? fieldToGetterFun.apply(field) : null; + if (getterName != null && noneMethodMatches(methods, getterName)) { + LOGGER.debugf("Forced getter added: %s", field); + BytecodeCreator getterMatch = zeroParamsBranch.createScope(); + // Match the getter name + BytecodeCreator notMatched = getterMatch.ifTrue(Gizmo.equals(getterMatch, getterMatch.load(getterName), + name)).falseBranch(); + // Match the property name + notMatched.ifTrue(Gizmo.equals(notMatched, notMatched.load(field.name()), + name)).falseBranch().breakScope(getterMatch); + ResultHandle value = getterMatch.invokeVirtualMethod( + MethodDescriptor.ofMethod(clazz.name().toString(), getterName, + DescriptorUtils.typeToString(field.type())), + base); + getterMatch.returnValue(getterMatch.invokeStaticMethod(Descriptors.COMPLETED_STAGE, value)); + } else { + LOGGER.debugf("Field added: %s", field); + // Match field name + BytecodeCreator fieldMatch = zeroParamsBranch + .ifTrue(Gizmo.equals(zeroParamsBranch, resolve.load(field.name()), name)) + .trueBranch(); + ResultHandle value = fieldMatch + .readInstanceField(FieldDescriptor.of(clazzName, field.name(), field.type().name().toString()), + base); + fieldMatch.returnValue(fieldMatch.invokeStaticMethod(Descriptors.COMPLETED_STAGE, value)); + } + } - if (methodMatches.size() == 1) { - // Single method matches the name and number of params - matchMethod(methodMatches.iterator().next(), clazz, resolve, base, name, params, paramsCount, evalContext); + for (MethodKey methodKey : noParamMethods) { + // No params - just invoke the method if the name matches + MethodInfo method = methodKey.method; + LOGGER.debugf("No-args method added %s", method); + try (BytecodeCreator matchScope = createMatchScope(zeroParamsBranch, method.name(), -1, method.returnType(), name, + params, paramsCount)) { + ResultHandle ret; + boolean hasCompletionStage = !skipMemberType(method.returnType()) + && hasCompletionStageInTypeClosure(index.getClassByName(method.returnType().name()), index); + ResultHandle invokeRet; + if (Modifier.isInterface(clazz.flags())) { + invokeRet = matchScope.invokeInterfaceMethod(MethodDescriptor.of(method), base); } else { - // Multiple methods match the name and number of params - matchMethods(match.name, match.paramsCount, methodMatches, clazz, resolve, base, name, - params, paramsCount, evalContext); + invokeRet = matchScope.invokeVirtualMethod(MethodDescriptor.of(method), base); + } + if (hasCompletionStage) { + ret = invokeRet; + } else { + ret = matchScope.invokeStaticMethod(Descriptors.COMPLETED_STAGE, invokeRet); } + matchScope.returnValue(ret); } + } - // For varargs methods we also need to match name and any number of params - Map> varargsMap = new HashMap<>(); - for (Entry> entry : varargsMatches.entrySet()) { - List list = varargsMap.get(entry.getKey().name); - if (list == null) { - list = new ArrayList<>(); - varargsMap.put(entry.getKey().name, list); - } - list.addAll(entry.getValue()); + // Match methods by name and number of params + for (Entry> entry : matches.entrySet()) { + Match match = entry.getKey(); + + // The set of matching methods is made up of the methods matching the name and number of params + varargs methods matching the name and minimal number of params + // For example both the methods getList(int age, String... names) and getList(int age) match "getList" and 1 param + Set methodMatches = new HashSet<>(entry.getValue()); + varargsMatches.entrySet().stream() + .filter(e -> e.getKey().name.equals(match.name) && e.getKey().paramsCount >= match.paramsCount) + .forEach(e -> methodMatches.addAll(e.getValue())); + + if (methodMatches.size() == 1) { + // Single method matches the name and number of params + matchMethod(methodMatches.iterator().next(), clazz, resolve, base, name, params, paramsCount, evalContext); + } else { + // Multiple methods match the name and number of params + matchMethods(match.name, match.paramsCount, methodMatches, clazz, resolve, base, name, + params, paramsCount, evalContext); } - for (Entry> entry : varargsMap.entrySet()) { - matchMethods(entry.getKey(), Integer.MIN_VALUE, entry.getValue(), clazz, resolve, base, name, params, - paramsCount, evalContext); + } + + // For varargs methods we also need to match name and any number of params + Map> varargsMap = new HashMap<>(); + for (Entry> entry : varargsMatches.entrySet()) { + List list = varargsMap.get(entry.getKey().name); + if (list == null) { + list = new ArrayList<>(); + varargsMap.put(entry.getKey().name, list); } + list.addAll(entry.getValue()); + } + for (Entry> entry : varargsMap.entrySet()) { + matchMethods(entry.getKey(), Integer.MIN_VALUE, entry.getValue(), clazz, resolve, base, name, params, + paramsCount, evalContext); } + resolve.returnValue(resolve.invokeStaticMethod(Descriptors.RESULTS_NOT_FOUND_EC, evalContext)); return true; } @@ -477,9 +478,7 @@ private boolean implementNamespaceResolve(ClassCreator valueResolver, String cla LOGGER.debugf("Static field added: %s", field); // Match field name BytecodeCreator fieldMatch = zeroParamsBranch - .ifNonZero( - zeroParamsBranch.invokeVirtualMethod(Descriptors.EQUALS, - resolve.load(field.name()), name)) + .ifTrue(Gizmo.equals(zeroParamsBranch, resolve.load(field.name()), name)) .trueBranch(); ResultHandle value = fieldMatch .readStaticField(FieldDescriptor.of(clazzName, field.name(), field.type().name().toString())); @@ -899,19 +898,21 @@ private BytecodeCreator createMatchScope(BytecodeCreator bytecodeCreator, String Type returnType, ResultHandle name, ResultHandle params, ResultHandle paramsCount) { BytecodeCreator matchScope = bytecodeCreator.createScope(); + // Match name - BytecodeCreator notMatched = matchScope.ifTrue(matchScope.invokeVirtualMethod(Descriptors.EQUALS, - matchScope.load(methodName), - name)) - .falseBranch(); - // Match the property name for getters, ie. "foo" for "getFoo" - if (methodParams == 0 && isGetterName(methodName, returnType)) { - notMatched.ifNonZero(notMatched.invokeVirtualMethod(Descriptors.EQUALS, - notMatched.load(getPropertyName(methodName)), - name)).falseBranch().breakScope(matchScope); + if (methodParams <= 0 && isGetterName(methodName, returnType)) { + // Getter found - match the property name first + BytecodeCreator notMatched = matchScope + .ifTrue(Gizmo.equals(matchScope, matchScope.load(getPropertyName(methodName)), name)) + .falseBranch(); + // If the property does not match then use the exact method name + notMatched.ifTrue(Gizmo.equals(notMatched, matchScope.load(methodName), name)).falseBranch().breakScope(matchScope); } else { - notMatched.breakScope(matchScope); + // No getter - only match the exact method name + matchScope.ifTrue(Gizmo.equals(matchScope, matchScope.load(methodName), name)) + .falseBranch().breakScope(matchScope); } + // Match number of params if (methodParams >= 0) { matchScope.ifIntegerEqual(matchScope.load(methodParams), paramsCount).falseBranch().breakScope(matchScope);