diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules')
6 files changed, 127 insertions, 36 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java index 32e2aa5b70..040f60635e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java @@ -1073,7 +1073,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_PROGUARD_SEEDS); Artifact proguardUsage = ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_PROGUARD_USAGE); - ProguardOutput result = ProguardHelper.createProguardAction( + ProguardOutput result = ProguardHelper.createOptimizationActions( ruleContext, sdk.getProguard(), deployJarArtifact, diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java index 7b345a16af..5fc82a9535 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java @@ -790,6 +790,8 @@ public final class AndroidRuleClasses { .value(TriState.AUTO) .undocumented("No-op, soon to be removed")) .add(attr(":extra_proguard_specs", LABEL_LIST).value(JavaSemantics.EXTRA_PROGUARD_SPECS)) + .add(attr(":bytecode_optimizers", LABEL_LIST) + .cfg(HOST).value(JavaSemantics.BYTECODE_OPTIMIZERS)) .add(attr("rewrite_dexes_with_rex", BOOLEAN).value(false).undocumented("experimental")) /* File to be used as a package map for Rex tool that keeps the assignment of classes to diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java index c572dc0590..748258cd56 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java @@ -15,7 +15,9 @@ package com.google.devtools.build.lib.rules.java; import static com.google.common.base.Preconditions.checkArgument; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment; import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode; @@ -31,6 +33,7 @@ import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; import com.google.devtools.common.options.TriState; import java.util.List; +import java.util.Map; import javax.annotation.Nullable; /** A java compiler configuration containing the flags required for compilation. */ @@ -141,6 +144,7 @@ public final class JavaConfiguration extends Fragment { private final TriState bundleTranslations; private final ImmutableList<Label> translationTargets; private final JavaOptimizationMode javaOptimizationMode; + private final ImmutableMap<String, Optional<Label>> bytecodeOptimizers; private final Label javaToolchain; // TODO(dmarting): remove once we have a proper solution for #2539 @@ -185,6 +189,16 @@ public final class JavaConfiguration extends Fragment { } } this.translationTargets = translationsBuilder.build(); + + ImmutableMap.Builder<String, Optional<Label>> optimizersBuilder = ImmutableMap.builder(); + for (Map.Entry<String, Label> optimizer : javaOptions.bytecodeOptimizers.entrySet()) { + String mnemonic = optimizer.getKey(); + if (optimizer.getValue() == null && !"Proguard".equals(mnemonic)) { + throw new InvalidConfigurationException("Must supply label for optimizer " + mnemonic); + } + optimizersBuilder.put(mnemonic, Optional.fromNullable(optimizer.getValue())); + } + this.bytecodeOptimizers = optimizersBuilder.build(); } @SkylarkCallable(name = "default_javac_flags", structField = true, @@ -327,6 +341,13 @@ public final class JavaConfiguration extends Fragment { } /** + * Returns ordered list of optimizers to run. + */ + public ImmutableMap<String, Optional<Label>> getBytecodeOptimizers() { + return bytecodeOptimizers; + } + + /** * Returns true if java_test in Bazel should behave in legacy mode that existed before we * open-sourced our test runner. */ diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java index a7b7086ee8..b489c21022 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfiguration.LabelConverter; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration.LabelMapConverter; import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsConverter; import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode; import com.google.devtools.build.lib.analysis.config.DefaultsPackage; @@ -270,6 +271,18 @@ public class JavaOptions extends FragmentOptions { + "using this option only has an effect when Proguard is used anyway.") public List<Label> extraProguardSpecs; + /** + * Comma-separated list of Mnemonic=label pairs of optimizers to run in the given order, treating + * {@code Proguard} specially by substituting in the relevant Proguard binary automatically. + * All optimizers must understand the same flags as Proguard. + */ + @Option(name = "experimental_bytecode_optimizers", + defaultValue = "Proguard", + converter = LabelMapConverter.class, + category = "undocumented", + help = "Do not use.") + public Map<String, Label> bytecodeOptimizers; + @Option(name = "translations", defaultValue = "auto", category = "semantics", diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java index 9c3d443119..77cdbbe8ad 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java @@ -15,8 +15,10 @@ package com.google.devtools.build.lib.rules.java; import static com.google.devtools.build.lib.packages.BuildType.LABEL; +import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; @@ -38,6 +40,7 @@ import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplic import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression; import com.google.devtools.build.lib.rules.java.JavaCompilationArgs.ClasspathType; +import com.google.devtools.build.lib.rules.java.JavaConfiguration.JavaOptimizationMode; import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider; import com.google.devtools.build.lib.util.FileType; import com.google.devtools.build.lib.vfs.PathFragment; @@ -200,6 +203,29 @@ public interface JavaSemantics { } }; + LateBoundLabelList<BuildConfiguration> BYTECODE_OPTIMIZERS = + new LateBoundLabelList<BuildConfiguration>(JavaConfiguration.class) { + @Override + public List<Label> resolve( + Rule rule, AttributeMap attributes, BuildConfiguration configuration) { + // Use a modicum of smarts to avoid implicit dependencies where we don't need them. + JavaOptimizationMode optMode = + configuration.getFragment(JavaConfiguration.class).getJavaOptimizationMode(); + boolean hasProguardSpecs = attributes.has("proguard_specs") + && !attributes.get("proguard_specs", LABEL_LIST).isEmpty(); + if (optMode == JavaOptimizationMode.NOOP + || (optMode == JavaOptimizationMode.LEGACY && !hasProguardSpecs)) { + return ImmutableList.<Label>of(); + } + return ImmutableList.copyOf( + Optional.presentInstances( + configuration + .getFragment(JavaConfiguration.class) + .getBytecodeOptimizers() + .values())); + } + }; + String IJAR_LABEL = "//tools/defaults:ijar"; /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java index 49c13824ac..b6445e304f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java @@ -14,8 +14,10 @@ package com.google.devtools.build.lib.rules.java; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import com.google.common.base.Joiner; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedSet; @@ -24,15 +26,18 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.actions.FileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction.Builder; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.AttributeMap; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.rules.java.JavaConfiguration.JavaOptimizationMode; import com.google.devtools.build.lib.syntax.Type; +import java.util.Map; import javax.annotation.Nullable; /** @@ -186,7 +191,7 @@ public abstract class ProguardHelper { proguardOutputMap = ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_PROGUARD_MAP); } - return createProguardAction( + return createOptimizationActions( ruleContext, proguard, singleJar, @@ -364,15 +369,13 @@ public abstract class ProguardHelper { * @param proguardSpecs Proguard specification files to pass to Proguard * @param proguardMapping optional mapping file for Proguard to apply * @param libraryJars any other Jar files that the {@code programJar} will run against - * @param mappingRequested whether to ask Proguard to output a mapping file (a mapping will be - * produced anyway if --java_optimization_mode includes obfuscation) * @param optimizationPasses if not null specifies to break proguard up into multiple passes with * the given number of optimization passes. * @param proguardOutputMap mapping generated by Proguard if requested. could be null. * @param useSingleJarForProguardLibraryJars whether to combine all library jars into a single jar * file before processing with Proguard */ - public static ProguardOutput createProguardAction(RuleContext ruleContext, + public static ProguardOutput createOptimizationActions(RuleContext ruleContext, FilesToRunProvider proguard, Artifact programJar, ImmutableList<Artifact> proguardSpecs, @@ -409,7 +412,7 @@ public abstract class ProguardHelper { if (optimizationPasses == null) { // Run proguard as a single step. - Builder builder = makeBuilder( + SpawnAction.Builder builder = defaultAction( proguard, programJar, proguardSpecs, @@ -431,7 +434,7 @@ public abstract class ProguardHelper { Artifact lastStageOutput = getProguardTempArtifact( ruleContext, optMode.name().toLowerCase(), "proguard_preoptimization.jar"); ruleContext.registerAction( - makeBuilder( + defaultAction( proguard, programJar, proguardSpecs, @@ -450,34 +453,55 @@ public abstract class ProguardHelper { .addOutputArgument(lastStageOutput) .build(ruleContext)); - for (int i = 0; i < optimizationPasses; i++) { - Artifact optimizationOutput = getProguardTempArtifact( - ruleContext, optMode.name().toLowerCase(), "proguard_optimization_" + (i + 1) + ".jar"); - ruleContext.registerAction( - makeBuilder( - proguard, - programJar, - proguardSpecs, - proguardMapping, - libraryJars, - output.getOutputJar(), - /* proguardOutputMap */ null, - /* proguardOutputProtoMap */ null, - /* proguardSeeds */ null, - /* proguardUsage */ null, - /* constantStringObfuscatedMapping */ null, - /* proguardConfigOutput */ null) - .setProgressMessage("Trimming binary with Proguard: Optimization Pass " + (i + 1)) - .addArgument("-runtype OPTIMIZATION") - .addArgument("-laststageoutput") - .addInputArgument(lastStageOutput) - .addArgument("-nextstageoutput") - .addOutputArgument(optimizationOutput) - .build(ruleContext)); - lastStageOutput = optimizationOutput; + for (int i = 1; i <= optimizationPasses; i++) { + // Run configured optimizers in order in each pass + for (Map.Entry<String, Optional<Label>> optimizer : + getBytecodeOptimizers(ruleContext).entrySet()) { + String mnemonic = optimizer.getKey(); + Optional<Label> target = optimizer.getValue(); + FilesToRunProvider executable = null; + if (target.isPresent()) { + for (TransitiveInfoCollection optimizerDep : + ruleContext.getPrerequisites(":bytecode_optimizers", Mode.HOST)) { + if (optimizerDep.getLabel().equals(target.get())) { + executable = optimizerDep.getProvider(FilesToRunProvider.class); + break; + } + } + } else { + checkState("Proguard".equals(mnemonic), "Need label to run %s", mnemonic); + executable = proguard; + } + Artifact optimizationOutput = getProguardTempArtifact( + ruleContext, optMode.name().toLowerCase(), mnemonic + "_optimization_" + i + ".jar"); + ruleContext.registerAction( + defaultAction( + checkNotNull(executable, "couldn't find optimizer %s", optimizer), + programJar, + proguardSpecs, + proguardMapping, + libraryJars, + output.getOutputJar(), + /* proguardOutputMap */ null, + /* proguardOutputProtoMap */ null, + /* proguardSeeds */ null, + /* proguardUsage */ null, + /* constantStringObfuscatedMapping */ null, + /* proguardConfigOutput */ null) + .setProgressMessage( + "Trimming binary with " + mnemonic + ": Optimization Pass " + i) + .setMnemonic(mnemonic) + .addArgument("-runtype OPTIMIZATION") + .addArgument("-laststageoutput") + .addInputArgument(lastStageOutput) + .addArgument("-nextstageoutput") + .addOutputArgument(optimizationOutput) + .build(ruleContext)); + lastStageOutput = optimizationOutput; + } } - Builder builder = makeBuilder( + SpawnAction.Builder builder = defaultAction( proguard, programJar, proguardSpecs, @@ -502,8 +526,8 @@ public abstract class ProguardHelper { return output; } - private static Builder makeBuilder( - FilesToRunProvider proguard, + private static SpawnAction.Builder defaultAction( + FilesToRunProvider executable, Artifact programJar, ImmutableList<Artifact> proguardSpecs, @Nullable Artifact proguardMapping, @@ -519,7 +543,7 @@ public abstract class ProguardHelper { Builder builder = new SpawnAction.Builder() .addInputs(libraryJars) .addInputs(proguardSpecs) - .setExecutable(proguard) + .setExecutable(executable) .setMnemonic("Proguard") .addArgument("-forceprocessing") .addArgument("-injars") @@ -611,4 +635,9 @@ public abstract class ProguardHelper { return ruleContext.getConfiguration().getFragment(JavaConfiguration.class) .getJavaOptimizationMode(); } + + private static Map<String, Optional<Label>> getBytecodeOptimizers(RuleContext ruleContext) { + return ruleContext.getConfiguration().getFragment(JavaConfiguration.class) + .getBytecodeOptimizers(); + } } |