aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Corso <bcorso@google.com>2023-12-14 17:06:32 -0800
committerDagger Team <dagger-dev+copybara@google.com>2023-12-14 17:09:37 -0800
commitbe77d24b57008987399853893a8eb4bfb198a40f (patch)
treef8ff6ea220db22f5f7508c28a35816e830df1595
parent8372c630821d298dc6c4f237d38e216ae3bdfb73 (diff)
downloaddagger2-be77d24b57008987399853893a8eb4bfb198a40f.tar.gz
Dagger build performance optimizations.
This CL: 1. Adds state to keep track of any generated monitoring modules that Dagger generates, and uses this state to eagerly defer processing of components to the next round. This is useful to avoid doing work in the current round which will likely end up getting deferred anyway due to referencing the monitoring module. 2. Adds a cache for ComponentDescriptors similar to our caches for other descriptors to avoid recomputing these descriptors. RELNOTES=N/A PiperOrigin-RevId: 591092232
-rw-r--r--java/dagger/internal/codegen/DelegateComponentProcessor.java10
-rw-r--r--java/dagger/internal/codegen/binding/BindingGraphFactory.java5
-rw-r--r--java/dagger/internal/codegen/binding/ComponentDescriptor.java18
-rw-r--r--java/dagger/internal/codegen/binding/MonitoringModules.java46
-rw-r--r--java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java9
-rw-r--r--java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java12
-rw-r--r--javatests/dagger/internal/codegen/ProductionGraphValidationTest.java5
7 files changed, 97 insertions, 8 deletions
diff --git a/java/dagger/internal/codegen/DelegateComponentProcessor.java b/java/dagger/internal/codegen/DelegateComponentProcessor.java
index 8f8d5040b..432daa686 100644
--- a/java/dagger/internal/codegen/DelegateComponentProcessor.java
+++ b/java/dagger/internal/codegen/DelegateComponentProcessor.java
@@ -34,9 +34,11 @@ import dagger.internal.codegen.base.SourceFileGenerationException;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.base.SourceFileHjarGenerator;
import dagger.internal.codegen.binding.BindingGraphFactory;
+import dagger.internal.codegen.binding.ComponentDescriptor;
import dagger.internal.codegen.binding.InjectBindingRegistry;
import dagger.internal.codegen.binding.MembersInjectionBinding;
import dagger.internal.codegen.binding.ModuleDescriptor;
+import dagger.internal.codegen.binding.MonitoringModules;
import dagger.internal.codegen.binding.ProductionBinding;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.bindinggraphvalidation.BindingGraphValidationModule;
@@ -172,6 +174,14 @@ final class DelegateComponentProcessor {
@Binds
@IntoSet
+ ClearableCache componentDescriptorFactory(ComponentDescriptor.Factory cache);
+
+ @Binds
+ @IntoSet
+ ClearableCache monitoringModules(MonitoringModules cache);
+
+ @Binds
+ @IntoSet
ClearableCache bindingGraphFactory(BindingGraphFactory cache);
@Binds
diff --git a/java/dagger/internal/codegen/binding/BindingGraphFactory.java b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
index 941001044..f5161c614 100644
--- a/java/dagger/internal/codegen/binding/BindingGraphFactory.java
+++ b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
@@ -185,7 +185,8 @@ public final class BindingGraphFactory implements ClearableCache {
ImmutableSet.Builder<SubcomponentDeclaration> subcomponentDeclarations = ImmutableSet.builder();
// Collect transitive module bindings and multibinding declarations.
- for (ModuleDescriptor moduleDescriptor : modules(componentDescriptor, parentResolver)) {
+ ImmutableSet<ModuleDescriptor> modules = modules(componentDescriptor, parentResolver);
+ for (ModuleDescriptor moduleDescriptor : modules) {
explicitBindingsBuilder.addAll(moduleDescriptor.bindings());
multibindingDeclarations.addAll(moduleDescriptor.multibindingDeclarations());
subcomponentDeclarations.addAll(moduleDescriptor.subcomponentDeclarations());
@@ -223,7 +224,7 @@ public final class BindingGraphFactory implements ClearableCache {
if (createFullBindingGraph) {
// Resolve the keys for all bindings in all modules, stripping any multibinding contribution
// identifier so that the multibinding itself is resolved.
- modules(componentDescriptor, parentResolver).stream()
+ modules.stream()
.flatMap(module -> module.allBindingKeys().stream())
.map(Key::withoutMultibindingContributionIdentifier)
.forEach(requestResolver::resolve);
diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptor.java b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
index 2e5d6b545..b0a0183b9 100644
--- a/java/dagger/internal/codegen/binding/ComponentDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
@@ -28,6 +28,7 @@ import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnot
import static dagger.internal.codegen.base.ComponentCreatorAnnotation.creatorAnnotationsFor;
import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
import static dagger.internal.codegen.base.Scopes.productionScope;
+import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.isSubcomponentCreator;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
@@ -57,6 +58,7 @@ import com.squareup.javapoet.TypeName;
import dagger.Component;
import dagger.Module;
import dagger.Subcomponent;
+import dagger.internal.codegen.base.ClearableCache;
import dagger.internal.codegen.base.ComponentAnnotation;
import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.ModuleAnnotation;
@@ -70,6 +72,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
+import javax.inject.Singleton;
/**
* A component declaration.
@@ -388,12 +391,14 @@ public abstract class ComponentDescriptor {
}
/** A factory for creating a {@link ComponentDescriptor}. */
- public static final class Factory {
+ @Singleton
+ public static final class Factory implements ClearableCache {
private final XProcessingEnv processingEnv;
private final DependencyRequestFactory dependencyRequestFactory;
private final ModuleDescriptor.Factory moduleDescriptorFactory;
private final InjectionAnnotations injectionAnnotations;
private final DaggerSuperficialValidation superficialValidation;
+ private final Map<XTypeElement, ComponentDescriptor> cache = new HashMap<>();
@Inject
Factory(
@@ -437,6 +442,12 @@ public abstract class ComponentDescriptor {
private ComponentDescriptor create(
XTypeElement typeElement, ComponentAnnotation componentAnnotation) {
+ return reentrantComputeIfAbsent(
+ cache, typeElement, unused -> createUncached(typeElement, componentAnnotation));
+ }
+
+ private ComponentDescriptor createUncached(
+ XTypeElement typeElement, ComponentAnnotation componentAnnotation) {
ImmutableSet<ComponentRequirement> componentDependencies =
componentAnnotation.dependencyTypes().stream()
.map(ComponentRequirement::forDependency)
@@ -572,5 +583,10 @@ public abstract class ComponentDescriptor {
return descriptor.build();
}
+
+ @Override
+ public void clearCache() {
+ cache.clear();
+ }
}
}
diff --git a/java/dagger/internal/codegen/binding/MonitoringModules.java b/java/dagger/internal/codegen/binding/MonitoringModules.java
new file mode 100644
index 000000000..fc6dc021c
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/MonitoringModules.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.binding;
+
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.base.ClearableCache;
+import java.util.HashSet;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Keeps track of modules generated in the current round by {@link MonitoringModuleGenerator}. */
+@Singleton
+public final class MonitoringModules implements ClearableCache {
+ Set<ClassName> cache = new HashSet<>();
+
+ @Inject
+ MonitoringModules() {}
+
+ public void add(ClassName module) {
+ cache.add(module);
+ }
+
+ public boolean isEmpty() {
+ return cache.isEmpty();
+ }
+
+ @Override
+ public void clearCache() {
+ cache.clear();
+ }
+}
diff --git a/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java b/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java
index 00b033d96..3692144cf 100644
--- a/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java
+++ b/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java
@@ -35,6 +35,7 @@ import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import dagger.Module;
import dagger.internal.codegen.base.SourceFileGenerator;
+import dagger.internal.codegen.binding.MonitoringModules;
import dagger.internal.codegen.binding.SourceFiles;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.multibindings.Multibinds;
@@ -42,10 +43,15 @@ import javax.inject.Inject;
/** Generates a monitoring module for use with production components. */
final class MonitoringModuleGenerator extends SourceFileGenerator<XTypeElement> {
+ private final MonitoringModules monitoringModules;
@Inject
- MonitoringModuleGenerator(XFiler filer, XProcessingEnv processingEnv) {
+ MonitoringModuleGenerator(
+ XFiler filer,
+ XProcessingEnv processingEnv,
+ MonitoringModules monitoringModules) {
super(filer, processingEnv);
+ this.monitoringModules = monitoringModules;
}
@Override
@@ -55,6 +61,7 @@ final class MonitoringModuleGenerator extends SourceFileGenerator<XTypeElement>
@Override
public ImmutableList<TypeSpec.Builder> topLevelTypes(XTypeElement componentElement) {
+ monitoringModules.add(SourceFiles.generatedMonitoringModuleName(componentElement));
return ImmutableList.of(
classBuilder(SourceFiles.generatedMonitoringModuleName(componentElement))
.addAnnotation(Module.class)
diff --git a/java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java b/java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java
index 5d6a64f3d..7ff47532a 100644
--- a/java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java
+++ b/java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java
@@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Maps;
import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.DaggerSuperficialValidation.ValidationException;
+import dagger.internal.codegen.binding.MonitoringModules;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.xprocessing.XElements;
import java.util.ArrayList;
@@ -51,6 +52,7 @@ abstract class TypeCheckingProcessingStep<E extends XElement> implements XProces
@Inject XMessager messager;
@Inject CompilerOptions compilerOptions;
@Inject SuperficialValidator superficialValidator;
+ @Inject MonitoringModules monitoringModules;
@Override
public final ImmutableSet<String> annotations() {
@@ -70,6 +72,16 @@ abstract class TypeCheckingProcessingStep<E extends XElement> implements XProces
.forEach(
(element, annotations) -> {
try {
+ if (this instanceof ComponentProcessingStep && !monitoringModules.isEmpty()) {
+ // If there were any monitoring modules generated by Dagger in this round then we
+ // should just defer processing the components until the next round. This is an
+ // optimization to avoid unnecessary processing of components that will likely
+ // need to be reprocessed next round anyway due to the missing module. We should
+ // be guaranteed that there will be a next round since the monitoring modules were
+ // generated in this round.
+ deferredElements.add(element);
+ return;
+ }
// The XBasicAnnotationProcessor only validates the element itself. However, we
// validate the enclosing type here to keep the previous behavior of
// BasicAnnotationProcessor, since Dagger still relies on this behavior.
diff --git a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java
index 1b0b85bbd..cfcf8ee88 100644
--- a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java
+++ b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java
@@ -195,14 +195,11 @@ public class ProductionGraphValidationTest {
.buildOrThrow())
.compile(
subject -> {
- subject.hasErrorCount(2);
+ subject.hasErrorCount(1);
subject.hasErrorContaining(
"TestClass.A is a provision, which cannot depend on a production.")
.onSource(component)
.onLineContaining("class AModule");
- subject.hasErrorContaining("test.TestClass.AModule has errors")
- .onSource(component)
- .onLineContaining("@ProductionComponent");
});
}