Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/sourcetools/j9constantpool/com/ibm/oti/VMCPTool/Main.java
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2004, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
package com.ibm.oti.VMCPTool;
23
24
import java.io.File;
25
import java.io.FileNotFoundException;
26
import java.io.FileReader;
27
import java.io.FileWriter;
28
import java.io.IOException;
29
import java.io.PrintWriter;
30
import java.io.StringWriter;
31
import java.util.HashMap;
32
import java.util.Map;
33
import java.util.Set;
34
import java.util.TreeMap;
35
36
import javax.xml.parsers.DocumentBuilder;
37
import javax.xml.parsers.DocumentBuilderFactory;
38
39
import org.w3c.dom.Document;
40
import org.w3c.dom.Element;
41
import org.w3c.dom.Node;
42
import org.w3c.dom.NodeList;
43
44
@SuppressWarnings("nls")
45
public class Main implements Constants {
46
47
static final class JCLRuntimeFlag {
48
final String flagName;
49
final int value;
50
int useCount;
51
52
public JCLRuntimeFlag(String flagName, int value) {
53
this.flagName = flagName;
54
this.value = value;
55
this.useCount = 0;
56
}
57
58
public String cDefine() {
59
StringBuilder buf = new StringBuilder();
60
61
buf.append("#define JCL_RTFLAG_");
62
63
for (int i = 0, length = flagName.length(); i < length; ++i) {
64
char c = flagName.charAt(i);
65
if (Character.isUpperCase(c)) {
66
buf.append("_");
67
}
68
buf.append(Character.toUpperCase(c));
69
}
70
71
buf.append(" 0x").append(Integer.toHexString(value));
72
73
return buf.toString();
74
}
75
}
76
77
private static final String[] endianMacros = {
78
"#ifdef J9VM_ENV_LITTLE_ENDIAN",
79
"",
80
"/* U_16 U_8 U_8 */",
81
"#define WORD_BYTE_BYTE(a, b, c) ( ((U_32)a) | ((U_32)b << 16) | ((U_32)c << 24) )",
82
"/* U_8 U_8 U_8 U_8 */",
83
"#define BYTE_BYTE_BYTE_BYTE(a, b, c, d) ( ((U_32)a) | ((U_32)b << 8) | ((U_32)c << 16) | ((U_32)d << 24) )",
84
"/* U_8 U_8 U_16 */",
85
"#define BYTE_BYTE_WORD(a, b, c) ( ((U_32)a) | ((U_32)b << 8) | ((U_32)c << 16) )",
86
"/* U_16 U_16 */",
87
"#define WORD_WORD(a, b) ( ((U_32)a ) | ((U_32)b << 16 ) )",
88
"",
89
"#else /* J9VM_ENV_LITTLE_ENDIAN */",
90
"",
91
"/* U_16 U_8 U_8 */",
92
"#define WORD_BYTE_BYTE(a, b, c) ( ((U_32)a << 16) | ((U_32)b << 8) | ((U_32)c) )",
93
"/* U_8 U_8 U_8 U_8 */",
94
"#define BYTE_BYTE_BYTE_BYTE(a, b, c, d) ( ((U_32)a << 24) | ((U_32)b << 16) | ((U_32)c << 8) | ((U_32)d) )",
95
"/* U_8 U_8 U_16 */",
96
"#define BYTE_BYTE_WORD(a, b, c) ( ((U_32)a << 24) | ((U_32)b << 16) | ((U_32)c) )",
97
"/* U_16 U_16 */",
98
"#define WORD_WORD(a, b) ( ((U_32)a << 16) | ((U_32)b) )",
99
"",
100
"#endif /* J9VM_ENV_LITTLE_ENDIAN */"
101
};
102
103
private static final String[] openDefinition = {
104
"/* Autogenerated file */",
105
"",
106
"#include \"j9.h\"",
107
"#include \"j9consts.h\""
108
};
109
110
private static final String[] openHeader = {
111
"/* Autogenerated header */",
112
"",
113
"#ifndef J9VM_CONSTANT_POOL_H",
114
"#define J9VM_CONSTANT_POOL_H",
115
"",
116
"/* @ddr_namespace: map_to_type=J9VmconstantpoolConstants */"
117
};
118
119
private static final String[] classMacros = {
120
"#define J9VMCONSTANTPOOL_CLASSREF_AT(vm, index) ((J9RAMClassRef*)(&(vm)->jclConstantPool[(index)]))",
121
"#define J9VMCONSTANTPOOL_CLASS_AT(vm, index) (J9VMCONSTANTPOOL_CLASSREF_AT(vm, index)->value == NULL \\",
122
"\t? (vm)->internalVMFunctions->resolveKnownClass(vm, index) \\",
123
"\t: J9VMCONSTANTPOOL_CLASSREF_AT(vm, index)->value)"
124
};
125
126
private static final String[] fieldMacros = {
127
"#define J9VMCONSTANTPOOL_AT(vm, index, kind) ((kind*)&(vm)->jclConstantPool[index])",
128
"#define J9VMCONSTANTPOOL_FIELDREF_AT(vm, index) J9VMCONSTANTPOOL_AT(vm, index, J9RAMFieldRef)",
129
"#define J9VMCONSTANTPOOL_FIELD_OFFSET(vm, index) (J9JAVAVM_OBJECT_HEADER_SIZE(vm) + J9VMCONSTANTPOOL_FIELDREF_AT(vm, index)->valueOffset)",
130
"",
131
"#if !defined(J9VM_ENV_LITTLE_ENDIAN) && !defined(J9VM_ENV_DATA64)",
132
"#define J9VMCONSTANTPOOL_ADDRESS_OFFSET(vm, index) J9VMCONSTANTPOOL_FIELD_OFFSET(vm, index) + sizeof(UDATA)",
133
"#else",
134
"#define J9VMCONSTANTPOOL_ADDRESS_OFFSET(vm, index) J9VMCONSTANTPOOL_FIELD_OFFSET(vm, index)",
135
"#endif"
136
};
137
138
private static final String[] staticFieldMacros = {
139
"#define J9VMCONSTANTPOOL_STATICFIELDREF_AT(vm, index) J9VMCONSTANTPOOL_AT(vm, index, J9RAMStaticFieldRef)",
140
"#define J9VMCONSTANTPOOL_STATICFIELD_ADDRESS(vm, index) (J9RAMSTATICFIELDREF_VALUEADDRESS(J9VMCONSTANTPOOL_STATICFIELDREF_AT(vm, index)))",
141
};
142
143
private static final String[] staticMethodMacros = {
144
"#define J9VMCONSTANTPOOL_STATICMETHODREF_AT(vm, index) J9VMCONSTANTPOOL_AT(vm, index, J9RAMStaticMethodRef)",
145
"#define J9VMCONSTANTPOOL_STATICMETHOD_AT(vm, index) (J9VMCONSTANTPOOL_STATICMETHODREF_AT(vm, index)->method)"
146
};
147
148
private static final String[] virtualMethodMacros = {
149
"#define J9VMCONSTANTPOOL_VIRTUALMETHODREF_AT(vm, index) J9VMCONSTANTPOOL_AT(vm, index, J9RAMVirtualMethodRef)",
150
"#define J9VMCONSTANTPOOL_VIRTUALMETHOD_AT(vm, index) (J9VMCONSTANTPOOL_VIRTUALMETHODREF_AT(vm, index)->methodIndexAndArgCount)"
151
};
152
153
private static final String[] specialMethodMacros = {
154
"#define J9VMCONSTANTPOOL_SPECIALMETHODREF_AT(vm, index) J9VMCONSTANTPOOL_AT(vm, index, J9RAMSpecialMethodRef)",
155
"#define J9VMCONSTANTPOOL_SPECIALMETHOD_AT(vm, index) (J9VMCONSTANTPOOL_SPECIALMETHODREF_AT(vm, index)->method)"
156
};
157
158
private static final String[] interfaceMethodMacros = {
159
"#define J9VMCONSTANTPOOL_INTERFACEMETHODREF_AT(vm, index) J9VMCONSTANTPOOL_AT(vm, index, J9RAMInterfaceMethodRef)",
160
"#define J9VMCONSTANTPOOL_INTERFACEMETHOD_AT(vm, index) (J9VMCONSTANTPOOL_INTERFACEMETHODREF_AT(vm, index)->methodIndexAndArgCount)"
161
};
162
163
private static final String[] closeHeader = {
164
"#endif /* J9VM_CONSTANT_POOL_H */"
165
};
166
167
private static final String optionBuildSpecId = "-buildSpecId";
168
private static final String optionHelp = "-help";
169
private static final String optionVersion = "-version";
170
private static final String optionRootDir = "-rootDir";
171
private static final String optionConfigDir = "-configDir";
172
private static final String optionOutputDir = "-outputDir";
173
private static final String optionCmakeCache = "-cmakeCache";
174
private static final String optionVerbose = "-verbose";
175
private static final String constantPool = "vmconstantpool.xml";
176
177
private static String buildSpecId;
178
private static Integer version;
179
private static String configDirectory;
180
private static String rootDirectory = ".";
181
private static String outputDirectory;
182
private static String cmakeCache;
183
private static boolean verbose;
184
185
private static IFlagInfo flagInfo;
186
private static TreeMap<String, JCLRuntimeFlag> runtimeFlagDefs;
187
188
private static boolean parseOptions(String[] args) {
189
boolean isValid = true;
190
191
try {
192
for (int i = 0; i < args.length; ++i) {
193
String arg = args[i];
194
if (optionHelp.equalsIgnoreCase(arg)) {
195
return false;
196
} else if (optionVersion.equalsIgnoreCase(arg)) {
197
String versionValue = args[++i];
198
try {
199
version = Integer.valueOf(versionValue);
200
} catch (NumberFormatException e) {
201
System.err.printf("ERROR: argument for '%s' must be numeric (%s)\n", optionVersion, versionValue);
202
isValid = false;
203
}
204
} else if (optionRootDir.equalsIgnoreCase(arg)) {
205
rootDirectory = args[++i];
206
} else if (optionConfigDir.equalsIgnoreCase(arg)) {
207
configDirectory = args[++i];
208
} else if (optionBuildSpecId.equalsIgnoreCase(arg)) {
209
buildSpecId = args[++i];
210
} else if (optionOutputDir.equalsIgnoreCase(arg)) {
211
outputDirectory = args[++i];
212
} else if (optionCmakeCache.equalsIgnoreCase(arg)) {
213
cmakeCache = args[++i];
214
} else if (optionVerbose.equalsIgnoreCase(arg)) {
215
verbose = true;
216
} else {
217
System.err.printf("Unrecognized option '%s'\n", arg);
218
return false;
219
}
220
}
221
} catch (ArrayIndexOutOfBoundsException e) {
222
return false;
223
}
224
225
if (version == null) {
226
System.err.printf("ERROR: required argument '%s' not given\n", optionVersion);
227
isValid = false;
228
}
229
230
if (rootDirectory == null) {
231
System.err.printf("ERROR: required argument '%s' not given\n", optionRootDir);
232
isValid = false;
233
}
234
235
if (cmakeCache == null) {
236
if (configDirectory == null) {
237
System.err.printf("ERROR: required argument '%s' not given\n", optionConfigDir);
238
isValid = false;
239
}
240
if (buildSpecId == null) {
241
System.err.printf("ERROR: required argument '%s' not given\n", optionBuildSpecId);
242
isValid = false;
243
}
244
}
245
246
return isValid;
247
}
248
249
private static void printHelp() {
250
System.err.println(Main.class.getName() + ":");
251
System.err.println();
252
System.err.println("Usage:");
253
254
String commonOptStr = "\t" + optionRootDir + " <directory> [" + optionOutputDir + " <directory>] ";
255
String trailingOptStr = optionVersion + " <version>";
256
257
System.err.println(commonOptStr + optionConfigDir + " <directory> " + optionBuildSpecId + "<specId> " + trailingOptStr);
258
System.err.println(commonOptStr + optionCmakeCache + " <cacheFile> " + trailingOptStr);
259
}
260
261
public static void main(String[] args) throws Throwable {
262
if (!parseOptions(args)) {
263
printHelp();
264
System.exit(1);
265
}
266
267
if (cmakeCache != null) {
268
if (configDirectory != null) {
269
System.err.println("Ignoring option " + optionConfigDir);
270
}
271
if (buildSpecId != null) {
272
System.err.println("Ignoring option " + optionBuildSpecId);
273
}
274
flagInfo = new CmakeFlagInfo(cmakeCache);
275
} else {
276
flagInfo = new UmaFlagInfo(configDirectory, buildSpecId);
277
}
278
279
ConstantPool pool = parseConstantPool();
280
281
pool.removeNonApplicableItems(version.intValue(), flagInfo.getAllSetFlags());
282
283
writeHeader(pool);
284
writeDefinition(pool, version.intValue(), flagInfo.getAllSetFlags());
285
}
286
287
private static File getOutputFile(String directory, String fileName) throws FileNotFoundException {
288
File dir;
289
// If -outputDir was not set on commandline, default to outputting in the root directory
290
if (outputDirectory == null) {
291
dir = new File(rootDirectory, directory);
292
} else {
293
// Note: if -outputDir was specified we output all files in that directory (not in any sub directories)
294
// so we ignore the directory argument
295
dir = new File(outputDirectory);
296
}
297
298
File file = new File(dir, fileName);
299
return file;
300
}
301
302
private static void printOn(PrintWriter out, String[] lines) {
303
for (int i = 0; i < lines.length; ++i) {
304
out.println(lines[i]);
305
}
306
}
307
308
private static void writeDefinition(ConstantPool pool, int version, Set<String> flags) throws Throwable {
309
System.out.println("Generating JCL constant pool definitions for Java " + version);
310
StringWriter buffer = new StringWriter();
311
PrintWriter out = new PrintWriter(buffer);
312
printOn(out, openDefinition);
313
out.println();
314
printOn(out, endianMacros);
315
out.println();
316
317
pool.writeForClassLibrary(version, flags, out);
318
319
out.flush();
320
out.close();
321
322
writeToDisk(getOutputFile("jcl", "j9vmconstantpool.c"), buffer.toString());
323
}
324
325
private static void writeHeader(ConstantPool pool) throws Throwable {
326
System.out.print("Generating header file ");
327
StringWriter buffer = new StringWriter();
328
PrintWriter out = new PrintWriter(buffer);
329
printOn(out, openHeader);
330
out.println();
331
332
out.println("/* Runtime flag definitions */");
333
for (JCLRuntimeFlag flag : runtimeFlagDefs.values()) {
334
out.println(flag.cDefine());
335
}
336
out.println();
337
338
printOn(out, classMacros);
339
out.println();
340
printOn(out, fieldMacros);
341
out.println();
342
printOn(out, staticFieldMacros);
343
out.println();
344
printOn(out, staticMethodMacros);
345
out.println();
346
printOn(out, virtualMethodMacros);
347
out.println();
348
printOn(out, specialMethodMacros);
349
out.println();
350
printOn(out, interfaceMethodMacros);
351
out.println();
352
pool.writeMacros(out);
353
out.println();
354
out.println("#define J9VM_VMCONSTANTPOOL_SIZE " + pool.constantPoolSize());
355
out.println();
356
printOn(out, closeHeader);
357
358
out.flush();
359
out.close();
360
writeToDisk(getOutputFile("oti", "j9vmconstantpool.h"), buffer.toString());
361
}
362
363
private static ConstantPool parseConstantPool() throws IOException {
364
NodeList nodes;
365
366
try {
367
File dir = new File(rootDirectory, "oti");
368
File file = new File(dir, constantPool);
369
System.out.println("Reading constant pool from " + file.getPath());
370
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
371
Document document = builder.parse(file.toURI().toURL().toExternalForm());
372
nodes = document.getDocumentElement().getChildNodes();
373
} catch (Exception e) {
374
e.printStackTrace();
375
System.exit(-1);
376
return null; // unreachable
377
}
378
379
Map<String, ClassRef> classes = new HashMap<>();
380
final int nodeCount = nodes.getLength();
381
382
// Find classref elements.
383
for (int i = 0; i < nodeCount; ++i) {
384
Node node = nodes.item(i);
385
if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(CLASSREF)) {
386
Element element = (Element) node;
387
if (element.hasAttribute("name")) {
388
classes.put(element.getAttribute("name"), new ClassRef(element));
389
} else {
390
System.err.println("Missing name for " + CLASSREF + " element");
391
System.exit(-1);
392
}
393
}
394
}
395
396
// Build constant pool
397
ConstantPool pool = new ConstantPool();
398
// TreeMap keeps flags ordered by name.
399
runtimeFlagDefs = new TreeMap<>();
400
401
int lastFlagValue = 0x1;
402
JCLRuntimeFlag defaultFlag = new JCLRuntimeFlag("default", lastFlagValue);
403
runtimeFlagDefs.put("default", defaultFlag);
404
405
for (int i = 0; i < nodeCount; ++i) {
406
Node node = nodes.item(i);
407
if (node.getNodeType() == Node.ELEMENT_NODE) {
408
PrimaryItem cpItem = cpItem((Element) node, classes);
409
410
/* Extract and validate flags */
411
Node flagsNode = node.getAttributes().getNamedItem("flags");
412
if (null == flagsNode) {
413
defaultFlag.useCount += 1;
414
} else {
415
/* non-null flags= attribute */
416
String flagName = flagsNode.getTextContent();
417
418
/* validate flags used in constantpool.xml */
419
if (!flagInfo.isFlagValid(flagName)) {
420
System.err.println("Invalid flag used ->" + flagName);
421
System.exit(-1);
422
}
423
424
if (flagName.startsWith("!")) {
425
// skip flag w/ starting !
426
flagName = flagName.substring(1);
427
}
428
/* Find or create the flag object */
429
JCLRuntimeFlag flag = runtimeFlagDefs.get(flagName);
430
if (null == flag) {
431
lastFlagValue <<= 1;
432
flag = new JCLRuntimeFlag(flagName, lastFlagValue);
433
runtimeFlagDefs.put(flagName, flag);
434
}
435
436
/* increment the useCount */
437
flag.useCount += 1;
438
}
439
440
pool.add(cpItem);
441
}
442
}
443
444
System.out.println("Found " + runtimeFlagDefs.size() + " flags used, declaring runtime constants.");
445
446
for (JCLRuntimeFlag flag : runtimeFlagDefs.values()) {
447
System.out.println("\t" + flag.cDefine() + " (useCount=" + flag.useCount + ")");
448
}
449
450
return pool;
451
}
452
453
private static PrimaryItem cpItem(Element e, Map<String, ClassRef> classes) {
454
String type = e.getNodeName();
455
if (CLASSREF.equals(type)) {
456
return classes.get(e.getAttribute("name"));
457
} else if (FIELDREF.equals(type)) {
458
return new FieldRef(e, classes);
459
} else if (STATICFIELDREF.equals(type)) {
460
return new StaticFieldRef(e, classes);
461
} else if (STATICMETHODREF.equals(type)) {
462
return new StaticMethodRef(e, classes);
463
} else if (VIRTUALMETHODREF.equals(type)) {
464
return new VirtualMethodRef(e, classes);
465
} else if (SPECIALMETHODREF.equals(type)) {
466
return new SpecialMethodRef(e, classes);
467
} else if (INTERFACEMETHODREF.equals(type)) {
468
return new InterfaceMethodRef(e, classes);
469
} else {
470
System.err.println("Unrecognized node type: " + type);
471
System.exit(-1);
472
return null; // unreachable
473
}
474
}
475
476
public static JCLRuntimeFlag getRuntimeFlag(String key) {
477
return runtimeFlagDefs.get(key);
478
}
479
480
/**
481
* Checks if a file with given name exists on disk. Returns true if it does
482
* not exist. If the file exists, compares it with generated buffer and
483
* returns true if they are equal.
484
*
485
* @param fileName
486
* @param desiredContent
487
* @return boolean TRUE|FALSE
488
*/
489
private static boolean differentFromCopyOnDisk(String fileName, String desiredContent) {
490
File fileOnDisk = new File(fileName);
491
boolean returnValue = true;
492
493
if (fileOnDisk.exists()) {
494
StringBuilder fileBuffer = new StringBuilder();
495
try {
496
try (FileReader fr = new FileReader(fileOnDisk)) {
497
char charArray[] = new char[1024];
498
499
int numRead = -1;
500
while ((numRead = fr.read(charArray)) != -1) {
501
fileBuffer.append(charArray, 0, numRead);
502
}
503
504
if (desiredContent.equals(fileBuffer.toString())) {
505
returnValue = false;
506
}
507
}
508
} catch (IOException e) {
509
// ignore
510
}
511
}
512
513
return returnValue;
514
}
515
516
/**
517
* Compares the given buffer and file and if they are different it writes
518
* the buffer into a new file.
519
*
520
* @param file
521
* @param desiredContent
522
* @return
523
* @throws IOException
524
*/
525
private static void writeToDisk(File file, String desiredContent) throws IOException {
526
if (differentFromCopyOnDisk(file.getPath(), desiredContent)) {
527
System.out.println("** Writing " + file.getPath());
528
file.delete();
529
530
try (FileWriter fw = new FileWriter(file.getPath())) {
531
fw.write(desiredContent);
532
}
533
} else if (verbose) {
534
System.out.println("** Skipped writing [same as on file system]: " + file.getPath());
535
}
536
}
537
538
}
539
540