Skip to content

Commit

Permalink
Merge pull request #25647 from mkouba/qute-build-steps-optimizations-02
Browse files Browse the repository at this point in the history
Qute - optimize build steps - round 2
  • Loading branch information
mkouba authored May 18, 2022
2 parents 0890992 + 5f6d0a7 commit 8e15ed6
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -528,20 +528,28 @@ public String apply(String id) {
// Map implicit class -> set of used members
Map<DotName, Set<String>> implicitClassToMembersUsed = new HashMap<>();

Map<String, TemplateDataBuildItem> namespaceTemplateData = templateData.stream()
.filter(TemplateDataBuildItem::hasNamespace)
.collect(Collectors.toMap(TemplateDataBuildItem::getNamespace, Function.identity()));
Map<String, TemplateDataBuildItem> namespaceTemplateData = new HashMap<>();
for (TemplateDataBuildItem td : templateData) {
if (td.hasNamespace()) {
namespaceTemplateData.put(td.getNamespace(), td);
}
}

Map<String, List<TemplateExtensionMethodBuildItem>> namespaceExtensionMethods = templateExtensionMethods.stream()
.filter(TemplateExtensionMethodBuildItem::hasNamespace)
.sorted(Comparator.comparingInt(TemplateExtensionMethodBuildItem::getPriority).reversed())
.collect(Collectors.groupingBy(TemplateExtensionMethodBuildItem::getNamespace));

List<TemplateExtensionMethodBuildItem> regularExtensionMethods = templateExtensionMethods.stream()
.filter(Predicate.not(TemplateExtensionMethodBuildItem::hasNamespace)).collect(Collectors.toUnmodifiableList());
List<TemplateExtensionMethodBuildItem> regularExtensionMethods = new ArrayList<>();
for (TemplateExtensionMethodBuildItem extensionMethod : templateExtensionMethods) {
if (!extensionMethod.hasNamespace()) {
regularExtensionMethods.add(extensionMethod);
}
}

LookupConfig lookupConfig = new FixedLookupConfig(index, initDefaultMembersFilter(), false);
Map<DotName, AssignableInfo> assignableCache = new HashMap<>();
int expressionsValidated = 0;

for (TemplateAnalysis templateAnalysis : templatesAnalysis.getAnalysis()) {
// The relevant checked template, may be null
Expand All @@ -568,7 +576,7 @@ public String apply(String id) {
if (defaultValue != null) {
Match match;
if (defaultValue.isLiteral()) {
match = new Match(index);
match = new Match(index, assignableCache);
setMatchValues(match, defaultValue, generatedIdsToMatches, index);
} else {
match = generatedIdsToMatches.get(defaultValue.getGeneratedId());
Expand Down Expand Up @@ -598,8 +606,12 @@ public String apply(String id) {

expressionMatches
.produce(new TemplateExpressionMatchesBuildItem(templateAnalysis.generatedId, generatedIdsToMatches));

expressionsValidated += generatedIdsToMatches.size();
}

LOGGER.debugf("Validated %s expressions", expressionsValidated);

// Register an implicit value resolver for the classes collected during validation
for (Entry<DotName, Set<String>> entry : implicitClassToMembersUsed.entrySet()) {
if (entry.getValue().isEmpty()) {
Expand Down Expand Up @@ -690,7 +702,7 @@ static Match validateNestedExpressions(QuteConfig config, TemplateAnalysis templ
}
}

Match match = new Match(index);
Match match = new Match(index, assignableCache);

String namespace = expression.getNamespace();
TemplateDataBuildItem templateData = null;
Expand Down Expand Up @@ -1712,25 +1724,19 @@ static void processLoopElementHint(Match match, IndexView index, Expression expr
} else if (match.isClass() || match.isParameterizedType()) {
Set<Type> closure = Types.getTypeClosure(match.clazz, Types.buildResolvedMap(
match.getParameterizedTypeArguments(), match.getTypeParameters(), new HashMap<>(), index), index);
Function<Type, Type> firstParamType = t -> t.asParameterizedType().arguments().get(0);
// Iterable<Item> => Item
matchType = extractMatchType(closure, Names.ITERABLE, firstParamType);
matchType = extractMatchType(closure, Names.ITERABLE, FIRST_PARAM_TYPE_EXTRACT_FUN);
if (matchType == null) {
// Stream<Long> => Long
matchType = extractMatchType(closure, Names.STREAM, firstParamType);
matchType = extractMatchType(closure, Names.STREAM, FIRST_PARAM_TYPE_EXTRACT_FUN);
}
if (matchType == null) {
// Entry<K,V> => Entry<String,Item>
matchType = extractMatchType(closure, Names.MAP, t -> {
Type[] args = new Type[2];
args[0] = t.asParameterizedType().arguments().get(0);
args[1] = t.asParameterizedType().arguments().get(1);
return ParameterizedType.create(Names.MAP_ENTRY, args, null);
});
matchType = extractMatchType(closure, Names.MAP, MAP_ENTRY_EXTRACT_FUN);
}
if (matchType == null) {
// Iterator<Item> => Item
matchType = extractMatchType(closure, Names.ITERATOR, firstParamType);
matchType = extractMatchType(closure, Names.ITERATOR, FIRST_PARAM_TYPE_EXTRACT_FUN);
}
}

Expand All @@ -1743,19 +1749,48 @@ static void processLoopElementHint(Match match, IndexView index, Expression expr
}
}

static final Function<Type, Type> FIRST_PARAM_TYPE_EXTRACT_FUN = new Function<Type, Type>() {

@Override
public Type apply(Type type) {
return type.asParameterizedType().arguments().get(0);
}

};

static final Function<Type, Type> MAP_ENTRY_EXTRACT_FUN = new Function<Type, Type>() {

@Override
public Type apply(Type type) {
Type[] args = new Type[2];
args[0] = type.asParameterizedType().arguments().get(0);
args[1] = type.asParameterizedType().arguments().get(1);
return ParameterizedType.create(Names.MAP_ENTRY, args, null);
}

};

static Type extractMatchType(Set<Type> closure, DotName matchName, Function<Type, Type> extractFun) {
Type type = closure.stream().filter(t -> t.name().equals(matchName)).findFirst().orElse(null);
Type type = null;
for (Type t : closure) {
if (t.name().equals(matchName)) {
type = t;
}
}
return type != null ? extractFun.apply(type) : null;
}

static class Match {

private final IndexView index;
private final Map<DotName, AssignableInfo> assignableCache;

private ClassInfo clazz;
private Type type;

Match(IndexView index) {
Match(IndexView index, Map<DotName, AssignableInfo> assignableCache) {
this.index = index;
this.assignableCache = assignableCache;
}

List<Type> getParameterizedTypeArguments() {
Expand Down Expand Up @@ -1808,17 +1843,20 @@ boolean isEmpty() {
}

void autoExtractType() {
boolean hasCompletionStage = ValueResolverGenerator.hasCompletionStageInTypeClosure(clazz, index);
boolean hasUni = hasCompletionStage ? false
: ValueResolverGenerator.hasClassInTypeClosure(clazz, Names.UNI, index);
if (hasCompletionStage || hasUni) {
Set<Type> closure = Types.getTypeClosure(clazz, Types.buildResolvedMap(
getParameterizedTypeArguments(), getTypeParameters(), new HashMap<>(), index), index);
Function<Type, Type> firstParamType = t -> t.asParameterizedType().arguments().get(0);
// CompletionStage<List<Item>> => List<Item>
// Uni<List<String>> => List<String>
this.type = extractMatchType(closure, hasCompletionStage ? Names.COMPLETION_STAGE : Names.UNI, firstParamType);
this.clazz = index.getClassByName(type.name());
if (clazz != null) {
boolean hasCompletionStage = Types.isAssignableFrom(Names.COMPLETION_STAGE, clazz.name(), index,
assignableCache);
boolean hasUni = hasCompletionStage ? false
: Types.isAssignableFrom(Names.UNI, clazz.name(), index, assignableCache);
if (hasCompletionStage || hasUni) {
Set<Type> closure = Types.getTypeClosure(clazz, Types.buildResolvedMap(
getParameterizedTypeArguments(), getTypeParameters(), new HashMap<>(), index), index);
// CompletionStage<List<Item>> => List<Item>
// Uni<List<String>> => List<String>
this.type = extractMatchType(closure, hasCompletionStage ? Names.COMPLETION_STAGE : Names.UNI,
FIRST_PARAM_TYPE_EXTRACT_FUN);
this.clazz = index.getClassByName(type.name());
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationTarget.Kind;
Expand Down Expand Up @@ -273,15 +272,24 @@ private boolean implementResolve(ClassCreator valueResolver, String clazzName, C
Function<FieldInfo, String> fieldToGetterFun = forceGettersFunction != null ? forceGettersFunction.apply(clazz) : null;

// First collect and sort methods (getters must come before is/has properties, etc.)
List<MethodKey> methods = clazz.methods().stream().filter(filter::test).map(MethodKey::new).sorted()
.collect(Collectors.toList());
List<MethodKey> methods = new ArrayList<>();
for (MethodInfo method : clazz.methods()) {
if (filter.test(method)) {
methods.add(new MethodKey(method));
}
}
methods.sort(null);

if (!ignoreSuperclasses && !clazz.isEnum()) {
DotName superName = clazz.superName();
while (superName != null && !superName.equals(DotNames.OBJECT)) {
ClassInfo superClass = index.getClassByName(superName);
if (superClass != null) {
methods.addAll(
superClass.methods().stream().filter(filter::test).map(MethodKey::new).collect(Collectors.toSet()));
for (MethodInfo method : superClass.methods()) {
if (filter.test(method)) {
methods.add(new MethodKey(method));
}
}
superName = superClass.superName();
} else {
superName = null;
Expand All @@ -290,7 +298,12 @@ private boolean implementResolve(ClassCreator valueResolver, String clazzName, C
}
}

List<FieldInfo> fields = clazz.fields().stream().filter(filter::test).collect(Collectors.toList());
List<FieldInfo> fields = new ArrayList<>();
for (FieldInfo field : clazz.fields()) {
if (filter.test(field)) {
fields.add(field);
}
}
if (!fields.isEmpty()) {
BytecodeCreator zeroParamsBranch = resolve.ifNonZero(paramsCount).falseBranch();
for (FieldInfo field : fields) {
Expand Down Expand Up @@ -437,24 +450,28 @@ private boolean implementNamespaceResolve(ClassCreator valueResolver, String cla
ResultHandle paramsCount = resolve.invokeInterfaceMethod(Descriptors.COLLECTION_SIZE, params);

// First collect static members
List<MethodKey> methods = clazz.methods().stream()
.filter(filter::test)
.map(MethodKey::new)
.sorted()
.collect(Collectors.toList());
List<MethodKey> staticMethods = new ArrayList<>();
for (MethodInfo method : clazz.methods()) {
if (filter.test(method)) {
staticMethods.add(new MethodKey(method));
}
}
staticMethods.sort(null);

List<FieldInfo> fields = clazz.fields().stream()
.filter(filter::test)
.collect(Collectors.toList());
List<FieldInfo> staticFields = new ArrayList<>();
for (FieldInfo field : clazz.fields()) {
if (filter.test(field)) {
staticFields.add(field);
}
}

if (methods.isEmpty() && fields.isEmpty()) {
if (staticMethods.isEmpty() && staticFields.isEmpty()) {
return false;
}

// Static fields
if (!fields.isEmpty()) {
if (!staticFields.isEmpty()) {
BytecodeCreator zeroParamsBranch = resolve.ifNonZero(paramsCount).falseBranch();
for (FieldInfo field : fields) {
for (FieldInfo field : staticFields) {
LOGGER.debugf("Static field added: %s", field);
// Match field name
BytecodeCreator fieldMatch = zeroParamsBranch
Expand All @@ -468,13 +485,12 @@ private boolean implementNamespaceResolve(ClassCreator valueResolver, String cla
}
}

// Static methods
if (!methods.isEmpty()) {
if (!staticMethods.isEmpty()) {
// name, number of params -> list of methods
Map<Match, List<MethodInfo>> matches = new HashMap<>();
Map<Match, List<MethodInfo>> varargsMatches = new HashMap<>();

for (MethodKey methodKey : methods) {
for (MethodKey methodKey : staticMethods) {
MethodInfo method = methodKey.method;
List<Type> methodParams = method.parameters();
if (methodParams.isEmpty()) {
Expand Down Expand Up @@ -991,13 +1007,27 @@ private Predicate<AnnotationTarget> initFilters(AnnotationInstance templateData)
// @TemplateData is present
AnnotationValue ignoreValue = templateData.value(IGNORE);
if (ignoreValue != null) {
List<Pattern> ignore = Arrays.asList(ignoreValue.asStringArray()).stream().map(Pattern::compile)
.collect(Collectors.toList());
List<Pattern> ignores = new ArrayList<>();
for (String pattern : Arrays.asList(ignoreValue.asStringArray())) {
ignores.add(Pattern.compile(pattern));
}
filter = filter.and(t -> {
if (t.kind() == Kind.FIELD) {
return !ignore.stream().anyMatch(p -> p.matcher(t.asField().name()).matches());
String fieldName = t.asField().name();
for (Pattern p : ignores) {
if (p.matcher(fieldName).matches()) {
return false;
}
}
return true;
} else {
return !ignore.stream().anyMatch(p -> p.matcher(t.asMethod().name()).matches());
String methodName = t.asMethod().name();
for (Pattern p : ignores) {
if (p.matcher(methodName).matches()) {
return false;
}
}
return true;
}
});
}
Expand Down

0 comments on commit 8e15ed6

Please sign in to comment.