Begin parsing class files eagerly
Change-Id: Ib34270e86968d1cd9ae66901387d92a094a5b463
diff --git a/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
index 392a4bb..8a89dde 100644
--- a/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.OneShotByteResource;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.io.ByteStreams;
import java.io.Closeable;
@@ -28,6 +29,7 @@
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -95,6 +97,33 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ ZipFile zipFile = ensureZipFile();
+ try {
+ final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ try (InputStream stream = zipFile.getInputStream(entry)) {
+ String name = entry.getName();
+ Origin entryOrigin = new ArchiveEntryOrigin(name, origin);
+ if (ZipUtils.isClassFile(name) && include.test(name)) {
+ String descriptor = DescriptorUtils.guessTypeDescriptor(name);
+ ProgramResource resource =
+ OneShotByteResource.create(
+ Kind.CF,
+ entryOrigin,
+ ByteStreams.toByteArray(stream),
+ Collections.singleton(descriptor));
+ consumer.accept(resource);
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
public void finished(DiagnosticsHandler handler) throws IOException {
close();
}
@@ -136,7 +165,7 @@
try {
reopenZipFile();
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new UncheckedIOException(e);
}
}
return lazyZipFile;
diff --git a/src/main/java/com/android/tools/r8/ArchiveProgramResourceProvider.java b/src/main/java/com/android/tools/r8/ArchiveProgramResourceProvider.java
index 1d98610..e541923 100644
--- a/src/main/java/com/android/tools/r8/ArchiveProgramResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/ArchiveProgramResourceProvider.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.origin.ArchiveEntryOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.ZipUtils;
@@ -22,6 +23,7 @@
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
@@ -138,4 +140,41 @@
throw new ResourceException(origin, e);
}
}
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) throws ResourceException {
+ try {
+ BooleanBox seenCf = new BooleanBox();
+ BooleanBox seenDex = new BooleanBox();
+ readArchive(
+ (entry, stream) -> {
+ String name = entry.getEntryName();
+ if (include.test(name)) {
+ if (ZipUtils.isDexFile(name)) {
+ consumer.accept(
+ ProgramResource.fromBytes(
+ entry, Kind.DEX, ByteStreams.toByteArray(stream), null));
+ seenDex.set();
+ } else if (ZipUtils.isClassFile(name)) {
+ String descriptor = DescriptorUtils.guessTypeDescriptor(name);
+ consumer.accept(
+ ProgramResource.fromBytes(
+ entry,
+ Kind.CF,
+ ByteStreams.toByteArray(stream),
+ Collections.singleton(descriptor)));
+ seenCf.set();
+ }
+ }
+ });
+ if (seenCf.isTrue() && seenDex.isTrue()) {
+ throw new CompilationError(
+ "Cannot create android app from an archive containing both DEX and Java-bytecode "
+ + "content.",
+ origin);
+ }
+ } catch (IOException e) {
+ throw new ResourceException(origin, e);
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ClassFileResourceProvider.java b/src/main/java/com/android/tools/r8/ClassFileResourceProvider.java
index 29b468f..2177c57 100644
--- a/src/main/java/com/android/tools/r8/ClassFileResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/ClassFileResourceProvider.java
@@ -3,9 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
import java.io.IOException;
import java.util.Set;
+import java.util.function.Consumer;
/**
* Program resource provider for program resources of class-file kind.
@@ -36,6 +38,10 @@
*/
ProgramResource getProgramResource(String descriptor);
+ default void getProgramResources(Consumer<ProgramResource> consumer) {
+ throw new Unimplemented();
+ }
+
/**
* Callback signifying that a given compilation unit is done using the resource provider.
*
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 5e116de..464fa02 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -58,6 +58,7 @@
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
/**
* The D8 dex compiler.
@@ -172,7 +173,11 @@
throws IOException {
timing.begin("Application read");
ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
- LazyLoadedDexApplication app = applicationReader.read(executor);
+ boolean readDirect =
+ options.partialSubCompilationConfiguration != null
+ || (options.isGeneratingDex() && !options.mainDexKeepRules.isEmpty());
+ DexApplication app =
+ readDirect ? applicationReader.readDirect(executor) : applicationReader.read(executor);
timing.end();
timing.begin("Load desugared lib");
options.getLibraryDesugaringOptions().loadMachineDesugaredLibrarySpecification(timing, app);
@@ -469,6 +474,11 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ resources.forEach(consumer);
+ }
+
+ @Override
public void finished(DiagnosticsHandler handler) {}
}
}
diff --git a/src/main/java/com/android/tools/r8/FeatureSplitProgramResourceProvider.java b/src/main/java/com/android/tools/r8/FeatureSplitProgramResourceProvider.java
index b8eab10..00482e0 100644
--- a/src/main/java/com/android/tools/r8/FeatureSplitProgramResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/FeatureSplitProgramResourceProvider.java
@@ -8,6 +8,7 @@
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Set;
+import java.util.function.Consumer;
/**
* A wrapper around the ProgramResourceProvider of a feature split, which intentionally returns an
@@ -42,6 +43,24 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) throws ResourceException {
+ assert factory != null;
+ // If the types in this provider has been unset, then the ClassToFeatureSplitMap has already
+ // been created and we no longer need tracking.
+ if (types == null) {
+ programResourceProvider.getProgramResources(consumer);
+ } else {
+ programResourceProvider.getProgramResources(
+ programResource -> {
+ for (String classDescriptor : programResource.getClassDescriptors()) {
+ types.add(factory.createType(classDescriptor));
+ }
+ consumer.accept(programResource);
+ });
+ }
+ }
+
+ @Override
public DataResourceProvider getDataResourceProvider() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index a2d7fef..41bc7e2 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -14,8 +14,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
-import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.shaking.Enqueuer;
@@ -48,8 +48,8 @@
private void run(AndroidApp app, ExecutorService executor, SortingStringConsumer consumer)
throws IOException {
try {
- LazyLoadedDexApplication application =
- new ApplicationReader(app, options, Timing.empty()).read(executor);
+ DirectMappedDexApplication application =
+ new ApplicationReader(app, options, Timing.empty()).readDirect(executor);
traceMainDexForGenerateMainDexList(executor, application)
.forEach(type -> consumer.accept(type.toBinaryName() + ".class", options.reporter));
consumer.finished(options.reporter);
@@ -62,13 +62,13 @@
throws ExecutionException {
return traceMainDex(
AppView.createForD8MainDexTracing(
- appView.app().asLazy().toDirect(), appView.appInfo().getMainDexInfo()),
+ appView.app().asDirect(), appView.appInfo().getMainDexInfo()),
executor);
}
public MainDexInfo traceMainDexForGenerateMainDexList(
- ExecutorService executor, LazyLoadedDexApplication application) throws ExecutionException {
- return traceMainDex(AppView.createForR8(application.toDirect()), executor);
+ ExecutorService executor, DirectMappedDexApplication application) throws ExecutionException {
+ return traceMainDex(AppView.createForR8(application), executor);
}
private MainDexInfo traceMainDex(
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
index cb5ac75..aaf316f 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
@@ -161,7 +161,7 @@
throws IOException {
timing.begin("Application read");
ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
- DirectMappedDexApplication app = applicationReader.read(executor).toDirect();
+ DirectMappedDexApplication app = applicationReader.readDirect(executor);
timing.end();
AppInfo appInfo =
timing.time(
diff --git a/src/main/java/com/android/tools/r8/JdkClassFileProvider.java b/src/main/java/com/android/tools/r8/JdkClassFileProvider.java
index a8b8b1d..22e2a15 100644
--- a/src/main/java/com/android/tools/r8/JdkClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/JdkClassFileProvider.java
@@ -24,6 +24,7 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
/**
* Lazy Java class file resource provider loading class files from a JDK.
@@ -37,7 +38,7 @@
*/
@KeepForApi
public class JdkClassFileProvider implements ClassFileResourceProvider, Closeable {
- private Origin origin;
+ private final Origin origin;
private final Set<String> descriptors = new HashSet<>();
private final Map<String, String> descriptorToModule = new HashMap<>();
private URLClassLoader jrtFsJarLoader;
@@ -162,6 +163,13 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ for (String descriptor : descriptors) {
+ consumer.accept(getProgramResource(descriptor));
+ }
+ }
+
+ @Override
@SuppressWarnings("Finalize")
protected void finalize() throws Throwable {
close();
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 023f3dd..48edf4d 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -496,6 +496,11 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ resources.forEach(consumer);
+ }
+
+ @Override
public void finished(DiagnosticsHandler handler) {}
}
diff --git a/src/main/java/com/android/tools/r8/ProgramResourceProvider.java b/src/main/java/com/android/tools/r8/ProgramResourceProvider.java
index f75e570..9fac5a4 100644
--- a/src/main/java/com/android/tools/r8/ProgramResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/ProgramResourceProvider.java
@@ -3,9 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
import java.io.IOException;
import java.util.Collection;
+import java.util.function.Consumer;
/** Program resource provider. */
@KeepForApi
@@ -13,6 +15,10 @@
Collection<ProgramResource> getProgramResources() throws ResourceException;
+ default void getProgramResources(Consumer<ProgramResource> consumer) throws ResourceException {
+ throw new Unimplemented();
+ }
+
default DataResourceProvider getDataResourceProvider() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index fd20ec5..8089d42 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -31,7 +31,6 @@
import com.android.tools.r8.graph.GenericSignatureContextBuilder;
import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper;
import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
-import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
@@ -291,12 +290,11 @@
{
timing.begin("Read app");
ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
- LazyLoadedDexApplication lazyLoaded = applicationReader.read(executorService);
+ DirectMappedDexApplication application = applicationReader.readDirect(executorService);
keepDeclarations =
options.partialSubCompilationConfiguration != null
? options.partialSubCompilationConfiguration.asR8().getAndClearKeepDeclarations()
- : lazyLoaded.getKeepDeclarations();
- DirectMappedDexApplication application = lazyLoaded.toDirect(timing);
+ : application.getKeepDeclarations();
timing.end();
options
.getLibraryDesugaringOptions()
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 7eb7c38..f640e5c 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -48,6 +48,7 @@
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ArchiveResourceProvider;
import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.DumpInputFlags;
import com.android.tools.r8.utils.EmbeddedRulesExtractor;
import com.android.tools.r8.utils.ExceptionDiagnostic;
@@ -1098,7 +1099,7 @@
}
// Wrapper class to ensure that R8 does not allow DEX as program inputs.
- private static class EnsureNonDexProgramResourceProvider implements ProgramResourceProvider {
+ public static class EnsureNonDexProgramResourceProvider implements ProgramResourceProvider {
final ProgramResourceProvider provider;
@@ -1107,12 +1108,30 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) throws ResourceException {
+ Box<ProgramResource> dexResource = new Box<>();
+ provider.getProgramResources(
+ resource -> {
+ if (resource.getKind() == Kind.CF) {
+ consumer.accept(resource);
+ } else {
+ assert resource.getKind() == Kind.DEX;
+ dexResource.set(resource);
+ }
+ });
+ if (dexResource.isSet()) {
+ throw new ResourceException(
+ dexResource.get().getOrigin(), "R8 does not support compiling DEX inputs");
+ }
+ }
+
+ @Override
public Collection<ProgramResource> getProgramResources() throws ResourceException {
Collection<ProgramResource> resources = provider.getProgramResources();
for (ProgramResource resource : resources) {
if (resource.getKind() == Kind.DEX) {
- throw new ResourceException(resource.getOrigin(),
- "R8 does not support compiling DEX inputs");
+ throw new ResourceException(
+ resource.getOrigin(), "R8 does not support compiling DEX inputs");
}
}
return resources;
@@ -1122,6 +1141,15 @@
public DataResourceProvider getDataResourceProvider() {
return provider.getDataResourceProvider();
}
+
+ public static ProgramResourceProvider unwrap(ProgramResourceProvider provider) {
+ if (provider instanceof EnsureNonDexProgramResourceProvider) {
+ EnsureNonDexProgramResourceProvider wrapper =
+ (EnsureNonDexProgramResourceProvider) provider;
+ return wrapper.provider;
+ }
+ return provider;
+ }
}
static String getUsageMessage() {
diff --git a/src/main/java/com/android/tools/r8/R8Partial.java b/src/main/java/com/android/tools/r8/R8Partial.java
index fec7386..535a1d5 100644
--- a/src/main/java/com/android/tools/r8/R8Partial.java
+++ b/src/main/java/com/android/tools/r8/R8Partial.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.features.FeatureSplitConfiguration;
import com.android.tools.r8.graph.DexClasspathClass;
import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.keepanno.ast.KeepDeclaration;
import com.android.tools.r8.metadata.impl.R8PartialCompilationStatsMetadataBuilder;
import com.android.tools.r8.partial.R8PartialD8Input;
@@ -36,6 +35,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
class R8Partial {
@@ -93,10 +93,9 @@
private R8PartialD8Input runProcessInputStep(AndroidApp androidApp, ExecutorService executor)
throws IOException {
- LazyLoadedDexApplication lazyApp =
- new ApplicationReader(androidApp, options, timing).read(executor);
- List<KeepDeclaration> keepDeclarations = lazyApp.getKeepDeclarations();
- DirectMappedDexApplication app = lazyApp.toDirect();
+ DirectMappedDexApplication app =
+ new ApplicationReader(androidApp, options, timing).readDirect(executor);
+ List<KeepDeclaration> keepDeclarations = app.getKeepDeclarations();
R8PartialProgramPartitioning partitioning = R8PartialProgramPartitioning.create(app);
partitioning.printForTesting(options);
options.getLibraryDesugaringOptions().loadMachineDesugaredLibrarySpecification(timing, app);
@@ -210,6 +209,11 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ // Intentionally empty.
+ }
+
+ @Override
public DataResourceProvider getDataResourceProvider() {
return programResourceProvider.getDataResourceProvider();
}
@@ -307,6 +311,11 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ throw new Unreachable();
+ }
+
+ @Override
public DataResourceProvider getDataResourceProvider() {
return programResourceProvider.getDataResourceProvider();
}
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index f361d81..d9e3a01 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -9,11 +9,9 @@
import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException;
import com.android.tools.r8.ClassFileResourceProvider;
-import com.android.tools.r8.DataResourceProvider;
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.ProgramResource;
-import com.android.tools.r8.ProgramResource.Kind;
-import com.android.tools.r8.ProgramResourceProvider;
+import com.android.tools.r8.R8Command.EnsureNonDexProgramResourceProvider;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.dump.DumpOptions;
@@ -30,9 +28,12 @@
import com.android.tools.r8.graph.DexLibraryClass;
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.JarApplicationReader;
import com.android.tools.r8.graph.JarClassFileReader;
import com.android.tools.r8.graph.LazyLoadedDexApplication;
+import com.android.tools.r8.graph.LazyLoadedDexApplication.AllClasses;
+import com.android.tools.r8.keepanno.ast.KeepDeclaration;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.MainDexInfo;
@@ -46,19 +47,21 @@
import com.android.tools.r8.utils.DumpInputFlags;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.LibraryClassCollection;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.MainDexListParser;
+import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.timing.Timing;
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
public class ApplicationReader {
@@ -123,7 +126,7 @@
}
timing.begin("DexApplication.read");
- final LazyLoadedDexApplication.Builder builder = DexApplication.builder(options, timing);
+ LazyLoadedDexApplication.Builder builder = DexApplication.builder(options, timing);
TaskCollection<?> tasks = new TaskCollection<>(options, executorService);
try {
// Still preload some of the classes, primarily for two reasons:
@@ -135,17 +138,16 @@
// TODO: try and preload less classes.
readProguardMap(proguardMap, builder, tasks);
ClassReader classReader = new ClassReader(tasks);
- classReader.readSources();
- tasks.await();
- flags = classReader.getDexApplicationReadFlags();
- builder.setFlags(flags);
classReader.initializeLazyClassCollection(builder);
- for (ProgramResourceProvider provider : inputApp.getProgramResourceProviders()) {
- DataResourceProvider dataResourceProvider = provider.getDataResourceProvider();
- if (dataResourceProvider != null) {
- builder.addDataResourceProvider(dataResourceProvider);
- }
- }
+ classReader.readSources();
+ timing.time("Await read", () -> tasks.await());
+ flags = classReader.getDexApplicationReadFlags();
+ return builder
+ .addDataResourceProviders(inputApp.getProgramResourceProviders())
+ .addProgramClasses(classReader.programClasses)
+ .setFlags(flags)
+ .setKeepDeclarations(classReader.getKeepDeclarations())
+ .build();
} catch (ExecutionException e) {
throw unwrapExecutionException(e);
} catch (ResourceException e) {
@@ -153,7 +155,58 @@
} finally {
timing.end();
}
- return builder.build();
+ }
+
+ @Deprecated
+ public DirectMappedDexApplication readDirectSingleThreaded() throws IOException {
+ ExecutorService executor = options.getThreadingModule().createSingleThreadedExecutorService();
+ try {
+ return readDirect(executor);
+ } finally {
+ executor.shutdown();
+ }
+ }
+
+ public DirectMappedDexApplication readDirect(ExecutorService executorService) throws IOException {
+ assert verifyMainDexOptionsCompatible(inputApp, options);
+ dumpApplication(options.getDumpInputFlags());
+
+ if (options.testing.verifyInputs) {
+ inputApp.validateInputs();
+ }
+
+ timing.begin("DexApplication.readDirect");
+ DirectMappedDexApplication.Builder builder =
+ DirectMappedDexApplication.directBuilder(options, timing);
+ TaskCollection<?> tasks = new TaskCollection<>(options, executorService);
+ try {
+ readProguardMap(inputApp.getProguardMapInputData(), builder, tasks);
+ ClassReader classReader = new ClassReader(tasks);
+ AllClasses.Builder allClassesBuilder = AllClasses.builder();
+ classReader.acceptClasspathAndLibraryClassCollections(
+ allClassesBuilder::setClasspathClasses, allClassesBuilder::setLibraryClasses);
+ allClassesBuilder.forceLoadNonProgramClassCollections(options, tasks, timing);
+ classReader.readSources();
+ timing.time("Await read", () -> tasks.await());
+ allClassesBuilder.setProgramClasses(
+ ProgramClassCollection.resolveConflicts(classReader.programClasses, options));
+ AllClasses allClasses = allClassesBuilder.build(options, timing);
+ flags = classReader.getDexApplicationReadFlags();
+ return builder
+ .addDataResourceProviders(inputApp.getProgramResourceProviders())
+ .addProgramClasses(allClasses.getProgramClasses())
+ .replaceClasspathClasses(allClasses.getClasspathClasses())
+ .replaceLibraryClasses(allClasses.getLibraryClasses())
+ .setFlags(flags)
+ .setKeepDeclarations(classReader.getKeepDeclarations())
+ .build();
+ } catch (ExecutionException e) {
+ throw unwrapExecutionException(e);
+ } catch (ResourceException e) {
+ throw options.reporter.fatalError(new StringDiagnostic(e.getMessage(), e.getOrigin()));
+ } finally {
+ timing.end();
+ }
}
public final void dump(DumpInputFlags dumpInputFlags) {
@@ -293,11 +346,8 @@
private final class ClassReader {
private final TaskCollection<?> tasks;
- // We use concurrent queues to collect classes
- // since the classes can be collected concurrently.
+ // We use concurrent queues to collect classes since the classes can be collected concurrently.
private final Queue<DexProgramClass> programClasses = new ConcurrentLinkedQueue<>();
- private final Queue<DexClasspathClass> classpathClasses = new ConcurrentLinkedQueue<>();
- private final Queue<DexLibraryClass> libraryClasses = new ConcurrentLinkedQueue<>();
// Jar application reader to share across all class readers.
private final DexApplicationReadFlags.Builder readFlagsBuilder =
DexApplicationReadFlags.builder();
@@ -325,12 +375,15 @@
.build();
}
- private void readDexSources(List<ProgramResource> dexSources, Queue<DexProgramClass> classes)
+ public List<KeepDeclaration> getKeepDeclarations() {
+ return application.getKeepDeclarations();
+ }
+
+ private void readDexSources(List<ProgramResource> dexSources)
throws IOException, ResourceException, ExecutionException {
if (dexSources.isEmpty()) {
return;
}
- hasReadProgramResourceFromDex = true;
List<DexParser<DexProgramClass>> dexParsers = new ArrayList<>(dexSources.size());
List<DexParser<DexProgramClass>> dexContainerParsers = new ArrayList<>(4);
AndroidApiLevel computedMinApiLevel = options.getMinApiLevel();
@@ -360,16 +413,13 @@
ApplicationReaderMap applicationReaderMap = ApplicationReaderMap.getInstance(options);
// Read the DexCode items and DexProgramClass items in parallel.
for (DexParser<DexProgramClass> dexParser : dexParsers) {
- tasks.submit(
- () -> {
- dexParser.addClassDefsTo(
- classes::add, applicationReaderMap); // Depends on Methods, Code items etc.
- });
+ // Depends on Methods, Code items etc.
+ tasks.submit(() -> dexParser.addClassDefsTo(programClasses, applicationReaderMap));
}
// All DEX parsers for container sections use the same DEX reader,
// so don't process in parallel.
for (DexParser<DexProgramClass> dexParser : dexContainerParsers) {
- dexParser.addClassDefsTo(classes::add, applicationReaderMap);
+ dexParser.addClassDefsTo(programClasses, applicationReaderMap);
}
}
}
@@ -394,94 +444,80 @@
return retentionAnnotation.annotation.toString().contains("RUNTIME");
}
- private void readClassSources(
- List<ProgramResource> classSources, Queue<DexProgramClass> classes)
- throws ExecutionException {
- if (classSources.isEmpty()) {
- return;
- }
- hasReadProgramResourceFromCf = true;
- JarClassFileReader<DexProgramClass> reader =
+ void readSources() throws IOException, ResourceException, ExecutionException {
+ timing.begin("Compute all program resources");
+ List<ProgramResource> dexResources = new ArrayList<>();
+ JarClassFileReader<DexProgramClass> cfReader =
new JarClassFileReader<>(
application,
clazz -> {
if (clazz.isAnnotation() && !includeAnnotationClass(clazz)) {
return;
}
- classes.add(clazz);
+ programClasses.add(clazz);
},
PROGRAM);
- // Read classes in parallel.
- for (ProgramResource input : classSources) {
- tasks.submit(() -> reader.read(input));
- }
- }
-
- void readSources() throws IOException, ResourceException, ExecutionException {
- Collection<ProgramResource> resources =
- inputApp.computeAllProgramResources(
- internalProvider -> programClasses.addAll(internalProvider.getClasses()));
- List<ProgramResource> dexResources = new ArrayList<>(resources.size());
- List<ProgramResource> cfResources = new ArrayList<>(resources.size());
- for (ProgramResource resource : resources) {
- if (resource.getKind() == Kind.DEX) {
- dexResources.add(resource);
- } else {
- assert resource.getKind() == Kind.CF;
- cfResources.add(resource);
- }
- }
- readDexSources(dexResources, programClasses);
- readClassSources(cfResources, programClasses);
+ inputApp.computeAllProgramResources(
+ resource -> {
+ if (resource.getKind() == ProgramResource.Kind.CF) {
+ hasReadProgramResourceFromCf = true;
+ tasks.submitUnchecked(
+ () -> {
+ Timing threadTiming =
+ timing.createThreadTiming("Read program resource", options);
+ cfReader.read(resource);
+ threadTiming.end().notifyThreadTimingFinished();
+ });
+ } else {
+ assert resource.getKind() == ProgramResource.Kind.DEX;
+ dexResources.add(resource);
+ }
+ },
+ internalProvider -> programClasses.addAll(internalProvider.getClasses()),
+ legacyProgramResourceProvider ->
+ options.reporter.warning(
+ "Program resource provider does not support async parsing: "
+ + EnsureNonDexProgramResourceProvider.unwrap(legacyProgramResourceProvider)
+ .getClass()
+ .getTypeName()),
+ timing);
+ hasReadProgramResourceFromDex = !dexResources.isEmpty();
+ timing.end();
+ readDexSources(dexResources);
}
private <T extends DexClass> ClassProvider<T> buildClassProvider(
- ClassKind<T> classKind,
- Queue<T> preloadedClasses,
- List<ClassFileResourceProvider> resourceProviders,
- JarApplicationReader reader) {
- List<ClassProvider<T>> providers = new ArrayList<>();
-
- // Preloaded classes.
- if (!preloadedClasses.isEmpty()) {
- providers.add(ClassProvider.forPreloadedClasses(classKind, preloadedClasses));
- }
-
- // Class file resource providers.
- for (ClassFileResourceProvider provider : resourceProviders) {
- providers.add(ClassProvider.forClassFileResources(classKind, provider, reader));
- }
-
- // Combine if needed.
- if (providers.isEmpty()) {
- return null;
- }
- return providers.size() == 1 ? providers.get(0)
- : ClassProvider.combine(classKind, providers);
+ ClassKind<T> classKind, List<ClassFileResourceProvider> resourceProviders) {
+ return ClassProvider.combine(
+ classKind,
+ ListUtils.map(
+ resourceProviders,
+ resourceProvider ->
+ ClassProvider.forClassFileResources(classKind, resourceProvider, application)));
}
- void initializeLazyClassCollection(LazyLoadedDexApplication.Builder builder) {
- // Add all program classes to the builder.
- for (DexProgramClass clazz : programClasses) {
- builder.addProgramClass(clazz.asProgramClass());
- }
-
+ void acceptClasspathAndLibraryClassCollections(
+ Consumer<ClasspathClassCollection> classpathClassCollectionConsumer,
+ Consumer<LibraryClassCollection> libraryClassCollectionConsumer) {
// Create classpath class collection if needed.
- ClassProvider<DexClasspathClass> classpathClassProvider = buildClassProvider(CLASSPATH,
- classpathClasses, inputApp.getClasspathResourceProviders(), application);
+ ClassProvider<DexClasspathClass> classpathClassProvider =
+ buildClassProvider(CLASSPATH, inputApp.getClasspathResourceProviders());
if (classpathClassProvider != null) {
- builder.setClasspathClassCollection(new ClasspathClassCollection(classpathClassProvider));
+ classpathClassCollectionConsumer.accept(
+ new ClasspathClassCollection(classpathClassProvider));
}
// Create library class collection if needed.
- ClassProvider<DexLibraryClass> libraryClassProvider = buildClassProvider(LIBRARY,
- libraryClasses, inputApp.getLibraryResourceProviders(), application);
+ ClassProvider<DexLibraryClass> libraryClassProvider =
+ buildClassProvider(LIBRARY, inputApp.getLibraryResourceProviders());
if (libraryClassProvider != null) {
- builder.setLibraryClassCollection(new LibraryClassCollection(libraryClassProvider));
+ libraryClassCollectionConsumer.accept(new LibraryClassCollection(libraryClassProvider));
}
+ }
- // Transfer the keep declarations found during reading.
- builder.setKeepDeclarations(application.getKeepDeclarations());
+ void initializeLazyClassCollection(LazyLoadedDexApplication.Builder builder) {
+ acceptClasspathAndLibraryClassCollections(
+ builder::setClasspathClassCollection, builder::setLibraryClassCollection);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index fcb52ce..6405725 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -91,9 +91,9 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -848,7 +848,7 @@
return methods;
}
- void addClassDefsTo(Consumer<T> classCollection, ApplicationReaderMap applicationReaderMap) {
+ void addClassDefsTo(Collection<T> classCollection, ApplicationReaderMap applicationReaderMap) {
final DexSection dexSection = lookupSection(Constants.TYPE_CLASS_DEF_ITEM);
final int length = dexSection.length;
indexedItems.initializeClasses(length);
@@ -969,7 +969,7 @@
// Interpreting reachability sensitivity from DEX inputs is not supported.
// The compiler does not support building IR from DEX with debug information.
ReachabilitySensitiveValue.DISABLED);
- classCollection.accept(clazz); // Update the application object.
+ classCollection.add(clazz); // Update the application object.
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index a8665ac..5a4d355 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -280,12 +280,13 @@
timing);
}
- public static AppView<AppInfoWithClassHierarchy> createForR8(DexApplication application) {
+ public static AppView<AppInfoWithClassHierarchy> createForR8(
+ DirectMappedDexApplication application) {
return createForR8(application, MainDexInfo.none());
}
public static AppView<AppInfoWithClassHierarchy> createForR8(
- DexApplication application, MainDexInfo mainDexInfo) {
+ DirectMappedDexApplication application, MainDexInfo mainDexInfo) {
ClassToFeatureSplitMap classToFeatureSplitMap =
ClassToFeatureSplitMap.createInitialR8ClassToFeatureSplitMap(application.options);
AppInfoWithClassHierarchy appInfo =
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 38264ec..f4aa5d0 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -69,8 +69,7 @@
this.writeCode = writeCode;
if (writeIR) {
this.appInfo =
- AppInfo.createInitialAppInfo(
- application.toDirect(), GlobalSyntheticsStrategy.forNonSynthesizing());
+ AppInfo.createInitialAppInfo(application, GlobalSyntheticsStrategy.forNonSynthesizing());
if (options.programConsumer == null) {
// Use class-file backend, since the CF frontend for testing does not support desugaring of
// synchronized methods for the DEX backend (b/109789541).
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index a74e532..de7d2a2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -7,6 +7,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.DataResourceProvider;
+import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.timing.Timing;
@@ -179,8 +180,9 @@
return null;
}
- public void setFlags(DexApplicationReadFlags flags) {
+ public T setFlags(DexApplicationReadFlags flags) {
this.flags = flags;
+ return self();
}
public synchronized T setProguardMap(ClassNameMapper proguardMap) {
@@ -219,8 +221,13 @@
return self();
}
- public synchronized T addDataResourceProvider(DataResourceProvider provider) {
- dataResourceProviders.add(provider);
+ public synchronized T addDataResourceProviders(List<ProgramResourceProvider> providers) {
+ for (ProgramResourceProvider provider : providers) {
+ DataResourceProvider dataResourceProvider = provider.getDataResourceProvider();
+ if (dataResourceProvider != null) {
+ dataResourceProviders.add(dataResourceProvider);
+ }
+ }
return self();
}
@@ -242,11 +249,7 @@
return programClasses;
}
- public final S build() {
- return build(Timing.empty());
- }
-
- public abstract S build(Timing timing);
+ public abstract S build();
}
public static LazyLoadedDexApplication.Builder builder(InternalOptions options, Timing timing) {
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index 702bd04..30c2029 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.DataResourceProvider;
import com.android.tools.r8.graph.LazyLoadedDexApplication.AllClasses;
import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.keepanno.ast.KeepDeclaration;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.timing.Timing;
@@ -20,6 +21,7 @@
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -32,6 +34,7 @@
// Mapping from code objects to their encoded-method owner. Used for asserting unique ownership
// and debugging purposes.
private final Map<Code, DexEncodedMethod> codeOwners = new IdentityHashMap<>();
+ private List<KeepDeclaration> keepDeclarations;
// Unmodifiable mapping of all types to their definitions.
private final ImmutableMap<DexType, ProgramOrClasspathClass> programOrClasspathClasses;
@@ -49,6 +52,7 @@
ImmutableCollection<DexProgramClass> programClasses,
ImmutableCollection<DexClasspathClass> classpathClasses,
ImmutableList<DataResourceProvider> dataResourceProviders,
+ List<KeepDeclaration> keepDeclarations,
InternalOptions options,
Timing timing) {
super(proguardMap, flags, dataResourceProviders, options, timing);
@@ -56,6 +60,11 @@
this.libraryClasses = libraryClasses;
this.programClasses = programClasses;
this.classpathClasses = classpathClasses;
+ this.keepDeclarations = keepDeclarations;
+ }
+
+ public static Builder directBuilder(InternalOptions options, Timing timing) {
+ return new Builder(options, timing);
}
public Collection<DexClasspathClass> classpathClasses() {
@@ -77,6 +86,10 @@
libraryClasses.forEach((type, clazz) -> consumer.accept(type));
}
+ public List<KeepDeclaration> getKeepDeclarations() {
+ return keepDeclarations;
+ }
+
public Collection<DexLibraryClass> libraryClasses() {
return libraryClasses.values();
}
@@ -210,15 +223,16 @@
private ImmutableCollection<DexClasspathClass> classpathClasses;
private Map<DexType, DexLibraryClass> libraryClasses;
+ private List<KeepDeclaration> keepDeclarations = Collections.emptyList();
private final List<DexClasspathClass> pendingClasspathClasses = new ArrayList<>();
private final Set<DexType> pendingClasspathRemovalIfPresent = Sets.newIdentityHashSet();
Builder(LazyLoadedDexApplication application, AllClasses allClasses) {
super(application);
- classpathClasses = allClasses.getClasspathClasses().values();
+ classpathClasses = ImmutableList.copyOf(allClasses.getClasspathClasses());
libraryClasses = allClasses.getLibraryClasses();
- replaceProgramClasses(allClasses.getProgramClasses().values());
+ replaceProgramClasses(allClasses.getProgramClasses());
}
private Builder(DirectMappedDexApplication application) {
@@ -227,6 +241,10 @@
libraryClasses = application.libraryClasses;
}
+ private Builder(InternalOptions options, Timing timing) {
+ super(options, timing);
+ }
+
@Override
public boolean isDirect() {
return true;
@@ -312,13 +330,22 @@
public Builder replaceLibraryClasses(Collection<DexLibraryClass> libraryClasses) {
ImmutableMap.Builder<DexType, DexLibraryClass> builder = ImmutableMap.builder();
- libraryClasses.forEach(clazz -> builder.put(clazz.type, clazz));
- this.libraryClasses = builder.build();
+ libraryClasses.forEach(clazz -> builder.put(clazz.getType(), clazz));
+ return replaceLibraryClasses(builder.build());
+ }
+
+ public Builder replaceLibraryClasses(Map<DexType, DexLibraryClass> libraryClasses) {
+ this.libraryClasses = libraryClasses;
return self();
}
+ public Builder setKeepDeclarations(List<KeepDeclaration> declarations) {
+ this.keepDeclarations = declarations;
+ return this;
+ }
+
@Override
- public DirectMappedDexApplication build(Timing timing) {
+ public DirectMappedDexApplication build() {
try (Timing t0 = timing.begin("Build")) {
// Rebuild the map. This will fail if keys are not unique.
// TODO(zerny): Consider not rebuilding the map if no program classes are added.
@@ -348,6 +375,7 @@
ImmutableList.copyOf(getProgramClasses()),
newClasspathClasses,
ImmutableList.copyOf(dataResourceProviders),
+ keepDeclarations,
options,
timing);
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index 447178a..ffb88ba 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -6,10 +6,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException;
+import static com.google.common.base.Predicates.alwaysTrue;
+
import com.android.tools.r8.DataResourceProvider;
-import com.android.tools.r8.dex.ApplicationReader.ProgramClassConflictResolver;
+import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.keepanno.ast.KeepDeclaration;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.threading.TaskCollection;
import com.android.tools.r8.utils.ClasspathClassCollection;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.LibraryClassCollection;
@@ -18,12 +22,16 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -63,7 +71,8 @@
@Override
List<DexProgramClass> programClasses() {
- return programClasses.forceLoad().getAllClasses();
+ assert programClasses.isFullyLoaded();
+ return programClasses.getAllClasses();
}
@Override
@@ -141,11 +150,11 @@
return programClasses.get(type);
}
- static class AllClasses {
+ public static class AllClasses {
// Mapping of all types to their definitions.
// Collections of the three different types for iteration.
- private final ImmutableMap<DexType, DexProgramClass> programClasses;
+ private final Map<DexType, DexProgramClass> programClasses;
private final ImmutableMap<DexType, DexClasspathClass> classpathClasses;
private final ImmutableMap<DexType, DexLibraryClass> libraryClasses;
@@ -153,44 +162,28 @@
LibraryClassCollection libraryClassesLoader,
ClasspathClassCollection classpathClassesLoader,
Map<DexType, DexClasspathClass> synthesizedClasspathClasses,
- ProgramClassCollection programClassesLoader,
+ Map<DexType, DexProgramClass> allProgramClasses,
InternalOptions options,
Timing timing) {
- // When desugaring VarHandle do not read the VarHandle and MethodHandles$Lookup classes
- // from the library as they will be synthesized during desugaring.
- DexItemFactory factory = options.dexItemFactory();
- Predicate<DexType> forceLoadPredicate =
- type ->
- !(options.shouldDesugarVarHandle()
- && (type.isIdenticalTo(factory.varHandleType)
- || type.isIdenticalTo(factory.lookupType)));
-
// Force-load library classes.
ImmutableMap<DexType, DexLibraryClass> allLibraryClasses;
try (Timing t0 = timing.begin("Force-load library classes")) {
if (libraryClassesLoader != null) {
- libraryClassesLoader.forceLoad(forceLoadPredicate);
+ assert libraryClassesLoader.isFullyLoaded();
allLibraryClasses = libraryClassesLoader.getAllClassesInMap();
} else {
allLibraryClasses = ImmutableMap.of();
}
}
- // Program classes should be fully loaded.
- ImmutableMap<DexType, DexProgramClass> allProgramClasses;
- try (Timing t0 = timing.begin("Force-load program classes")) {
- assert programClassesLoader != null;
- assert programClassesLoader.isFullyLoaded();
- allProgramClasses = programClassesLoader.forceLoad().getAllClassesInMap();
- }
-
// Force-load classpath classes.
ImmutableMap<DexType, DexClasspathClass> allClasspathClasses;
try (Timing t0 = timing.begin("Force-load classpath classes")) {
ImmutableMap.Builder<DexType, DexClasspathClass> allClasspathClassesBuilder =
ImmutableMap.builder();
if (classpathClassesLoader != null) {
- classpathClassesLoader.forceLoad().forEach(allClasspathClassesBuilder::put);
+ assert classpathClassesLoader.isFullyLoaded();
+ classpathClassesLoader.forEach(allClasspathClassesBuilder::put);
}
if (synthesizedClasspathClasses != null) {
allClasspathClassesBuilder.putAll(synthesizedClasspathClasses);
@@ -228,17 +221,94 @@
}
}
- public ImmutableMap<DexType, DexProgramClass> getProgramClasses() {
- return programClasses;
+ public static Builder builder() {
+ return new Builder();
}
- public ImmutableMap<DexType, DexClasspathClass> getClasspathClasses() {
- return classpathClasses;
+ public Collection<DexProgramClass> getProgramClasses() {
+ return programClasses.values();
+ }
+
+ public Collection<DexClasspathClass> getClasspathClasses() {
+ return classpathClasses.values();
}
public ImmutableMap<DexType, DexLibraryClass> getLibraryClasses() {
return libraryClasses;
}
+
+ public static class Builder {
+
+ private LibraryClassCollection libraryClasses;
+ private ClasspathClassCollection classpathClasses;
+ private Map<DexType, DexClasspathClass> synthesizedClasspathClasses;
+ private Map<DexType, DexProgramClass> programClasses;
+
+ private Builder() {}
+
+ public Builder setClasspathClasses(ClasspathClassCollection classpathClasses) {
+ this.classpathClasses = classpathClasses;
+ return this;
+ }
+
+ public Builder setLibraryClasses(LibraryClassCollection libraryClasses) {
+ this.libraryClasses = libraryClasses;
+ return this;
+ }
+
+ public Builder setProgramClasses(Map<DexType, DexProgramClass> programClasses) {
+ this.programClasses = programClasses;
+ return this;
+ }
+
+ public Builder setSynthesizedClasspathClasses(
+ Map<DexType, DexClasspathClass> synthesizedClasspathClasses) {
+ this.synthesizedClasspathClasses = synthesizedClasspathClasses;
+ return this;
+ }
+
+ public Builder forceLoadNonProgramClassCollections(
+ InternalOptions options, TaskCollection<?> tasks, Timing timing) {
+ // When desugaring VarHandle do not read the VarHandle and MethodHandles$Lookup classes
+ // from the library as they will be synthesized during desugaring.
+ Predicate<ProgramResource> forceLoadPredicate =
+ programResource -> {
+ if (!options.shouldDesugarVarHandle()) {
+ return true;
+ }
+ Set<String> descriptors = programResource.getClassDescriptors();
+ if (descriptors.size() != 1) {
+ return true;
+ }
+ String descriptor = descriptors.iterator().next();
+ return !descriptor.equals(DexItemFactory.varHandleDescriptorString)
+ && !descriptor.equals(DexItemFactory.methodHandlesLookupDescriptorString);
+ };
+ if (classpathClasses != null) {
+ classpathClasses.forceLoad(options, tasks, timing, alwaysTrue());
+ }
+ if (libraryClasses != null) {
+ libraryClasses.forceLoad(options, tasks, timing, forceLoadPredicate);
+ }
+ return this;
+ }
+
+ public AllClasses build(InternalOptions options, Timing timing) {
+ if (classpathClasses != null) {
+ classpathClasses.setFullyLoaded();
+ }
+ if (libraryClasses != null) {
+ libraryClasses.setFullyLoaded();
+ }
+ return new AllClasses(
+ libraryClasses,
+ classpathClasses,
+ synthesizedClasspathClasses,
+ programClasses,
+ options,
+ timing);
+ }
+ }
}
private static <T extends DexClass> ImmutableMap<DexType, T> fillPrioritizedClasses(
@@ -286,14 +356,18 @@
}
/** Force load all classes and return type -> class map containing all the classes. */
- public AllClasses loadAllClasses(Timing timing) {
- return new AllClasses(
- libraryClasses,
- classpathClasses,
- synthesizedClasspathClasses,
- programClasses,
- options,
- timing);
+ public AllClasses loadAllClasses(ExecutorService executorService, Timing timing)
+ throws ExecutionException {
+ TaskCollection<?> tasks = new TaskCollection<>(options, executorService);
+ AllClasses.Builder allClassesBuilder =
+ AllClasses.builder()
+ .setClasspathClasses(classpathClasses)
+ .setLibraryClasses(libraryClasses)
+ .setProgramClasses(programClasses.getAllClassesInMap())
+ .setSynthesizedClasspathClasses(synthesizedClasspathClasses)
+ .forceLoadNonProgramClassCollections(options, tasks, timing);
+ tasks.await();
+ return allClassesBuilder.build(options, timing);
}
public static class Builder extends DexApplication.Builder<LazyLoadedDexApplication, Builder> {
@@ -356,15 +430,11 @@
}
@Override
- public LazyLoadedDexApplication build(Timing timing) {
- ProgramClassConflictResolver resolver =
- options.programClassConflictResolver == null
- ? ProgramClassCollection.defaultConflictResolver(options.reporter)
- : options.programClassConflictResolver;
+ public LazyLoadedDexApplication build() {
return new LazyLoadedDexApplication(
proguardMap,
flags,
- ProgramClassCollection.create(getProgramClasses(), resolver),
+ ProgramClassCollection.create(getProgramClasses(), options),
ImmutableList.copyOf(dataResourceProviders),
classpathClasses,
synthesizedClasspathClasses,
@@ -385,17 +455,22 @@
return this;
}
- public DirectMappedDexApplication toDirect() {
- return toDirect(Timing.empty());
+ @Deprecated
+ public DirectMappedDexApplication toDirectSingleThreadedForTesting() {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ return toDirectForTesting(executor);
}
- public DirectMappedDexApplication toDirect(Timing timing) {
+ @Deprecated
+ private DirectMappedDexApplication toDirectForTesting(ExecutorService executorService) {
try (Timing t0 = timing.begin("To direct app")) {
// As a side-effect, this will force-load all classes.
- AllClasses allClasses = loadAllClasses(timing);
+ AllClasses allClasses = loadAllClasses(executorService, timing);
DirectMappedDexApplication.Builder builder =
new DirectMappedDexApplication.Builder(this, allClasses);
- return builder.build(timing);
+ return builder.build();
+ } catch (ExecutionException e) {
+ throw unwrapExecutionException(e);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
index bc3be29..1f79756 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
@@ -312,7 +311,7 @@
}
AndroidApp implementation = appBuilder.build();
DirectMappedDexApplication implementationApplication =
- new ApplicationReader(implementation, options, Timing.empty()).read().toDirect();
+ new ApplicationReader(implementation, options, Timing.empty()).readDirectSingleThreaded();
List<DexMethod> backports = new ArrayList<>();
List<DexField> backportFields = new ArrayList<>();
@@ -504,7 +503,7 @@
ExecutorService executorService = ThreadUtils.getExecutorService(options);
assert !options.ignoreJavaLibraryOverride;
options.ignoreJavaLibraryOverride = true;
- LazyLoadedDexApplication appForMax = applicationReader.read(executorService);
+ DirectMappedDexApplication appForMax = applicationReader.readDirect(executorService);
options.ignoreJavaLibraryOverride = false;
DexClass varHandle =
appForMax.definitionFor(
@@ -514,7 +513,7 @@
"SupportedClassesGenerator expects library above or equal to T, it works below, but the"
+ " modifiers are not correct which is fine for lint but not html doc generation.");
}
- return appForMax.toDirect();
+ return appForMax;
}
private Set<DexMethod> getParallelMethods() {
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 9deb733..1fae401 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialApplicationWriter.java
@@ -54,7 +54,7 @@
// during writing, which we bypass. The D8 lenses may arise from synthetic finalization and
// horizontal class merging of synthetics.
rewriteCodeWithLens(executorService);
- subCompilationConfiguration.writeApplication(appView);
+ subCompilationConfiguration.writeApplication(appView, executorService);
}
private void rewriteCodeWithLens(ExecutorService executorService) throws ExecutionException {
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 61362ac..b776d08 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
@@ -39,6 +39,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
public abstract class R8PartialSubCompilationConfiguration {
@@ -171,7 +172,7 @@
return this;
}
- public void writeApplication(AppView<AppInfo> appView) {
+ public void writeApplication(AppView<AppInfo> appView, ExecutorService executorService) {
artProfiles = appView.getArtProfileCollection().transformForR8Partial(appView);
classToFeatureSplitMap =
appView.appInfo().getClassToFeatureSplitMap().commitSyntheticsForR8Partial(appView);
@@ -184,7 +185,7 @@
desugaredOutputClasses.add(clazz);
}
}
- DirectMappedDexApplication app = appView.app().asLazy().toDirect();
+ DirectMappedDexApplication app = appView.app().asDirect();
outputClasspathClasses = app.classpathClasses();
outputLibraryClasses = app.libraryClasses();
startupProfile = appView.getStartupProfile();
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
index 764240d..9d0ef51 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
@@ -83,7 +83,8 @@
AppView<AppInfoWithClassHierarchy> appView =
AppView.createForTracer(
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
- new ApplicationReader(builder.build(), options, Timing.empty()).read().toDirect(),
+ new ApplicationReader(builder.build(), options, Timing.empty())
+ .readDirectSingleThreaded(),
ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
MainDexInfo.none(),
GlobalSyntheticsStrategy.forSingleOutputMode()));
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesBridge.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesBridge.java
deleted file mode 100644
index 5c0b302..0000000
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesBridge.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2024, 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.tracereferences;
-
-import com.android.tools.r8.ResourceException;
-import java.io.IOException;
-
-// Provide access to some package private APIs.
-public class TraceReferencesBridge {
-
- public static TraceReferencesCommand makeCommand(TraceReferencesCommand.Builder builder) {
- return builder.makeCommand();
- }
-
- public static void runInternal(TraceReferencesCommand command)
- throws IOException, ResourceException {
- TraceReferences.runInternal(command, command.getInternalOptions());
- }
-}
diff --git a/src/main/java/com/android/tools/r8/utils/AarArchiveResourceProvider.java b/src/main/java/com/android/tools/r8/utils/AarArchiveResourceProvider.java
index 6b36180..dd297fb 100644
--- a/src/main/java/com/android/tools/r8/utils/AarArchiveResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/AarArchiveResourceProvider.java
@@ -24,6 +24,7 @@
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
+import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
@@ -44,9 +45,9 @@
this.archive = archive;
}
- private List<ProgramResource> readClassesJar(ZipInputStream stream) throws IOException {
+ private void readClassesJar(ZipInputStream stream, Consumer<ProgramResource> consumer)
+ throws IOException {
ZipEntry entry;
- List<ProgramResource> resources = new ArrayList<>();
while (null != (entry = stream.getNextEntry())) {
String name = entry.getName();
if (ZipUtils.isClassFile(name)) {
@@ -58,14 +59,12 @@
entryOrigin,
ByteStreams.toByteArray(stream),
Collections.singleton(descriptor));
- resources.add(resource);
+ consumer.accept(resource);
}
}
- return resources;
}
- private List<ProgramResource> readArchive() throws IOException {
- List<ProgramResource> classResources = null;
+ private void readArchive(Consumer<ProgramResource> consumer) throws IOException {
try (ZipFile zipFile = FileUtils.createZipFile(archive.toFile(), StandardCharsets.UTF_8)) {
final Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
@@ -74,7 +73,7 @@
String name = entry.getName();
if (name.equals("classes.jar")) {
try (ZipInputStream classesStream = new ZipInputStream(stream)) {
- classResources = readClassesJar(classesStream);
+ readClassesJar(classesStream, consumer);
}
break;
}
@@ -83,13 +82,23 @@
} catch (ZipException e) {
throw new CompilationError("Zip error while reading '" + archive + "': " + e.getMessage(), e);
}
- return classResources == null ? Collections.emptyList() : classResources;
}
@Override
public Collection<ProgramResource> getProgramResources() throws ResourceException {
try {
- return readArchive();
+ List<ProgramResource> classResources = new ArrayList<>();
+ readArchive(classResources::add);
+ return classResources;
+ } catch (IOException e) {
+ throw new ResourceException(origin, e);
+ }
+ }
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) throws ResourceException {
+ try {
+ readArchive(consumer);
} catch (IOException e) {
throw new ResourceException(origin, e);
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 5cfde66..95e30ba 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
+import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.isAarFile;
import static com.android.tools.r8.utils.FileUtils.isArchive;
@@ -29,6 +30,7 @@
import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.ProgramResourceProvider;
+import com.android.tools.r8.R8Command.EnsureNonDexProgramResourceProvider;
import com.android.tools.r8.Resource;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.StringResource;
@@ -36,6 +38,7 @@
import com.android.tools.r8.dump.DumpOptions;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.features.FeatureSplitConfiguration;
@@ -50,6 +53,7 @@
import com.android.tools.r8.shaking.FilteredClassPath;
import com.android.tools.r8.startup.StartupProfileProvider;
import com.android.tools.r8.synthesis.SyntheticItems;
+import com.android.tools.r8.utils.timing.Timing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
@@ -271,22 +275,35 @@
}
public Collection<ProgramResource> computeAllProgramResources() throws ResourceException {
- return computeAllProgramResources(null);
+ List<ProgramResource> programResources = new ArrayList<>();
+ computeAllProgramResources(programResources::add, null, emptyConsumer(), Timing.empty());
+ return programResources;
}
/** Get full collection of all program resources from all program providers. */
- public Collection<ProgramResource> computeAllProgramResources(
- Consumer<InternalProgramClassProvider> internalProviderConsumer) throws ResourceException {
- List<ProgramResource> resources = new ArrayList<>();
+ public void computeAllProgramResources(
+ Consumer<ProgramResource> consumer,
+ Consumer<InternalProgramClassProvider> internalProviderConsumer,
+ Consumer<ProgramResourceProvider> legacyProgramResourceProviderConsumer,
+ Timing timing)
+ throws ResourceException {
for (ProgramResourceProvider provider : programResourceProviders) {
+ timing.begin(
+ "Process "
+ + EnsureNonDexProgramResourceProvider.unwrap(provider).getClass().getTypeName());
if (provider instanceof InternalProgramClassProvider) {
InternalProgramClassProvider internalProvider = (InternalProgramClassProvider) provider;
internalProviderConsumer.accept(internalProvider);
} else {
- resources.addAll(provider.getProgramResources());
+ try {
+ provider.getProgramResources(consumer);
+ } catch (Unimplemented e) {
+ legacyProgramResourceProviderConsumer.accept(provider);
+ provider.getProgramResources().forEach(consumer);
+ }
}
+ timing.end();
}
- return resources;
}
// TODO(zerny): Remove this method.
@@ -1299,7 +1316,11 @@
}
public Builder setProguardMapInputData(Path mapPath) {
- this.proguardMapInputData = StringResource.fromFile(mapPath);
+ return setProguardMapInputData(StringResource.fromFile(mapPath));
+ }
+
+ public Builder setProguardMapInputData(StringResource proguardMapInputData) {
+ this.proguardMapInputData = proguardMapInputData;
return this;
}
@@ -1384,6 +1405,11 @@
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ finalProgramResources.forEach(consumer);
+ }
+
+ @Override
public DataResourceProvider getDataResourceProvider() {
if (!finalDataResources.isEmpty()) {
return new DataResourceProvider() {
diff --git a/src/main/java/com/android/tools/r8/utils/ArchiveResourceProvider.java b/src/main/java/com/android/tools/r8/utils/ArchiveResourceProvider.java
index 23c4481..5267e8c 100644
--- a/src/main/java/com/android/tools/r8/utils/ArchiveResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/ArchiveResourceProvider.java
@@ -61,9 +61,9 @@
return origin;
}
- private List<ProgramResource> readArchive() throws IOException {
- List<ProgramResource> dexResources = new ArrayList<>();
- List<ProgramResource> classResources = new ArrayList<>();
+ private void readArchive(Consumer<ProgramResource> consumer) throws ResourceException {
+ BooleanBox seenCf = new BooleanBox();
+ BooleanBox seenDex = new BooleanBox();
try (ZipFile zipFile =
FileUtils.createZipFile(archive.getPath().toFile(), StandardCharsets.UTF_8)) {
final Enumeration<? extends ZipEntry> entries = zipFile.entries();
@@ -78,7 +78,8 @@
ProgramResource resource =
OneShotByteResource.create(
Kind.DEX, entryOrigin, ByteStreams.toByteArray(stream), null);
- dexResources.add(resource);
+ consumer.accept(resource);
+ seenDex.set();
}
} else if (ZipUtils.isClassFile(name)) {
String descriptor = DescriptorUtils.guessTypeDescriptor(name);
@@ -88,7 +89,8 @@
entryOrigin,
ByteStreams.toByteArray(stream),
Collections.singleton(descriptor));
- classResources.add(resource);
+ consumer.accept(resource);
+ seenCf.set();
}
}
}
@@ -96,24 +98,28 @@
} catch (ZipException e) {
throw new CompilationError(
"Zip error while reading '" + archive + "': " + e.getMessage(), e);
+ } catch (IOException e) {
+ throw new ResourceException(origin, e);
}
- if (!dexResources.isEmpty() && !classResources.isEmpty()) {
+ if (seenCf.isTrue() && seenDex.isTrue()) {
throw new CompilationError(
"Cannot create android app from an archive '"
+ archive
+ "' containing both DEX and Java-bytecode content",
origin);
}
- return !dexResources.isEmpty() ? dexResources : classResources;
}
@Override
public Collection<ProgramResource> getProgramResources() throws ResourceException {
- try {
- return readArchive();
- } catch (IOException e) {
- throw new ResourceException(origin, e);
- }
+ List<ProgramResource> programResources = new ArrayList<>();
+ readArchive(programResources::add);
+ return programResources;
+ }
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) throws ResourceException {
+ readArchive(consumer);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/utils/ClassMap.java b/src/main/java/com/android/tools/r8/utils/ClassMap.java
index 6871538..f9e89bd 100644
--- a/src/main/java/com/android/tools/r8/utils/ClassMap.java
+++ b/src/main/java/com/android/tools/r8/utils/ClassMap.java
@@ -3,22 +3,18 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
-import static com.google.common.base.Predicates.alwaysTrue;
-
+import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.threading.TaskCollection;
+import com.android.tools.r8.utils.timing.Timing;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
@@ -40,13 +36,13 @@
/**
* For each type which has ever been queried stores one class loaded from resources provided by
* different resource providers.
- * <p>
- * <b>NOTE:</b> mutated concurrently but we require that the value assigned to a keys never
+ *
+ * <p><b>NOTE:</b> mutated concurrently but we require that the value assigned to a keys never
* changes its meaning, i.e., the supplier object might change but the contained value does not.
* We also allow the transition from Supplier of a null value to the actual value null and vice
* versa.
*/
- private final Map<DexType, Supplier<T>> classes;
+ private final ConcurrentHashMap<DexType, Supplier<T>> classes;
/**
* Class provider if available.
@@ -59,9 +55,14 @@
*/
private final AtomicReference<ClassProvider<T>> classProvider = new AtomicReference<>();
- ClassMap(Map<DexType, Supplier<T>> classes, ClassProvider<T> classProvider) {
+ ClassMap(ConcurrentHashMap<DexType, Supplier<T>> classes) {
+ this.classes = classes;
+ this.classProvider.set(null);
+ }
+
+ ClassMap(ClassProvider<T> classProvider) {
assert classProvider == null || classProvider.getClassKind() == getClassKind();
- this.classes = classes == null ? new ConcurrentHashMap<>() : classes;
+ this.classes = new ConcurrentHashMap<>();
this.classProvider.set(classProvider);
}
@@ -80,7 +81,7 @@
@Override
public String toString() {
- return classes.size() + " loaded, provider: " + Objects.toString(this.classProvider.get());
+ return classes.size() + " loaded, provider: " + this.classProvider.get();
}
/**
@@ -88,34 +89,18 @@
*/
public T get(DexType type) {
// If this collection is fully loaded, just return the found result.
- if (classProvider.get() == null) {
+ ClassProvider<T> classProvider = this.classProvider.get();
+ if (classProvider == null) {
Supplier<T> supplier = classes.get(type);
return supplier == null ? null : supplier.get();
}
+ return internalGetNotFullyLoaded(type, classProvider);
+ }
- Supplier<T> supplier = classes.get(type);
- // If we find a result, we can just return it as it won't change.
- if (supplier != null) {
- return supplier.get();
- }
-
- // Otherwise, we have to do the full dance with locking to avoid creating two suppliers.
- // Lock on this to ensure classProvider is not changed concurrently, so we do not create
- // a concurrent class loader with a null classProvider.
- synchronized (this) {
- supplier = classes.computeIfAbsent(type, key -> {
- // Get class supplier, create it if it does not
- // exist and the collection is NOT fully loaded.
- if (classProvider.get() == null) {
- // There is no supplier, the collection is fully loaded.
- return null;
- }
-
- return new ConcurrentClassLoader<>(this, classProvider.get(), type);
- });
- }
-
- return supplier == null ? null : supplier.get();
+ private T internalGetNotFullyLoaded(DexType type, ClassProvider<T> classProvider) {
+ return classes
+ .computeIfAbsent(type, key -> new ConcurrentClassLoader<>(this, classProvider, type))
+ .get();
}
/**
@@ -151,6 +136,9 @@
}
public ImmutableMap<DexType, T> getAllClassesInMap() {
+ if (classProvider.get() != null) {
+ throw new Unreachable("Getting all classes from not fully loaded collection.");
+ }
ImmutableMap.Builder<DexType, T> builder = ImmutableMap.builder();
// This is fully loaded, so the class map will no longer change.
forEach(builder::put);
@@ -177,10 +165,6 @@
"Cannot access all types since the classProvider is no longer available");
}
- public ClassMap<T> forceLoad() {
- return forceLoad(alwaysTrue());
- }
-
/**
* Forces loading of all the classes satisfying the criteria specified.
*
@@ -188,75 +172,41 @@
* sealed. This has one side-effect: if we filter out some of the classes with `load` predicate,
* these classes will never be loaded.
*/
- @SuppressWarnings("ReferenceEquality")
- public ClassMap<T> forceLoad(Predicate<DexType> load) {
- Set<DexType> knownClasses;
- ClassProvider<T> classProvider;
-
+ public ClassMap<T> forceLoad(
+ InternalOptions options,
+ TaskCollection<?> tasks,
+ Timing timing,
+ Predicate<ProgramResource> load) {
// Cache value of class provider, as it might change concurrently.
if (isFullyLoaded()) {
return this;
}
- classProvider = this.classProvider.get();
- // Collects the types which might be represented in fully loaded class map.
- knownClasses = Sets.newIdentityHashSet();
- knownClasses.addAll(classes.keySet());
-
- // Add all types the class provider provides. Note that it may take time for class
- // provider to collect these types, so we do it outside synchronized context.
- knownClasses.addAll(classProvider.collectTypes());
-
- // Make sure all the types in `knownClasses` are loaded.
- //
- // We just go and touch every class, thus triggering their loading if they
- // are not loaded so far. In case the class has already been loaded,
- // touching the class will be a no-op with minimal overhead.
- for (DexType type : knownClasses) {
- if (load.test(type)) {
- get(type);
- }
- }
-
- // Lock on this to prevent concurrent changes to classProvider state and to ensure that
- // only one thread proceeds to rewriting the map.
- synchronized (this) {
- if (this.classProvider.get() == null) {
- return this; // Has been force-loaded concurrently.
- }
-
- // We avoid calling get() on a class supplier unless we know it was loaded.
- // At this time `classes` may have more types then `knownClasses`, but for
- // all extra classes we expect the supplier to return 'null' after loading.
- Iterator<Map.Entry<DexType, Supplier<T>>> iterator = classes.entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry<DexType, Supplier<T>> e = iterator.next();
-
- if (knownClasses.contains(e.getKey())) {
- // Get the class (it is expected to be loaded by this time).
- T clazz = e.getValue().get();
- if (clazz != null) {
- // Since the class is already loaded, get rid of possible wrapping suppliers.
- assert clazz.type == e.getKey();
- e.setValue(getTransparentSupplier(clazz));
- continue;
- }
- }
-
- // If the type is not in `knownClasses` or resolves to `null`,
- // just remove the record from the map.
- iterator.remove();
- }
-
- // Mark the class map as fully loaded. This has to be the last operation, as this toggles
- // the class map into fully loaded state and the get operation will no longer try to load
- // classes by blocking on 'this' and hence wait for the loading operation to finish.
- this.classProvider.set(null);
- }
-
+ ClassProvider<T> classProvider = this.classProvider.get();
+ classProvider.forceLoad(
+ clazz ->
+ classes.compute(
+ clazz.getType(),
+ (type, existing) ->
+ getTransparentSupplier(
+ existing == null ? clazz : resolveClassConflict(existing.get(), clazz))),
+ options,
+ load,
+ tasks,
+ timing);
return this;
}
+ public void setFullyLoaded() {
+ // Remove null entries.
+ MapUtils.removeIf(classes, (type, supplier) -> supplier.get() == null);
+
+ // Mark the class map as fully loaded. This has to be the last operation, as this toggles
+ // the class map into fully loaded state and the get operation will no longer try to load
+ // classes by blocking on 'this' and hence wait for the loading operation to finish.
+ this.classProvider.set(null);
+ }
+
public boolean isFullyLoaded() {
return this.classProvider.get() == null;
}
diff --git a/src/main/java/com/android/tools/r8/utils/ClassProvider.java b/src/main/java/com/android/tools/r8/utils/ClassProvider.java
index 9608497..c1475af 100644
--- a/src/main/java/com/android/tools/r8/utils/ClassProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/ClassProvider.java
@@ -7,20 +7,22 @@
import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.JarApplicationReader;
import com.android.tools.r8.graph.JarClassFileReader;
-import com.google.common.collect.ImmutableListMultimap;
+import com.android.tools.r8.threading.TaskCollection;
+import com.android.tools.r8.utils.timing.Timing;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/** Represents a provider for classes loaded from different sources. */
public abstract class ClassProvider<T extends DexClass> {
@@ -55,22 +57,19 @@
*/
public abstract Collection<DexType> collectTypes();
+ public abstract void forceLoad(
+ Consumer<T> classConsumer,
+ InternalOptions options,
+ Predicate<ProgramResource> predicate,
+ TaskCollection<?> tasks,
+ Timing timing);
+
/** Create class provider for java class resource provider. */
public static <T extends DexClass> ClassProvider<T> forClassFileResources(
ClassKind<T> classKind, ClassFileResourceProvider provider, JarApplicationReader reader) {
return new ClassFileResourceReader<>(classKind, provider, reader);
}
- /** Create class provider for preloaded classes, classes may have conflicting names. */
- public static <T extends DexClass> ClassProvider<T> forPreloadedClasses(
- ClassKind<T> classKind, Collection<T> classes) {
- ImmutableListMultimap.Builder<DexType, T> builder = ImmutableListMultimap.builder();
- for (T clazz : classes) {
- builder.put(clazz.type, clazz);
- }
- return new PreloadedClassProvider<>(classKind, builder.build());
- }
-
public FilteringClassProvider<T> without(Set<DexType> filteredTypes) {
return new FilteringClassProvider<>(classKind, this, filteredTypes);
}
@@ -78,7 +77,13 @@
/** Create class provider for preloaded classes. */
public static <T extends DexClass> ClassProvider<T> combine(
ClassKind<T> classKind, List<ClassProvider<T>> providers) {
- return new CombinedClassProvider<>(classKind, providers);
+ if (providers.isEmpty()) {
+ return null;
+ } else if (providers.size() == 1) {
+ return providers.get(0);
+ } else {
+ return new CombinedClassProvider<>(classKind, providers);
+ }
}
private static class ClassFileResourceReader<T extends DexClass> extends ClassProvider<T> {
@@ -133,35 +138,51 @@
return types;
}
+ @SuppressWarnings("unchecked")
@Override
- public String toString() {
- return "class-resource-provider(" + provider.toString() + ")";
- }
- }
-
- private static class PreloadedClassProvider<T extends DexClass> extends ClassProvider<T> {
- private final Multimap<DexType, T> classes;
-
- private PreloadedClassProvider(ClassKind<T> classKind, Multimap<DexType, T> classes) {
- super(classKind);
- this.classes = classes;
- }
-
- @Override
- public void collectClass(DexType type, Consumer<T> classConsumer) {
- for (T clazz : classes.get(type)) {
- classConsumer.accept(clazz);
+ public void forceLoad(
+ Consumer<T> classConsumer,
+ InternalOptions options,
+ Predicate<ProgramResource> predicate,
+ TaskCollection<?> tasks,
+ Timing timing) {
+ if (provider instanceof InternalClasspathOrLibraryClassProvider) {
+ InternalClasspathOrLibraryClassProvider<T> internalProvider =
+ (InternalClasspathOrLibraryClassProvider<T>) provider;
+ internalProvider.getClasses().forEach(classConsumer);
+ } else {
+ JarClassFileReader<T> classReader =
+ new JarClassFileReader<>(reader, classConsumer, classKind);
+ try {
+ provider.getProgramResources(
+ programResource -> {
+ if (predicate.test(programResource)) {
+ tasks.submitUnchecked(
+ () -> {
+ Timing threadTiming = timing.createThreadTiming("Force load", options);
+ try {
+ classReader.read(programResource);
+ } catch (ResourceException e) {
+ throw new RuntimeException(e);
+ }
+ threadTiming.end().notifyThreadTimingFinished();
+ });
+ }
+ });
+ } catch (Unimplemented e) {
+ options.reporter.warning(
+ "Class file resource provider does not support async parsing: "
+ + provider.getClass().getTypeName());
+ for (DexType type : collectTypes()) {
+ collectClass(type, classConsumer);
+ }
+ }
}
}
@Override
- public Collection<DexType> collectTypes() {
- return classes.keys();
- }
-
- @Override
public String toString() {
- return "preloaded(" + classes.size() + ")";
+ return "class-resource-provider(" + provider.toString() + ")";
}
}
@@ -179,6 +200,25 @@
}
@Override
+ public void forceLoad(
+ Consumer<T> classConsumer,
+ InternalOptions options,
+ Predicate<ProgramResource> predicate,
+ TaskCollection<?> tasks,
+ Timing timing) {
+ provider.forceLoad(
+ clazz -> {
+ if (!filteredOut.contains(clazz.getType())) {
+ classConsumer.accept(clazz);
+ }
+ },
+ options,
+ predicate,
+ tasks,
+ timing);
+ }
+
+ @Override
public FilteringClassProvider<T> without(Set<DexType> filteredTypes) {
ImmutableSet<DexType> newSet =
ImmutableSet.<DexType>builder().addAll(filteredOut).addAll(filteredTypes).build();
@@ -231,6 +271,18 @@
}
@Override
+ public void forceLoad(
+ Consumer<T> classConsumer,
+ InternalOptions options,
+ Predicate<ProgramResource> predicate,
+ TaskCollection<?> tasks,
+ Timing timing) {
+ for (ClassProvider<T> provider : providers) {
+ provider.forceLoad(classConsumer, options, predicate, tasks, timing);
+ }
+ }
+
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
String prefix = "combined(";
diff --git a/src/main/java/com/android/tools/r8/utils/ClasspathClassCollection.java b/src/main/java/com/android/tools/r8/utils/ClasspathClassCollection.java
index e14d8ed..8a425af 100644
--- a/src/main/java/com/android/tools/r8/utils/ClasspathClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ClasspathClassCollection.java
@@ -16,7 +16,7 @@
}
public ClasspathClassCollection(ClassProvider<DexClasspathClass> classProvider) {
- super(null, classProvider);
+ super(classProvider);
}
public static ClasspathClassCollection empty() {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalArchiveClassFileProvider.java b/src/main/java/com/android/tools/r8/utils/InternalArchiveClassFileProvider.java
index 7685a95..e3ac36c 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalArchiveClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalArchiveClassFileProvider.java
@@ -29,8 +29,10 @@
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
import java.util.zip.ZipFile;
/**
@@ -103,6 +105,34 @@
}
}
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ try (ZipFile zipFile = FileUtils.createZipFile(path.toFile(), StandardCharsets.UTF_8)) {
+ final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ try (InputStream stream = zipFile.getInputStream(entry)) {
+ String name = entry.getName();
+ Origin entryOrigin = new ArchiveEntryOrigin(name, origin);
+ if (ZipUtils.isClassFile(name)) {
+ String descriptor = DescriptorUtils.guessTypeDescriptor(name);
+ ProgramResource resource =
+ OneShotByteResource.create(
+ Kind.CF,
+ entryOrigin,
+ ByteStreams.toByteArray(stream),
+ Collections.singleton(descriptor));
+ consumer.accept(resource);
+ }
+ }
+ }
+ } catch (ZipException e) {
+ throw new CompilationError("Zip error while reading '" + path + "': " + e.getMessage(), e);
+ } catch (IOException e) {
+ throw new RuntimeException(new ResourceException(origin, e));
+ }
+ }
+
private ZipFile getOpenZipFile() throws IOException {
if (openedZipFile == null) {
try {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalClasspathOrLibraryClassProvider.java b/src/main/java/com/android/tools/r8/utils/InternalClasspathOrLibraryClassProvider.java
index 5229dd4..aaea34c 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalClasspathOrLibraryClassProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalClasspathOrLibraryClassProvider.java
@@ -30,6 +30,10 @@
return classes.get(type);
}
+ public Collection<T> getClasses() {
+ return classes.values();
+ }
+
public Collection<DexType> getTypes() {
return classes.keySet();
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java
index 33edbcb..8f48413 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
+import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
+
import com.android.tools.r8.GlobalSyntheticsResourceProvider;
import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResource.Kind;
@@ -19,6 +21,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -50,12 +53,22 @@
@Override
public Collection<ProgramResource> getProgramResources() throws ResourceException {
if (resources == null) {
- ensureResources();
+ ensureResources(emptyConsumer());
}
return resources;
}
- private synchronized void ensureResources() throws ResourceException {
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) throws ResourceException {
+ if (resources == null) {
+ ensureResources(consumer);
+ } else {
+ resources.forEach(consumer);
+ }
+ }
+
+ private synchronized void ensureResources(Consumer<ProgramResource> consumer)
+ throws ResourceException {
if (resources != null) {
return;
}
@@ -101,7 +114,9 @@
"Invalid global synthetics provider does not specify its content kind.");
}
for (Function<Kind, ProgramResource> fn : delayedResouces) {
- resources.add(fn.apply(providerKind));
+ ProgramResource resource = fn.apply(providerKind);
+ consumer.accept(resource);
+ resources.add(resource);
}
}
this.resources = resources;
diff --git a/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java b/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
index d1957a4..6ee5fc1 100644
--- a/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
@@ -10,7 +10,7 @@
/** Represents a collection of library classes. */
public class LibraryClassCollection extends ClassMap<DexLibraryClass> {
public LibraryClassCollection(ClassProvider<DexLibraryClass> classProvider) {
- super(null, classProvider);
+ super(classProvider);
}
public static LibraryClassCollection empty() {
diff --git a/src/main/java/com/android/tools/r8/utils/OneShotByteResource.java b/src/main/java/com/android/tools/r8/utils/OneShotByteResource.java
index 76be7da..92d164f 100644
--- a/src/main/java/com/android/tools/r8/utils/OneShotByteResource.java
+++ b/src/main/java/com/android/tools/r8/utils/OneShotByteResource.java
@@ -10,7 +10,7 @@
import java.io.InputStream;
import java.util.Set;
-class OneShotByteResource implements ProgramResource {
+public class OneShotByteResource implements ProgramResource {
private final Origin origin;
private final Kind kind;
diff --git a/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java b/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
index 82e6a7e..6ac0afa 100644
--- a/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
@@ -12,6 +12,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
/**
* Lazy Java class file resource provider based on preloaded/prebuilt context.
@@ -49,6 +50,16 @@
if (bytes == null) {
return null;
}
+ return createProgramResource(descriptor, bytes);
+ }
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ content.forEach(
+ (descriptor, bytes) -> consumer.accept(createProgramResource(descriptor, bytes)));
+ }
+
+ private static ProgramResource createProgramResource(String descriptor, byte[] bytes) {
return ProgramResource.fromBytes(
new ClassDescriptorOrigin(descriptor), Kind.CF, bytes, Collections.singleton(descriptor));
}
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index b177056..bdd7532 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.ClassConflictResolver;
import com.android.tools.r8.dex.ApplicationReader.ProgramClassConflictResolver;
import com.android.tools.r8.errors.DuplicateTypesDiagnostic;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
@@ -14,31 +15,53 @@
import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramProvider.GlobalsEntryOrigin;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.IdentityHashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
-/** Represents a collection of library classes. */
+/** Represents a collection of program classes. */
public class ProgramClassCollection extends ClassMap<DexProgramClass> {
- private final ProgramClassConflictResolver conflictResolver;
-
public static ProgramClassCollection create(
- List<DexProgramClass> classes, ProgramClassConflictResolver conflictResolver) {
+ List<DexProgramClass> classes, InternalOptions options) {
// We have all classes preloaded, but not necessarily without conflicts.
ConcurrentHashMap<DexType, Supplier<DexProgramClass>> map = new ConcurrentHashMap<>();
+ ProgramClassConflictResolver conflictResolver = createConflictResolver(options);
for (DexProgramClass clazz : classes) {
map.merge(
- clazz.type, clazz, (a, b) -> conflictResolver.resolveClassConflict(a.get(), b.get()));
+ clazz.getType(),
+ clazz,
+ (a, b) -> conflictResolver.resolveClassConflict(a.get(), b.get()));
}
- return new ProgramClassCollection(map, conflictResolver);
+ return new ProgramClassCollection(map);
}
- private ProgramClassCollection(
- ConcurrentHashMap<DexType, Supplier<DexProgramClass>> classes,
- ProgramClassConflictResolver conflictResolver) {
- super(classes, null);
- this.conflictResolver = conflictResolver;
+ public static ProgramClassConflictResolver createConflictResolver(InternalOptions options) {
+ // The default conflict resolver only merges synthetic classes generated by D8 correctly.
+ // All other conflicts are reported as a fatal error.
+ return options.programClassConflictResolver == null
+ ? wrappedConflictResolver(null, options.reporter)
+ : options.programClassConflictResolver;
+ }
+
+ public static Map<DexType, DexProgramClass> resolveConflicts(
+ Collection<DexProgramClass> classes, InternalOptions options) {
+ Map<DexType, DexProgramClass> map = new IdentityHashMap<>();
+ ProgramClassConflictResolver conflictResolver = createConflictResolver(options);
+ for (DexProgramClass clazz : classes) {
+ map.merge(
+ clazz.getType(),
+ clazz,
+ (a, b) -> conflictResolver.resolveClassConflict(a.get(), b.get()));
+ }
+ return map;
+ }
+
+ private ProgramClassCollection(ConcurrentHashMap<DexType, Supplier<DexProgramClass>> classes) {
+ super(classes);
}
@Override
@@ -48,7 +71,7 @@
@Override
DexProgramClass resolveClassConflict(DexProgramClass a, DexProgramClass b) {
- return conflictResolver.resolveClassConflict(a, b);
+ throw new Unreachable();
}
@Override
@@ -61,12 +84,6 @@
return ClassKind.PROGRAM;
}
- public static ProgramClassConflictResolver defaultConflictResolver(Reporter reporter) {
- // The default conflict resolver only merges synthetic classes generated by D8 correctly.
- // All other conflicts are reported as a fatal error.
- return wrappedConflictResolver(null, reporter);
- }
-
@SuppressWarnings("ReferenceEquality")
public static ProgramClassConflictResolver wrappedConflictResolver(
ClassConflictResolver clientResolver, Reporter reporter) {
diff --git a/src/test/java/com/android/tools/r8/androidresources/AlwaysKeepIDsInLegacyMode.java b/src/test/java/com/android/tools/r8/androidresources/AlwaysKeepIDsInLegacyMode.java
index 61f007c..5adea06 100644
--- a/src/test/java/com/android/tools/r8/androidresources/AlwaysKeepIDsInLegacyMode.java
+++ b/src/test/java/com/android/tools/r8/androidresources/AlwaysKeepIDsInLegacyMode.java
@@ -54,7 +54,8 @@
.addProgramClasses(FooBar.class)
.addAndroidResources(getTestResources(temp))
.addKeepMainRule(FooBar.class)
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.compile()
.inspectShrunkenResources(
resourceTableInspector -> {
diff --git a/src/test/java/com/android/tools/r8/androidresources/ColorInliningTest.java b/src/test/java/com/android/tools/r8/androidresources/ColorInliningTest.java
index c3d5cf9..daa9310 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ColorInliningTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ColorInliningTest.java
@@ -99,7 +99,8 @@
o.enableXmlInlining = true;
o.enableColorInlining = true;
}))
- .applyIf(optimize, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimize, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.applyIf(
addResourcesSubclass,
builder ->
diff --git a/src/test/java/com/android/tools/r8/androidresources/DuplicatedEntriesEmptyUnusedTest.java b/src/test/java/com/android/tools/r8/androidresources/DuplicatedEntriesEmptyUnusedTest.java
index 07045d6..92e4008 100644
--- a/src/test/java/com/android/tools/r8/androidresources/DuplicatedEntriesEmptyUnusedTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/DuplicatedEntriesEmptyUnusedTest.java
@@ -74,7 +74,8 @@
.addAndroidResources(getTestResources(temp))
.addFeatureSplitAndroidResources(
getFeatureSplitTestResources(featureSplitTemp), FeatureSplit.class.getName())
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.addKeepMainRule(Base.class)
.addKeepMainRule(FeatureSplitMain.class)
.compile()
diff --git a/src/test/java/com/android/tools/r8/androidresources/KeepXmlFilesTest.java b/src/test/java/com/android/tools/r8/androidresources/KeepXmlFilesTest.java
index 34c870a..c8b0a4e 100644
--- a/src/test/java/com/android/tools/r8/androidresources/KeepXmlFilesTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/KeepXmlFilesTest.java
@@ -56,7 +56,8 @@
.addProgramClasses(FooBar.class)
.addAndroidResources(getTestResources(temp))
.addKeepMainRule(FooBar.class)
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.compile()
.inspectShrunkenResources(
resourceTableInspector -> {
diff --git a/src/test/java/com/android/tools/r8/androidresources/NoOptResourceShrinkingTest.java b/src/test/java/com/android/tools/r8/androidresources/NoOptResourceShrinkingTest.java
index 3e19e29..1b3c4a9 100644
--- a/src/test/java/com/android/tools/r8/androidresources/NoOptResourceShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/NoOptResourceShrinkingTest.java
@@ -53,7 +53,8 @@
AndroidTestResource testResources = getTestResources(temp);
testForR8(parameters)
.addProgramClasses(FooBar.class)
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.addAndroidResources(testResources)
.addKeepMainRule(FooBar.class)
.addDontOptimize()
diff --git a/src/test/java/com/android/tools/r8/androidresources/RClassResourceGeneration.java b/src/test/java/com/android/tools/r8/androidresources/RClassResourceGeneration.java
index 4d2a0e8..9c16b45 100644
--- a/src/test/java/com/android/tools/r8/androidresources/RClassResourceGeneration.java
+++ b/src/test/java/com/android/tools/r8/androidresources/RClassResourceGeneration.java
@@ -50,6 +50,7 @@
.addProgramClasses(FooBar.class)
.addAndroidResources(testResource)
.addKeepMainRule(FooBar.class)
+ .allowStderrMessages()
.run(parameters.getRuntime(), FooBar.class)
// The values from the aapt2 generated R class (validated in testResourceRewriting below)
// drawable:
diff --git a/src/test/java/com/android/tools/r8/androidresources/RClassStaticValuesIgnoreTest.java b/src/test/java/com/android/tools/r8/androidresources/RClassStaticValuesIgnoreTest.java
index fdc8a87..b61d5e8 100644
--- a/src/test/java/com/android/tools/r8/androidresources/RClassStaticValuesIgnoreTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/RClassStaticValuesIgnoreTest.java
@@ -56,6 +56,7 @@
DescriptorUtils.descriptorToJavaType(RClassDescriptor))
.addAndroidResources(testResources)
.addKeepMainRule(FooBar.class)
+ .allowStderrMessages()
.compile()
.inspectShrunkenResources(
resourceTableInspector -> {
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceNameWithDotsRegressionTest.java b/src/test/java/com/android/tools/r8/androidresources/ResourceNameWithDotsRegressionTest.java
index 1e28ef0..226f3ab 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourceNameWithDotsRegressionTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceNameWithDotsRegressionTest.java
@@ -56,6 +56,7 @@
.addRunClasspathFiles(resourcesClass)
.addAndroidResources(testResources)
.addKeepMainRule(FooBar.class)
+ .allowStderrMessages()
.compile()
.inspectShrunkenResources(
resourceTableInspector -> {
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerLoggingTest.java b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerLoggingTest.java
index 3759c64..317c67c 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerLoggingTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerLoggingTest.java
@@ -53,7 +53,8 @@
Assume.assumeTrue(optimized || parameters.getPartialCompilationTestParameters().isNone());
testForR8(parameters)
.addProgramClasses(FooBar.class)
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.addResourceShrinkerLogCapture()
.addAndroidResources(getTestResources(temp))
.addKeepMainRule(FooBar.class)
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingMultiApkAsFeaturesplits.java b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingMultiApkAsFeaturesplits.java
index 1d0655a..cc9893e 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingMultiApkAsFeaturesplits.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingMultiApkAsFeaturesplits.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.androidresources;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.R8TestCompileResultBase;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -70,7 +71,10 @@
// For the feature, we don't add the R class (we already have it in the base)
// and to test we add one less xml file.
getTestResources(featureSplitTemp, false, VIEW), featureSplitName)
- .applyIf(optimized, b -> b.enableOptimizedShrinking())
+ .applyIf(
+ optimized,
+ R8TestBuilder::enableOptimizedShrinking,
+ R8TestBuilder::allowStderrMessages)
.addKeepMainRule(Base.class)
.compile()
.inspectShrunkenResources(
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithFeatures.java b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithFeatures.java
index 818afca..e543df1 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithFeatures.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithFeatures.java
@@ -74,7 +74,10 @@
try {
testForR8(parameters)
.addProgramClasses(Base.class)
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized,
+ R8TestBuilder::enableOptimizedShrinking,
+ R8TestBuilder::allowStderrMessages)
.addFeatureSplit(builder -> builder.build())
.compileWithExpectedDiagnostics(
diagnostics -> {
@@ -114,7 +117,10 @@
.addAndroidResources(getTestResources(temp))
.addFeatureSplitAndroidResources(
getFeatureSplitTestResources(featureSplitTemp), FeatureSplit.class.getName())
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized,
+ R8TestBuilder::enableOptimizedShrinking,
+ R8TestBuilder::allowStderrMessages)
.addKeepMainRule(Base.class)
.addKeepMainRule(FeatureSplitMain.class)
.compile();
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithFeaturesAndDuplicatedResEntryTest.java b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithFeaturesAndDuplicatedResEntryTest.java
index cc75a09..110fa44 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithFeaturesAndDuplicatedResEntryTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithFeaturesAndDuplicatedResEntryTest.java
@@ -74,7 +74,8 @@
.addAndroidResources(getTestResources(temp))
.addFeatureSplitAndroidResources(
getFeatureSplitTestResources(featureSplitTemp), FeatureSplit.class.getName())
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.addKeepMainRule(Base.class)
.addKeepMainRule(FeatureSplit.FeatureSplitMain.class)
.compile()
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithSeveralFeaturesTest.java b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithSeveralFeaturesTest.java
index fc1f76d..5fd1e0c 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithSeveralFeaturesTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingWithSeveralFeaturesTest.java
@@ -84,7 +84,8 @@
getFeatureSplitTestResources(featureSplitTemp), FeatureSplit.class.getName())
.addFeatureSplitAndroidResources(
getFeatureSplit2TestResources(featureSplit2Temp), FeatureSplit2.class.getName())
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.addResourceShrinkerLogCapture()
.addKeepMainRule(Base.class)
.addKeepMainRule(FeatureSplitMain.class)
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourcesInFilledNewArrayDataTest.java b/src/test/java/com/android/tools/r8/androidresources/ResourcesInFilledNewArrayDataTest.java
index faccca3..5a7ae29 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourcesInFilledNewArrayDataTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourcesInFilledNewArrayDataTest.java
@@ -43,6 +43,7 @@
.addProgramClasses(FooBar.class)
.addAndroidResources(getTestResources(temp))
.addKeepMainRule(FooBar.class)
+ .allowStderrMessages()
.compile()
// Ensure that we have the fillednewarraydata
.inspect(
diff --git a/src/test/java/com/android/tools/r8/androidresources/SimpleNoCodeReferenceAndroidResourceTest.java b/src/test/java/com/android/tools/r8/androidresources/SimpleNoCodeReferenceAndroidResourceTest.java
index 8e3a5e9..e59f484 100644
--- a/src/test/java/com/android/tools/r8/androidresources/SimpleNoCodeReferenceAndroidResourceTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/SimpleNoCodeReferenceAndroidResourceTest.java
@@ -70,7 +70,8 @@
.addInnerClasses(getClass())
.setMinApi(parameters)
.addAndroidResources(testResource, output)
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.addKeepMainRule(FooBar.class)
.compile()
.inspectShrunkenResources(
diff --git a/src/test/java/com/android/tools/r8/androidresources/TestArchiveCompression.java b/src/test/java/com/android/tools/r8/androidresources/TestArchiveCompression.java
index e7d0e79..ae5bb2c 100644
--- a/src/test/java/com/android/tools/r8/androidresources/TestArchiveCompression.java
+++ b/src/test/java/com/android/tools/r8/androidresources/TestArchiveCompression.java
@@ -57,6 +57,7 @@
.addProgramClasses(FooBar.class)
.addAndroidResources(testResources, resourceOutput)
.addKeepMainRule(FooBar.class)
+ .allowStderrMessages()
.compile()
.run(parameters.getRuntime(), FooBar.class)
.assertSuccess();
diff --git a/src/test/java/com/android/tools/r8/androidresources/TestNameRemovalInResourceTable.java b/src/test/java/com/android/tools/r8/androidresources/TestNameRemovalInResourceTable.java
index bef5ad8..0c44bf6 100644
--- a/src/test/java/com/android/tools/r8/androidresources/TestNameRemovalInResourceTable.java
+++ b/src/test/java/com/android/tools/r8/androidresources/TestNameRemovalInResourceTable.java
@@ -56,7 +56,10 @@
testForR8(parameters)
.addProgramClasses(FooBar.class)
.addAndroidResources(getTestResources(temp))
- .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimized,
+ R8TestBuilder::enableOptimizedShrinking,
+ R8TestBuilder::allowStderrMessages)
.addKeepMainRule(FooBar.class)
.compile();
r8TestCompileResult
diff --git a/src/test/java/com/android/tools/r8/androidresources/TestResourceInlining.java b/src/test/java/com/android/tools/r8/androidresources/TestResourceInlining.java
index f9de0e0..b86f549 100644
--- a/src/test/java/com/android/tools/r8/androidresources/TestResourceInlining.java
+++ b/src/test/java/com/android/tools/r8/androidresources/TestResourceInlining.java
@@ -93,7 +93,8 @@
})
.addAndroidResources(getTestResources(temp))
.addKeepMainRule(FooBar.class)
- .applyIf(optimize, R8TestBuilder::enableOptimizedShrinking)
+ .applyIf(
+ optimize, R8TestBuilder::enableOptimizedShrinking, R8TestBuilder::allowStderrMessages)
.addRunClasspathFiles(AndroidResourceTestingUtils.resourcesClassAsDex(temp))
.compile()
.inspectShrunkenResources(
diff --git a/src/test/java/com/android/tools/r8/androidresources/TestShrinkingWithCodeReferences.java b/src/test/java/com/android/tools/r8/androidresources/TestShrinkingWithCodeReferences.java
index 5bd64e3..24be04f 100644
--- a/src/test/java/com/android/tools/r8/androidresources/TestShrinkingWithCodeReferences.java
+++ b/src/test/java/com/android/tools/r8/androidresources/TestShrinkingWithCodeReferences.java
@@ -40,6 +40,7 @@
.addProgramClasses(FooBar.class)
.addAndroidResources(getTestResources(temp))
.addKeepMainRule(FooBar.class)
+ .allowStderrMessages()
.compile()
.inspectShrunkenResources(
resourceTableInspector -> {
diff --git a/src/test/java/com/android/tools/r8/androidresources/XmlFilesWithReferences.java b/src/test/java/com/android/tools/r8/androidresources/XmlFilesWithReferences.java
index b55edff..1935590 100644
--- a/src/test/java/com/android/tools/r8/androidresources/XmlFilesWithReferences.java
+++ b/src/test/java/com/android/tools/r8/androidresources/XmlFilesWithReferences.java
@@ -41,6 +41,7 @@
.addProgramClasses(FooBar.class)
.addAndroidResources(getTestResources(temp))
.addKeepMainRule(FooBar.class)
+ .allowStderrMessages()
.compile()
.inspectShrunkenResources(
resourceTableInspector -> {
diff --git a/src/test/java/com/android/tools/r8/androidresources/optimizedshrinking/TestOptimizedShrinking.java b/src/test/java/com/android/tools/r8/androidresources/optimizedshrinking/TestOptimizedShrinking.java
index 584426b..b23dd1e 100644
--- a/src/test/java/com/android/tools/r8/androidresources/optimizedshrinking/TestOptimizedShrinking.java
+++ b/src/test/java/com/android/tools/r8/androidresources/optimizedshrinking/TestOptimizedShrinking.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.androidresources.optimizedshrinking;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.ResourceShrinkerConfiguration;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -61,7 +62,8 @@
internalOptions.resourceShrinkerConfiguration =
ResourceShrinkerConfiguration.builder(null)
.enableOptimizedShrinkingWithR8()
- .build()))
+ .build()),
+ R8TestBuilder::allowStderrMessages)
.applyIf(debug, builder -> builder.debug())
.compile()
.inspectShrunkenResources(
diff --git a/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java b/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
index c6c128f..f810c1b 100644
--- a/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
@@ -27,6 +27,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -165,6 +166,11 @@
Origin.unknown(), Kind.CF, bytes, Collections.singleton(descriptor));
}
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ getClassDescriptors().forEach(descriptor -> consumer.accept(getProgramResource(descriptor)));
+ }
+
private byte[] transformPackageName(Class<?> clazz) throws IOException {
return transformer(clazz)
.setClassDescriptor(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryInvokeAllResolveTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryInvokeAllResolveTest.java
index 4fc37c5..c284d66 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryInvokeAllResolveTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryInvokeAllResolveTest.java
@@ -115,12 +115,12 @@
.build();
InternalOptions options = inspector.getApplication().options;
DirectMappedDexApplication libHolder =
- new ApplicationReader(build, options, Timing.empty()).read().toDirect();
+ new ApplicationReader(build, options, Timing.empty()).readDirectSingleThreaded();
DirectMappedDexApplication finalApp =
inspector
.getApplication()
.asLazy()
- .toDirect()
+ .toDirectSingleThreadedForTesting()
.builder()
.replaceLibraryClasses(libHolder.libraryClasses())
.build();
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DumpCoreLibUsage.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DumpCoreLibUsage.java
index 69d123c..49b768e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DumpCoreLibUsage.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DumpCoreLibUsage.java
@@ -66,8 +66,7 @@
AndroidApp.builder().addLibraryFiles(ToolHelper.getAndroidJar(apiLevel)).build();
DirectMappedDexApplication dexApplication =
new ApplicationReader(input, new InternalOptions(factory, new Reporter()), Timing.empty())
- .read()
- .toDirect();
+ .readDirectSingleThreaded();
Set<DexReference> found = Sets.newIdentityHashSet();
found.addAll(filter);
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitTest.java b/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitTest.java
index 130f0e5..5bdb446 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitTest.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitTest.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.FeatureSplit;
+import com.android.tools.r8.ProgramResource;
+import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.TestParameters;
@@ -28,7 +30,9 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.Collections;
import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.junit.Test;
@@ -54,7 +58,19 @@
private static FeatureSplit emptySplitProvider(FeatureSplit.Builder builder) {
builder
- .addProgramResourceProvider(ImmutableList::of)
+ .addProgramResourceProvider(
+ new ProgramResourceProvider() {
+
+ @Override
+ public Collection<ProgramResource> getProgramResources() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ // Intentionally empty.
+ }
+ })
.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
return builder.build();
}
diff --git a/src/test/java/com/android/tools/r8/files/ArchiveWithDexTest.java b/src/test/java/com/android/tools/r8/files/ArchiveWithDexTest.java
index 85b25f3..621c9da 100644
--- a/src/test/java/com/android/tools/r8/files/ArchiveWithDexTest.java
+++ b/src/test/java/com/android/tools/r8/files/ArchiveWithDexTest.java
@@ -53,12 +53,17 @@
private static Origin zipWithDexAndClassOrigin;
@BeforeClass
- public static void createZipWitDexAndClass() throws IOException {
+ public static void createZipWitDexAndClass() throws CompilationFailedException, IOException {
Path zipContent = getStaticTemp().newFolder().toPath();
Files.copy(
ToolHelper.getClassFileForTestClass(TestClass.class),
zipContent.resolve("TestClass.class"));
- Files.createFile(zipContent.resolve("other.dex"));
+ testForD8(getStaticTemp())
+ .addProgramClasses(OtherTestClass.class)
+ .setMinApi(AndroidApiLevel.B)
+ .release()
+ .compile()
+ .writeSingleDexOutputToFile(zipContent.resolve("other.dex"));
zipWithDexAndClass = getStaticTemp().newFolder().toPath().resolve("input.zip");
ZipUtils.zip(zipWithDexAndClass, zipContent);
zipWithDexAndClassOrigin = new PathOrigin(zipWithDexAndClass);
@@ -213,4 +218,11 @@
System.out.println("Hello, world!");
}
}
+
+ static class OtherTestClass {
+
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/graph/DexTypeTest.java b/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
index 4b05030..282faa9 100644
--- a/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
+++ b/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
@@ -35,8 +35,7 @@
.build(),
options,
Timing.empty())
- .read()
- .toDirect();
+ .readDirectSingleThreaded();
factory = options.itemFactory;
appInfo = AppView.createForR8(application).appInfo();
}
diff --git a/src/test/java/com/android/tools/r8/ir/InlineTest.java b/src/test/java/com/android/tools/r8/ir/InlineTest.java
index 5058af1..74075e9 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -17,8 +17,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
-import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -157,7 +157,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
@@ -239,7 +239,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
@@ -316,7 +316,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
@@ -449,7 +449,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
@@ -464,7 +464,7 @@
application, options, methodSubject, ImmutableList.of(codeA, codeB));
}
- protected LazyLoadedDexApplication buildApplication(
+ protected DirectMappedDexApplication buildApplication(
SmaliBuilder builder, InternalOptions options) {
try {
AndroidApp app =
@@ -472,7 +472,7 @@
.addDexProgramData(builder.compile(), Origin.unknown())
.addLibraryFile(getMostRecentAndroidJar())
.build();
- return new ApplicationReader(app, options, Timing.empty()).read();
+ return new ApplicationReader(app, options, Timing.empty()).readDirectSingleThreaded();
} catch (IOException | RecognitionException | ExecutionException e) {
throw new RuntimeException(e);
}
@@ -576,7 +576,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
@@ -687,7 +687,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
@@ -800,7 +800,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
@@ -956,7 +956,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
@@ -1202,7 +1202,7 @@
);
InternalOptions options = createOptions();
- DexApplication application = buildApplication(builder, options).toDirect();
+ DexApplication application = buildApplication(builder, options);
// Return the processed method for inspection.
MethodSubject methodSubject = getMethodSubject(application, signature);
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
index 2f0a421..ace2c2c 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
@@ -136,8 +136,7 @@
.build(),
options,
timing)
- .read()
- .toDirect();
+ .readDirectSingleThreaded();
return AppView.createForR8(application);
}
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
index 6364e7c..fd671df 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
@@ -60,8 +60,7 @@
.build(),
options,
Timing.empty())
- .read()
- .toDirect();
+ .readDirectSingleThreaded();
factory = options.itemFactory;
appView = AppView.createForR8(application);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
index ecc4fa8..455f5c0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
@@ -111,8 +111,7 @@
.build(),
options,
Timing.empty())
- .read()
- .toDirect();
+ .readDirectSingleThreaded();
AppView<AppInfoWithClassHierarchy> appView = AppView.createForR8(application);
// Type references.
diff --git a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepAnnoTestExtractedRulesBase.java b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepAnnoTestExtractedRulesBase.java
index 0add3e3..5a06c1d 100644
--- a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepAnnoTestExtractedRulesBase.java
+++ b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepAnnoTestExtractedRulesBase.java
@@ -407,17 +407,22 @@
}
@Override
- public Collection<ProgramResource> getProgramResources() throws ResourceException {
+ public Collection<ProgramResource> getProgramResources() {
return programResources;
}
@Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ programResources.forEach(consumer);
+ }
+
+ @Override
public DataResourceProvider getDataResourceProvider() {
return this;
}
@Override
- public void accept(Visitor visitor) throws ResourceException {
+ public void accept(Visitor visitor) {
dataResources.forEach(visitor::visit);
}
}
diff --git a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
index d44d061..b8c1595 100644
--- a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
@@ -51,7 +51,7 @@
.addProgramFiles(ToolHelper.getClassFileForTestClass(Foo.class))
.build();
DirectMappedDexApplication application =
- new ApplicationReader(app, options, timing).read().toDirect();
+ new ApplicationReader(app, options, timing).readDirectSingleThreaded();
AppInfoWithClassHierarchy appInfo = AppView.createForR8(application).appInfo();
DexItemFactory factory = options.itemFactory;
DexType fooType =
diff --git a/src/test/java21/com/android/tools/r8/jdk21/autocloseable/AutoCloseableDesugaringClassesPresentAtKitKatTest.java b/src/test/java21/com/android/tools/r8/jdk21/autocloseable/AutoCloseableDesugaringClassesPresentAtKitKatTest.java
index fdd9e74..f2392e4 100644
--- a/src/test/java21/com/android/tools/r8/jdk21/autocloseable/AutoCloseableDesugaringClassesPresentAtKitKatTest.java
+++ b/src/test/java21/com/android/tools/r8/jdk21/autocloseable/AutoCloseableDesugaringClassesPresentAtKitKatTest.java
@@ -47,7 +47,7 @@
Path androidJarK = ToolHelper.getAndroidJar(AndroidApiLevel.K);
AndroidApp app = AndroidApp.builder().addProgramFile(androidJarK).build();
DirectMappedDexApplication libHolder =
- new ApplicationReader(app, options, Timing.empty()).read().toDirect();
+ new ApplicationReader(app, options, Timing.empty()).readDirectSingleThreaded();
AppInfo initialAppInfo =
AppInfo.createInitialAppInfo(libHolder, GlobalSyntheticsStrategy.forNonSynthesizing());
AppView<AppInfo> appView = AppView.createForD8(initialAppInfo, Timing.empty());
diff --git a/src/test/java21/com/android/tools/r8/jdk21/twr/LookUpCloseResourceTest.java b/src/test/java21/com/android/tools/r8/jdk21/twr/LookUpCloseResourceTest.java
index 7e7a721..737dd23 100644
--- a/src/test/java21/com/android/tools/r8/jdk21/twr/LookUpCloseResourceTest.java
+++ b/src/test/java21/com/android/tools/r8/jdk21/twr/LookUpCloseResourceTest.java
@@ -185,7 +185,7 @@
private AppView<?> getAppInfo(InternalOptions options, int api) throws IOException {
AndroidApp app = AndroidApp.builder().addProgramFile(ToolHelper.getAndroidJar(api)).build();
DirectMappedDexApplication libHolder =
- new ApplicationReader(app, options, Timing.empty()).read().toDirect();
+ new ApplicationReader(app, options, Timing.empty()).readDirectSingleThreaded();
AppInfo initialAppInfo =
AppInfo.createInitialAppInfo(libHolder, GlobalSyntheticsStrategy.forNonSynthesizing());
return AppView.createForD8(initialAppInfo, Timing.empty());
diff --git a/src/test/testbase/java/com/android/tools/r8/SingleTestRunResult.java b/src/test/testbase/java/com/android/tools/r8/SingleTestRunResult.java
index 7ee3103..68cc6c8 100644
--- a/src/test/testbase/java/com/android/tools/r8/SingleTestRunResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/SingleTestRunResult.java
@@ -149,7 +149,7 @@
return self();
}
- public RR disassemble(PrintStream ps) throws IOException {
+ public RR disassemble(PrintStream ps) throws ExecutionException, IOException {
ToolHelper.disassemble(app, ps);
return self();
}
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBase.java b/src/test/testbase/java/com/android/tools/r8/TestBase.java
index 4fe4ad3..6220f5d 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBase.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBase.java
@@ -960,7 +960,8 @@
optionsConsumer.accept(options);
}
LazyLoadedDexApplication dexApplication = readApplicationForDexOutput(app, options);
- AppView<AppInfoWithClassHierarchy> appView = AppView.createForR8(dexApplication.toDirect());
+ AppView<AppInfoWithClassHierarchy> appView =
+ AppView.createForR8(dexApplication.toDirectSingleThreadedForTesting());
appView.setAppServices(AppServices.builder(appView).build());
return appView;
}
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
index 55d667b..93d901b 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
@@ -23,6 +23,7 @@
import java.util.Collection;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
public abstract class TestBaseBuilder<
C extends BaseCommand,
@@ -175,6 +176,11 @@
public ProgramResource getProgramResource(String descriptor) {
return resources.get(descriptor);
}
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ resources.values().forEach(consumer);
+ }
};
}
diff --git a/src/test/testbase/java/com/android/tools/r8/TestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/TestCompileResult.java
index dac774b..86fe067 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestCompileResult.java
@@ -651,7 +651,7 @@
return self();
}
- public CR disassemble(PrintStream ps) throws IOException {
+ public CR disassemble(PrintStream ps) throws ExecutionException, IOException {
ToolHelper.disassemble(app, ps);
return self();
}
diff --git a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
index e929946..cc057b1 100644
--- a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
@@ -1686,7 +1686,8 @@
.addProgramFiles(ListUtils.map(fileNames, Paths::get))
.addLibraryFiles(androidJar)
.build();
- return new ApplicationReader(input, new InternalOptions(), Timing.empty()).read().toDirect();
+ return new ApplicationReader(input, new InternalOptions(), Timing.empty())
+ .readDirectSingleThreaded();
}
public static ProguardConfiguration loadProguardConfiguration(
@@ -2704,7 +2705,8 @@
R8.writeApplication(appView, null, Executors.newSingleThreadExecutor());
}
- public static void disassemble(AndroidApp app, PrintStream ps) throws IOException {
+ public static void disassemble(AndroidApp app, PrintStream ps)
+ throws ExecutionException, IOException {
LazyLoadedDexApplication application =
new ApplicationReader(app, new InternalOptions(), Timing.empty()).read();
new AssemblyWriter(application, new InternalOptions(), true, false, true).write(ps);