Dex and desugar in single D8 compilation in R8 partial
Change-Id: Ib94c300bea11e2502ec33adb0066c540f2ccaef6
diff --git a/src/main/java/com/android/tools/r8/R8Partial.java b/src/main/java/com/android/tools/r8/R8Partial.java
index 9302b2a..e0bf09a 100644
--- a/src/main/java/com/android/tools/r8/R8Partial.java
+++ b/src/main/java/com/android/tools/r8/R8Partial.java
@@ -6,12 +6,10 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.diagnostic.R8VersionDiagnostic;
import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.partial.R8PartialD8DexResult;
-import com.android.tools.r8.partial.R8PartialDesugarResult;
+import com.android.tools.r8.partial.R8PartialD8Result;
import com.android.tools.r8.partial.R8PartialInput;
import com.android.tools.r8.partial.R8PartialProgramPartioning;
-import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration.R8PartialD8DesugarSubCompilationConfiguration;
-import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration.R8PartialD8DexSubCompilationConfiguration;
+import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration.R8PartialD8SubCompilationConfiguration;
import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration.R8PartialR8SubCompilationConfiguration;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ExceptionUtils;
@@ -24,19 +22,14 @@
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
-import java.util.function.Consumer;
class R8Partial {
private final InternalOptions options;
- private final Consumer<AndroidApp> r8InputAppConsumer;
- private final Consumer<AndroidApp> d8InputAppConsumer;
private final Timing timing;
R8Partial(InternalOptions options) {
this.options = options;
- this.r8InputAppConsumer = options.partialCompilationConfiguration.r8InputAppConsumer;
- this.d8InputAppConsumer = options.partialCompilationConfiguration.d8InputAppConsumer;
this.timing = Timing.create("R8 partial " + Version.LABEL, options);
}
@@ -66,14 +59,11 @@
timing.begin("Process input");
R8PartialInput input = runProcessInputStep(app, executor);
- timing.end().begin("Run dexing");
- R8PartialD8DexResult dexingResult = runDexingStep(input, executor);
-
- timing.end().begin("Run desugaring");
- R8PartialDesugarResult desugarResult = runDesugarStep(input, executor);
+ timing.end().begin("Run D8");
+ R8PartialD8Result d8Result = runD8Step(input, executor);
timing.end().begin("Run R8");
- runR8PartialStep(app, input, dexingResult, desugarResult, executor);
+ runR8Step(app, input, d8Result, executor);
timing.end();
if (options.isPrintTimesReportingEnabled()) {
@@ -94,8 +84,11 @@
app.libraryClasses());
}
- private R8PartialD8DexResult runDexingStep(R8PartialInput input, ExecutorService executor)
+ private R8PartialD8Result runD8Step(R8PartialInput input, ExecutorService executor)
throws IOException {
+ // TODO(b/389039057): This will desugar the entire R8 part. For build speed, look into if some
+ // desugarings can be postponed to the R8 compilation, since we do not desugar dead code in R8.
+ // As a simple example, it should be safe to postpone backporting to the R8 compilation.
D8Command.Builder d8Builder =
D8Command.builder(options.reporter)
.setMinApiLevel(options.getMinApiLevel().getLevel())
@@ -106,51 +99,19 @@
d8Builder.validate();
D8Command d8Command = d8Builder.makeD8Command(options.dexItemFactory());
AndroidApp d8App = d8Command.getInputApp();
- if (d8InputAppConsumer != null) {
- d8InputAppConsumer.accept(d8App);
- }
InternalOptions d8Options = d8Command.getInternalOptions();
options.partialCompilationConfiguration.d8DexOptionsConsumer.accept(d8Options);
- R8PartialD8DexSubCompilationConfiguration subCompilationConfiguration =
- new R8PartialD8DexSubCompilationConfiguration(timing);
+ R8PartialD8SubCompilationConfiguration subCompilationConfiguration =
+ new R8PartialD8SubCompilationConfiguration(input.getD8Types(), input.getR8Types(), timing);
d8Options.partialSubCompilationConfiguration = subCompilationConfiguration;
D8.runInternal(d8App, d8Options, executor);
- return new R8PartialD8DexResult(subCompilationConfiguration.getOutputClasses());
+ return new R8PartialD8Result(
+ subCompilationConfiguration.getDexedOutputClasses(),
+ subCompilationConfiguration.getDesugaredOutputClasses());
}
- private R8PartialDesugarResult runDesugarStep(R8PartialInput input, ExecutorService executor)
- throws IOException {
- // TODO(b/389575762): Consume the DexProgramClasses instead of writing to a zip.
- // TODO(b/389039057): This will desugar the entire R8 part. For build speed, look into if some
- // desugarings can be postponed to the R8 compilation, since we do not desugar dead code in R8.
- // As a simple example, it should be safe to postpone backporting to the R8 compilation.
- // TODO(b/389039057): This runs a full D8 compilation. For build speed, consider if the various
- // passes in D8 can be disabled when the `partialSubCompilationConfiguration` is set.
- D8Command.Builder d8Builder =
- D8Command.builder(options.reporter)
- .setMinApiLevel(options.getMinApiLevel().getLevel())
- .setMode(options.getCompilationMode())
- .setProgramConsumer(ClassFileConsumer.emptyConsumer());
- // TODO(b/390327883): This should enable intermediate mode.
- input.configureDesugar(d8Builder);
- d8Builder.validate();
- D8Command d8Command = d8Builder.makeD8Command(options.dexItemFactory());
- AndroidApp d8App = d8Command.getInputApp();
- InternalOptions d8Options = d8Command.getInternalOptions();
- options.partialCompilationConfiguration.d8DesugarOptionsConsumer.accept(d8Options);
- R8PartialD8DesugarSubCompilationConfiguration subCompilationConfiguration =
- new R8PartialD8DesugarSubCompilationConfiguration(timing);
- d8Options.partialSubCompilationConfiguration = subCompilationConfiguration;
- D8.runInternal(d8App, d8Options, executor);
- return new R8PartialDesugarResult(subCompilationConfiguration.getOutputClasses());
- }
-
- private void runR8PartialStep(
- AndroidApp app,
- R8PartialInput input,
- R8PartialD8DexResult dexingResult,
- R8PartialDesugarResult desugarResult,
- ExecutorService executor)
+ private void runR8Step(
+ AndroidApp app, R8PartialInput input, R8PartialD8Result d8Result, ExecutorService executor)
throws IOException {
// Compile R8 input with R8 using the keep rules from trace references.
DiagnosticsHandler r8DiagnosticsHandler =
@@ -169,7 +130,7 @@
R8Command.Builder r8Builder =
R8Command.builder(r8DiagnosticsHandler)
.addProgramResourceProvider(
- new InternalProgramClassProvider(desugarResult.getOutputClasses()))
+ new InternalProgramClassProvider(d8Result.getDesugaredClasses()))
.enableLegacyFullModeForKeepRules(true)
.setMinApiLevel(options.getMinApiLevel().getLevel())
.setMode(options.getCompilationMode())
@@ -207,13 +168,10 @@
R8Command r8Command =
r8Builder.makeR8Command(options.dexItemFactory(), options.getProguardConfiguration());
AndroidApp r8App = r8Command.getInputApp();
- if (r8InputAppConsumer != null) {
- r8InputAppConsumer.accept(r8App);
- }
InternalOptions r8Options = r8Command.getInternalOptions();
options.partialCompilationConfiguration.r8OptionsConsumer.accept(r8Options);
r8Options.partialSubCompilationConfiguration =
- new R8PartialR8SubCompilationConfiguration(dexingResult.getOutputClasses(), timing);
+ new R8PartialR8SubCompilationConfiguration(d8Result.getDexedClasses(), timing);
r8Options.mapConsumer = options.mapConsumer;
if (options.androidResourceProvider != null) {
r8Options.androidResourceProvider = options.androidResourceProvider;
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
index bcb7abe..c5bdfa5 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -195,7 +195,7 @@
OptimizationFeedbackIgnore.getInstance(),
methodProcessor,
methodProcessingContext,
- MethodConversionOptions.forD8(converter.appView)));
+ MethodConversionOptions.forD8(converter.appView, method)));
}
@SuppressWarnings("ReferenceEquality")
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index 0f1c8de..1d8da6e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -53,6 +53,7 @@
import com.android.tools.r8.horizontalclassmerging.policies.SameNestHost;
import com.android.tools.r8.horizontalclassmerging.policies.SamePackageForNonGlobalMergeSynthetic;
import com.android.tools.r8.horizontalclassmerging.policies.SameParentClass;
+import com.android.tools.r8.horizontalclassmerging.policies.SamePartialSubCompilation;
import com.android.tools.r8.horizontalclassmerging.policies.SameStartupPartition;
import com.android.tools.r8.horizontalclassmerging.policies.SyntheticItemsPolicy;
import com.android.tools.r8.horizontalclassmerging.policies.VerifyMultiClassPolicyAlwaysSatisfied;
@@ -217,6 +218,9 @@
private static List<? extends Policy> getMultiClassPoliciesForD8(AppView<AppInfo> appView) {
ImmutableList.Builder<MultiClassPolicy> builder = ImmutableList.builder();
+ if (appView.options().partialSubCompilationConfiguration != null) {
+ builder.add(new SamePartialSubCompilation(appView));
+ }
builder.add(
new CheckAbstractClasses(appView),
new SameFeatureSplit(appView),
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SamePartialSubCompilation.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SamePartialSubCompilation.java
new file mode 100644
index 0000000..aed18c7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SamePartialSubCompilation.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2025, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.MultiClassSameReferencePolicy;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
+import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration.R8PartialD8SubCompilationConfiguration;
+
+public class SamePartialSubCompilation
+ extends MultiClassSameReferencePolicy<MethodConversionOptions.Target> {
+
+ private final AppView<AppInfo> appView;
+ private final R8PartialD8SubCompilationConfiguration subCompilationConfiguration;
+
+ public SamePartialSubCompilation(AppView<AppInfo> appView) {
+ assert appView.options().partialSubCompilationConfiguration != null;
+ this.appView = appView;
+ this.subCompilationConfiguration = appView.options().partialSubCompilationConfiguration.asD8();
+ }
+
+ @Override
+ public MethodConversionOptions.Target getMergeKey(DexProgramClass clazz) {
+ return subCompilationConfiguration.getTargetFor(clazz, appView);
+ }
+
+ @Override
+ public String getName() {
+ return "SamePartialSubCompilation";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
index 4fc003f..768fec4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
@@ -120,7 +120,7 @@
OptimizationFeedbackIgnore.getInstance(),
this,
processorContext.createMethodProcessingContext(method),
- MethodConversionOptions.forD8(converter.appView)));
+ MethodConversionOptions.forD8(converter.appView, method)));
}
public void scheduleDesugaredMethodsForProcessing(Iterable<ProgramMethod> methods) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 433f6f0..278e799 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -289,7 +289,8 @@
fieldAccessAnalysis = null;
}
- private boolean needsIRConversion(ProgramMethod method) {
+ private boolean needsIRConversion(
+ ProgramMethod method, MethodConversionOptions conversionOptions) {
if (method.getDefinition().getCode().isThrowNullCode()) {
return false;
}
@@ -300,6 +301,10 @@
return true;
}
assert method.getDefinition().getCode().isCfCode();
+ if (options.partialSubCompilationConfiguration != null) {
+ assert conversionOptions.isGeneratingClassFiles() || conversionOptions.isGeneratingDex();
+ return conversionOptions.isGeneratingDex();
+ }
return !options.isGeneratingClassFiles();
}
@@ -475,7 +480,7 @@
options.testing.hookInIrConversion.run();
}
- if (!needsIRConversion(method) || options.skipIR) {
+ if (!needsIRConversion(method, conversionOptions) || options.skipIR) {
feedback.markProcessed(method.getDefinition(), ConstraintWithTarget.NEVER);
return Timing.empty();
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
index 970479e..d9e6322 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
@@ -6,7 +6,9 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration;
public abstract class MethodConversionOptions {
@@ -32,12 +34,16 @@
return forD8(appView);
}
assert appView.testing().isSupportedLirPhase();
- return new MutableMethodConversionOptions(determineTarget(appView));
+ return new MutableMethodConversionOptions(determineTarget(appView, null));
}
public static MutableMethodConversionOptions forD8(AppView<?> appView) {
+ return forD8(appView, null);
+ }
+
+ public static MutableMethodConversionOptions forD8(AppView<?> appView, ProgramMethod method) {
assert !appView.enableWholeProgramOptimizations();
- return new MutableMethodConversionOptions(determineTarget(appView));
+ return new MutableMethodConversionOptions(determineTarget(appView, method));
}
public static MutableMethodConversionOptions nonConverting() {
@@ -55,13 +61,13 @@
return new IRToDexFinalizer(appView, deadCodeRemover);
}
- private enum Target {
+ public enum Target {
CF,
DEX,
LIR
}
- private static Target determineTarget(AppView<?> appView) {
+ private static Target determineTarget(AppView<?> appView, ProgramMethod method) {
if (appView.testing().canUseLir(appView)) {
return Target.LIR;
}
@@ -69,6 +75,11 @@
return Target.CF;
}
assert appView.options().isGeneratingDex();
+ R8PartialSubCompilationConfiguration subCompilationConfiguration =
+ appView.options().partialSubCompilationConfiguration;
+ if (subCompilationConfiguration != null && subCompilationConfiguration.isD8()) {
+ return subCompilationConfiguration.asD8().getTargetFor(method, appView);
+ }
return Target.DEX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
index ddc3b2a..f8294d1 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
@@ -360,20 +360,19 @@
methodProcessingContext));
}
- @SuppressWarnings("UnusedVariable")
private Timing rewriteNonDesugaredCodeInternal(
ProgramMethod method,
CfInstructionDesugaringEventConsumer desugaringEventConsumer,
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
MethodProcessingContext methodProcessingContext) {
- boolean didDesugar = desugar(method, desugaringEventConsumer, methodProcessingContext);
+ desugar(method, desugaringEventConsumer, methodProcessingContext);
return rewriteDesugaredCodeInternal(
method,
feedback,
methodProcessor,
methodProcessingContext,
- MethodConversionOptions.forD8(appView));
+ MethodConversionOptions.forD8(appView, method));
}
private boolean desugar(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index aa3cbe9..901e1fa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -734,7 +734,9 @@
// Since we've copied the code object from an existing method from the same class, the
// code is already processed, and thus we don't need to schedule it for processing in D8.
assert !appView.options().isGeneratingClassFiles() || replacement.getCode().isCfCode();
- assert !appView.options().isGeneratingDex() || replacement.getCode().isDexCode();
+ assert !appView.options().isGeneratingDex()
+ || replacement.getCode().isDexCode()
+ || appView.options().partialSubCompilationConfiguration != null;
return new ProgramMethod(implMethodHolder, replacement);
}
// The method might already have been moved by another invoke-dynamic targeting it.
diff --git a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
index 9f3ea10..a21ad04 100644
--- a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
@@ -25,7 +25,7 @@
}
InternalOptions options = appView.options();
if (options.partialSubCompilationConfiguration != null
- && !options.partialSubCompilationConfiguration.isR8()) {
+ && options.partialSubCompilationConfiguration.isD8()) {
return;
}
appView.setNamingLens(new PrefixRewritingNamingLens(appView));
diff --git a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
index a2ad972..517377d 100644
--- a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
@@ -29,7 +29,7 @@
return;
}
if (options.partialSubCompilationConfiguration != null
- && !options.partialSubCompilationConfiguration.isR8()) {
+ && options.partialSubCompilationConfiguration.isD8()) {
return;
}
appView.setNamingLens(new RecordRewritingNamingLens(appView));
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialApplicationWriter.java b/src/main/java/com/android/tools/r8/partial/R8PartialApplicationWriter.java
index 04780c4..88a2160 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialApplicationWriter.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration.R8PartialD8SubCompilationConfiguration;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
@@ -33,18 +34,18 @@
private final AppView<AppInfo> appView;
private final InternalOptions options;
- private final R8PartialSubCompilationConfiguration subCompilationConfiguration;
+ private final R8PartialD8SubCompilationConfiguration subCompilationConfiguration;
public R8PartialApplicationWriter(AppView<AppInfo> appView) {
this.appView = appView;
this.options = appView.options();
- this.subCompilationConfiguration = appView.options().partialSubCompilationConfiguration;
+ this.subCompilationConfiguration = appView.options().partialSubCompilationConfiguration.asD8();
}
public void write(ExecutorService executorService) throws ExecutionException {
assert appView.getNamingLens().isIdentityLens();
rewriteCodeWithLens(executorService);
- subCompilationConfiguration.writeApplication(appView.appInfo().classes(), options);
+ subCompilationConfiguration.writeApplication(appView);
}
private void rewriteCodeWithLens(ExecutorService executorService) throws ExecutionException {
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialD8DexResult.java b/src/main/java/com/android/tools/r8/partial/R8PartialD8DexResult.java
deleted file mode 100644
index 4daf363..0000000
--- a/src/main/java/com/android/tools/r8/partial/R8PartialD8DexResult.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2025, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.partial;
-
-import com.android.tools.r8.graph.DexProgramClass;
-import java.util.Collection;
-
-public class R8PartialD8DexResult {
-
- private final Collection<DexProgramClass> outputClasses;
-
- public R8PartialD8DexResult(Collection<DexProgramClass> outputClasses) {
- this.outputClasses = outputClasses;
- }
-
- public Collection<DexProgramClass> getOutputClasses() {
- return outputClasses;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialD8Result.java b/src/main/java/com/android/tools/r8/partial/R8PartialD8Result.java
new file mode 100644
index 0000000..d698676
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialD8Result.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2025, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.partial;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import java.util.Collection;
+
+public class R8PartialD8Result {
+
+ private final Collection<DexProgramClass> dexedClasses;
+ private final Collection<DexProgramClass> desugaredClasses;
+
+ public R8PartialD8Result(
+ Collection<DexProgramClass> dexedClasses, Collection<DexProgramClass> desugaredClasses) {
+ this.dexedClasses = dexedClasses;
+ this.desugaredClasses = desugaredClasses;
+ }
+
+ public Collection<DexProgramClass> getDexedClasses() {
+ return dexedClasses;
+ }
+
+ public Collection<DexProgramClass> getDesugaredClasses() {
+ return desugaredClasses;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialDesugarResult.java b/src/main/java/com/android/tools/r8/partial/R8PartialDesugarResult.java
deleted file mode 100644
index 37bae17..0000000
--- a/src/main/java/com/android/tools/r8/partial/R8PartialDesugarResult.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2025, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.partial;
-
-import com.android.tools.r8.graph.DexProgramClass;
-import java.util.Collection;
-
-public class R8PartialDesugarResult {
-
- private final Collection<DexProgramClass> outputClasses;
-
- public R8PartialDesugarResult(Collection<DexProgramClass> outputClasses) {
- this.outputClasses = outputClasses;
- }
-
- public Collection<DexProgramClass> getOutputClasses() {
- return outputClasses;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialInput.java b/src/main/java/com/android/tools/r8/partial/R8PartialInput.java
index 5698cb6..ba75e6b 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialInput.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialInput.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.partial;
-
import com.android.tools.r8.BaseCompilerCommand;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.R8Command;
@@ -15,10 +14,12 @@
import com.android.tools.r8.utils.InternalClasspathOrLibraryClassProvider;
import com.android.tools.r8.utils.InternalProgramClassProvider;
import com.android.tools.r8.utils.MapUtils;
+import com.android.tools.r8.utils.SetUtils;
import java.io.IOException;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Map;
+import java.util.Set;
public class R8PartialInput {
@@ -44,18 +45,7 @@
configureBase(commandBuilder);
commandBuilder
.addProgramResourceProvider(new InternalProgramClassProvider(d8Classes))
- .addClasspathResourceProvider(
- new InternalClasspathOrLibraryClassProvider<>(
- DexClasspathClass.toClasspathClasses(r8Classes)));
- }
-
- public void configureDesugar(D8Command.Builder commandBuilder) {
- configureBase(commandBuilder);
- commandBuilder
- .addProgramResourceProvider(new InternalProgramClassProvider(r8Classes))
- .addClasspathResourceProvider(
- new InternalClasspathOrLibraryClassProvider<>(
- DexClasspathClass.toClasspathClasses(d8Classes)));
+ .addProgramResourceProvider(new InternalProgramClassProvider(r8Classes));
}
public void configure(R8Command.Builder commandBuilder) throws IOException {
@@ -71,4 +61,16 @@
new InternalClasspathOrLibraryClassProvider<>(classpathClasses))
.addLibraryResourceProvider(new InternalClasspathOrLibraryClassProvider<>(libraryClasses));
}
+
+ public Set<DexType> getD8Types() {
+ // Intentionally not returning d8Classes.keySet(). This allows clearing the map after providing
+ // the classes to the D8 compilation.
+ return SetUtils.mapIdentityHashSet(d8Classes, DexClass::getType);
+ }
+
+ public Set<DexType> getR8Types() {
+ // Intentionally not returning r8Classes.keySet(). This allows clearing the map after providing
+ // the classes to the D8 compilation.
+ return SetUtils.mapIdentityHashSet(r8Classes, DexClass::getType);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
index 35d84d1..ec8b0a9 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
@@ -9,10 +9,14 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.Target;
import com.android.tools.r8.shaking.MissingClasses;
-import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.Timing;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
@@ -24,6 +28,14 @@
this.timing = timing;
}
+ public boolean isD8() {
+ return false;
+ }
+
+ public R8PartialD8SubCompilationConfiguration asD8() {
+ return null;
+ }
+
public boolean isR8() {
return false;
}
@@ -32,50 +44,75 @@
return null;
}
- /** Returns true if normal writing should be aborted. */
- public void writeApplication(Collection<DexProgramClass> outputClasses, InternalOptions options) {
- assert false;
- }
-
- public static class R8PartialD8DexSubCompilationConfiguration
+ public static class R8PartialD8SubCompilationConfiguration
extends R8PartialSubCompilationConfiguration {
- private Collection<DexProgramClass> outputClasses;
+ private final Set<DexType> d8Types;
+ private final Set<DexType> r8Types;
- public R8PartialD8DexSubCompilationConfiguration(Timing timing) {
+ private Collection<DexProgramClass> dexedOutputClasses;
+ private Collection<DexProgramClass> desugaredOutputClasses;
+
+ public R8PartialD8SubCompilationConfiguration(
+ Set<DexType> d8Types, Set<DexType> r8Types, Timing timing) {
super(timing);
+ this.d8Types = d8Types;
+ this.r8Types = r8Types;
}
- public Collection<DexProgramClass> getOutputClasses() {
- assert outputClasses != null;
- return outputClasses;
+ public Collection<DexProgramClass> getDexedOutputClasses() {
+ assert dexedOutputClasses != null;
+ return dexedOutputClasses;
+ }
+
+ public Collection<DexProgramClass> getDesugaredOutputClasses() {
+ assert desugaredOutputClasses != null;
+ return desugaredOutputClasses;
+ }
+
+ public MethodConversionOptions.Target getTargetFor(
+ ProgramDefinition definition, AppView<?> appView) {
+ DexType type = definition.getContextType();
+ if (d8Types.contains(type)) {
+ return Target.DEX;
+ } else if (r8Types.contains(type)) {
+ return Target.CF;
+ } else {
+ SyntheticItems syntheticItems = appView.getSyntheticItems();
+ assert syntheticItems.isSynthetic(definition.getContextClass());
+ Collection<DexType> syntheticContexts =
+ syntheticItems.getSynthesizingContextTypes(definition.getContextType());
+ assert syntheticContexts.size() == 1;
+ DexType syntheticContext = syntheticContexts.iterator().next();
+ if (d8Types.contains(syntheticContext)) {
+ return Target.DEX;
+ } else {
+ assert r8Types.contains(syntheticContext);
+ return Target.CF;
+ }
+ }
}
@Override
- public void writeApplication(
- Collection<DexProgramClass> outputClasses, InternalOptions options) {
- this.outputClasses = outputClasses;
- }
- }
-
- public static class R8PartialD8DesugarSubCompilationConfiguration
- extends R8PartialSubCompilationConfiguration {
-
- private Collection<DexProgramClass> outputClasses;
-
- public R8PartialD8DesugarSubCompilationConfiguration(Timing timing) {
- super(timing);
- }
-
- public Collection<DexProgramClass> getOutputClasses() {
- assert outputClasses != null;
- return outputClasses;
+ public boolean isD8() {
+ return true;
}
@Override
- public void writeApplication(
- Collection<DexProgramClass> outputClasses, InternalOptions options) {
- this.outputClasses = outputClasses;
+ public R8PartialD8SubCompilationConfiguration asD8() {
+ return this;
+ }
+
+ public void writeApplication(AppView<?> appView) {
+ dexedOutputClasses = new ArrayList<>();
+ desugaredOutputClasses = new ArrayList<>();
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ if (getTargetFor(clazz, appView) == Target.DEX) {
+ dexedOutputClasses.add(clazz);
+ } else {
+ desugaredOutputClasses.add(clazz);
+ }
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java b/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
index c87e7fc..bb8dad6 100644
--- a/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
@@ -24,13 +24,7 @@
private final List<Predicate<DexString>> includePredicates;
private final List<Predicate<DexString>> excludePredicates;
- public Consumer<AndroidApp> r8InputAppConsumer;
- public Consumer<AndroidApp> d8InputAppConsumer;
- public Consumer<AndroidApp> r8OutputAppConsumer;
- public Consumer<AndroidApp> d8OutputAppConsumer;
-
public Consumer<InternalOptions> d8DexOptionsConsumer = ConsumerUtils.emptyConsumer();
- public Consumer<InternalOptions> d8DesugarOptionsConsumer = ConsumerUtils.emptyConsumer();
public Consumer<InternalOptions> r8OptionsConsumer = ConsumerUtils.emptyConsumer();
private static final R8PartialCompilationConfiguration disabledConfiguration =
diff --git a/src/test/java/com/android/tools/r8/partial/ClassHierarchyInterleavedD8AndR8Test.java b/src/test/java/com/android/tools/r8/partial/ClassHierarchyInterleavedD8AndR8Test.java
index 71922c9..85b0fb5 100644
--- a/src/test/java/com/android/tools/r8/partial/ClassHierarchyInterleavedD8AndR8Test.java
+++ b/src/test/java/com/android/tools/r8/partial/ClassHierarchyInterleavedD8AndR8Test.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.partial;
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -39,7 +38,6 @@
private void runTest(
Consumer<R8PartialCompilationConfiguration.Builder> partialConfigurationBuilderConsumer,
- ThrowingConsumer<CodeInspector, RuntimeException> d8Inspector,
ThrowingConsumer<CodeInspector, RuntimeException> inspector)
throws Exception {
testForR8Partial(parameters.getBackend())
@@ -48,7 +46,6 @@
.addKeepMainRule(Main.class)
.setR8PartialConfiguration(partialConfigurationBuilderConsumer)
.compile()
- .inspectD8Input(d8Inspector)
.inspect(inspector)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithEmptyOutput();
@@ -60,11 +57,6 @@
partialConfigurationBuilder ->
partialConfigurationBuilder.includeAll().excludeClasses(A.class),
inspector -> {
- assertThat(inspector.programClass(A.class), isPresent());
- assertThat(inspector.programClass(B.class), isAbsent());
- assertThat(inspector.programClass(C.class), isAbsent());
- },
- inspector -> {
assertThat(inspector.clazz(A.class), isPresentAndNotRenamed());
assertThat(inspector.clazz(B.class), isAbsent()); // Merged into C.
assertThat(inspector.clazz(C.class), isPresentAndRenamed());
@@ -77,11 +69,6 @@
partialConfigurationBuilder ->
partialConfigurationBuilder.includeAll().excludeClasses(B.class),
inspector -> {
- assertThat(inspector.programClass(A.class), isPresent());
- assertThat(inspector.programClass(B.class), isPresent());
- assertThat(inspector.programClass(C.class), isAbsent());
- },
- inspector -> {
assertThat(inspector.clazz(A.class), isPresentAndNotRenamed());
assertThat(inspector.clazz(B.class), isPresentAndNotRenamed());
assertThat(inspector.clazz(C.class), isPresentAndRenamed());
@@ -94,11 +81,6 @@
partialConfigurationBuilder ->
partialConfigurationBuilder.includeAll().excludeClasses(C.class),
inspector -> {
- assertThat(inspector.programClass(A.class), isPresent());
- assertThat(inspector.programClass(B.class), isPresent());
- assertThat(inspector.programClass(C.class), isPresent());
- },
- inspector -> {
assertThat(inspector.clazz(A.class), isPresentAndNotRenamed());
assertThat(inspector.clazz(B.class), isPresentAndNotRenamed());
assertThat(inspector.clazz(C.class), isPresentAndNotRenamed());
diff --git a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicPreviewPatternsTest.java b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicPreviewPatternsTest.java
index d77f004..de63504 100644
--- a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicPreviewPatternsTest.java
+++ b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicPreviewPatternsTest.java
@@ -25,9 +25,9 @@
@RunWith(Parameterized.class)
public class PartialCompilationBasicPreviewPatternsTest extends TestBase {
- private static String PKG1 = getPackageName(A1.class);
- private static String SUBPKG = getPackageName(B.class);
- private static String PKG2 = getPackageName(C2.class);
+ private static final String PKG1 = getPackageName(A1.class);
+ private static final String SUBPKG = getPackageName(B.class);
+ private static final String PKG2 = getPackageName(C2.class);
private static String getPackageName(Class<?> clazz) {
return clazz.getTypeName().substring(0, clazz.getTypeName().lastIndexOf('.'));
@@ -62,9 +62,6 @@
.addProgramClasses(ALL_CLASSES)
.setR8PartialConfiguration(builder -> builder.addJavaTypeIncludePattern(PKG1 + ".**"))
.compile()
- .inspectD8Input(
- inspector ->
- assertTrue(inspector.hasExactlyProgramClasses(C1.class, C2.class, Main.class)))
.inspect(
inspector ->
assertTrue(inspector.hasExactlyProgramClasses(C1.class, C2.class, Main.class)))
@@ -84,10 +81,6 @@
.addProgramClasses(ALL_CLASSES)
.setR8PartialConfiguration(builder -> builder.addJavaTypeIncludePattern(PKG1 + ".*"))
.compile()
- .inspectD8Input(
- inspector ->
- assertTrue(
- inspector.hasExactlyProgramClasses(B.class, C1.class, C2.class, Main.class)))
.inspect(
inspector ->
assertTrue(
@@ -108,10 +101,6 @@
.addJavaTypeIncludePattern(PKG1 + ".**")
.addJavaTypeExcludePattern(SUBPKG + ".*"))
.compile()
- .inspectD8Input(
- inspector ->
- assertTrue(
- inspector.hasExactlyProgramClasses(C1.class, C2.class, B.class, Main.class)))
.inspect(
inspector ->
assertTrue(
@@ -132,11 +121,6 @@
.addJavaTypeIncludePattern(PKG1 + ".**")
.addJavaTypeExcludePattern(PKG1 + ".A*"))
.compile()
- .inspectD8Input(
- inspector ->
- assertTrue(
- inspector.hasExactlyProgramClasses(
- A1.class, A2.class, C1.class, C2.class, Main.class)))
.inspect(
inspector ->
assertTrue(
@@ -159,11 +143,6 @@
.addJavaTypeExcludePattern(PKG1 + ".A1")
.addJavaTypeExcludePattern(PKG1 + ".A2"))
.compile()
- .inspectD8Input(
- inspector ->
- assertTrue(
- inspector.hasExactlyProgramClasses(
- A1.class, A2.class, C1.class, C2.class, Main.class)))
.inspect(
inspector ->
assertTrue(
@@ -186,8 +165,6 @@
.addJavaTypeIncludePattern(PKG2 + ".**")
.addJavaTypeExcludePattern(PKG2 + ".C1"))
.compile()
- .inspectD8Input(
- inspector -> assertTrue(inspector.hasExactlyProgramClasses(C1.class, Main.class)))
.inspect(inspector -> assertTrue(inspector.hasExactlyProgramClasses(C1.class, Main.class)))
.run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES)
.assertSuccessWithOutputLines(
@@ -211,8 +188,6 @@
.addJavaTypeIncludePattern(PKG2 + ".*")
.addJavaTypeExcludePattern(PKG1 + ".A1"))
.compile()
- .inspectD8Input(
- inspector -> assertTrue(inspector.hasExactlyProgramClasses(A1.class, Main.class)))
.inspect(inspector -> assertTrue(inspector.hasExactlyProgramClasses(A1.class, Main.class)))
.run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES)
.assertSuccessWithOutputLines(
@@ -235,8 +210,6 @@
.addJavaTypeIncludePattern(PKG2 + ".**")
.addJavaTypeExcludePattern(SUBPKG + ".*"))
.compile()
- .inspectD8Input(
- inspector -> assertTrue(inspector.hasExactlyProgramClasses(B.class, Main.class)))
.inspect(inspector -> assertTrue(inspector.hasExactlyProgramClasses(B.class, Main.class)))
.run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES)
.assertSuccessWithOutputLines(
diff --git a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java
index 76f2fc4..bb9bccd 100644
--- a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java
+++ b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java
@@ -39,12 +39,6 @@
.addKeepMainRule(Main.class)
.setR8PartialConfiguration(builder -> builder.includeAll().excludeClasses(A.class))
.compile()
- .inspectD8Input(
- inspector -> {
- assertThat(inspector.programClass(A.class), isPresent());
- assertThat(inspector.programClass(B.class), isAbsent());
- assertThat(inspector.programClass(Main.class), isAbsent());
- })
.inspect(
inspector -> {
assertThat(inspector.clazz(A.class), isPresent());
@@ -63,14 +57,6 @@
.addKeepMainRule(Main.class)
.setR8PartialConfiguration(builder -> builder.includeAll().excludeClasses(B.class))
.compile()
- .inspectD8Input(
- inspector -> {
- // TODO(b/309743298): These are all present as inspection currently also look at
- // classpath.
- assertThat(inspector.programClass(A.class), isAbsent());
- assertThat(inspector.programClass(B.class), isPresent());
- assertThat(inspector.programClass(Main.class), isAbsent());
- })
.inspect(
inspector -> {
assertThat(inspector.clazz(A.class), isAbsent());
diff --git a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
index 83dec8f..0b2db9f 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
@@ -137,12 +137,8 @@
Box<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer,
StringBuilder proguardMapBuilder)
throws CompilationFailedException {
- Box<AndroidApp> d8InputAppBox = new Box<>();
builder.setPartialCompilationConfiguration(getPartialConfiguration());
- Consumer<InternalOptions> configureR8PartialCompilation =
- options -> options.partialCompilationConfiguration.d8InputAppConsumer = d8InputAppBox::set;
- ToolHelper.runAndBenchmarkR8PartialWithoutResult(
- builder, configureR8PartialCompilation.andThen(optionsConsumer), benchmarkResults);
+ ToolHelper.runAndBenchmarkR8PartialWithoutResult(builder, optionsConsumer, benchmarkResults);
return new R8PartialTestCompileResult(
getState(),
getOutputMode(),
@@ -157,8 +153,7 @@
residualArtProfiles,
resourceShrinkerOutput,
resourceShrinkerOutputForFeatures,
- buildMetadata != null ? buildMetadata.get() : null,
- d8InputAppBox.get());
+ buildMetadata != null ? buildMetadata.get() : null);
}
@Override
diff --git a/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java
index a722661..18f75fb 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java
@@ -8,20 +8,13 @@
import com.android.tools.r8.shaking.CollectingGraphConsumer;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ThrowingConsumer;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
-import java.util.function.Consumer;
public class R8PartialTestCompileResult
extends R8TestCompileResultBase<R8PartialTestCompileResult> {
- private final AndroidApp d8InputApp;
-
R8PartialTestCompileResult(
TestState state,
OutputMode outputMode,
@@ -36,8 +29,7 @@
List<ExternalArtProfile> residualArtProfiles,
Path resourceShrinkerOutput,
HashMap<String, Path> resourceShrinkerOutputForFeatures,
- R8BuildMetadata buildMetadata,
- AndroidApp d8InputApp) {
+ R8BuildMetadata buildMetadata) {
super(
state,
outputMode,
@@ -53,26 +45,10 @@
resourceShrinkerOutput,
resourceShrinkerOutputForFeatures,
buildMetadata);
- this.d8InputApp = d8InputApp;
}
@Override
public R8PartialTestCompileResult self() {
return this;
}
-
- public CodeInspector inspectorD8Input() throws IOException {
- return new CodeInspector(d8InputApp);
- }
-
- public CodeInspector inspectorD8Input(Consumer<InternalOptions> debugOptionsConsumer)
- throws IOException {
- return new CodeInspector(d8InputApp, debugOptionsConsumer);
- }
-
- public <E extends Throwable> R8PartialTestCompileResult inspectD8Input(
- ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E {
- consumer.accept(inspectorD8Input());
- return self();
- }
}
diff --git a/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
index 106cc4e..b017214 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -176,8 +176,6 @@
DEFAULT_OPTIONS.andThen(
options -> {
options.partialCompilationConfiguration.d8DexOptionsConsumer = DEFAULT_D8_OPTIONS;
- options.partialCompilationConfiguration.d8DesugarOptionsConsumer =
- DEFAULT_D8_OPTIONS;
options.partialCompilationConfiguration.r8OptionsConsumer = DEFAULT_R8_OPTIONS;
});
} else {