Skip to content

Commit 38baaa9

Browse files
author
Satyen Subramaniam
committed
8339366: [jittester] Make it possible to generate tests without execution
Backport-of: 559fc711e03cf0086bea399ffb40cf294cbbb6e1
1 parent da23377 commit 38baaa9

File tree

7 files changed

+188
-80
lines changed

7 files changed

+188
-80
lines changed

test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/Automatic.java

Lines changed: 6 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,13 +23,6 @@
2323

2424
package jdk.test.lib.jittester;
2525

26-
import jdk.test.lib.util.Pair;
27-
import jdk.test.lib.jittester.factories.IRNodeBuilder;
28-
import jdk.test.lib.jittester.types.TypeKlass;
29-
import jdk.test.lib.jittester.utils.FixedTrees;
30-
import jdk.test.lib.jittester.utils.OptionResolver;
31-
import jdk.test.lib.jittester.utils.OptionResolver.Option;
32-
import jdk.test.lib.jittester.utils.PseudoRandom;
3326
import java.time.LocalTime;
3427
import java.util.ArrayList;
3528
import java.util.List;
@@ -39,57 +32,6 @@
3932
public class Automatic {
4033
public static final int MINUTES_TO_WAIT = Integer.getInteger("jdk.test.lib.jittester", 3);
4134

42-
private static Pair<IRNode, IRNode> generateIRTree(String name) {
43-
ProductionLimiter.resetTimer();
44-
SymbolTable.removeAll();
45-
TypeList.removeAll();
46-
47-
IRNodeBuilder builder = new IRNodeBuilder()
48-
.setPrefix(name)
49-
.setName(name)
50-
.setLevel(0);
51-
52-
Long complexityLimit = ProductionParams.complexityLimit.value();
53-
IRNode privateClasses = null;
54-
if (!ProductionParams.disableClasses.value()) {
55-
long privateClassComlexity = (long) (complexityLimit * PseudoRandom.random());
56-
try {
57-
privateClasses = builder.setComplexityLimit(privateClassComlexity)
58-
.getClassDefinitionBlockFactory()
59-
.produce();
60-
} catch (ProductionFailedException ex) {
61-
ex.printStackTrace(System.out);
62-
}
63-
}
64-
long mainClassComplexity = (long) (complexityLimit * PseudoRandom.random());
65-
IRNode mainClass = null;
66-
try {
67-
mainClass = builder.setComplexityLimit(mainClassComplexity)
68-
.getMainKlassFactory()
69-
.produce();
70-
TypeKlass aClass = new TypeKlass(name);
71-
mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, true));
72-
mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, false));
73-
} catch (ProductionFailedException ex) {
74-
ex.printStackTrace(System.out);
75-
}
76-
return new Pair<>(mainClass, privateClasses);
77-
}
78-
79-
private static void initializeTestGenerator(String[] params) {
80-
OptionResolver parser = new OptionResolver();
81-
Option<String> propertyFileOpt = parser.addStringOption('p', "property-file",
82-
"conf/default.properties", "File to read properties from");
83-
ProductionParams.register(parser);
84-
parser.parse(params, propertyFileOpt);
85-
PseudoRandom.reset(ProductionParams.seed.value());
86-
TypesParser.parseTypesAndMethods(ProductionParams.classesFile.value(),
87-
ProductionParams.excludeMethodsFile.value());
88-
if (ProductionParams.specificSeed.isSet()) {
89-
PseudoRandom.setCurrentSeed(ProductionParams.specificSeed.value());
90-
}
91-
}
92-
9335
private static List<TestsGenerator> getTestGenerators() {
9436
List<TestsGenerator> result = new ArrayList<>();
9537
Class<?> factoryClass;
@@ -109,7 +51,9 @@ private static List<TestsGenerator> getTestGenerators() {
10951
}
11052

11153
public static void main(String[] args) {
112-
initializeTestGenerator(args);
54+
ProductionParams.initializeFromCmdline(args);
55+
IRTreeGenerator.initializeWithProductionParams();
56+
11357
int counter = 0;
11458
System.out.printf("Generating %d tests...%n", ProductionParams.numberOfTests.value());
11559
System.out.printf(" %13s | %8s | %8s | %8s |%n", "start time", "count", "generat",
@@ -121,15 +65,15 @@ public static void main(String[] args) {
12165
try {
12266
System.out.print("[" + LocalTime.now() + "] |");
12367
String name = "Test_" + counter;
124-
Pair<IRNode, IRNode> irTree = generateIRTree(name);
68+
var test = IRTreeGenerator.generateIRTree(name);
12569
System.out.printf(" %8d |", counter);
12670
long maxWaitTime = TimeUnit.MINUTES.toMillis(MINUTES_TO_WAIT);
12771
double generationTime = System.currentTimeMillis() - start;
12872
System.out.printf(" %8.0f |", generationTime);
12973
start = System.currentTimeMillis();
13074
Thread generatorThread = new Thread(() -> {
13175
for (TestsGenerator generator : generators) {
132-
generator.accept(irTree.first, irTree.second);
76+
generator.accept(test);
13377
}
13478
});
13579
generatorThread.start();

test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ByteCodeGenerator.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -47,16 +47,17 @@ class ByteCodeGenerator extends TestsGenerator {
4747
}
4848

4949
@Override
50-
public void accept(IRNode mainClass, IRNode privateClasses) {
51-
generateClassFiles(mainClass, privateClasses);
52-
generateSeparateJtregHeader(mainClass);
50+
public void accept(IRTreeGenerator.Test test) {
51+
IRNode mainClass = test.mainClass();
52+
generateClassFiles(mainClass, test.privateClasses());
53+
generateSeparateJtregHeader(test.seed(), mainClass);
5354
compilePrinter();
5455
generateGoldenOut(mainClass.getName());
5556
}
5657

57-
private void generateSeparateJtregHeader(IRNode mainClass) {
58+
private void generateSeparateJtregHeader(long seed, IRNode mainClass) {
5859
String mainClassName = mainClass.getName();
59-
writeFile(generatorDir, mainClassName + ".java", getJtregHeader(mainClassName));
60+
writeFile(generatorDir, mainClassName + ".java", getJtregHeader(mainClassName, seed));
6061
}
6162

6263
private void generateClassFiles(IRNode mainClass, IRNode privateClasses) {
@@ -94,4 +95,17 @@ private void writeFile(String fileName, byte[] bytecode) {
9495
ex.printStackTrace();
9596
}
9697
}
98+
99+
public static void main(String[] args) throws Exception {
100+
ProductionParams.initializeFromCmdline(args);
101+
IRTreeGenerator.initializeWithProductionParams();
102+
103+
ByteCodeGenerator generator = new ByteCodeGenerator();
104+
105+
for (String mainClass : ProductionParams.mainClassNames.value()) {
106+
var test = IRTreeGenerator.generateIRTree(mainClass);
107+
generator.generateClassFiles(test.mainClass(), test.privateClasses());
108+
generator.generateSeparateJtregHeader(test.seed(), test.mainClass());
109+
}
110+
}
97111
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package jdk.test.lib.jittester;
25+
26+
import jdk.test.lib.jittester.factories.IRNodeBuilder;
27+
import jdk.test.lib.jittester.types.TypeKlass;
28+
import jdk.test.lib.jittester.utils.FixedTrees;
29+
import jdk.test.lib.jittester.utils.PseudoRandom;
30+
31+
/**
32+
* Generates IR trees for fuzzy test classes.
33+
*/
34+
public class IRTreeGenerator {
35+
36+
/**
37+
* Generated Test - main and private classes trees along with random seed used for generation.
38+
*/
39+
public record Test (long seed, IRNode mainClass, IRNode privateClasses) {};
40+
41+
/**
42+
* Generates IR trees for main and private classes.
43+
*
44+
* @param name main class name
45+
* @return a pair (main class; private classes)
46+
*/
47+
public static Test generateIRTree(String name) {
48+
long seed = PseudoRandom.getCurrentSeed();
49+
ProductionLimiter.resetTimer();
50+
//NB: SymbolTable is a widely-used singleton, hence all the locking.
51+
SymbolTable.removeAll();
52+
TypeList.removeAll();
53+
54+
IRNodeBuilder builder = new IRNodeBuilder()
55+
.setPrefix(name)
56+
.setName(name)
57+
.setLevel(0);
58+
59+
Long complexityLimit = ProductionParams.complexityLimit.value();
60+
IRNode privateClasses = null;
61+
if (!ProductionParams.disableClasses.value()) {
62+
long privateClassComlexity = (long) (complexityLimit * PseudoRandom.random());
63+
try {
64+
privateClasses = builder.setComplexityLimit(privateClassComlexity)
65+
.getClassDefinitionBlockFactory()
66+
.produce();
67+
} catch (ProductionFailedException ex) {
68+
ex.printStackTrace(System.out);
69+
}
70+
}
71+
long mainClassComplexity = (long) (complexityLimit * PseudoRandom.random());
72+
IRNode mainClass = null;
73+
try {
74+
mainClass = builder.setComplexityLimit(mainClassComplexity)
75+
.getMainKlassFactory()
76+
.produce();
77+
TypeKlass aClass = new TypeKlass(name);
78+
mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, true));
79+
mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, false));
80+
} catch (ProductionFailedException ex) {
81+
ex.printStackTrace(System.out);
82+
}
83+
return new Test(seed, mainClass, privateClasses);
84+
}
85+
86+
/**
87+
* Initializes the generator from ProductionParams static class.
88+
*/
89+
public static void initializeWithProductionParams() {
90+
TypesParser.parseTypesAndMethods(ProductionParams.classesFile.value(),
91+
ProductionParams.excludeMethodsFile.value());
92+
if (ProductionParams.specificSeed.isSet()) {
93+
PseudoRandom.setCurrentSeed(ProductionParams.specificSeed.value());
94+
}
95+
}
96+
97+
}

test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,20 @@ public class JavaCodeGenerator extends TestsGenerator {
4242
}
4343

4444
@Override
45-
public void accept(IRNode mainClass, IRNode privateClasses) {
45+
public void accept(IRTreeGenerator.Test test) {
46+
IRNode mainClass = test.mainClass();
4647
String mainClassName = mainClass.getName();
47-
generateSources(mainClass, privateClasses);
48+
generateSources(test.seed(), mainClass, test.privateClasses());
4849
compilePrinter();
4950
compileJavaFile(mainClassName);
5051
generateGoldenOut(mainClassName);
5152
}
5253

53-
private void generateSources(IRNode mainClass, IRNode privateClasses) {
54+
private void generateSources(long seed, IRNode mainClass, IRNode privateClasses) {
5455
String mainClassName = mainClass.getName();
5556
StringBuilder code = new StringBuilder();
5657
JavaCodeVisitor vis = new JavaCodeVisitor();
57-
code.append(getJtregHeader(mainClassName));
58+
code.append(getJtregHeader(mainClassName, seed));
5859
if (privateClasses != null) {
5960
code.append(privateClasses.accept(vis));
6061
}
@@ -79,7 +80,19 @@ private void compileJavaFile(String mainClassName) {
7980
}
8081
}
8182

82-
private static String[] generatePrerunAction(String mainClassName) {
83+
protected static String[] generatePrerunAction(String mainClassName) {
8384
return new String[] {"@compile " + mainClassName + ".java"};
8485
}
86+
87+
public static void main(String[] args) throws Exception {
88+
ProductionParams.initializeFromCmdline(args);
89+
IRTreeGenerator.initializeWithProductionParams();
90+
91+
JavaCodeGenerator generator = new JavaCodeGenerator();
92+
93+
for (String mainClass : ProductionParams.mainClassNames.value()) {
94+
var test = IRTreeGenerator.generateIRTree(mainClass);
95+
generator.generateSources(test.seed(), test.mainClass(), test.privateClasses());
96+
}
97+
}
8598
}

test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,15 @@
2323

2424
package jdk.test.lib.jittester;
2525

26+
import java.util.List;
27+
2628
import jdk.test.lib.jittester.utils.OptionResolver;
2729
import jdk.test.lib.jittester.utils.OptionResolver.Option;
30+
import jdk.test.lib.jittester.utils.PseudoRandom;
2831

2932
public class ProductionParams {
3033

34+
public static Option<List<String>> mainClassNames = null;
3135
public static Option<Integer> productionLimit = null;
3236
public static Option<Integer> productionLimitSeconds = null;
3337
public static Option<Integer> dataMemberLimit = null;
@@ -72,6 +76,7 @@ public class ProductionParams {
7276
// workaraound: to reduce chance throwing ArrayIndexOutOfBoundsException
7377
public static Option<Integer> chanceExpressionIndex = null;
7478
public static Option<String> testbaseDir = null;
79+
public static Option<String> tempDir = null;
7580
public static Option<Integer> numberOfTests = null;
7681
public static Option<String> seed = null;
7782
public static Option<Long> specificSeed = null;
@@ -81,6 +86,7 @@ public class ProductionParams {
8186
public static Option<String> generatorsFactories = null;
8287

8388
public static void register(OptionResolver optionResolver) {
89+
mainClassNames = optionResolver.addRepeatingOption('k', "main-class", "", "Main class name");
8490
productionLimit = optionResolver.addIntegerOption('l', "production-limit", 100, "Limit on steps in the production of an expression");
8591
productionLimitSeconds = optionResolver.addIntegerOption("production-limit-seconds", 600, "Limit the time a test generation may take");
8692
dataMemberLimit = optionResolver.addIntegerOption('v', "data-member-limit", 10, "Upper limit on data members");
@@ -124,6 +130,7 @@ public static void register(OptionResolver optionResolver) {
124130
enableFinalizers = optionResolver.addBooleanOption("enable-finalizers", "Enable finalizers (for stress testing)");
125131
chanceExpressionIndex = optionResolver.addIntegerOption("chance-expression-index", 0, "A non negative decimal integer used to restrict chane of generating expression in array index while creating or accessing by index");
126132
testbaseDir = optionResolver.addStringOption("testbase-dir", ".", "Testbase dir");
133+
tempDir = optionResolver.addStringOption("temp-dir", ".", "Temp dir path");
127134
numberOfTests = optionResolver.addIntegerOption('n', "number-of-tests", 0, "Number of test classes to generate");
128135
seed = optionResolver.addStringOption("seed", "", "Random seed");
129136
specificSeed = optionResolver.addLongOption('z', "specificSeed", 0L, "A seed to be set for specific test generation(regular seed still needed for initialization)");
@@ -132,4 +139,18 @@ public static void register(OptionResolver optionResolver) {
132139
generators = optionResolver.addStringOption("generators", "", "Comma-separated list of generator names");
133140
generatorsFactories = optionResolver.addStringOption("generatorsFactories", "", "Comma-separated list of generators factories class names");
134141
}
142+
143+
/**
144+
* Initializes from the given command-line args
145+
*
146+
* @param args command-line arguments to use for initialization
147+
*/
148+
public static void initializeFromCmdline(String[] args) {
149+
OptionResolver parser = new OptionResolver();
150+
Option<String> propertyFileOpt = parser.addStringOption('p', "property-file",
151+
"conf/default.properties", "File to read properties from");
152+
ProductionParams.register(parser);
153+
parser.parse(args, propertyFileOpt);
154+
PseudoRandom.reset(ProductionParams.seed.value());
155+
}
135156
}

test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,12 @@
3030
import java.nio.file.Path;
3131
import java.nio.file.Paths;
3232
import java.util.concurrent.TimeUnit;
33-
import java.util.function.BiConsumer;
33+
import java.util.function.Consumer;
3434
import java.util.function.Function;
3535
import java.util.stream.Collectors;
3636
import jdk.test.lib.jittester.types.TypeKlass;
37-
import jdk.test.lib.jittester.utils.PseudoRandom;
3837

39-
public abstract class TestsGenerator implements BiConsumer<IRNode, IRNode> {
38+
public abstract class TestsGenerator implements Consumer<IRTreeGenerator.Test> {
4039
private static final int DEFAULT_JTREG_TIMEOUT = 120;
4140
protected static final String JAVA_BIN = getJavaPath();
4241
protected static final String JAVAC = Paths.get(JAVA_BIN, "javac").toString();
@@ -121,9 +120,9 @@ protected static void ensureExisting(Path path) {
121120
}
122121
}
123122

124-
protected String getJtregHeader(String mainClassName) {
123+
protected String getJtregHeader(String mainClassName, long seed) {
125124
String synopsis = "seed = '" + ProductionParams.seed.value() + "'"
126-
+ ", specificSeed = '" + PseudoRandom.getCurrentSeed() + "'";
125+
+ ", specificSeed = '" + seed + "'";
127126
StringBuilder header = new StringBuilder();
128127
header.append("/*\n * @test\n * @summary ")
129128
.append(synopsis)

0 commit comments

Comments
 (0)