Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/misc/CDS.java
41159 views
1
/*
2
* Copyright (c) 2020, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package jdk.internal.misc;
27
28
import java.io.BufferedReader;
29
import java.io.File;
30
import java.io.InputStreamReader;
31
import java.io.InputStream;
32
import java.io.IOException;
33
import java.io.PrintStream;
34
import java.util.Arrays;
35
import java.util.ArrayList;
36
import java.util.List;
37
import java.util.Map;
38
import java.util.Objects;
39
import java.util.stream.Stream;
40
41
import jdk.internal.access.JavaLangInvokeAccess;
42
import jdk.internal.access.SharedSecrets;
43
44
public class CDS {
45
private static final boolean isDumpingClassList;
46
private static final boolean isDumpingArchive;
47
private static final boolean isSharingEnabled;
48
static {
49
isDumpingClassList = isDumpingClassList0();
50
isDumpingArchive = isDumpingArchive0();
51
isSharingEnabled = isSharingEnabled0();
52
}
53
54
/**
55
* indicator for dumping class list.
56
*/
57
public static boolean isDumpingClassList() {
58
return isDumpingClassList;
59
}
60
61
/**
62
* Is the VM writing to a (static or dynamic) CDS archive.
63
*/
64
public static boolean isDumpingArchive() {
65
return isDumpingArchive;
66
}
67
68
/**
69
* Is sharing enabled via the UseSharedSpaces flag.
70
*/
71
public static boolean isSharingEnabled() {
72
return isSharingEnabled;
73
}
74
75
private static native boolean isDumpingClassList0();
76
private static native boolean isDumpingArchive0();
77
private static native boolean isSharingEnabled0();
78
private static native void logLambdaFormInvoker(String line);
79
80
/**
81
* Initialize archived static fields in the given Class using archived
82
* values from CDS dump time. Also initialize the classes of objects in
83
* the archived graph referenced by those fields.
84
*
85
* Those static fields remain as uninitialized if there is no mapped CDS
86
* java heap data or there is any error during initialization of the
87
* object class in the archived graph.
88
*/
89
public static native void initializeFromArchive(Class<?> c);
90
91
/**
92
* Ensure that the native representation of all archived java.lang.Module objects
93
* are properly restored.
94
*/
95
public static native void defineArchivedModules(ClassLoader platformLoader, ClassLoader systemLoader);
96
97
/**
98
* Returns a predictable "random" seed derived from the VM's build ID and version,
99
* to be used by java.util.ImmutableCollections to ensure that archived
100
* ImmutableCollections are always sorted the same order for the same VM build.
101
*/
102
public static native long getRandomSeedForDumping();
103
104
/**
105
* log lambda form invoker holder, name and method type
106
*/
107
public static void traceLambdaFormInvoker(String prefix, String holder, String name, String type) {
108
if (isDumpingClassList) {
109
logLambdaFormInvoker(prefix + " " + holder + " " + name + " " + type);
110
}
111
}
112
113
/**
114
* log species
115
*/
116
public static void traceSpeciesType(String prefix, String cn) {
117
if (isDumpingClassList) {
118
logLambdaFormInvoker(prefix + " " + cn);
119
}
120
}
121
122
static final String DIRECT_HOLDER_CLASS_NAME = "java.lang.invoke.DirectMethodHandle$Holder";
123
static final String DELEGATING_HOLDER_CLASS_NAME = "java.lang.invoke.DelegatingMethodHandle$Holder";
124
static final String BASIC_FORMS_HOLDER_CLASS_NAME = "java.lang.invoke.LambdaForm$Holder";
125
static final String INVOKERS_HOLDER_CLASS_NAME = "java.lang.invoke.Invokers$Holder";
126
127
private static boolean isValidHolderName(String name) {
128
return name.equals(DIRECT_HOLDER_CLASS_NAME) ||
129
name.equals(DELEGATING_HOLDER_CLASS_NAME) ||
130
name.equals(BASIC_FORMS_HOLDER_CLASS_NAME) ||
131
name.equals(INVOKERS_HOLDER_CLASS_NAME);
132
}
133
134
private static boolean isBasicTypeChar(char c) {
135
return "LIJFDV".indexOf(c) >= 0;
136
}
137
138
private static boolean isValidMethodType(String type) {
139
String[] typeParts = type.split("_");
140
// check return type (second part)
141
if (typeParts.length != 2 || typeParts[1].length() != 1
142
|| !isBasicTypeChar(typeParts[1].charAt(0))) {
143
return false;
144
}
145
// first part
146
if (!isBasicTypeChar(typeParts[0].charAt(0))) {
147
return false;
148
}
149
for (int i = 1; i < typeParts[0].length(); i++) {
150
char c = typeParts[0].charAt(i);
151
if (!isBasicTypeChar(c)) {
152
if (!(c >= '0' && c <= '9')) {
153
return false;
154
}
155
}
156
}
157
return true;
158
}
159
160
// Throw exception on invalid input
161
private static void validateInputLines(String[] lines) {
162
for (String s: lines) {
163
if (!s.startsWith("[LF_RESOLVE]") && !s.startsWith("[SPECIES_RESOLVE]")) {
164
throw new IllegalArgumentException("Wrong prefix: " + s);
165
}
166
167
String[] parts = s.split(" ");
168
boolean isLF = s.startsWith("[LF_RESOLVE]");
169
170
if (isLF) {
171
if (parts.length != 4) {
172
throw new IllegalArgumentException("Incorrect number of items in the line: " + parts.length);
173
}
174
if (!isValidHolderName(parts[1])) {
175
throw new IllegalArgumentException("Invalid holder class name: " + parts[1]);
176
}
177
if (!isValidMethodType(parts[3])) {
178
throw new IllegalArgumentException("Invalid method type: " + parts[3]);
179
}
180
} else {
181
if (parts.length != 2) {
182
throw new IllegalArgumentException("Incorrect number of items in the line: " + parts.length);
183
}
184
}
185
}
186
}
187
188
/**
189
* called from vm to generate MethodHandle holder classes
190
* @return {@code Object[]} if holder classes can be generated.
191
* @param lines in format of LF_RESOLVE or SPECIES_RESOLVE output
192
*/
193
private static Object[] generateLambdaFormHolderClasses(String[] lines) {
194
Objects.requireNonNull(lines);
195
validateInputLines(lines);
196
Stream<String> lineStream = Arrays.stream(lines);
197
Map<String, byte[]> result = SharedSecrets.getJavaLangInvokeAccess().generateHolderClasses(lineStream);
198
int size = result.size();
199
Object[] retArray = new Object[size * 2];
200
int index = 0;
201
for (Map.Entry<String, byte[]> entry : result.entrySet()) {
202
retArray[index++] = entry.getKey();
203
retArray[index++] = entry.getValue();
204
};
205
return retArray;
206
}
207
208
private static native void dumpClassList(String listFileName);
209
private static native void dumpDynamicArchive(String archiveFileName);
210
211
private static String drainOutput(InputStream stream, long pid, String tail, List<String> cmds) {
212
String fileName = "java_pid" + pid + "_" + tail;
213
new Thread( ()-> {
214
try (InputStreamReader isr = new InputStreamReader(stream);
215
BufferedReader rdr = new BufferedReader(isr);
216
PrintStream prt = new PrintStream(fileName)) {
217
prt.println("Command:");
218
for (String s : cmds) {
219
prt.print(s + " ");
220
}
221
prt.println("");
222
String line;
223
while((line = rdr.readLine()) != null) {
224
prt.println(line);
225
}
226
} catch (IOException e) {
227
throw new RuntimeException("IOExeption happens during drain stream to file " +
228
fileName + ": " + e.getMessage());
229
}}).start();
230
return fileName;
231
}
232
233
private static String[] excludeFlags = {
234
"-XX:DumpLoadedClassList=",
235
"-XX:+DumpSharedSpaces",
236
"-XX:+DynamicDumpSharedSpaces",
237
"-XX:+RecordDynamicDumpInfo",
238
"-Xshare:",
239
"-XX:SharedClassListFile=",
240
"-XX:SharedArchiveFile=",
241
"-XX:ArchiveClassesAtExit=",
242
"-XX:+UseSharedSpaces",
243
"-XX:+RequireSharedSpaces"};
244
private static boolean containsExcludedFlags(String testStr) {
245
for (String e : excludeFlags) {
246
if (testStr.contains(e)) {
247
return true;
248
}
249
}
250
return false;
251
}
252
253
/**
254
* called from jcmd VM.cds to dump static or dynamic shared archive
255
* @param isStatic true for dump static archive or false for dynnamic archive.
256
* @param fileName user input archive name, can be null.
257
*/
258
private static void dumpSharedArchive(boolean isStatic, String fileName) throws Exception {
259
String currentPid = String.valueOf(ProcessHandle.current().pid());
260
String archiveFileName = fileName != null ? fileName :
261
"java_pid" + currentPid + (isStatic ? "_static.jsa" : "_dynamic.jsa");
262
263
String tempArchiveFileName = archiveFileName + ".temp";
264
File tempArchiveFile = new File(tempArchiveFileName);
265
// The operation below may cause exception if the file or its dir is protected.
266
if (!tempArchiveFile.exists()) {
267
tempArchiveFile.createNewFile();
268
}
269
tempArchiveFile.delete();
270
271
if (isStatic) {
272
String listFileName = archiveFileName + ".classlist";
273
File listFile = new File(listFileName);
274
if (listFile.exists()) {
275
listFile.delete();
276
}
277
dumpClassList(listFileName);
278
String jdkHome = System.getProperty("java.home");
279
String classPath = System.getProperty("java.class.path");
280
List<String> cmds = new ArrayList<String>();
281
cmds.add(jdkHome + File.separator + "bin" + File.separator + "java"); // java
282
cmds.add("-cp");
283
cmds.add(classPath);
284
cmds.add("-Xlog:cds");
285
cmds.add("-Xshare:dump");
286
cmds.add("-XX:SharedClassListFile=" + listFileName);
287
cmds.add("-XX:SharedArchiveFile=" + tempArchiveFileName);
288
289
// All runtime args.
290
String[] vmArgs = VM.getRuntimeArguments();
291
if (vmArgs != null) {
292
for (String arg : vmArgs) {
293
if (arg != null && !containsExcludedFlags(arg)) {
294
cmds.add(arg);
295
}
296
}
297
}
298
299
Process proc = Runtime.getRuntime().exec(cmds.toArray(new String[0]));
300
301
// Drain stdout/stderr to files in new threads.
302
String stdOutFile = drainOutput(proc.getInputStream(), proc.pid(), "stdout", cmds);
303
String stdErrFile = drainOutput(proc.getErrorStream(), proc.pid(), "stderr", cmds);
304
305
proc.waitFor();
306
// done, delete classlist file.
307
listFile.delete();
308
309
// Check if archive has been successfully dumped. We won't reach here if exception happens.
310
// Throw exception if file is not created.
311
if (!tempArchiveFile.exists()) {
312
throw new RuntimeException("Archive file " + tempArchiveFileName +
313
" is not created, please check stdout file " +
314
stdOutFile + " or stderr file " +
315
stdErrFile + " for more detail");
316
}
317
} else {
318
dumpDynamicArchive(tempArchiveFileName);
319
if (!tempArchiveFile.exists()) {
320
throw new RuntimeException("Archive file " + tempArchiveFileName +
321
" is not created, please check process " +
322
currentPid + " output for more detail");
323
}
324
}
325
// Override the existing archive file
326
File archiveFile = new File(archiveFileName);
327
if (archiveFile.exists()) {
328
archiveFile.delete();
329
}
330
if (!tempArchiveFile.renameTo(archiveFile)) {
331
throw new RuntimeException("Cannot rename temp file " + tempArchiveFileName + " to archive file" + archiveFileName);
332
}
333
// Everyting goes well, print out the file name.
334
System.out.println((isStatic ? "Static" : " Dynamic") + " dump to file " + archiveFileName);
335
}
336
}
337
338