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 public static boolean isSingleThreadVM() {
86 return isDumpingStaticArchive();
87 }
88
89 private static native int getCDSConfigStatus();
90 private static native void logLambdaFormInvoker(String line);
91
92
93 // Used only when dumping static archive to keep weak references alive to
94 // ensure that Soft/Weak Reference objects can be reliably archived.
95 private static ArrayList<Object> keepAliveList;
96
97 public static void keepAlive(Object s) {
98 assert isSingleThreadVM(); // no need for synchronization
99 assert isDumpingStaticArchive();
100 if (keepAliveList == null) {
101 keepAliveList = new ArrayList<>();
102 }
103 keepAliveList.add(s);
104 }
137 public static native long getRandomSeedForDumping();
138
139 /**
140 * log lambda form invoker holder, name and method type
141 */
142 public static void logLambdaFormInvoker(String prefix, String holder, String name, String type) {
143 if (isLoggingLambdaFormInvokers()) {
144 logLambdaFormInvoker(prefix + " " + holder + " " + name + " " + type);
145 }
146 }
147
148 /**
149 * log species
150 */
151 public static void logSpeciesType(String prefix, String cn) {
152 if (isLoggingLambdaFormInvokers()) {
153 logLambdaFormInvoker(prefix + " " + cn);
154 }
155 }
156
157 static final String DIRECT_HOLDER_CLASS_NAME = "java.lang.invoke.DirectMethodHandle$Holder";
158 static final String DELEGATING_HOLDER_CLASS_NAME = "java.lang.invoke.DelegatingMethodHandle$Holder";
159 static final String BASIC_FORMS_HOLDER_CLASS_NAME = "java.lang.invoke.LambdaForm$Holder";
160 static final String INVOKERS_HOLDER_CLASS_NAME = "java.lang.invoke.Invokers$Holder";
161
162 private static boolean isValidHolderName(String name) {
163 return name.equals(DIRECT_HOLDER_CLASS_NAME) ||
164 name.equals(DELEGATING_HOLDER_CLASS_NAME) ||
165 name.equals(BASIC_FORMS_HOLDER_CLASS_NAME) ||
166 name.equals(INVOKERS_HOLDER_CLASS_NAME);
167 }
168
169 private static boolean isBasicTypeChar(char c) {
170 return "LIJFDV".indexOf(c) >= 0;
171 }
172
173 private static boolean isValidMethodType(String type) {
174 String[] typeParts = type.split("_");
175 // check return type (second part)
176 if (typeParts.length != 2 || typeParts[1].length() != 1
483
484 if (name.equals(currentClassName)) {
485 // Note: the following call will call back to <code>this.findClass(name)</code> to
486 // resolve the super types of the named class.
487 return super.findClass(name);
488 }
489 if (name.equals(currentSuperClass.getName())) {
490 return currentSuperClass;
491 }
492 if (currentInterfaces != null) {
493 for (Class<?> c : currentInterfaces) {
494 if (name.equals(c.getName())) {
495 return c;
496 }
497 }
498 }
499
500 throw new ClassNotFoundException(name);
501 }
502 }
503 }
|
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 public static boolean isSingleThreadVM() {
106 return isDumpingStaticArchive();
107 }
108
109 private static native int getCDSConfigStatus();
110 private static native void logLambdaFormInvoker(String line);
111
112
113 // Used only when dumping static archive to keep weak references alive to
114 // ensure that Soft/Weak Reference objects can be reliably archived.
115 private static ArrayList<Object> keepAliveList;
116
117 public static void keepAlive(Object s) {
118 assert isSingleThreadVM(); // no need for synchronization
119 assert isDumpingStaticArchive();
120 if (keepAliveList == null) {
121 keepAliveList = new ArrayList<>();
122 }
123 keepAliveList.add(s);
124 }
157 public static native long getRandomSeedForDumping();
158
159 /**
160 * log lambda form invoker holder, name and method type
161 */
162 public static void logLambdaFormInvoker(String prefix, String holder, String name, String type) {
163 if (isLoggingLambdaFormInvokers()) {
164 logLambdaFormInvoker(prefix + " " + holder + " " + name + " " + type);
165 }
166 }
167
168 /**
169 * log species
170 */
171 public static void logSpeciesType(String prefix, String cn) {
172 if (isLoggingLambdaFormInvokers()) {
173 logLambdaFormInvoker(prefix + " " + cn);
174 }
175 }
176
177 public static void logDynamicProxy(ClassLoader loader, String proxyName,
178 Class<?>[] interfaces, int accessFlags) {
179 Objects.requireNonNull(proxyName);
180 Objects.requireNonNull(interfaces);
181 logDynamicProxy0(loader, proxyName, interfaces, accessFlags);
182 }
183 private static native void logDynamicProxy0(ClassLoader loader, String proxyName,
184 Class<?>[] interfaces, int accessFlags);
185
186 static final String DIRECT_HOLDER_CLASS_NAME = "java.lang.invoke.DirectMethodHandle$Holder";
187 static final String DELEGATING_HOLDER_CLASS_NAME = "java.lang.invoke.DelegatingMethodHandle$Holder";
188 static final String BASIC_FORMS_HOLDER_CLASS_NAME = "java.lang.invoke.LambdaForm$Holder";
189 static final String INVOKERS_HOLDER_CLASS_NAME = "java.lang.invoke.Invokers$Holder";
190
191 private static boolean isValidHolderName(String name) {
192 return name.equals(DIRECT_HOLDER_CLASS_NAME) ||
193 name.equals(DELEGATING_HOLDER_CLASS_NAME) ||
194 name.equals(BASIC_FORMS_HOLDER_CLASS_NAME) ||
195 name.equals(INVOKERS_HOLDER_CLASS_NAME);
196 }
197
198 private static boolean isBasicTypeChar(char c) {
199 return "LIJFDV".indexOf(c) >= 0;
200 }
201
202 private static boolean isValidMethodType(String type) {
203 String[] typeParts = type.split("_");
204 // check return type (second part)
205 if (typeParts.length != 2 || typeParts[1].length() != 1
512
513 if (name.equals(currentClassName)) {
514 // Note: the following call will call back to <code>this.findClass(name)</code> to
515 // resolve the super types of the named class.
516 return super.findClass(name);
517 }
518 if (name.equals(currentSuperClass.getName())) {
519 return currentSuperClass;
520 }
521 if (currentInterfaces != null) {
522 for (Class<?> c : currentInterfaces) {
523 if (name.equals(c.getName())) {
524 return c;
525 }
526 }
527 }
528
529 throw new ClassNotFoundException(name);
530 }
531 }
532
533 /**
534 * This class is used only by native JVM code to spawn a child JVM process to assemble
535 * the AOT cache. <code>args[]</code> are passed in the <code>JAVA_TOOL_OPTIONS</code>
536 * environment variable as described in
537 * https://docs.oracle.com/en/java/javase/24/docs/specs/jvmti.html#tooloptions
538 */
539 private static class ProcessLauncher {
540 static int execWithJavaToolOptions(String javaLauncher, String args[]) throws IOException, InterruptedException {
541 ProcessBuilder pb = new ProcessBuilder().inheritIO().command(javaLauncher);
542 StringBuilder sb = new StringBuilder();
543 String prefix = "";
544 for (String arg : args) {
545 sb.append(prefix);
546
547 for (int i = 0; i < arg.length(); i++) {
548 char c = arg.charAt(i);
549 if (c == '"' || Character.isWhitespace(c)) {
550 sb.append('\'');
551 sb.append(c);
552 sb.append('\'');
553 } else if (c == '\'') {
554 sb.append('"');
555 sb.append(c);
556 sb.append('"');
557 } else {
558 sb.append(c);
559 }
560 }
561
562 prefix = " ";
563 }
564
565 Map<String, String> env = pb.environment();
566 env.put("JAVA_TOOL_OPTIONS", sb.toString());
567 env.remove("_JAVA_OPTIONS");
568 env.remove("CLASSPATH");
569 Process process = pb.start();
570 return process.waitFor();
571 }
572 }
573
574 /**
575 * This class is to ensure that the dynamic CDS archive contains at least one class, so we can avoid
576 * error handling for the degenerative case where the dynamic archive is completely empty (which doesn't
577 * happen for realistic applications).
578 */
579 private static class DummyForDynamicArchive {}
580 }
|