Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java
41161 views
1
/*
2
* Copyright (c) 2015, 2019, 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
package optionsvalidation;
24
25
import com.sun.tools.attach.VirtualMachine;
26
import com.sun.tools.attach.AttachOperationFailedException;
27
import java.util.ArrayList;
28
import java.util.Arrays;
29
import java.util.HashSet;
30
import java.util.List;
31
import java.util.Set;
32
import jdk.test.lib.management.DynamicVMOption;
33
import jdk.test.lib.process.OutputAnalyzer;
34
import jdk.test.lib.process.ProcessTools;
35
import jdk.test.lib.dcmd.CommandExecutor;
36
import jdk.test.lib.dcmd.JMXExecutor;
37
import jdk.test.lib.Platform;
38
import sun.tools.attach.HotSpotVirtualMachine;
39
40
import static optionsvalidation.JVMOptionsUtils.failedMessage;
41
import static optionsvalidation.JVMOptionsUtils.GCType;
42
import static optionsvalidation.JVMOptionsUtils.printOutputContent;
43
import static optionsvalidation.JVMOptionsUtils.VMType;
44
45
public abstract class JVMOption {
46
47
private static final String UNLOCK_FLAG1 = "-XX:+UnlockDiagnosticVMOptions";
48
private static final String UNLOCK_FLAG2 = "-XX:+UnlockExperimentalVMOptions";
49
50
/**
51
* Executor for JCMD
52
*/
53
private final static CommandExecutor executor = new JMXExecutor();
54
55
/**
56
* Name of the tested parameter
57
*/
58
protected String name;
59
60
/**
61
* Range is defined for option inside VM
62
*/
63
protected boolean withRange;
64
65
/**
66
* Test valid min range value and additional small values
67
*/
68
protected boolean testMinRange;
69
70
/**
71
* Test valid max range value and additional big values
72
*/
73
protected boolean testMaxRange;
74
75
private Set<Integer> allowedExitCodes;
76
77
/**
78
* Prepend string which added before testing option to the command line
79
*/
80
private final List<String> prepend;
81
private final StringBuilder prependString;
82
83
protected JVMOption() {
84
this.prepend = new ArrayList<>();
85
prependString = new StringBuilder();
86
allowedExitCodes = new HashSet<>();
87
allowedExitCodes.add(0);
88
allowedExitCodes.add(1);
89
withRange = false;
90
testMinRange = true;
91
testMaxRange = true;
92
}
93
94
/**
95
* Create JVM Option with given type and name.
96
*
97
* @param type type: "intx", "size_t", "uintx", "uint64_t" or "double"
98
* @param name name of the option
99
* @return created JVMOption
100
*/
101
static JVMOption createVMOption(String type, String name) {
102
JVMOption parameter;
103
104
switch (type) {
105
case "int":
106
case "intx":
107
case "size_t":
108
case "uint":
109
case "uintx":
110
case "uint64_t":
111
parameter = new IntJVMOption(name, type);
112
break;
113
case "double":
114
parameter = new DoubleJVMOption(name);
115
break;
116
default:
117
throw new Error("Expected only \"int\", \"intx\", \"size_t\", "
118
+ "\"uint\", \"uintx\", \"uint64_t\", or \"double\" "
119
+ "option types! Got " + type + " type!");
120
}
121
122
return parameter;
123
}
124
125
/**
126
* Add passed options to the prepend options of the option. Prepend options
127
* will be added before testing option to the command line.
128
*
129
* @param options array of prepend options
130
*/
131
public final void addPrepend(String... options) {
132
String toAdd;
133
134
for (String option : options) {
135
if (option.startsWith("-")) {
136
toAdd = option;
137
} else {
138
/* Add "-" before parameter name */
139
toAdd = "-" + option;
140
141
}
142
prepend.add(toAdd);
143
prependString.append(toAdd).append(" ");
144
}
145
}
146
147
/**
148
* Get name of the option
149
*
150
* @return name of the option
151
*/
152
public final String getName() {
153
return name;
154
}
155
156
/**
157
* Mark this option as option which range is defined inside VM
158
*/
159
final void optionWithRange() {
160
withRange = true;
161
}
162
163
/**
164
* Exclude testing of min range value for this option
165
*/
166
public final void excludeTestMinRange() {
167
testMinRange = false;
168
}
169
170
/**
171
* Exclude testing of max range value for this option
172
*/
173
public final void excludeTestMaxRange() {
174
testMaxRange = false;
175
}
176
177
public final void setAllowedExitCodes(Integer... allowedExitCodes) {
178
this.allowedExitCodes.addAll(Arrays.asList(allowedExitCodes));
179
}
180
181
/**
182
* Set new minimum option value
183
*
184
* @param min new minimum value
185
*/
186
abstract void setMin(String min);
187
188
/**
189
* Get string with minimum value of the option
190
*
191
* @return string with minimum value of the option
192
*/
193
abstract String getMin();
194
195
/**
196
* Set new maximum option value
197
*
198
* @param max new maximum value
199
*/
200
abstract void setMax(String min);
201
202
/**
203
* Get string with maximum value of the option
204
*
205
* @return string with maximum value of the option
206
*/
207
abstract String getMax();
208
209
/**
210
* Return list of strings with valid option values which used for testing
211
* using jcmd, attach and etc.
212
*
213
* @return list of strings which contain valid values for option
214
*/
215
protected abstract List<String> getValidValues();
216
217
/**
218
* Return list of strings with invalid option values which used for testing
219
* using jcmd, attach and etc.
220
*
221
* @return list of strings which contain invalid values for option
222
*/
223
protected abstract List<String> getInvalidValues();
224
225
/**
226
* Return expected error message for option with value "value" when it used
227
* on command line with passed value
228
*
229
* @param value option value
230
* @return expected error message
231
*/
232
protected abstract String getErrorMessageCommandLine(String value);
233
234
/**
235
* Testing writeable option using DynamicVMOption isValidValue and
236
* isInvalidValue methods
237
*
238
* @return number of failed tests
239
*/
240
public int testDynamic() {
241
DynamicVMOption option = new DynamicVMOption(name);
242
int failedTests = 0;
243
String origValue;
244
245
if (option.isWriteable()) {
246
247
System.out.println("Testing " + name + " option dynamically by DynamicVMOption");
248
249
origValue = option.getValue();
250
251
for (String value : getValidValues()) {
252
if (!option.isValidValue(value)) {
253
failedMessage(String.format("Option %s: Valid value \"%s\" is invalid", name, value));
254
failedTests++;
255
}
256
}
257
258
for (String value : getInvalidValues()) {
259
if (option.isValidValue(value)) {
260
failedMessage(String.format("Option %s: Invalid value \"%s\" is valid", name, value));
261
failedTests++;
262
}
263
}
264
265
option.setValue(origValue);
266
}
267
268
return failedTests;
269
}
270
271
/**
272
* Testing writeable option using Jcmd
273
*
274
* @return number of failed tests
275
*/
276
public int testJcmd() {
277
DynamicVMOption option = new DynamicVMOption(name);
278
int failedTests = 0;
279
OutputAnalyzer out;
280
String origValue;
281
282
if (option.isWriteable()) {
283
284
System.out.println("Testing " + name + " option dynamically by jcmd");
285
286
origValue = option.getValue();
287
288
for (String value : getValidValues()) {
289
out = executor.execute(String.format("VM.set_flag %s %s", name, value), true);
290
291
if (out.getOutput().contains(name + " error")) {
292
failedMessage(String.format("Option %s: Can not change "
293
+ "option to valid value \"%s\" via jcmd", name, value));
294
printOutputContent(out);
295
failedTests++;
296
}
297
}
298
299
for (String value : getInvalidValues()) {
300
out = executor.execute(String.format("VM.set_flag %s %s", name, value), true);
301
302
if (!out.getOutput().contains(name + " error")) {
303
failedMessage(String.format("Option %s: Error not reported for "
304
+ "option when it chagned to invalid value \"%s\" via jcmd", name, value));
305
printOutputContent(out);
306
failedTests++;
307
}
308
}
309
310
option.setValue(origValue);
311
}
312
313
return failedTests;
314
}
315
316
private boolean setFlagAttach(HotSpotVirtualMachine vm, String flagName, String flagValue) throws Exception {
317
boolean result;
318
319
try {
320
vm.setFlag(flagName, flagValue);
321
result = true;
322
} catch (AttachOperationFailedException e) {
323
result = false;
324
}
325
326
return result;
327
}
328
329
/**
330
* Testing writeable option using attach method
331
*
332
* @return number of failed tests
333
* @throws Exception if an error occurred while attaching to the target JVM
334
*/
335
public int testAttach() throws Exception {
336
DynamicVMOption option = new DynamicVMOption(name);
337
int failedTests = 0;
338
String origValue;
339
340
if (option.isWriteable()) {
341
342
System.out.println("Testing " + name + " option dynamically via attach");
343
344
origValue = option.getValue();
345
346
HotSpotVirtualMachine vm = (HotSpotVirtualMachine) VirtualMachine.attach(String.valueOf(ProcessTools.getProcessId()));
347
348
for (String value : getValidValues()) {
349
if (!setFlagAttach(vm, name, value)) {
350
failedMessage(String.format("Option %s: Can not change option to valid value \"%s\" via attach", name, value));
351
failedTests++;
352
}
353
}
354
355
for (String value : getInvalidValues()) {
356
if (setFlagAttach(vm, name, value)) {
357
failedMessage(String.format("Option %s: Option changed to invalid value \"%s\" via attach", name, value));
358
failedTests++;
359
}
360
}
361
362
vm.detach();
363
364
option.setValue(origValue);
365
}
366
367
return failedTests;
368
}
369
370
/**
371
* Run java with passed parameter and check the result depending on the
372
* 'valid' parameter
373
*
374
* @param param tested parameter passed to the JVM
375
* @param valid indicates whether the JVM should fail or not
376
* @return true - if test passed
377
* @throws Exception if java process can not be started
378
*/
379
private boolean runJavaWithParam(String optionValue, boolean valid) throws Exception {
380
int exitCode = 0;
381
boolean result = true;
382
String errorMessage = null;
383
String explicitGC = null;
384
List<String> runJava = new ArrayList<>();
385
OutputAnalyzer out = null;
386
387
if (VMType != null) {
388
runJava.add(VMType);
389
}
390
391
// Run with a small heap to avoid excessive execution time
392
long max = Runtime.getRuntime().maxMemory() / 1024 / 1024;
393
if (max > 1024) {
394
runJava.add("-Xmx1024m");
395
}
396
397
if (Platform.isDebugBuild()) {
398
// Avoid excessive execution time.
399
runJava.add("-XX:-ZapUnusedHeapArea");
400
}
401
402
if (GCType != null &&
403
!(prepend.contains("-XX:+UseSerialGC") ||
404
prepend.contains("-XX:+UseParallelGC") ||
405
prepend.contains("-XX:+UseG1GC"))) {
406
explicitGC = GCType;
407
}
408
409
if (explicitGC != null) {
410
runJava.add(explicitGC);
411
}
412
413
runJava.add(UNLOCK_FLAG1);
414
runJava.add(UNLOCK_FLAG2);
415
416
runJava.addAll(prepend);
417
runJava.add(optionValue);
418
runJava.add(JVMStartup.class.getName());
419
420
out = new OutputAnalyzer(ProcessTools.createJavaProcessBuilder(runJava).start());
421
422
exitCode = out.getExitValue();
423
String exitCodeString = null;
424
if (exitCode != 0) {
425
exitCodeString = exitCode + " [0x" + Integer.toHexString(exitCode).toUpperCase() + "]";
426
}
427
428
if (out.getOutput().contains("A fatal error has been detected by the Java Runtime Environment")) {
429
/* Always consider "fatal error" in output as fail */
430
errorMessage = "JVM output reports a fatal error. JVM exited with code " + exitCodeString + "!";
431
} else if (out.getStderr().contains("Ignoring option " + name)) {
432
// Watch for newly obsoleted, but not yet removed, flags
433
System.out.println("SKIPPED: Ignoring test result for obsolete flag " + name);
434
} else if (valid == true) {
435
if (!allowedExitCodes.contains(exitCode)) {
436
errorMessage = "JVM exited with unexpected error code = " + exitCodeString;
437
} else if ((exitCode != 0) && (out.getOutput().isEmpty() == true)) {
438
errorMessage = "JVM exited with error(exitcode == " + exitCodeString + "), but with empty stdout and stderr. " +
439
"Description of error is needed!";
440
} else if (out.getOutput().contains("is outside the allowed range")) {
441
errorMessage = "JVM output contains \"is outside the allowed range\"";
442
}
443
} else {
444
// valid == false
445
String value = optionValue.substring(optionValue.lastIndexOf("=") + 1);
446
String errorMessageCommandLineValue = getErrorMessageCommandLine(value);
447
if (exitCode == 0) {
448
errorMessage = "JVM successfully exit";
449
} else if (exitCode != 1) {
450
errorMessage = "JVM exited with code " + exitCodeString + " which does not equal to 1";
451
} else if (!out.getOutput().contains(errorMessageCommandLineValue)) {
452
errorMessage = "JVM output does not contain expected output \"" + errorMessageCommandLineValue + "\"";
453
}
454
}
455
456
if (errorMessage != null) {
457
String fullOptionString = String.format("%s %s %s %s",
458
VMType == null ? "" : VMType, explicitGC == null ? "" : explicitGC, prependString.toString(), optionValue).trim().replaceAll(" +", " ");
459
failedMessage(name, fullOptionString, valid, errorMessage);
460
printOutputContent(out);
461
result = false;
462
}
463
464
System.out.println("");
465
466
return result;
467
}
468
469
/**
470
* Construct option string with passed value
471
*
472
* @param value parameter value
473
* @return string containing option with passed value
474
*/
475
private String constructOption(String value) {
476
return "-XX:" + name + "=" + value;
477
}
478
479
/**
480
* Return list of strings which contain options with valid values which can
481
* be used for testing on command line
482
*
483
* @return list of strings which contain options with valid values
484
*/
485
private List<String> getValidCommandLineOptions() {
486
List<String> validParameters = new ArrayList<>();
487
488
for (String value : getValidValues()) {
489
validParameters.add(constructOption(value));
490
}
491
492
return validParameters;
493
}
494
495
/**
496
* Return list of strings which contain options with invalid values which
497
* can be used for testing on command line
498
*
499
* @return list of strings which contain options with invalid values
500
*/
501
private List<String> getInvalidCommandLineOptions() {
502
List<String> invalidParameters = new ArrayList<>();
503
504
for (String value : getInvalidValues()) {
505
invalidParameters.add(constructOption(value));
506
}
507
508
return invalidParameters;
509
}
510
511
/**
512
* Perform test of the parameter. Call java with valid option values and
513
* with invalid option values.
514
*
515
* @return number of failed tests
516
* @throws Exception if java process can not be started
517
*/
518
public int testCommandLine() throws Exception {
519
ProcessBuilder pb;
520
int failed = 0;
521
List<String> optionValuesList;
522
523
optionValuesList = getValidCommandLineOptions();
524
525
if (optionValuesList.isEmpty() != true) {
526
System.out.println("Testing valid " + name + " values.");
527
for (String optionValid : optionValuesList) {
528
if (runJavaWithParam(optionValid, true) == false) {
529
failed++;
530
}
531
}
532
}
533
534
optionValuesList = getInvalidCommandLineOptions();
535
536
if (optionValuesList.isEmpty() != true) {
537
System.out.println("Testing invalid " + name + " values.");
538
539
for (String optionInvalid : optionValuesList) {
540
if (runJavaWithParam(optionInvalid, false) == false) {
541
failed++;
542
}
543
}
544
}
545
546
/* return number of failed tests for this option */
547
return failed;
548
}
549
550
}
551
552