Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/debugtools/DDR_Autoblob/src/com/ibm/j9ddr/autoblob/GenerateBlobC.java
6007 views
1
/*******************************************************************************
2
* Copyright (c) 2010, 2019 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.j9ddr.autoblob;
23
24
import java.io.File;
25
import java.io.FileWriter;
26
import java.io.IOException;
27
import java.io.PrintWriter;
28
import java.util.Collection;
29
import java.util.HashMap;
30
import java.util.LinkedList;
31
import java.util.List;
32
import java.util.Map;
33
import java.util.Set;
34
import java.util.SortedSet;
35
import java.util.TreeSet;
36
37
import org.xml.sax.SAXException;
38
39
import com.ibm.j9ddr.autoblob.config.BlobHeader;
40
import com.ibm.j9ddr.autoblob.config.Configuration;
41
import com.ibm.j9ddr.autoblob.datamodel.EnumType;
42
import com.ibm.j9ddr.autoblob.datamodel.ITypeCollection;
43
import com.ibm.j9ddr.autoblob.datamodel.StructType;
44
import com.ibm.j9ddr.autoblob.datamodel.UserDefinedType;
45
import com.ibm.j9ddr.autoblob.datamodel.Typedef;
46
import com.ibm.j9ddr.autoblob.datamodel.UnionType;
47
import com.ibm.j9ddr.autoblob.linenumbers.IHeaderResolver;
48
import com.ibm.j9ddr.autoblob.linenumbers.PreProcessedSourceParser;
49
import com.ibm.j9ddr.autoblob.xmlparser.StructureXMLParser;
50
51
/**
52
* Combines structure data from an XML file generated by the EDG extract_structures tool with
53
* constants parsed from C/C++ headers to produce C/C++ blob generation code.
54
*
55
* @author andhall
56
*
57
*/
58
@SuppressWarnings("nls")
59
public class GenerateBlobC
60
{
61
62
private static final String PROPERTIES_ARGUMENT = "-props";
63
64
private static final String CFILE_ARGUMENT = "-cfile";
65
66
private static final String XMLFILE_ARGUMENT = "-xmlfile";
67
68
private static final String OUTFILE_ARGUMENT = "-outfile";
69
70
private static final String INCLUDE_ARGUMENT = "-I";
71
72
private static final String DEFINE_ARGUMENT = "-D";
73
74
private static final String J9_FLAGS = "-j9flags";
75
76
/**
77
* @param args
78
* @throws IOException
79
* @throws SAXException
80
*/
81
public static void main(String[] args) throws IOException, SAXException
82
{
83
printHeader();
84
GenerateBlobCConfig config = handleArgs(args);
85
process(config);
86
}
87
88
private static void process(GenerateBlobCConfig config) throws IOException, SAXException
89
{
90
//Do a first pass to extract line numbers
91
PreProcessedSourceParser preProcessedSourceParser = new PreProcessedSourceParser(config.cFile, null);
92
93
StructureXMLParser parser = new StructureXMLParser(config.xmlFile, preProcessedSourceParser.getLineNumberConvertor());
94
writeCFile(config.cFile, parser, config);
95
}
96
97
/**
98
* Data class for types parsed from a particular C file.
99
* @author andhall
100
*
101
*/
102
public static class FileTypes implements ITypeCollection
103
{
104
FileTypes(File file)
105
{
106
this.file = file;
107
}
108
109
public final File file;
110
111
public final List<Typedef> typedefs = new LinkedList<Typedef>();
112
113
public final Map<String, StructType> structs = new HashMap<String, StructType>();
114
115
public final Map<String, UnionType> unions = new HashMap<String, UnionType>();
116
117
public final Map<String, EnumType> enums = new HashMap<String, EnumType>();
118
119
public final List<EnumType> anonymousEnums = new LinkedList<EnumType>();
120
121
public UserDefinedType findType(String name)
122
{
123
UserDefinedType toReturn;
124
125
toReturn = findTypeIn(name, typedefs);
126
if (toReturn != null) {
127
return toReturn;
128
}
129
130
toReturn = findTypeIn(name, structs.values());
131
if (toReturn != null) {
132
return toReturn;
133
}
134
135
toReturn = findTypeIn(name, unions.values());
136
if (toReturn != null) {
137
return toReturn;
138
}
139
140
toReturn = findTypeIn(name, enums.values());
141
if (toReturn != null) {
142
return toReturn;
143
}
144
145
return null;
146
}
147
148
private UserDefinedType findTypeIn(String name, Collection<? extends UserDefinedType> types)
149
{
150
for (UserDefinedType t : types) {
151
if (t.getName().equals(name)) {
152
return t;
153
}
154
}
155
return null;
156
}
157
158
public void loadTypes(SortedSet<UserDefinedType> typesToWrite, GenerateBlobCConfig config)
159
{
160
GenerateBlobC.loadTypes(typesToWrite, typedefs, config);
161
GenerateBlobC.loadTypes(typesToWrite, structs.values(), config);
162
GenerateBlobC.loadTypes(typesToWrite, enums.values(), config);
163
GenerateBlobC.loadTypes(typesToWrite, unions.values(), config);
164
}
165
166
}
167
168
private static void writeCFile(File inputFile, StructureXMLParser parser, GenerateBlobCConfig config) throws IOException, SAXException
169
{
170
applyInheritanceRelationships(parser, config);
171
172
Map<String, FileTypes> typesByFile = extractTypes(config, parser);
173
174
PrintWriter out = new PrintWriter(new FileWriter(config.outputFile));
175
PrintWriter ssout = new PrintWriter(new FileWriter(config.outputSuperSetFile));
176
177
try {
178
writeHeader(out, config, parser);
179
180
SortedSet<UserDefinedType> typesToWrite = new TreeSet<UserDefinedType>();
181
182
loadTypes(typesToWrite, config.autoblobConfiguration.getPseudoTypes().values(), config);
183
184
for (BlobHeader header : config.autoblobConfiguration.getBlobHeaders()) {
185
String thisFileName = header.getName();
186
187
FileTypes types = typesByFile.get(thisFileName);
188
189
File file = config.headerResolver.findHeader(header.getName());
190
191
if (null == file) {
192
continue;
193
}
194
195
List<UserDefinedType> constantPseudoTypes = header.loadConstants(file, types, parser);
196
197
loadTypes(typesToWrite, constantPseudoTypes, config);
198
199
if (null != types ) {
200
types.loadTypes(typesToWrite, config);
201
}
202
}
203
204
for (UserDefinedType t : typesToWrite) {
205
t.writeFieldsAndConstantsAsBlobC(out, ssout);
206
}
207
208
writeFooter(out, typesToWrite, config, parser);
209
} finally {
210
out.close();
211
ssout.close();
212
}
213
}
214
215
static void loadTypes(SortedSet<UserDefinedType> typesToWrite, Collection<? extends UserDefinedType> toLoad, GenerateBlobCConfig config)
216
{
217
for (UserDefinedType t : toLoad) {
218
if (t.shouldBeInBlob()) {
219
t.applyTypeOverrides(config.autoblobConfiguration);
220
typesToWrite.add(t);
221
}
222
}
223
}
224
225
private static void applyInheritanceRelationships(StructureXMLParser parser, GenerateBlobCConfig config)
226
{
227
Map<String, String> inheritanceRelationships = config.autoblobConfiguration.getInheritanceRelationships();
228
for (String subClassName : inheritanceRelationships.keySet()) {
229
String superClassName = inheritanceRelationships.get(subClassName);
230
231
UserDefinedType subclass = findType(subClassName, parser, config.autoblobConfiguration);
232
233
if (null == subclass) {
234
System.err.println("Cannot apply inheritance rule " + subClassName + " extends " + superClassName + ": can't match subclass");
235
continue;
236
}
237
238
UserDefinedType superclass = findType(superClassName, parser, config.autoblobConfiguration);
239
240
if (null == superclass) {
241
System.err.println("Cannot apply inheritance rule " + subClassName + " extends " + superClassName + ": can't match superclass");
242
continue;
243
}
244
245
subclass.setSuperClass(superclass);
246
}
247
}
248
249
private static UserDefinedType findType(String name, StructureXMLParser parser, Configuration config)
250
{
251
/* Checking PseudoTypes first allows us to override existing types with PseudoTypes. */
252
UserDefinedType t = config.getPseudoTypes().get(name);
253
254
if (t == null) {
255
t = parser.findType(name);
256
}
257
258
return t;
259
}
260
261
private static void writeHeader(PrintWriter out, GenerateBlobCConfig config, StructureXMLParser parser)
262
{
263
out.println("/* Generated by J9DDR GenerateBlobC - DO NOT EDIT DIRECTLY */");
264
out.println();
265
out.println("#include \"j9ddr.h\"");
266
config.autoblobConfiguration.writeCIncludes(out);
267
out.println();
268
269
if (parser.readCPlusPlus()) {
270
String className = getCPlusPlusClassName(config);
271
out.println("class " + className);
272
out.println("{");
273
out.println("public:");
274
out.println("\tstatic const J9DDRStructDefinition *getStructTable();");
275
out.println("};");
276
out.println();
277
out.println("const J9DDRStructDefinition *" + className + "::getStructTable()");
278
out.println("{");
279
}
280
}
281
282
private static String getCPlusPlusClassName(GenerateBlobCConfig config)
283
{
284
String className = "J9DDRStructTable" + config.autoblobConfiguration.getName();
285
return className;
286
}
287
288
private static void writeFooter(PrintWriter out, Set<UserDefinedType> writtenOutTypes, GenerateBlobCConfig config, StructureXMLParser parser)
289
{
290
if (parser.readCPlusPlus()) {
291
writeCPlusPlusFooter(out,writtenOutTypes, config);
292
} else {
293
writeCFooter(out,writtenOutTypes, config);
294
}
295
}
296
297
private static void writeCFooter(PrintWriter out, Set<UserDefinedType> writtenOutTypes, GenerateBlobCConfig config)
298
{
299
out.println();
300
out.println("J9DDRStructTableBegin(" + config.autoblobConfiguration.getName() + ")");
301
for (UserDefinedType type : writtenOutTypes) {
302
type.writeStructDefinitionAsBlobC(out);
303
}
304
out.println("J9DDRStructTableEnd");
305
out.println();
306
out.println("const J9DDRStructDefinition *get" + config.autoblobConfiguration.getName() + "StructTable(struct OMRPortLibrary *portLib)");
307
out.println("{");
308
out.println("\treturn J9DDR_" + config.autoblobConfiguration.getName() + "_structs;");
309
out.println("}");
310
}
311
312
private static void writeCPlusPlusFooter(PrintWriter out,
313
Set<UserDefinedType> writtenOutTypes, GenerateBlobCConfig config)
314
{
315
out.println();
316
out.println("static J9DDRStructTableBegin(" + config.autoblobConfiguration.getName() + ")");
317
for (UserDefinedType type : writtenOutTypes) {
318
type.writeStructDefinitionAsBlobC(out);
319
}
320
out.println("J9DDRStructTableEnd");
321
out.println();
322
out.println("\treturn J9DDR_" + config.autoblobConfiguration.getName() + "_structs;");
323
out.println("}");
324
out.println("extern \"C\" {");
325
out.println();
326
out.println("\tconst J9DDRStructDefinition *get" + config.autoblobConfiguration.getName() + "StructTable(struct OMRPortLibrary *portLib)");
327
out.println("\t{");
328
out.println("\t\treturn " + getCPlusPlusClassName(config) + "::getStructTable();");
329
out.println("\t}");
330
out.println();
331
out.println("}");
332
}
333
334
private static Map<String, FileTypes> extractTypes(GenerateBlobCConfig config, StructureXMLParser parser) throws IOException
335
{
336
Map<String, FileTypes> typesByAbsolutePath = extractTypesByAbsolutePath(parser);
337
Map<String, FileTypes> typesByHeaderName = stripPaths(typesByAbsolutePath);
338
Map<String, String> absolutePathsByHeaderName = mapFileNamesToAbsolutePaths(typesByAbsolutePath.keySet());
339
340
Map<String, FileTypes> typesByShortPath = new HashMap<String, FileTypes>();
341
342
for (BlobHeader header: config.autoblobConfiguration.getBlobHeaders()) {
343
String headerName = header.getName();
344
File headerPath = config.headerResolver.findHeader(headerName);
345
346
if (headerPath == null) {
347
continue;
348
}
349
350
String absolutePath = headerPath.getCanonicalPath();
351
FileTypes types = typesByAbsolutePath.get(absolutePath);
352
353
if (types != null) {
354
typesByShortPath.put(headerName, types);
355
} else {
356
/*
357
* CMVC 193975 - adam
358
*
359
* When running the build on Windows if a relative path has been used with / delimiters for the name
360
* e.g. common/thrtypes , then Windows will treat the entire string as the file name rather than a directory
361
* followed by a file name as Linux does. In order to correctly fallback to match just the name of the
362
* header file on Window's systems, only the characters after the last / can be used.
363
*/
364
int pos = headerName.lastIndexOf('/');
365
if((pos != -1) && (pos < (headerName.length() + 1))) {
366
System.err.println("Relative header name character found in : " + headerName);
367
headerName = headerName.substring(pos + 1);
368
System.err.println("Now trying to match header name : " + headerName);
369
}
370
371
/* Jazz 45699 - lpnguyen
372
* There is a known issue where with #includes using relative paths we can end up with headers in the
373
* typesByAbsolutePath collection from outside the current working directory (ddr/gc_ddr).
374
*
375
* We'll fall back to searching based on just headerName in this case to find its FileTypes
376
*/
377
378
types = typesByHeaderName.get(headerName);
379
if (types != null) {
380
typesByShortPath.put(header.getName(), types);
381
System.err.println("Warning: Using " + absolutePathsByHeaderName.get(headerName) + " instead of " + absolutePath);
382
}
383
}
384
}
385
386
return typesByShortPath;
387
}
388
389
/* Generate mapping between header name and their absolute paths */
390
private static Map<String, String> mapFileNamesToAbsolutePaths(Collection<String> absolutePaths)
391
{
392
Map<String, String> absolutePathsByHeaderName = new HashMap<String, String>();
393
394
for (String absolutePath : absolutePaths) {
395
String fileName = new File(absolutePath).getName();
396
String oldValue = absolutePathsByHeaderName.put(fileName, absolutePath);
397
if (null != oldValue) {
398
System.err.println("Warning: duplicate headers:" + oldValue + " and " + absolutePath + " found");
399
}
400
}
401
402
return absolutePathsByHeaderName;
403
}
404
405
/* Strip the absolute path in the typesByAbsolutePath mapping keyset */
406
private static Map<String, FileTypes> stripPaths(Map<String, FileTypes> typesByAbsolutePath)
407
{
408
Map<String, FileTypes> typesByFileName = new HashMap<String, FileTypes>();
409
410
for (String fileName : typesByAbsolutePath.keySet()) {
411
String strippedFileName = new File(fileName).getName();
412
typesByFileName.put(strippedFileName, typesByAbsolutePath.get(fileName));
413
//will report overwrites in mapFileNamesToAbsolutePaths()
414
}
415
416
return typesByFileName;
417
}
418
419
private static Map<String, FileTypes> extractTypesByAbsolutePath(StructureXMLParser parser)
420
{
421
Map<String, FileTypes> typesByFile = new HashMap<String, FileTypes>();
422
423
//Typedefs
424
for (Typedef typedef : parser.getTypedefs().values()) {
425
String filename = typedef.getDefinitionLocation() == null ? "<unknown>" : typedef.getDefinitionLocation().getFileName();
426
427
FileTypes types = typesByFile.get(filename);
428
429
if (null == types) {
430
types = new FileTypes(new File(filename));
431
typesByFile.put(filename,types);
432
}
433
434
types.typedefs.add(typedef);
435
}
436
437
for (StructType struct : parser.getStructures()) {
438
String filename = struct.getDefinitionLocation() == null ? "<unknown>" : struct.getDefinitionLocation().getFileName();
439
440
FileTypes types = typesByFile.get(filename);
441
442
if (null == types) {
443
types = new FileTypes(new File(filename));
444
typesByFile.put(filename,types);
445
}
446
447
types.structs.put(struct.getName(), struct);
448
}
449
450
for (UnionType union : parser.getUnions()) {
451
String filename = union.getDefinitionLocation() == null ? "<unknown>" : union.getDefinitionLocation().getFileName();
452
453
FileTypes types = typesByFile.get(filename);
454
455
if (null == types) {
456
types = new FileTypes(new File(filename));
457
typesByFile.put(filename,types);
458
}
459
460
types.unions.put(union.getName(), union);
461
}
462
463
for (EnumType thisEnum : parser.getEnums()) {
464
String filename = thisEnum.getDefinitionLocation() == null ? "<unknown>" : thisEnum.getDefinitionLocation().getFileName();
465
466
FileTypes types = typesByFile.get(filename);
467
468
if (null == types) {
469
types = new FileTypes(new File(filename));
470
typesByFile.put(filename,types);
471
}
472
473
types.enums.put(thisEnum.getName(), thisEnum);
474
}
475
476
for (EnumType thisEnum : parser.getTopScopeAnonymousEnums()) {
477
String filename = thisEnum.getDefinitionLocation() == null ? "<unknown>" : thisEnum.getDefinitionLocation().getFileName();
478
479
FileTypes types = typesByFile.get(filename);
480
481
if (null == types) {
482
types = new FileTypes(new File(filename));
483
typesByFile.put(filename,types);
484
}
485
486
types.anonymousEnums.add(thisEnum);
487
}
488
489
return typesByFile;
490
}
491
492
private static void printHeader()
493
{
494
System.out.println("J9DDR Automatic DDR Structure Blob Generator");
495
}
496
497
private static GenerateBlobCConfig handleArgs(String[] args) throws IOException, SAXException
498
{
499
File configFile = null;
500
File cFile = null;
501
File xmlFile = null;
502
File outputFile = null;
503
File j9FlagsFile = null;
504
List<File> includeSearchPath = new LinkedList<File>();
505
506
for (int i=0; i < args.length; i++) {
507
String currentArg = args[i];
508
boolean argConsumed = false;
509
510
if (i < args.length - 1) {
511
if (currentArg.equalsIgnoreCase(PROPERTIES_ARGUMENT)) {
512
configFile = new File(args[i + 1]);
513
//Step over value
514
i++;
515
argConsumed = true;
516
} else if (currentArg.equalsIgnoreCase(CFILE_ARGUMENT)) {
517
cFile = new File(args[i + 1]);
518
i++;
519
argConsumed = true;
520
} else if (currentArg.equalsIgnoreCase(XMLFILE_ARGUMENT)) {
521
xmlFile = new File(args[i + 1]);
522
i++;
523
argConsumed = true;
524
} else if (currentArg.equalsIgnoreCase(OUTFILE_ARGUMENT)) {
525
outputFile = new File(args[i + 1]);
526
i++;
527
argConsumed = true;
528
} else if (currentArg.equalsIgnoreCase(J9_FLAGS)) {
529
j9FlagsFile = new File(args[i + 1]);
530
i++;
531
argConsumed = true;
532
}
533
}
534
535
if (currentArg.startsWith(INCLUDE_ARGUMENT)) {
536
File path = new File(currentArg.substring(INCLUDE_ARGUMENT.length()));
537
538
includeSearchPath.add(path);
539
argConsumed = true;
540
} else if (currentArg.startsWith(DEFINE_ARGUMENT)) {
541
//Ignore
542
argConsumed = true;
543
}
544
545
if (! argConsumed) {
546
System.err.println("Couldn't consume argument: " + currentArg);
547
System.exit(1);
548
}
549
}
550
551
boolean badConfig = false;
552
if (null == configFile) {
553
System.err.println(PROPERTIES_ARGUMENT + " not specified");
554
badConfig = true;
555
}
556
557
if (null == cFile) {
558
System.err.println(CFILE_ARGUMENT + " not specified");
559
badConfig = true;
560
}
561
562
if (null == outputFile) {
563
System.err.println(OUTFILE_ARGUMENT + " not specified");
564
badConfig = true;
565
}
566
567
if (null == j9FlagsFile) {
568
System.err.println(J9_FLAGS + " not specified");
569
badConfig = true;
570
}
571
572
if (badConfig) {
573
usage();
574
System.exit(1);
575
}
576
577
return new GenerateBlobCConfig(cFile, xmlFile, outputFile, Configuration.loadConfiguration(configFile, j9FlagsFile), new HeaderResolver(includeSearchPath));
578
}
579
580
static class HeaderResolver implements IHeaderResolver
581
{
582
583
private final List<File> includePath;
584
585
public HeaderResolver(List<File> includePath)
586
{
587
this.includePath = includePath;
588
}
589
590
public File findHeader(String name)
591
{
592
for (File path : includePath) {
593
File possibleFile = new File(path, name);
594
if (possibleFile.exists()) {
595
return possibleFile;
596
}
597
}
598
599
return null;
600
}
601
602
}
603
604
private static void usage()
605
{
606
System.err.println(GenerateBlobC.class.getSimpleName());
607
System.err.println("Usage:");
608
System.err.println("java " + GenerateBlobC.class.getName() + "-props <config properties file> -infile <pre-processed input> -outfile <output file> -j9flags <j9.flags file> [-I<include path entry>]+");
609
System.err.println();
610
System.err.println("Note: this tool currently cannot handle C++.");
611
}
612
613
static class GenerateBlobCConfig
614
{
615
public final File cFile;
616
617
public final File xmlFile;
618
619
public final File outputFile;
620
621
public final File outputSuperSetFile;
622
623
public final Configuration autoblobConfiguration;
624
625
public final IHeaderResolver headerResolver;
626
627
public GenerateBlobCConfig(File cFile, File xmlFile, File outputFile, Configuration configuration, IHeaderResolver headerResolver)
628
{
629
this.cFile = cFile;
630
this.xmlFile = xmlFile;
631
this.outputFile = outputFile;
632
outputSuperSetFile = new File(outputFile.getAbsolutePath() + ".superset");
633
this.autoblobConfiguration = configuration;
634
this.headerResolver = headerResolver;
635
}
636
}
637
638
}
639
640