Path: blob/master/debugtools/DDR_Autoblob/src/com/ibm/j9ddr/autoblob/GenerateBlobC.java
6007 views
/*******************************************************************************1* Copyright (c) 2010, 2019 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* 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-exception20*******************************************************************************/21package com.ibm.j9ddr.autoblob;2223import java.io.File;24import java.io.FileWriter;25import java.io.IOException;26import java.io.PrintWriter;27import java.util.Collection;28import java.util.HashMap;29import java.util.LinkedList;30import java.util.List;31import java.util.Map;32import java.util.Set;33import java.util.SortedSet;34import java.util.TreeSet;3536import org.xml.sax.SAXException;3738import com.ibm.j9ddr.autoblob.config.BlobHeader;39import com.ibm.j9ddr.autoblob.config.Configuration;40import com.ibm.j9ddr.autoblob.datamodel.EnumType;41import com.ibm.j9ddr.autoblob.datamodel.ITypeCollection;42import com.ibm.j9ddr.autoblob.datamodel.StructType;43import com.ibm.j9ddr.autoblob.datamodel.UserDefinedType;44import com.ibm.j9ddr.autoblob.datamodel.Typedef;45import com.ibm.j9ddr.autoblob.datamodel.UnionType;46import com.ibm.j9ddr.autoblob.linenumbers.IHeaderResolver;47import com.ibm.j9ddr.autoblob.linenumbers.PreProcessedSourceParser;48import com.ibm.j9ddr.autoblob.xmlparser.StructureXMLParser;4950/**51* Combines structure data from an XML file generated by the EDG extract_structures tool with52* constants parsed from C/C++ headers to produce C/C++ blob generation code.53*54* @author andhall55*56*/57@SuppressWarnings("nls")58public class GenerateBlobC59{6061private static final String PROPERTIES_ARGUMENT = "-props";6263private static final String CFILE_ARGUMENT = "-cfile";6465private static final String XMLFILE_ARGUMENT = "-xmlfile";6667private static final String OUTFILE_ARGUMENT = "-outfile";6869private static final String INCLUDE_ARGUMENT = "-I";7071private static final String DEFINE_ARGUMENT = "-D";7273private static final String J9_FLAGS = "-j9flags";7475/**76* @param args77* @throws IOException78* @throws SAXException79*/80public static void main(String[] args) throws IOException, SAXException81{82printHeader();83GenerateBlobCConfig config = handleArgs(args);84process(config);85}8687private static void process(GenerateBlobCConfig config) throws IOException, SAXException88{89//Do a first pass to extract line numbers90PreProcessedSourceParser preProcessedSourceParser = new PreProcessedSourceParser(config.cFile, null);9192StructureXMLParser parser = new StructureXMLParser(config.xmlFile, preProcessedSourceParser.getLineNumberConvertor());93writeCFile(config.cFile, parser, config);94}9596/**97* Data class for types parsed from a particular C file.98* @author andhall99*100*/101public static class FileTypes implements ITypeCollection102{103FileTypes(File file)104{105this.file = file;106}107108public final File file;109110public final List<Typedef> typedefs = new LinkedList<Typedef>();111112public final Map<String, StructType> structs = new HashMap<String, StructType>();113114public final Map<String, UnionType> unions = new HashMap<String, UnionType>();115116public final Map<String, EnumType> enums = new HashMap<String, EnumType>();117118public final List<EnumType> anonymousEnums = new LinkedList<EnumType>();119120public UserDefinedType findType(String name)121{122UserDefinedType toReturn;123124toReturn = findTypeIn(name, typedefs);125if (toReturn != null) {126return toReturn;127}128129toReturn = findTypeIn(name, structs.values());130if (toReturn != null) {131return toReturn;132}133134toReturn = findTypeIn(name, unions.values());135if (toReturn != null) {136return toReturn;137}138139toReturn = findTypeIn(name, enums.values());140if (toReturn != null) {141return toReturn;142}143144return null;145}146147private UserDefinedType findTypeIn(String name, Collection<? extends UserDefinedType> types)148{149for (UserDefinedType t : types) {150if (t.getName().equals(name)) {151return t;152}153}154return null;155}156157public void loadTypes(SortedSet<UserDefinedType> typesToWrite, GenerateBlobCConfig config)158{159GenerateBlobC.loadTypes(typesToWrite, typedefs, config);160GenerateBlobC.loadTypes(typesToWrite, structs.values(), config);161GenerateBlobC.loadTypes(typesToWrite, enums.values(), config);162GenerateBlobC.loadTypes(typesToWrite, unions.values(), config);163}164165}166167private static void writeCFile(File inputFile, StructureXMLParser parser, GenerateBlobCConfig config) throws IOException, SAXException168{169applyInheritanceRelationships(parser, config);170171Map<String, FileTypes> typesByFile = extractTypes(config, parser);172173PrintWriter out = new PrintWriter(new FileWriter(config.outputFile));174PrintWriter ssout = new PrintWriter(new FileWriter(config.outputSuperSetFile));175176try {177writeHeader(out, config, parser);178179SortedSet<UserDefinedType> typesToWrite = new TreeSet<UserDefinedType>();180181loadTypes(typesToWrite, config.autoblobConfiguration.getPseudoTypes().values(), config);182183for (BlobHeader header : config.autoblobConfiguration.getBlobHeaders()) {184String thisFileName = header.getName();185186FileTypes types = typesByFile.get(thisFileName);187188File file = config.headerResolver.findHeader(header.getName());189190if (null == file) {191continue;192}193194List<UserDefinedType> constantPseudoTypes = header.loadConstants(file, types, parser);195196loadTypes(typesToWrite, constantPseudoTypes, config);197198if (null != types ) {199types.loadTypes(typesToWrite, config);200}201}202203for (UserDefinedType t : typesToWrite) {204t.writeFieldsAndConstantsAsBlobC(out, ssout);205}206207writeFooter(out, typesToWrite, config, parser);208} finally {209out.close();210ssout.close();211}212}213214static void loadTypes(SortedSet<UserDefinedType> typesToWrite, Collection<? extends UserDefinedType> toLoad, GenerateBlobCConfig config)215{216for (UserDefinedType t : toLoad) {217if (t.shouldBeInBlob()) {218t.applyTypeOverrides(config.autoblobConfiguration);219typesToWrite.add(t);220}221}222}223224private static void applyInheritanceRelationships(StructureXMLParser parser, GenerateBlobCConfig config)225{226Map<String, String> inheritanceRelationships = config.autoblobConfiguration.getInheritanceRelationships();227for (String subClassName : inheritanceRelationships.keySet()) {228String superClassName = inheritanceRelationships.get(subClassName);229230UserDefinedType subclass = findType(subClassName, parser, config.autoblobConfiguration);231232if (null == subclass) {233System.err.println("Cannot apply inheritance rule " + subClassName + " extends " + superClassName + ": can't match subclass");234continue;235}236237UserDefinedType superclass = findType(superClassName, parser, config.autoblobConfiguration);238239if (null == superclass) {240System.err.println("Cannot apply inheritance rule " + subClassName + " extends " + superClassName + ": can't match superclass");241continue;242}243244subclass.setSuperClass(superclass);245}246}247248private static UserDefinedType findType(String name, StructureXMLParser parser, Configuration config)249{250/* Checking PseudoTypes first allows us to override existing types with PseudoTypes. */251UserDefinedType t = config.getPseudoTypes().get(name);252253if (t == null) {254t = parser.findType(name);255}256257return t;258}259260private static void writeHeader(PrintWriter out, GenerateBlobCConfig config, StructureXMLParser parser)261{262out.println("/* Generated by J9DDR GenerateBlobC - DO NOT EDIT DIRECTLY */");263out.println();264out.println("#include \"j9ddr.h\"");265config.autoblobConfiguration.writeCIncludes(out);266out.println();267268if (parser.readCPlusPlus()) {269String className = getCPlusPlusClassName(config);270out.println("class " + className);271out.println("{");272out.println("public:");273out.println("\tstatic const J9DDRStructDefinition *getStructTable();");274out.println("};");275out.println();276out.println("const J9DDRStructDefinition *" + className + "::getStructTable()");277out.println("{");278}279}280281private static String getCPlusPlusClassName(GenerateBlobCConfig config)282{283String className = "J9DDRStructTable" + config.autoblobConfiguration.getName();284return className;285}286287private static void writeFooter(PrintWriter out, Set<UserDefinedType> writtenOutTypes, GenerateBlobCConfig config, StructureXMLParser parser)288{289if (parser.readCPlusPlus()) {290writeCPlusPlusFooter(out,writtenOutTypes, config);291} else {292writeCFooter(out,writtenOutTypes, config);293}294}295296private static void writeCFooter(PrintWriter out, Set<UserDefinedType> writtenOutTypes, GenerateBlobCConfig config)297{298out.println();299out.println("J9DDRStructTableBegin(" + config.autoblobConfiguration.getName() + ")");300for (UserDefinedType type : writtenOutTypes) {301type.writeStructDefinitionAsBlobC(out);302}303out.println("J9DDRStructTableEnd");304out.println();305out.println("const J9DDRStructDefinition *get" + config.autoblobConfiguration.getName() + "StructTable(struct OMRPortLibrary *portLib)");306out.println("{");307out.println("\treturn J9DDR_" + config.autoblobConfiguration.getName() + "_structs;");308out.println("}");309}310311private static void writeCPlusPlusFooter(PrintWriter out,312Set<UserDefinedType> writtenOutTypes, GenerateBlobCConfig config)313{314out.println();315out.println("static J9DDRStructTableBegin(" + config.autoblobConfiguration.getName() + ")");316for (UserDefinedType type : writtenOutTypes) {317type.writeStructDefinitionAsBlobC(out);318}319out.println("J9DDRStructTableEnd");320out.println();321out.println("\treturn J9DDR_" + config.autoblobConfiguration.getName() + "_structs;");322out.println("}");323out.println("extern \"C\" {");324out.println();325out.println("\tconst J9DDRStructDefinition *get" + config.autoblobConfiguration.getName() + "StructTable(struct OMRPortLibrary *portLib)");326out.println("\t{");327out.println("\t\treturn " + getCPlusPlusClassName(config) + "::getStructTable();");328out.println("\t}");329out.println();330out.println("}");331}332333private static Map<String, FileTypes> extractTypes(GenerateBlobCConfig config, StructureXMLParser parser) throws IOException334{335Map<String, FileTypes> typesByAbsolutePath = extractTypesByAbsolutePath(parser);336Map<String, FileTypes> typesByHeaderName = stripPaths(typesByAbsolutePath);337Map<String, String> absolutePathsByHeaderName = mapFileNamesToAbsolutePaths(typesByAbsolutePath.keySet());338339Map<String, FileTypes> typesByShortPath = new HashMap<String, FileTypes>();340341for (BlobHeader header: config.autoblobConfiguration.getBlobHeaders()) {342String headerName = header.getName();343File headerPath = config.headerResolver.findHeader(headerName);344345if (headerPath == null) {346continue;347}348349String absolutePath = headerPath.getCanonicalPath();350FileTypes types = typesByAbsolutePath.get(absolutePath);351352if (types != null) {353typesByShortPath.put(headerName, types);354} else {355/*356* CMVC 193975 - adam357*358* When running the build on Windows if a relative path has been used with / delimiters for the name359* e.g. common/thrtypes , then Windows will treat the entire string as the file name rather than a directory360* followed by a file name as Linux does. In order to correctly fallback to match just the name of the361* header file on Window's systems, only the characters after the last / can be used.362*/363int pos = headerName.lastIndexOf('/');364if((pos != -1) && (pos < (headerName.length() + 1))) {365System.err.println("Relative header name character found in : " + headerName);366headerName = headerName.substring(pos + 1);367System.err.println("Now trying to match header name : " + headerName);368}369370/* Jazz 45699 - lpnguyen371* There is a known issue where with #includes using relative paths we can end up with headers in the372* typesByAbsolutePath collection from outside the current working directory (ddr/gc_ddr).373*374* We'll fall back to searching based on just headerName in this case to find its FileTypes375*/376377types = typesByHeaderName.get(headerName);378if (types != null) {379typesByShortPath.put(header.getName(), types);380System.err.println("Warning: Using " + absolutePathsByHeaderName.get(headerName) + " instead of " + absolutePath);381}382}383}384385return typesByShortPath;386}387388/* Generate mapping between header name and their absolute paths */389private static Map<String, String> mapFileNamesToAbsolutePaths(Collection<String> absolutePaths)390{391Map<String, String> absolutePathsByHeaderName = new HashMap<String, String>();392393for (String absolutePath : absolutePaths) {394String fileName = new File(absolutePath).getName();395String oldValue = absolutePathsByHeaderName.put(fileName, absolutePath);396if (null != oldValue) {397System.err.println("Warning: duplicate headers:" + oldValue + " and " + absolutePath + " found");398}399}400401return absolutePathsByHeaderName;402}403404/* Strip the absolute path in the typesByAbsolutePath mapping keyset */405private static Map<String, FileTypes> stripPaths(Map<String, FileTypes> typesByAbsolutePath)406{407Map<String, FileTypes> typesByFileName = new HashMap<String, FileTypes>();408409for (String fileName : typesByAbsolutePath.keySet()) {410String strippedFileName = new File(fileName).getName();411typesByFileName.put(strippedFileName, typesByAbsolutePath.get(fileName));412//will report overwrites in mapFileNamesToAbsolutePaths()413}414415return typesByFileName;416}417418private static Map<String, FileTypes> extractTypesByAbsolutePath(StructureXMLParser parser)419{420Map<String, FileTypes> typesByFile = new HashMap<String, FileTypes>();421422//Typedefs423for (Typedef typedef : parser.getTypedefs().values()) {424String filename = typedef.getDefinitionLocation() == null ? "<unknown>" : typedef.getDefinitionLocation().getFileName();425426FileTypes types = typesByFile.get(filename);427428if (null == types) {429types = new FileTypes(new File(filename));430typesByFile.put(filename,types);431}432433types.typedefs.add(typedef);434}435436for (StructType struct : parser.getStructures()) {437String filename = struct.getDefinitionLocation() == null ? "<unknown>" : struct.getDefinitionLocation().getFileName();438439FileTypes types = typesByFile.get(filename);440441if (null == types) {442types = new FileTypes(new File(filename));443typesByFile.put(filename,types);444}445446types.structs.put(struct.getName(), struct);447}448449for (UnionType union : parser.getUnions()) {450String filename = union.getDefinitionLocation() == null ? "<unknown>" : union.getDefinitionLocation().getFileName();451452FileTypes types = typesByFile.get(filename);453454if (null == types) {455types = new FileTypes(new File(filename));456typesByFile.put(filename,types);457}458459types.unions.put(union.getName(), union);460}461462for (EnumType thisEnum : parser.getEnums()) {463String filename = thisEnum.getDefinitionLocation() == null ? "<unknown>" : thisEnum.getDefinitionLocation().getFileName();464465FileTypes types = typesByFile.get(filename);466467if (null == types) {468types = new FileTypes(new File(filename));469typesByFile.put(filename,types);470}471472types.enums.put(thisEnum.getName(), thisEnum);473}474475for (EnumType thisEnum : parser.getTopScopeAnonymousEnums()) {476String filename = thisEnum.getDefinitionLocation() == null ? "<unknown>" : thisEnum.getDefinitionLocation().getFileName();477478FileTypes types = typesByFile.get(filename);479480if (null == types) {481types = new FileTypes(new File(filename));482typesByFile.put(filename,types);483}484485types.anonymousEnums.add(thisEnum);486}487488return typesByFile;489}490491private static void printHeader()492{493System.out.println("J9DDR Automatic DDR Structure Blob Generator");494}495496private static GenerateBlobCConfig handleArgs(String[] args) throws IOException, SAXException497{498File configFile = null;499File cFile = null;500File xmlFile = null;501File outputFile = null;502File j9FlagsFile = null;503List<File> includeSearchPath = new LinkedList<File>();504505for (int i=0; i < args.length; i++) {506String currentArg = args[i];507boolean argConsumed = false;508509if (i < args.length - 1) {510if (currentArg.equalsIgnoreCase(PROPERTIES_ARGUMENT)) {511configFile = new File(args[i + 1]);512//Step over value513i++;514argConsumed = true;515} else if (currentArg.equalsIgnoreCase(CFILE_ARGUMENT)) {516cFile = new File(args[i + 1]);517i++;518argConsumed = true;519} else if (currentArg.equalsIgnoreCase(XMLFILE_ARGUMENT)) {520xmlFile = new File(args[i + 1]);521i++;522argConsumed = true;523} else if (currentArg.equalsIgnoreCase(OUTFILE_ARGUMENT)) {524outputFile = new File(args[i + 1]);525i++;526argConsumed = true;527} else if (currentArg.equalsIgnoreCase(J9_FLAGS)) {528j9FlagsFile = new File(args[i + 1]);529i++;530argConsumed = true;531}532}533534if (currentArg.startsWith(INCLUDE_ARGUMENT)) {535File path = new File(currentArg.substring(INCLUDE_ARGUMENT.length()));536537includeSearchPath.add(path);538argConsumed = true;539} else if (currentArg.startsWith(DEFINE_ARGUMENT)) {540//Ignore541argConsumed = true;542}543544if (! argConsumed) {545System.err.println("Couldn't consume argument: " + currentArg);546System.exit(1);547}548}549550boolean badConfig = false;551if (null == configFile) {552System.err.println(PROPERTIES_ARGUMENT + " not specified");553badConfig = true;554}555556if (null == cFile) {557System.err.println(CFILE_ARGUMENT + " not specified");558badConfig = true;559}560561if (null == outputFile) {562System.err.println(OUTFILE_ARGUMENT + " not specified");563badConfig = true;564}565566if (null == j9FlagsFile) {567System.err.println(J9_FLAGS + " not specified");568badConfig = true;569}570571if (badConfig) {572usage();573System.exit(1);574}575576return new GenerateBlobCConfig(cFile, xmlFile, outputFile, Configuration.loadConfiguration(configFile, j9FlagsFile), new HeaderResolver(includeSearchPath));577}578579static class HeaderResolver implements IHeaderResolver580{581582private final List<File> includePath;583584public HeaderResolver(List<File> includePath)585{586this.includePath = includePath;587}588589public File findHeader(String name)590{591for (File path : includePath) {592File possibleFile = new File(path, name);593if (possibleFile.exists()) {594return possibleFile;595}596}597598return null;599}600601}602603private static void usage()604{605System.err.println(GenerateBlobC.class.getSimpleName());606System.err.println("Usage:");607System.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>]+");608System.err.println();609System.err.println("Note: this tool currently cannot handle C++.");610}611612static class GenerateBlobCConfig613{614public final File cFile;615616public final File xmlFile;617618public final File outputFile;619620public final File outputSuperSetFile;621622public final Configuration autoblobConfiguration;623624public final IHeaderResolver headerResolver;625626public GenerateBlobCConfig(File cFile, File xmlFile, File outputFile, Configuration configuration, IHeaderResolver headerResolver)627{628this.cFile = cFile;629this.xmlFile = xmlFile;630this.outputFile = outputFile;631outputSuperSetFile = new File(outputFile.getAbsolutePath() + ".superset");632this.autoblobConfiguration = configuration;633this.headerResolver = headerResolver;634}635}636637}638639640