undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,61 @@
# Javac microbenchmarks
The Javac Microbenchmarks is a collection of microbenchmarks for measuring
the performance of Javac API using the
[JMH](http://openjdk.java.net/projects/code-tools/jmh/) framework.
## Building and running the project
Currently, the project can be built and run with JDK 9 and later. This is
a Maven project and is built by:
$ mvn clean install
After building, the executable jar is target/micros-javac-[version].jar.
Run the benchmarks with:
$ java -jar target/micros-javac-*.jar [optional jmh parameters]
See the entire list of benchmarks using:
$ java -jar target/micros-javacs-*.jar -l [optional regex to select benchmarks]
For example:
$ java -jar target/micros-javac-1.0-SNAPSHOT.jar -l
Benchmarks:
org.openjdk.bench.langtools.javac.GroupJavacBenchmark.coldGroup
org.openjdk.bench.langtools.javac.GroupJavacBenchmark.hotGroup
org.openjdk.bench.langtools.javac.SingleJavacBenchmark.compileCold
org.openjdk.bench.langtools.javac.SingleJavacBenchmark.compileHot
And the same regex syntax works to run some test:
$ java -jar target/micros-javac-1.0-SNAPSHOT.jar SingleJavacBenchmark.compileHot
## Troubleshooting
### Build of micros-javac module got stuck
If you build got stuck on `[get] Getting: https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip` then you are probably experiencing some networking or web proxy obstacles.
One solution is to download required reference JDK from [https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip](https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip) manually and then build the project with property pointing to the local copy:
$ mvn clean install -Djavac.benchmark.openjdk.zip.download.url=file:///<your download location>/openjdk-11+28_windows-x64_bin.zip
Note: Please use `openjdk-11+28_windows-x64_bin.zip` to build the project no matter what target platform is.
Another solution might be to add proxy settings:
$ mvn -Dhttps.proxyHost=... -Dhttps.proxyPort=... clean install
### Execution of micros-javac benchmarks takes several hours
micros-javac benchmarks consist of two sets of benchmarks:
* `SingleJavacBenchmark` (which is parametrized) measures each single javac compilation stage in an isolated run. This benchmark is designed for exact automated performance regression testing and it takes several hours to execute completely.
* `GroupJavacBenchmark` is grouping the measurements of all javac compilation stages into one run and its execution should take less than 30 minutes on a regular developers computer.
Solution to speed up javac benchmarking is to select only `GroupJavacBenchmark` for execution using following command line:
$ java -jar target/micros-javac-1.0-SNAPSHOT.jar .*GroupJavacBenchmark.*

View file

@ -0,0 +1,145 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 only, as
published by the Free Software Foundation.
This code is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
version 2 for more details (a copy is included in the LICENSE file that
accompanied this code).
You should have received a copy of the GNU General Public License version
2 along with this work; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
or visit www.oracle.com if you need additional information or have any
questions.
-->
<modelVersion>4.0.0</modelVersion>
<groupId>org.openjdk</groupId>
<artifactId>micros-javac</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>OpenJDK Microbenchmark of Java Compile</name>
<properties>
<!--
the code below is being compiled with source 25, see JDK-8372023,
if the source version being compiled changes to 26 or 26+, then
some adjustments will be needed at:
test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/JavacBenchmark.java
-->
<javac.benchmark.openjdk.zip.download.url>https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip</javac.benchmark.openjdk.zip.download.url>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jmh.version>1.36</jmh.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/BenchmarkList</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/CompilerHints</resource>
</transformer>
</transformers>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.1.1</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.4</version>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>process-resources</phase>
<configuration>
<target>
<mkdir dir="${project.build.outputDirectory}"/>
<get src="${javac.benchmark.openjdk.zip.download.url}" dest="${project.build.directory}/jdk-bin.zip" skipexisting="true" verbose="true"/>
<unzip src="${project.build.directory}/jdk-bin.zip" dest="${project.build.outputDirectory}">
<patternset>
<include name="*/lib/src.zip"/>
<include name="*/release"/>
</patternset>
<mapper type="flatten"/>
</unzip>
<loadfile srcFile="${project.build.outputDirectory}/release" property="release.info"/>
<echo>
-------------------------------------------------
Bundling JDK sources with following release info:
-------------------------------------------------
${release.info}
-------------------------------------------------
</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,231 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.langtools.javac;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Group;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
@State(Scope.Benchmark)
public class GroupJavacBenchmark extends JavacBenchmark {
public static final String COLD_GROUP_NAME = "coldGroup";
public static final int COLD_ITERATION_WARMUPS = 0;
public static final int COLD_ITERATIONS = 1;
public static final int COLD_FORK_WARMUPS = 1;
public static final int COLD_FORKS = 15;
public static final String HOT_GROUP_NAME = "hotGroup";
public static final int HOT_ITERATION_WARMUPS = 8;
public static final int HOT_ITERATIONS = 10;
public static final int HOT_FORK_WARMUPS = 0;
public static final int HOT_FORKS = 1;
@Benchmark
@Group(COLD_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = COLD_ITERATION_WARMUPS)
@Measurement(iterations = COLD_ITERATIONS)
@Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void cold1_Init() throws InterruptedException {
Stage.Init.waitFor();
}
@Benchmark
@Group(COLD_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = COLD_ITERATION_WARMUPS)
@Measurement(iterations = COLD_ITERATIONS)
@Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void cold2_Parse() throws InterruptedException {
Stage.Parse.waitFor();
}
@Benchmark
@Group(COLD_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = COLD_ITERATION_WARMUPS)
@Measurement(iterations = COLD_ITERATIONS)
@Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void cold3_InitModules() throws InterruptedException {
Stage.InitModules.waitFor();
}
@Benchmark
@Group(COLD_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = COLD_ITERATION_WARMUPS)
@Measurement(iterations = COLD_ITERATIONS)
@Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void cold4_Enter() throws InterruptedException {
Stage.Enter.waitFor();
}
@Benchmark
@Group(COLD_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = COLD_ITERATION_WARMUPS)
@Measurement(iterations = COLD_ITERATIONS)
@Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void cold5_Attribute() throws InterruptedException {
Stage.Attribute.waitFor();
}
@Benchmark
@Group(COLD_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = COLD_ITERATION_WARMUPS)
@Measurement(iterations = COLD_ITERATIONS)
@Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void cold6_Flow() throws InterruptedException {
Stage.Flow.waitFor();
}
@Benchmark
@Group(COLD_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = COLD_ITERATION_WARMUPS)
@Measurement(iterations = COLD_ITERATIONS)
@Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void cold7_Desugar() throws InterruptedException {
Stage.Desugar.waitFor();
}
@Benchmark
@Group(COLD_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = COLD_ITERATION_WARMUPS)
@Measurement(iterations = COLD_ITERATIONS)
@Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void cold8_Generate(Blackhole bh) throws IOException {
compile(bh, Stage.Generate);
}
@Benchmark
@Group(HOT_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = HOT_ITERATION_WARMUPS)
@Measurement(iterations = HOT_ITERATIONS)
@Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void hot1_Init() throws InterruptedException {
Stage.Init.waitFor();
}
@Benchmark
@Group(HOT_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = HOT_ITERATION_WARMUPS)
@Measurement(iterations = HOT_ITERATIONS)
@Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void hot2_Parse() throws InterruptedException {
Stage.Parse.waitFor();
}
@Benchmark
@Group(HOT_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = HOT_ITERATION_WARMUPS)
@Measurement(iterations = HOT_ITERATIONS)
@Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void hot3_InitModules() throws InterruptedException {
Stage.InitModules.waitFor();
}
@Benchmark
@Group(HOT_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = HOT_ITERATION_WARMUPS)
@Measurement(iterations = HOT_ITERATIONS)
@Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void hot4_Enter() throws InterruptedException {
Stage.Enter.waitFor();
}
@Benchmark
@Group(HOT_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = HOT_ITERATION_WARMUPS)
@Measurement(iterations = HOT_ITERATIONS)
@Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void hot5_Attribute() throws InterruptedException {
Stage.Attribute.waitFor();
}
@Benchmark
@Group(HOT_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = HOT_ITERATION_WARMUPS)
@Measurement(iterations = HOT_ITERATIONS)
@Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void hot6_Flow() throws InterruptedException {
Stage.Flow.waitFor();
}
@Benchmark
@Group(HOT_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = HOT_ITERATION_WARMUPS)
@Measurement(iterations = HOT_ITERATIONS)
@Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void hot7_Desugar() throws InterruptedException {
Stage.Desugar.waitFor();
}
@Benchmark
@Group(HOT_GROUP_NAME)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = HOT_ITERATION_WARMUPS)
@Measurement(iterations = HOT_ITERATIONS)
@Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void hot8_Generate(Blackhole bh) throws IOException {
compile(bh, Stage.Generate);
}
}

View file

@ -0,0 +1,198 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.langtools.javac;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Context.Factory;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Pair;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.Queue;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.CONFIG;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileObject;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.infra.Blackhole;
@State(Scope.Benchmark)
public class JavacBenchmark {
static final Logger LOG = Logger.getLogger(JavacBenchmark.class.getName());
public enum Stage {
Init, Parse, InitModules, Enter, Attribute, Flow, Desugar, Generate;
public synchronized void waitFor() throws InterruptedException {
wait();
}
public synchronized void notifyDone() {
notifyAll();
LOG.log(FINE, "{0} finished.", this.name());
}
public boolean isAfter(Stage other) {
return ordinal() > other.ordinal();
}
}
private Path root;
private Path srcList;
@Setup(Level.Trial)
public void setup(Blackhole bh) throws IOException, InterruptedException {
LOG.log(CONFIG, "Release info of the sources to be compiled by the benchmark:\n{0}", new String(JavacBenchmark.class.getResourceAsStream("/release").readAllBytes(), StandardCharsets.UTF_8));
root = Files.createTempDirectory("JavacBenchmarkRoot");
srcList = root.resolve("sources.list");
int i = 0;
try (PrintStream srcListOut = new PrintStream(srcList.toFile())) {
try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(JavacBenchmark.class.getResourceAsStream("/src.zip")))) {
for (ZipEntry entry; (entry = zis.getNextEntry()) != null;) {
final String ename = entry.getName();
if (!ename.startsWith("java.desktop") && !ename.startsWith("jdk.internal.vm.compiler") && !ename.startsWith("jdk.aot") && !ename.startsWith("jdk.accessibility") && !ename.startsWith("jdk.jsobject")) {
if (!entry.isDirectory() && ename.endsWith(".java")) {
Path dst = root.resolve(ename);
Files.createDirectories(dst.getParent());
Files.copy(zis, dst);
Files.readAllBytes(dst); //reads all the file back to exclude antivirus scanning time from following measurements
srcListOut.println(dst.toString());
i++;
}
}
}
}
}
Files.walk(root).map(Path::toFile).forEach(File::deleteOnExit); //mark all files and folders for deletion on JVM exit for cases when tearDown is not executed
Thread.sleep(10000); //give some more time for the system to catch a breath for more precise measurement
LOG.log(FINE, "Extracted {0} sources.", i);
}
@TearDown(Level.Trial)
public void tearDown() throws IOException {
Files.walk(root).sorted(Comparator.reverseOrder()).map(Path::toFile).forEachOrdered(File::delete);
LOG.fine("Sources deleted.");
}
protected void compile(Blackhole bh, final Stage stopAt) throws IOException {
final OutputStream bhos = new OutputStream() {
@Override
public void write(int b) throws IOException {
bh.consume(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
bh.consume(b);
}
};
final Context ctx = new Context();
//inject JavaCompiler wrapping all measured methods so they directly report to the benchmark
ctx.put(JavaCompiler.compilerKey, (Factory<JavaCompiler>)(c) -> {
return new JavaCompiler(c) {
@Override
public List<JCTree.JCCompilationUnit> parseFiles(Iterable<JavaFileObject> fileObjects) {
Stage.Init.notifyDone();
return stopAt.isAfter(Stage.Init) ? super.parseFiles(fileObjects) : List.nil();
}
@Override
public List<JCTree.JCCompilationUnit> initModules(List<JCTree.JCCompilationUnit> roots) {
Stage.Parse.notifyDone();
return stopAt.isAfter(Stage.Parse) ? super.initModules(roots) : List.nil();
}
@Override
public List<JCTree.JCCompilationUnit> enterTrees(List<JCTree.JCCompilationUnit> roots) {
Stage.InitModules.notifyDone();
return stopAt.isAfter(Stage.InitModules) ? super.enterTrees(roots) : List.nil();
}
@Override
public Queue<Env<AttrContext>> attribute(Queue<Env<AttrContext>> envs) {
Stage.Enter.notifyDone();
return stopAt.isAfter(Stage.Enter) ? super.attribute(envs) : new ListBuffer<>();
}
@Override
public Queue<Env<AttrContext>> flow(Queue<Env<AttrContext>> envs) {
Stage.Attribute.notifyDone();
return stopAt.isAfter(Stage.Attribute) ? super.flow(envs) : new ListBuffer<>();
}
@Override
public Queue<Pair<Env<AttrContext>, JCTree.JCClassDecl>> desugar(Queue<Env<AttrContext>> envs) {
Stage.Flow.notifyDone();
return stopAt.isAfter(Stage.Flow) ? super.desugar(envs) : new ListBuffer<>();
}
@Override
public void generate(Queue<Pair<Env<AttrContext>, JCTree.JCClassDecl>> queue) {
Stage.Desugar.notifyDone();
if (stopAt.isAfter(Stage.Desugar)) super.generate(queue);
}
};
});
//JavaFileManager directing all writes to a Blackhole to avoid measurement fluctuations due to delayed filesystem writes
try (JavacFileManager mngr = new JavacFileManager(ctx, true, null) {
@Override
public JavaFileObject getJavaFileForOutput(JavaFileManager.Location arg0, String arg1, JavaFileObject.Kind arg2, FileObject arg3) throws IOException {
return new ForwardingJavaFileObject<JavaFileObject>(super.getJavaFileForOutput(arg0, arg1, arg2, arg3)) {
@Override
public OutputStream openOutputStream() throws IOException {
return bhos;
}
};
}
}) {
String[] cmdLine = new String[] {"-source", "25", "-XDcompilePolicy=simple", "-implicit:none", "-nowarn", "--module-source-path", root.toString(), "-d", root.toString(), "-XDignore.symbol.file=true", "@" + srcList.toString()};
if (new Main("javac").compile(cmdLine, ctx).exitCode != 0) {
throw new IOException("compilation failed");
}
}
LOG.fine("Compilation finished.");
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.langtools.javac;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
@State(Scope.Benchmark)
public class SingleJavacBenchmark extends JavacBenchmark {
@Param
public Stage stopStage;
@Benchmark
@Threads(1)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = 0)
@Measurement(iterations = 1)
@Fork(warmups = 1, value = 15, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void compileCold(Blackhole bh) throws IOException {
compile(bh, stopStage);
}
@Benchmark
@Threads(1)
@BenchmarkMode(Mode.SingleShotTime)
@Warmup(iterations = 8)
@Measurement(iterations = 10)
@Fork(warmups = 0, value = 1, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" })
@OutputTimeUnit(TimeUnit.SECONDS)
public void compileHot(Blackhole bh) throws IOException {
compile(bh, stopStage);
}
}