Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/StressClassLoadingTest.java
41161 views
1
/*
2
* Copyright (c) 2010, 2021, 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 vm.mlvm.anonloader.share;
25
26
import java.lang.invoke.MethodHandles;
27
import java.lang.invoke.MethodHandles.Lookup;
28
29
import java.io.File;
30
import java.util.Objects;
31
import java.util.concurrent.atomic.AtomicBoolean;
32
import java.nio.file.Files;
33
import java.nio.file.Path;
34
import java.nio.file.Paths;
35
import nsk.share.test.Stresser;
36
import vm.share.options.Option;
37
import vm.share.options.OptionSupport;
38
import vm.share.options.IgnoreUnknownArgumentsHandler;
39
import vm.mlvm.share.Env;
40
import vm.mlvm.share.MlvmTest;
41
import vm.mlvm.share.CustomClassLoaders;
42
import vm.share.FileUtils;
43
import vm.share.UnsafeAccess;
44
45
/**
46
* Does stress-testing of class loading subsystem.
47
* This class should be subclassed by the tests
48
* to provide test class data.
49
*
50
* <p>StressClassLoadingTest performs a number of iterations
51
* (the default value is 100 000).
52
* Each iteration gets class bytes from the subclass
53
* and loads it into JVM using either:
54
* <ul>
55
* <li>a custom {@link java.lang.ClassLoader} implementation or
56
* <li>{@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} call.
57
* </ul>
58
*
59
* <p>Loading is done in a separate thread. If this thread is stuck,
60
* it is killed after some timeout (default is 10 seconds, please see
61
* -parseTimeout option). The class file is saved as hangXX.class, where XX
62
* starts at 00 and is increased on every hangup.
63
* A prefix can be added to the file name using {@link #setFileNamePrefix}
64
*
65
* <p>The test fails, if there were hangups.
66
*
67
* <p>By default, before loading class, the bytes are
68
* saved to {@code _AnonkTestee01.class} file in the current directory.
69
* If JVM crashes, the bytecodes can be analysed.
70
* Class saving is controlled by -saveClassFile option.
71
* A prefix can be added to the file name using {@link #setFileNamePrefix}
72
* function.
73
*/
74
public abstract class StressClassLoadingTest extends MlvmTest {
75
private static final String RESCUE_FILE_NAME = "_AnonkTestee01.class";
76
private static final String HUNG_CLASS_FILE_NAME = "hang.class";
77
78
@Option(name = "iterations", default_value = "100000",
79
description = "How many times generate a class and parse it")
80
private static int iterations;
81
82
@Option(name = "saveClassFile", default_value = "true",
83
description = "Save generated class file before loading."
84
+ " Useful when VM crashes on loading")
85
private static boolean saveClassFile;
86
87
@Option(name = "parseTimeout", default_value = "10000",
88
description = "Timeout in millisectionds to detect hung parser"
89
+ " thread. The parser thread is killed after the timeout")
90
private static int parseTimeout;
91
92
@Option(name = "hiddenLoad", default_value = "false",
93
description = "An option for adhoc experiments: load class as a hidden class.")
94
private static boolean hiddenLoad;
95
96
private String fileNamePrefix = "";
97
98
private final static AtomicBoolean classFileMessagePrinted
99
= new AtomicBoolean(false);
100
101
/**
102
* Sets prefix for names of the files, created by test:
103
* _AnonkTestee01.class and hangXX.class.
104
*
105
* @param p a prefix to add before file name.
106
* @throws java.lang.NullPointerException if p is null
107
*/
108
public void setFileNamePrefix(String p) {
109
Objects.requireNonNull(p);
110
fileNamePrefix = p;
111
}
112
113
static volatile boolean optionsSetup = false;
114
public static void setupOptions(Object instance) {
115
if (!optionsSetup) {
116
synchronized (StressClassLoadingTest.class) {
117
if (!optionsSetup) {
118
OptionSupport.setup(instance, Env.getArgParser().getRawArguments(), new IgnoreUnknownArgumentsHandler());
119
optionsSetup = true;
120
121
Env.traceNormal("StressClassLoadingTest options: iterations: " + iterations);
122
Env.traceNormal("StressClassLoadingTest options: hiddenLoad: " + hiddenLoad);
123
Env.traceNormal("StressClassLoadingTest options: parseTimeout: " + parseTimeout);
124
Env.traceNormal("StressClassLoadingTest options: saveClassFile: " + saveClassFile);
125
}
126
}
127
}
128
}
129
130
public boolean run() throws Exception {
131
setupOptions(this);
132
133
Stresser stresser = createStresser();
134
stresser.start(iterations);
135
136
while (stresser.continueExecution()) {
137
stresser.iteration();
138
139
byte[] classBytes = generateClassBytes();
140
Class<?> hostClass = getHostClass();
141
String className = hostClass.getName();
142
File rescueFile = new File(String.format("%s_%d_%s",
143
fileNamePrefix, stresser.getIteration(), RESCUE_FILE_NAME));
144
if (saveClassFile) {
145
// Write out the class file being loaded. It's useful
146
// to have if the JVM crashes.
147
FileUtils.writeBytesToFile(rescueFile, classBytes);
148
if (classFileMessagePrinted.compareAndSet(false, true)) {
149
Env.traceImportant("If the JVM crashes then "
150
+ "the class file causing the crash is saved as *_*_"
151
+ RESCUE_FILE_NAME);
152
}
153
}
154
155
Thread parserThread = new Thread() {
156
public void run() {
157
try {
158
Class<?> c;
159
if (hiddenLoad) {
160
Lookup lookup = MethodHandles.lookup();
161
c = lookup.defineHiddenClass(classBytes, true).lookupClass();
162
163
} else {
164
c = CustomClassLoaders.makeClassBytesLoader(classBytes, className)
165
.loadClass(className);
166
}
167
UnsafeAccess.unsafe.ensureClassInitialized(c);
168
} catch (Throwable e) {
169
Env.traceVerbose(e, "parser caught exception");
170
}
171
}
172
};
173
174
parserThread.start();
175
parserThread.join(parseTimeout);
176
177
if (parserThread.isAlive()) {
178
Env.traceImportant("parser thread may be hung!");
179
StackTraceElement[] stack = parserThread.getStackTrace();
180
Env.traceImportant("parser thread stack len: " + stack.length);
181
Env.traceImportant(parserThread + " stack trace:");
182
for (int i = 0; i < stack.length; ++i) {
183
Env.traceImportant(parserThread + "\tat " + stack[i]);
184
}
185
186
Path savedClassPath = Paths.get(fileNamePrefix + HUNG_CLASS_FILE_NAME);
187
188
if (saveClassFile) {
189
Files.move(rescueFile.toPath(), savedClassPath);
190
Env.traceImportant("There was a possible hangup during parsing."
191
+ " The class file, which produced the possible hangup, was saved as "
192
+ fileNamePrefix + HUNG_CLASS_FILE_NAME
193
+ "... in the test directory. You may want to analyse it "
194
+ "if this test times out.");
195
}
196
197
parserThread.join(); // Wait until either thread finishes or test times out.
198
if (saveClassFile) {
199
savedClassPath.toFile().delete();
200
}
201
} else if (saveClassFile) {
202
rescueFile.delete();
203
}
204
}
205
206
stresser.finish();
207
return true;
208
}
209
210
/**
211
* Generated class bytes. The method is called for each iteration.
212
*
213
* @return Byte array with the generated class
214
*/
215
protected abstract byte[] generateClassBytes();
216
217
/**
218
* Returns a host class for the generated class.
219
*
220
* @return A host class that for the generated class
221
*/
222
protected abstract Class<?> getHostClass();
223
}
224
225