35 import java.net.URLClassLoader;
36 import java.nio.file.InvalidPathException;
37 import java.nio.file.Path;
38 import java.util.Arrays;
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Objects;
43 import java.util.stream.Stream;
44
45 import jdk.internal.access.SharedSecrets;
46 import jdk.internal.util.StaticProperty;
47
48 public class CDS {
49 // Must be in sync with cdsConfig.hpp
50 private static final int IS_DUMPING_ARCHIVE = 1 << 0;
51 private static final int IS_DUMPING_METHOD_HANDLES = 1 << 1;
52 private static final int IS_DUMPING_STATIC_ARCHIVE = 1 << 2;
53 private static final int IS_LOGGING_LAMBDA_FORM_INVOKERS = 1 << 3;
54 private static final int IS_USING_ARCHIVE = 1 << 4;
55 private static final int configStatus = getCDSConfigStatus();
56
57 /**
58 * Should we log the use of lambda form invokers?
59 */
60 public static boolean isLoggingLambdaFormInvokers() {
61 return (configStatus & IS_LOGGING_LAMBDA_FORM_INVOKERS) != 0;
62 }
63
64 /**
65 * Is the VM writing to a (static or dynamic) CDS archive.
66 */
67 public static boolean isDumpingArchive() {
68 return (configStatus & IS_DUMPING_ARCHIVE) != 0;
69 }
70
71 /**
72 * Is the VM using at least one CDS archive?
73 */
74 public static boolean isUsingArchive() {
75 return (configStatus & IS_USING_ARCHIVE) != 0;
76 }
77
78 /**
79 * Is dumping static archive.
80 */
81 public static boolean isDumpingStaticArchive() {
82 return (configStatus & IS_DUMPING_STATIC_ARCHIVE) != 0;
83 }
84
85 private static native int getCDSConfigStatus();
86 private static native void logLambdaFormInvoker(String line);
87
88 /**
89 * Initialize archived static fields in the given Class using archived
90 * values from CDS dump time. Also initialize the classes of objects in
91 * the archived graph referenced by those fields.
92 *
93 * Those static fields remain as uninitialized if there is no mapped CDS
94 * java heap data or there is any error during initialization of the
95 * object class in the archived graph.
96 */
97 public static native void initializeFromArchive(Class<?> c);
98
99 /**
100 * Ensure that the native representation of all archived java.lang.Module objects
101 * are properly restored.
102 */
103 public static native void defineArchivedModules(ClassLoader platformLoader, ClassLoader systemLoader);
104
110 public static native long getRandomSeedForDumping();
111
112 /**
113 * log lambda form invoker holder, name and method type
114 */
115 public static void logLambdaFormInvoker(String prefix, String holder, String name, String type) {
116 if (isLoggingLambdaFormInvokers()) {
117 logLambdaFormInvoker(prefix + " " + holder + " " + name + " " + type);
118 }
119 }
120
121 /**
122 * log species
123 */
124 public static void logSpeciesType(String prefix, String cn) {
125 if (isLoggingLambdaFormInvokers()) {
126 logLambdaFormInvoker(prefix + " " + cn);
127 }
128 }
129
130 static final String DIRECT_HOLDER_CLASS_NAME = "java.lang.invoke.DirectMethodHandle$Holder";
131 static final String DELEGATING_HOLDER_CLASS_NAME = "java.lang.invoke.DelegatingMethodHandle$Holder";
132 static final String BASIC_FORMS_HOLDER_CLASS_NAME = "java.lang.invoke.LambdaForm$Holder";
133 static final String INVOKERS_HOLDER_CLASS_NAME = "java.lang.invoke.Invokers$Holder";
134
135 private static boolean isValidHolderName(String name) {
136 return name.equals(DIRECT_HOLDER_CLASS_NAME) ||
137 name.equals(DELEGATING_HOLDER_CLASS_NAME) ||
138 name.equals(BASIC_FORMS_HOLDER_CLASS_NAME) ||
139 name.equals(INVOKERS_HOLDER_CLASS_NAME);
140 }
141
142 private static boolean isBasicTypeChar(char c) {
143 return "LIJFDV".indexOf(c) >= 0;
144 }
145
146 private static boolean isValidMethodType(String type) {
147 String[] typeParts = type.split("_");
148 // check return type (second part)
149 if (typeParts.length != 2 || typeParts[1].length() != 1
456
457 if (name.equals(currentClassName)) {
458 // Note: the following call will call back to <code>this.findClass(name)</code> to
459 // resolve the super types of the named class.
460 return super.findClass(name);
461 }
462 if (name.equals(currentSuperClass.getName())) {
463 return currentSuperClass;
464 }
465 if (currentInterfaces != null) {
466 for (Class<?> c : currentInterfaces) {
467 if (name.equals(c.getName())) {
468 return c;
469 }
470 }
471 }
472
473 throw new ClassNotFoundException(name);
474 }
475 }
476 }
|
35 import java.net.URLClassLoader;
36 import java.nio.file.InvalidPathException;
37 import java.nio.file.Path;
38 import java.util.Arrays;
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Objects;
43 import java.util.stream.Stream;
44
45 import jdk.internal.access.SharedSecrets;
46 import jdk.internal.util.StaticProperty;
47
48 public class CDS {
49 // Must be in sync with cdsConfig.hpp
50 private static final int IS_DUMPING_ARCHIVE = 1 << 0;
51 private static final int IS_DUMPING_METHOD_HANDLES = 1 << 1;
52 private static final int IS_DUMPING_STATIC_ARCHIVE = 1 << 2;
53 private static final int IS_LOGGING_LAMBDA_FORM_INVOKERS = 1 << 3;
54 private static final int IS_USING_ARCHIVE = 1 << 4;
55 private static final int IS_DUMPING_HEAP = 1 << 5;
56 private static final int IS_LOGGING_DYNAMIC_PROXIES = 1 << 6;
57 private static final int IS_DUMPING_PACKAGES = 1 << 7;
58 private static final int IS_DUMPING_PROTECTION_DOMAINS = 1 << 8;
59 private static final int configStatus = getCDSConfigStatus();
60
61 /**
62 * Should we log the use of lambda form invokers?
63 */
64 public static boolean isLoggingLambdaFormInvokers() {
65 return (configStatus & IS_LOGGING_LAMBDA_FORM_INVOKERS) != 0;
66 }
67
68 /**
69 * Is the VM writing to a (static or dynamic) CDS archive.
70 */
71 public static boolean isDumpingArchive() {
72 return (configStatus & IS_DUMPING_ARCHIVE) != 0;
73 }
74
75 /**
76 * Is the VM using at least one CDS archive?
77 */
78 public static boolean isUsingArchive() {
79 return (configStatus & IS_USING_ARCHIVE) != 0;
80 }
81
82 /**
83 * Is dumping static archive.
84 */
85 public static boolean isDumpingStaticArchive() {
86 return (configStatus & IS_DUMPING_STATIC_ARCHIVE) != 0;
87 }
88
89 public static boolean isDumpingHeap() {
90 return (configStatus & IS_DUMPING_HEAP) != 0;
91 }
92
93 public static boolean isLoggingDynamicProxies() {
94 return (configStatus & IS_LOGGING_DYNAMIC_PROXIES) != 0;
95 }
96
97 public static boolean isDumpingPackages() {
98 return (configStatus & IS_DUMPING_PACKAGES) != 0;
99 }
100
101 public static boolean isDumpingProtectionDomains() {
102 return (configStatus & IS_DUMPING_PROTECTION_DOMAINS) != 0;
103 }
104
105 private static native int getCDSConfigStatus();
106 private static native void logLambdaFormInvoker(String line);
107
108 /**
109 * Initialize archived static fields in the given Class using archived
110 * values from CDS dump time. Also initialize the classes of objects in
111 * the archived graph referenced by those fields.
112 *
113 * Those static fields remain as uninitialized if there is no mapped CDS
114 * java heap data or there is any error during initialization of the
115 * object class in the archived graph.
116 */
117 public static native void initializeFromArchive(Class<?> c);
118
119 /**
120 * Ensure that the native representation of all archived java.lang.Module objects
121 * are properly restored.
122 */
123 public static native void defineArchivedModules(ClassLoader platformLoader, ClassLoader systemLoader);
124
130 public static native long getRandomSeedForDumping();
131
132 /**
133 * log lambda form invoker holder, name and method type
134 */
135 public static void logLambdaFormInvoker(String prefix, String holder, String name, String type) {
136 if (isLoggingLambdaFormInvokers()) {
137 logLambdaFormInvoker(prefix + " " + holder + " " + name + " " + type);
138 }
139 }
140
141 /**
142 * log species
143 */
144 public static void logSpeciesType(String prefix, String cn) {
145 if (isLoggingLambdaFormInvokers()) {
146 logLambdaFormInvoker(prefix + " " + cn);
147 }
148 }
149
150 public static void logDynamicProxy(ClassLoader loader, String proxyName,
151 Class<?>[] interfaces, int accessFlags) {
152 Objects.requireNonNull(proxyName);
153 Objects.requireNonNull(interfaces);
154 logDynamicProxy0(loader, proxyName, interfaces, accessFlags);
155 }
156 private static native void logDynamicProxy0(ClassLoader loader, String proxyName,
157 Class<?>[] interfaces, int accessFlags);
158
159 static final String DIRECT_HOLDER_CLASS_NAME = "java.lang.invoke.DirectMethodHandle$Holder";
160 static final String DELEGATING_HOLDER_CLASS_NAME = "java.lang.invoke.DelegatingMethodHandle$Holder";
161 static final String BASIC_FORMS_HOLDER_CLASS_NAME = "java.lang.invoke.LambdaForm$Holder";
162 static final String INVOKERS_HOLDER_CLASS_NAME = "java.lang.invoke.Invokers$Holder";
163
164 private static boolean isValidHolderName(String name) {
165 return name.equals(DIRECT_HOLDER_CLASS_NAME) ||
166 name.equals(DELEGATING_HOLDER_CLASS_NAME) ||
167 name.equals(BASIC_FORMS_HOLDER_CLASS_NAME) ||
168 name.equals(INVOKERS_HOLDER_CLASS_NAME);
169 }
170
171 private static boolean isBasicTypeChar(char c) {
172 return "LIJFDV".indexOf(c) >= 0;
173 }
174
175 private static boolean isValidMethodType(String type) {
176 String[] typeParts = type.split("_");
177 // check return type (second part)
178 if (typeParts.length != 2 || typeParts[1].length() != 1
485
486 if (name.equals(currentClassName)) {
487 // Note: the following call will call back to <code>this.findClass(name)</code> to
488 // resolve the super types of the named class.
489 return super.findClass(name);
490 }
491 if (name.equals(currentSuperClass.getName())) {
492 return currentSuperClass;
493 }
494 if (currentInterfaces != null) {
495 for (Class<?> c : currentInterfaces) {
496 if (name.equals(c.getName())) {
497 return c;
498 }
499 }
500 }
501
502 throw new ClassNotFoundException(name);
503 }
504 }
505
506 /**
507 * This class is used only by native JVM code to spawn a child JVM process to assemble
508 * the AOT cache. <code>args[]</code> are passed in the <code>JAVA_TOOL_OPTIONS</code>
509 * environment variable as described in
510 * https://docs.oracle.com/en/java/javase/24/docs/specs/jvmti.html#tooloptions
511 */
512 private static class ProcessLauncher {
513 static int execWithJavaToolOptions(String javaLauncher, String args[]) throws IOException, InterruptedException {
514 ProcessBuilder pb = new ProcessBuilder().inheritIO().command(javaLauncher);
515 StringBuilder sb = new StringBuilder();
516 String prefix = "";
517 for (String arg : args) {
518 sb.append(prefix);
519
520 for (int i = 0; i < arg.length(); i++) {
521 char c = arg.charAt(i);
522 if (c == '"' || Character.isWhitespace(c)) {
523 sb.append('\'');
524 sb.append(c);
525 sb.append('\'');
526 } else if (c == '\'') {
527 sb.append('"');
528 sb.append(c);
529 sb.append('"');
530 } else {
531 sb.append(c);
532 }
533 }
534
535 prefix = " ";
536 }
537
538 Map<String, String> env = pb.environment();
539 env.put("JAVA_TOOL_OPTIONS", sb.toString());
540 env.remove("_JAVA_OPTIONS");
541 env.remove("CLASSPATH");
542 Process process = pb.start();
543 return process.waitFor();
544 }
545 }
546
547 /**
548 * This class is to ensure that the dynamic CDS archive contains at least one class, so we can avoid
549 * error handling for the degenerative case where the dynamic archive is completely empty (which doesn't
550 * happen for realistic applications).
551 */
552 private static class DummyForDynamicArchive {}
553 }
|