From 76fac817e4dbe5aaece9ed6a962e1cc94815d4d6 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 14 Apr 2022 11:40:13 -0700 Subject: [PATCH] Add Blaze support for "local" optimization of individual Java libraries. This should allow optimization on a per-library level within Blaze of every artifact generated by javac. The purpose of this is for improved test coverage by the AppReduce team and is not intended for general use. See this thread for more context: [] This change should only add a dependency on the bytecode optimizer when --experimental_local_java_optimizations is true, so it should be a no-op for all standard builds. I implemented this in Java instead of Starlark because it allowed me to modify the produced JavaInfo much more simply. If this was implemented in Starlark, I'd have to be able to replace the JavaInfo object produced by a java_* target since the JavaInfo from javac is currently all still wired up in Java. My attempts at structuring the change that way seemed much more invasive to JavaInfo and more brittle. PiperOrigin-RevId: 441814811 --- .../lib/rules/java/JavaCompilationHelper.java | 70 +++++++++++++++++-- .../lib/rules/java/JavaConfiguration.java | 25 ++++++- .../build/lib/rules/java/JavaOptions.java | 25 +++++++ .../build/lib/rules/java/JavaSemantics.java | 15 +++- .../build/lib/rules/java/JavaToolchain.java | 8 +++ .../lib/rules/java/JavaToolchainProvider.java | 19 +++++ .../lib/rules/java/JavaToolchainRule.java | 9 +++ 7 files changed, 163 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java index a4906dc62152f8..7f94317e74677e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java @@ -270,6 +270,20 @@ && getJavaConfiguration().experimentalEnableJspecify() createResourceJarAction(originalOutput, ImmutableList.copyOf(resourceJars)); } + Artifact optimizedJar = null; + if (getJavaConfiguration().runLocalJavaOptimizations()) { + optimizedJar = outputs.output(); + outputs = + outputs.withOutput( + ruleContext.getDerivedArtifact( + FileSystemUtils.replaceExtension( + outputs + .output() + .getOutputDirRelativePath(getConfiguration().isSiblingRepositoryLayout()), + "-pre-optimization.jar"), + outputs.output().getRoot())); + } + ImmutableList javacopts = customJavacOpts; if (jspecify) { plugins = @@ -294,12 +308,13 @@ && getJavaConfiguration().experimentalEnableJspecify() builder.setCoverageArtifact(coverageArtifact); BootClassPathInfo bootClassPathInfo = getBootclasspathOrDefault(); builder.setBootClassPath(bootClassPathInfo); + NestedSet classpath = + NestedSetBuilder.naiveLinkOrder() + .addTransitive(bootClassPathInfo.auxiliary()) + .addTransitive(attributes.getCompileTimeClassPath()) + .build(); if (!bootClassPathInfo.auxiliary().isEmpty()) { - builder.setClasspathEntries( - NestedSetBuilder.naiveLinkOrder() - .addTransitive(bootClassPathInfo.auxiliary()) - .addTransitive(attributes.getCompileTimeClassPath()) - .build()); + builder.setClasspathEntries(classpath); builder.setDirectJars( NestedSetBuilder.naiveLinkOrder() .addTransitive(bootClassPathInfo.auxiliary()) @@ -355,6 +370,20 @@ && getJavaConfiguration().experimentalEnableJspecify() JavaCompileAction javaCompileAction = builder.build(); ruleContext.getAnalysisEnvironment().registerAction(javaCompileAction); + + if (optimizedJar != null) { + JavaConfiguration.NamedLabel optimizerLabel = getJavaConfiguration().getBytecodeOptimizer(); + createLocalOptimizationAction( + outputs.output(), + optimizedJar, + NestedSetBuilder.naiveLinkOrder() + .addTransitive(bootClassPathInfo.bootclasspath()) + .addTransitive(classpath) + .build(), + javaToolchain.getLocalJavaOptimizationConfiguration(), + javaToolchain.getBytecodeOptimizer().tool(), + optimizerLabel.name()); + } } /** @@ -705,6 +734,37 @@ public Artifact createCompileTimeJarAction( return jar; } + public void createLocalOptimizationAction( + Artifact unoptimizedOutputJar, + Artifact optimizedOutputJar, + NestedSet classpath, + List configs, + FilesToRunProvider optimizer, + String mnemonic) { + CustomCommandLine.Builder command = + CustomCommandLine.builder() + .add("-runtype", "LOCAL_ONLY") + .addExecPath("-injars", unoptimizedOutputJar) + .addExecPath("-outjars", optimizedOutputJar) + .addExecPaths("-libraryjars", CustomCommandLine.VectorArg.join(":").each(classpath)); + for (Artifact config : configs) { + command.addPrefixedExecPath("@", config); + } + + getRuleContext() + .registerAction( + new SpawnAction.Builder() + .addInput(unoptimizedOutputJar) + .addTransitiveInputs(classpath) + .addInputs(configs) + .addOutput(optimizedOutputJar) + .setExecutable(optimizer) + .addCommandLine(command.build()) + .setProgressMessage("Optimizing jar %{label}") + .setMnemonic(mnemonic) + .build(getRuleContext())); + } + private void addArgsAndJarsToAttributes( JavaCompilationArgsProvider args, NestedSet directJars) { // Can only be non-null when isStrict() returns true. 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 0543e88b0a8e17..57020b7d1ee1c1 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 @@ -91,6 +91,8 @@ public enum ImportDepsCheckingLevel { private final Label proguardBinary; private final ImmutableList