|
36 | 36 | import java.nio.file.Path;
|
37 | 37 | import java.nio.file.Paths;
|
38 | 38 | import java.util.List;
|
| 39 | +import java.util.Objects; |
| 40 | +import java.util.Set; |
39 | 41 | import java.util.UUID;
|
40 | 42 | import java.util.function.Predicate;
|
41 | 43 |
|
42 | 44 | import org.graalvm.collections.EconomicMap;
|
| 45 | +import org.graalvm.collections.EconomicSet; |
43 | 46 | import org.graalvm.collections.UnmodifiableEconomicMap;
|
44 | 47 | import org.graalvm.nativeimage.ImageInfo;
|
45 | 48 | import org.graalvm.nativeimage.ImageSingletons;
|
@@ -1381,4 +1384,79 @@ public static class TruffleStableOptions {
|
1381 | 1384 |
|
1382 | 1385 | @Option(help = "file:doc-files/LibGraalClassLoader.txt")//
|
1383 | 1386 | public static final HostedOptionKey<String> LibGraalClassLoader = new HostedOptionKey<>("");
|
| 1387 | + |
| 1388 | + private static final String FUTURE_DEFAULTS_OPTION = "future-defaults"; |
| 1389 | + |
| 1390 | + private static final String FUTURE_DEFAULTS_DEFAULT_NAME = "<default-value>"; |
| 1391 | + private static final String FUTURE_DEFAULTS_ALL_NAME = "all"; |
| 1392 | + private static final String FUTURE_DEFAULTS_NONE_NAME = "none"; |
| 1393 | + private static final String FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME = "run-time-initialized-jdk"; |
| 1394 | + |
| 1395 | + /** |
| 1396 | + * Note: what makes it into the future-defaults must not be an experimental feature that can be |
| 1397 | + * rolled back. The changes must be aligning native image with the Java spec and must be |
| 1398 | + * thoroughly reviewed. |
| 1399 | + */ |
| 1400 | + private static final Set<String> FUTURE_DEFAULTS_ALL_VALUES = Set.of(FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME, FUTURE_DEFAULTS_ALL_NAME, FUTURE_DEFAULTS_NONE_NAME); |
| 1401 | + private static final String FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT = "'" + FUTURE_DEFAULTS_ALL_NAME + "'" + |
| 1402 | + ", '" + FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME + "'" + |
| 1403 | + ", or '" + FUTURE_DEFAULTS_NONE_NAME + "'"; |
| 1404 | + |
| 1405 | + static { |
| 1406 | + assert FUTURE_DEFAULTS_ALL_VALUES.stream().allMatch(FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT::contains) : "A value is missing in the user-facing help text"; |
| 1407 | + } |
| 1408 | + |
| 1409 | + @APIOption(name = FUTURE_DEFAULTS_OPTION, defaultValue = FUTURE_DEFAULTS_DEFAULT_NAME) // |
| 1410 | + @Option(help = "Enable the future default behaviors for Native Image. Comma-separated list can contain " + FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT + ". " + |
| 1411 | + "For example: '--" + FUTURE_DEFAULTS_OPTION + "=" + FUTURE_DEFAULTS_ALL_NAME + "'.", type = OptionType.User) // |
| 1412 | + public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> FutureDefaults = new HostedOptionKey<>( |
| 1413 | + AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); |
| 1414 | + |
| 1415 | + private static EconomicSet<String> futureDefaults; |
| 1416 | + |
| 1417 | + @Platforms(Platform.HOSTED_ONLY.class) |
| 1418 | + public static void processFutureDefaults() { |
| 1419 | + futureDefaults = EconomicSet.create(FUTURE_DEFAULTS_ALL_VALUES.size()); |
| 1420 | + var valuesWithOrigin = FutureDefaults.getValue().getValuesWithOrigins(); |
| 1421 | + valuesWithOrigin.forEach(valueWithOrigin -> { |
| 1422 | + String value = valueWithOrigin.value(); |
| 1423 | + if (FUTURE_DEFAULTS_DEFAULT_NAME.equals(value)) { |
| 1424 | + throw UserError.abort("The '%s' from %s is forbidden. It can only contain: %s.", |
| 1425 | + SubstrateOptionsParser.commandArgument(FutureDefaults, FUTURE_DEFAULTS_DEFAULT_NAME), |
| 1426 | + valueWithOrigin.origin(), |
| 1427 | + FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT); |
| 1428 | + } |
| 1429 | + |
| 1430 | + if (!FUTURE_DEFAULTS_ALL_VALUES.contains(value)) { |
| 1431 | + throw UserError.abort("The '%s' option from %s contains invalid value '%s'. It can only contain: %s.", |
| 1432 | + SubstrateOptionsParser.commandArgument(FutureDefaults, value), |
| 1433 | + valueWithOrigin.origin(), |
| 1434 | + value, |
| 1435 | + FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT); |
| 1436 | + } |
| 1437 | + |
| 1438 | + if (value.equals(FUTURE_DEFAULTS_NONE_NAME)) { |
| 1439 | + if (!valueWithOrigin.origin().commandLineLike()) { |
| 1440 | + throw UserError.abort("The '%s' option can only be used from the command line. Detected usage from %s.", |
| 1441 | + SubstrateOptionsParser.commandArgument(FutureDefaults, FUTURE_DEFAULTS_NONE_NAME), |
| 1442 | + valueWithOrigin.origin()); |
| 1443 | + } |
| 1444 | + futureDefaults.clear(); |
| 1445 | + } |
| 1446 | + |
| 1447 | + futureDefaults.add(value); |
| 1448 | + }); |
| 1449 | + } |
| 1450 | + |
| 1451 | + private static EconomicSet<String> getFutureDefaults() { |
| 1452 | + return Objects.requireNonNull(futureDefaults, "must be initialized before usage"); |
| 1453 | + } |
| 1454 | + |
| 1455 | + public static boolean allFutureDefaults() { |
| 1456 | + return getFutureDefaults().contains(FUTURE_DEFAULTS_ALL_NAME); |
| 1457 | + } |
| 1458 | + |
| 1459 | + public static boolean isJDKInitializedAtRunTime() { |
| 1460 | + return allFutureDefaults() || getFutureDefaults().contains(FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME); |
| 1461 | + } |
1384 | 1462 | }
|
0 commit comments