Skip to content

Commit

Permalink
8332340: Add JavacBench as a test case for CDS
Browse files Browse the repository at this point in the history
Backport-of: 7fd9d6c760c66d3e2f4034cf1a6b1b583ff829a9
  • Loading branch information
GoeLin committed Sep 16, 2024
1 parent 58cc0a2 commit 2e3ef5f
Show file tree
Hide file tree
Showing 4 changed files with 607 additions and 0 deletions.
76 changes: 76 additions & 0 deletions test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2023, 2024, 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.
*
*/

/*
* @test id=static
* @summary Run JavacBenchApp with the classic static archive workflow
* @requires vm.cds
* @library /test/lib
* @run driver JavacBench STATIC
*/

/*
* @test id=dynamic
* @summary Run JavacBenchApp with the classic dynamic archive workflow
* @requires vm.cds
* @library /test/lib
* @run driver JavacBench DYNAMIC
*/

import jdk.test.lib.cds.CDSAppTester;
import jdk.test.lib.helpers.ClassFileInstaller;

public class JavacBench {
static String mainClass = JavacBenchApp.class.getName();
static String appJar;

public static void main(String args[]) throws Exception {
appJar = ClassFileInstaller.writeJar("JavacBenchApp.jar",
"JavacBenchApp",
"JavacBenchApp$ClassFile",
"JavacBenchApp$FileManager",
"JavacBenchApp$SourceFile");
JavacBenchTester tester = new JavacBenchTester();
tester.run(args);
}

static class JavacBenchTester extends CDSAppTester {
public JavacBenchTester() {
super("JavacBench");
}

@Override
public String classpath(RunMode runMode) {
return appJar;
}

@Override
public String[] appCommandLine(RunMode runMode) {
return new String[] {
mainClass,
"90",
};
}
}
}
228 changes: 228 additions & 0 deletions test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBenchApp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/*
* Copyright (c) 2023, 2024, 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.
*
*/

import java.lang.invoke.MethodHandles;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;

/**
* This program tries to compile a large number of classes that exercise a fair amount of
* features in javac.
*/
public class JavacBenchApp {
static class ClassFile extends SimpleJavaFileObject {
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
protected ClassFile(String name) {
super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS);
}
@Override
public ByteArrayOutputStream openOutputStream() {
return this.baos;
}
byte[] toByteArray() {
return baos.toByteArray();
}
}

static class FileManager extends ForwardingJavaFileManager<JavaFileManager> {
private Map<String, ClassFile> classesMap = new HashMap<String, ClassFile>();
protected FileManager(JavaFileManager fileManager) {
super(fileManager);
}
@Override
public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) {
ClassFile classFile = new ClassFile(name);
classesMap.put(name, classFile);
return classFile;
}
public Map<String, byte[]> getCompiledClasses() {
Map<String, byte[]> result = new HashMap<>();
for (Map.Entry<String, ClassFile> entry : classesMap.entrySet()) {
result.put(entry.getKey(), entry.getValue().toByteArray());
}
return result;
}
}

static class SourceFile extends SimpleJavaFileObject {
private CharSequence sourceCode;
public SourceFile(String name, CharSequence sourceCode) {
super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.sourceCode = sourceCode;
}
@Override
public CharSequence getCharContent(boolean ignore) {
return this.sourceCode;
}
}

public Map<String, byte[]> compile() {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> ds = new DiagnosticCollector<>();
Collection<SourceFile> sourceFiles = sources;

try (FileManager fileManager = new FileManager(compiler.getStandardFileManager(ds, null, null))) {
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, sourceFiles);
if (task.call()) {
return fileManager.getCompiledClasses();
} else {
for (Diagnostic<? extends JavaFileObject> d : ds.getDiagnostics()) {
System.out.format("Line: %d, %s in %s", d.getLineNumber(), d.getMessage(null), d.getSource().getName());
}
throw new InternalError("compilation failure");
}
} catch (IOException e) {
throw new InternalError(e);
}
}

List<SourceFile> sources;

static final String imports = """
import java.lang.*;
import java.util.*;
""";

static final String testClassBody = """
// Some comments
static long x;
static final long y;
static {
y = System.currentTimeMillis();
}
/* More comments */
@Deprecated
String func() { return "String " + this + y; }
public static void main(String args[]) {
try {
x = Long.parseLong(args[0]);
} catch (Throwable t) {
t.printStackTrace();
}
doit(() -> {
System.out.println("Hello Lambda");
Thread.dumpStack();
});
}
static List<String> list = List.of("1", "2");
class InnerClass1 {
static final long yy = y;
}
static void doit(Runnable r) {
for (var x : list) {
r.run();
}
}
static String patternMatch(String arg, Object o) {
if (o instanceof String s) {
return "1234";
}
final String b = "B";
return switch (arg) {
case "A" -> "a";
case b -> "b";
default -> "c";
};
}
public sealed class SealedInnerClass {}
public final class Foo extends SealedInnerClass {}
enum Expression {
ADDITION,
SUBTRACTION,
MULTIPLICATION,
DIVISION
}
public record Point(int x, int y) {
public Point(int x) {
this(x, 0);
}
}
""";

String sanitySource = """
public class Sanity implements java.util.concurrent.Callable<String> {
public String call() {
return "this is a test";
}
}
""";

void setup(int count) {
sources = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
String source = imports + "public class Test" + i + " {" + testClassBody + "}";
sources.add(new SourceFile("Test" + i, source));
}

sources.add(new SourceFile("Sanity", sanitySource));
}

@SuppressWarnings("unchecked")
static void validate(byte[] sanityClassFile) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class<?> cls = lookup.defineClass(sanityClassFile);
Callable<String> obj = (Callable<String>)cls.getDeclaredConstructor().newInstance();
String s = obj.call();
if (!s.equals("this is a test")) {
throw new RuntimeException("Expected \"this is a test\", but got \"" + s + "\"");
}
}

public static void main(String args[]) throws Throwable {
long started = System.currentTimeMillis();
JavacBenchApp bench = new JavacBenchApp();

int count = 0;
if (args.length > 0) {
count = Integer.parseInt(args[0]);
if (count >= 0) {
bench.setup(count);
Map<String, byte[]> allClasses = bench.compile();
validate(allClasses.get("Sanity"));
}
}
if (System.getProperty("JavacBenchApp.silent") == null) {
// Set this property when running with "perf stat", etc
long elapsed = System.currentTimeMillis() - started;
System.out.println("Generated source code for " + bench.sources.size() + " classes and compiled them in " + elapsed + " ms");
}
}
}

63 changes: 63 additions & 0 deletions test/lib/jdk/test/lib/StringArrayUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2023, 2024, 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.
*/

package jdk.test.lib;

import java.util.ArrayList;

public class StringArrayUtils {
/**
* The various concat() functions in this class can be used for building
* a command-line argument array for ProcessTools.createTestJavaProcessBuilder(),
* etc. When some of the arguments are conditional, this is more convenient
* than alternatives like ArrayList.
*
* Example:
*
* <pre>
* String args[] = StringArrayUtils.concat("-Xint", "-Xmx32m");
* if (verbose) {
* args = StringArrayUtils.concat(args, "-verbose");
* }
* args = StringArrayUtils.concat(args, "HelloWorld");
* ProcessTools.createTestJavaProcessBuilder(args);
* </pre>
*/
public static String[] concat(String... args) {
return args;
}

public static String[] concat(String[] prefix, String... extra) {
String[] ret = new String[prefix.length + extra.length];
System.arraycopy(prefix, 0, ret, 0, prefix.length);
System.arraycopy(extra, 0, ret, prefix.length, extra.length);
return ret;
}

public static String[] concat(String prefix, String[] extra) {
String[] ret = new String[1 + extra.length];
ret[0] = prefix;
System.arraycopy(extra, 0, ret, 1, extra.length);
return ret;
}
}
Loading

1 comment on commit 2e3ef5f

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.