Optimize Desugar action startup, option normalization, and classpath archive processing. PiperOrigin-RevId: 975774224 Change-Id: If52c4f6bb77913a0c93d4efa59a61e7141fb7426
diff --git a/src/tools/java/com/google/devtools/build/android/AndroidOptionsUtils.java b/src/tools/java/com/google/devtools/build/android/AndroidOptionsUtils.java index ac7188e..54a1413 100644 --- a/src/tools/java/com/google/devtools/build/android/AndroidOptionsUtils.java +++ b/src/tools/java/com/google/devtools/build/android/AndroidOptionsUtils.java
@@ -24,8 +24,11 @@ import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Path; -import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; /** Utility class for JCommander-based Android options. */ public class AndroidOptionsUtils { @@ -33,14 +36,13 @@ private AndroidOptionsUtils() {} /** Run the CompatShellQuotedParamsFilePreProcessor on a list of args. */ - public static String[] runArgFilePreprocessor(JCommander jc, String[] argsAsArray) - throws ParameterException { + public static String[] runArgFilePreprocessor(JCommander jc, String[] argsAsArray) { jc.setExpandAtSign(false); return runArgFilePreprocessor(argsAsArray); } /** Run the CompatShellQuotedParamsFilePreProcessor on a list of args. */ - public static String[] runArgFilePreprocessor(String[] argsAsArray) throws ParameterException { + public static String[] runArgFilePreprocessor(String[] argsAsArray) { List<String> args = ImmutableList.copyOf(argsAsArray); if (args.size() == 1 && args.get(0).startsWith("@")) { // Use CompatShellQuotedParamsFilePreProcessor to handle the arg file. @@ -53,19 +55,6 @@ return args.toArray(new String[0]); } - /** - * Same as AndroidOptionsUtils#normalizeBooleanOptions, but accepts an array of option classes - * instead. - */ - public static String[] normalizeBooleanOptions(Object[] options, String[] args) - throws ParameterException { - String[] normalizedArgs = args; - for (Object optionsObject : options) { - normalizedArgs = normalizeBooleanOptions(optionsObject, normalizedArgs); - } - return normalizedArgs; - } - private static int countLeadingChars(String s, char c) { int count = 0; for (int i = 0; i < s.length(); i++) { @@ -78,27 +67,36 @@ } /** + * Same as AndroidOptionsUtils#normalizeBooleanOptions, but accepts an array of option classes + * instead. + */ + public static String[] normalizeBooleanOptions(Object[] options, String[] args) { + String[] normalizedArgs = args; + for (Object optionsObject : options) { + normalizedArgs = normalizeBooleanOptions(optionsObject, normalizedArgs); + } + return normalizedArgs; + } + + /** * Normalize boolean options to use --<flagname>=true or --<flagname>=false syntax. * * <p>This is useful for JCommander-based options. */ public static String[] normalizeBooleanOptions(Object options, String[] args) { - List<String> booleanOptions = new ArrayList<>(); - // The normalized arg list will be as long as the original args. - List<String> normalizedArgs = new ArrayList<>(args.length); + Set<String> booleanOptionNames = new HashSet<>(); // Find the list of boolean fields for (Field field : options.getClass().getDeclaredFields()) { if (field.getType().equals(boolean.class)) { // Get the `names` from the annotation of this field. // Iterate through the annotations for (Annotation annotation : field.getAnnotations()) { - if (annotation instanceof Parameter) { - Parameter parameter = (Parameter) annotation; + if (annotation instanceof Parameter parameter) { for (String name : parameter.names()) { // Strip leading dashes from the name and assert that the name starts with --. try { Preconditions.checkState(name.startsWith("--") || name.startsWith("-")); - booleanOptions.add(name.substring(countLeadingChars(name, '-'))); + booleanOptionNames.add(name.substring(countLeadingChars(name, '-'))); } catch (IllegalStateException e) { throw new ParameterException( "ParameterException in args: Found an arg not prefixed with '--' or '-': '" @@ -112,17 +110,19 @@ } } - // Iterate through the args and normalize boolean options with --<flagname> syntax. - for (String arg : args) { - for (String booleanOption : booleanOptions) { - if (arg.equals("--no" + booleanOption)) { - arg = "--" + booleanOption + "=false"; - } else if (arg.equals("--" + booleanOption)) { - arg = "--" + booleanOption + "=true"; - } - } - normalizedArgs.add(arg); + Map<String, String> replacements = new HashMap<>(); + for (String booleanOption : booleanOptionNames) { + replacements.put("--no" + booleanOption, "--" + booleanOption + "=false"); + replacements.put("--" + booleanOption, "--" + booleanOption + "=true"); } - return normalizedArgs.toArray(new String[0]); + + // Iterate through the args and normalize boolean options with --<flagname> syntax. + String[] normalizedArgs = new String[args.length]; + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + String replacement = replacements.get(arg); + normalizedArgs[i] = replacement != null ? replacement : arg; + } + return normalizedArgs; } }
diff --git a/src/tools/java/com/google/devtools/build/android/r8/Desugar.java b/src/tools/java/com/google/devtools/build/android/r8/Desugar.java index 5dda2cd..3c82de3 100644 --- a/src/tools/java/com/google/devtools/build/android/r8/Desugar.java +++ b/src/tools/java/com/google/devtools/build/android/r8/Desugar.java
@@ -14,6 +14,7 @@ package com.google.devtools.build.android.r8; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.toImmutableList; import static java.lang.Math.max; import static java.util.stream.Collectors.joining; @@ -45,11 +46,13 @@ import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.logging.Logger; /** Desugar compatible wrapper based on D8 desugaring engine */ @@ -220,8 +223,6 @@ description = "Method invocations not to rewrite, given as \"class/Name#method\".") public List<String> dontTouchCoreLibraryMembers = ImmutableList.of(); - ; - @Parameter( names = "--preserve_core_library_override", description = @@ -332,9 +333,7 @@ @Override public void warning(Diagnostic warning) { - if (warning instanceof InterfaceDesugarMissingTypeDiagnostic) { - InterfaceDesugarMissingTypeDiagnostic missingTypeDiagnostic = - (InterfaceDesugarMissingTypeDiagnostic) warning; + if (warning instanceof InterfaceDesugarMissingTypeDiagnostic missingTypeDiagnostic) { outputConsumer.missingImplementedInterface( DescriptorUtils.descriptorToBinaryName( missingTypeDiagnostic.getContextType().getDescriptor()), @@ -360,8 +359,7 @@ @Override public void error(Diagnostic error) { - if (error instanceof DexFileOverflowDiagnostic) { - DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error; + if (error instanceof DexFileOverflowDiagnostic overflowDiagnostic) { if (!overflowDiagnostic.hasMainDexSpecification()) { DiagnosticsHandler.super.error( new StringDiagnostic( @@ -378,6 +376,14 @@ public void accept(ByteDataView data, ClassReference context, DiagnosticsHandler handler) {} } + private static ArchiveClassFileProvider createArchiveClassFileProvider(Path path) { + try { + return new ArchiveClassFileProvider(path); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + private void desugar( List<ClassFileResourceProvider> bootclasspathProviders, ClassFileResourceProvider classpath, @@ -438,19 +444,31 @@ private void desugar() throws CompilationFailedException, IOException { // Prepare bootclasspath and classpath. Some jars on the classpath are considered to be // bootclasspath, and are moved there. + ImmutableList<ClassFileResourceProvider> bootclasspathProvidersList = + options.bootclasspath.parallelStream() + .map(Desugar::createArchiveClassFileProvider) + .collect(toImmutableList()); + + ImmutableList<Map.Entry<ClassFileResourceProvider, Boolean>> evaluatedClasspath = + options.classpath.parallelStream() + .map( + path -> { + ClassFileResourceProvider provider = createArchiveClassFileProvider(path); + return Map.entry(provider, isPlatform(path, provider)); + }) + .collect(toImmutableList()); + ImmutableList.Builder<ClassFileResourceProvider> bootclasspathProvidersBuilder = ImmutableList.builder(); - for (Path path : options.bootclasspath) { - bootclasspathProvidersBuilder.add(new ArchiveClassFileProvider(path)); - } + bootclasspathProvidersBuilder.addAll(bootclasspathProvidersList); + ImmutableList.Builder<ClassFileResourceProvider> classpathProvidersBuilder = ImmutableList.builder(); - for (Path path : options.classpath) { - ClassFileResourceProvider provider = new ArchiveClassFileProvider(path); - if (isPlatform(path, provider)) { - bootclasspathProvidersBuilder.add(provider); + for (Map.Entry<ClassFileResourceProvider, Boolean> entry : evaluatedClasspath) { + if (entry.getValue()) { + bootclasspathProvidersBuilder.add(entry.getKey()); } else { - classpathProvidersBuilder.add(provider); + classpathProvidersBuilder.add(entry.getKey()); } } @@ -594,8 +612,7 @@ options.outputJars.size()); } - public static int processRequest(List<String> args, PrintStream diagnosticsHandlerPrintStream) - throws Exception { + public static int processRequest(List<String> args, PrintStream diagnosticsHandlerPrintStream) { setDesugarJvmFlags(); int exitCode = 0; try { @@ -660,7 +677,7 @@ } } - public static void main(String[] args) throws Exception { + public static void main(String[] args) { if (args.length > 0 && args[0].equals("--persistent_worker")) { System.exit(runPersistentWorker()); } else {
diff --git a/src/tools/java/com/google/devtools/build/android/r8/desugar/OrderedClassFileResourceProvider.java b/src/tools/java/com/google/devtools/build/android/r8/desugar/OrderedClassFileResourceProvider.java index 7687062..ce1159e 100644 --- a/src/tools/java/com/google/devtools/build/android/r8/desugar/OrderedClassFileResourceProvider.java +++ b/src/tools/java/com/google/devtools/build/android/r8/desugar/OrderedClassFileResourceProvider.java
@@ -16,32 +16,31 @@ import com.android.tools.r8.ClassFileResourceProvider; import com.android.tools.r8.ProgramResource; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Sets; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.annotation.Nullable; /** * Classpath provider which will de-dupe duplicate classes from several providers. For any defined * class the definition from the first provider defining the class is used. */ public class OrderedClassFileResourceProvider implements ClassFileResourceProvider { - private final Set<String> descriptors = Sets.newHashSet(); private final Map<String, ClassFileResourceProvider> descriptorToProvider = new HashMap<>(); public OrderedClassFileResourceProvider( ImmutableList<ClassFileResourceProvider> bootclasspathProviders, ImmutableList<ClassFileResourceProvider> classfileProviders) { - final Set<String> bootclasspathDescriptors = Sets.newHashSet(); + final Set<String> bootclasspathDescriptors = new HashSet<>(); bootclasspathProviders.forEach(p -> bootclasspathDescriptors.addAll(p.getClassDescriptors())); for (ClassFileResourceProvider provider : classfileProviders) { // Collect all descriptors provided and the first provider providing each. for (String descriptor : provider.getClassDescriptors()) { // Pick first definition of classpath class and filter out platform classes // from classpath if present. - if (!bootclasspathDescriptors.contains(descriptor) - && descriptors.add(descriptor)) { - descriptorToProvider.put(descriptor, provider); + if (!bootclasspathDescriptors.contains(descriptor)) { + descriptorToProvider.putIfAbsent(descriptor, provider); } } } @@ -49,10 +48,11 @@ @Override public Set<String> getClassDescriptors() { - return descriptors; + return descriptorToProvider.keySet(); } @Override + @Nullable public ProgramResource getProgramResource(String descriptor) { ClassFileResourceProvider provider = descriptorToProvider.get(descriptor); return provider != null ? provider.getProgramResource(descriptor) : null;