--- /dev/null 2019-02-13 16:01:02.292000000 +0300 +++ new/src/share/vm/jfr/GenerateJfrFiles.java 2019-02-15 19:02:57.542131071 +0300 @@ -0,0 +1,696 @@ +package build.tools.jfr; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; +import java.util.function.Predicate; + +import javax.xml.XMLConstants; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.validation.SchemaFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +public class GenerateJfrFiles { + + public static void main(String... args) throws Exception { + if (args.length != 3) { + System.err.println("Incorrect number of command line arguments."); + System.err.println("Usage:"); + System.err.println("java GenerateJfrFiles[.java] "); + System.exit(1); + } + try { + File metadataXml = new File(args[0]); + File metadataSchema = new File(args[1]); + File outputDirectory = new File(args[2]); + + Metadata metadata = new Metadata(metadataXml, metadataSchema); + metadata.verify(); + metadata.wireUpTypes(); + + printJfrPeriodicHpp(metadata, outputDirectory); + printJfrEventIdsHpp(metadata, outputDirectory); + printJfrEventControlHpp(metadata, outputDirectory); + printJfrTypesHpp(metadata, outputDirectory); + printJfrEventClassesHpp(metadata, outputDirectory); + + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + static class XmlType { + final String fieldType; + final String parameterType; + XmlType(String fieldType, String parameterType) { + this.fieldType = fieldType; + this.parameterType = parameterType; + } + } + + static class TypeElement { + List fields = new ArrayList<>(); + String name; + String fieldType; + String parameterType; + boolean supportStruct; + } + + static class Metadata { + final Map types = new LinkedHashMap<>(); + final Map xmlTypes = new HashMap<>(); + Metadata(File metadataXml, File metadataSchema) throws ParserConfigurationException, SAXException, FileNotFoundException, IOException { + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setSchema(schemaFactory.newSchema(metadataSchema)); + SAXParser sp = factory.newSAXParser(); + sp.parse(metadataXml, new MetadataHandler(this)); + } + + List getEvents() { + return getList(t -> t.getClass() == EventElement.class); + } + + List getEventsAndStructs() { + return getList(t -> t.getClass() == EventElement.class || t.supportStruct); + } + + List getTypesAndStructs() { + return getList(t -> t.getClass() == TypeElement.class || t.supportStruct); + } + + @SuppressWarnings("unchecked") + List getList(Predicate pred) { + List result = new ArrayList<>(types.size()); + for (TypeElement t : types.values()) { + if (pred.test(t)) { + result.add((T) t); + } + } + return result; + } + + List getPeriodicEvents() { + return getList(t -> t.getClass() == EventElement.class && ((EventElement) t).periodic); + } + + List getNonEventsAndNonStructs() { + return getList(t -> t.getClass() != EventElement.class && !t.supportStruct); + } + + List getTypes() { + return getList(t -> t.getClass() == TypeElement.class && !t.supportStruct); + } + + List getStructs() { + return getList(t -> t.getClass() == TypeElement.class && t.supportStruct); + } + + void verify() { + for (TypeElement t : types.values()) { + for (FieldElement f : t.fields) { + if (!xmlTypes.containsKey(f.typeName)) { // ignore primitives + if (!types.containsKey(f.typeName)) { + throw new IllegalStateException("Could not find definition of type '" + f.typeName + "' used by " + t.name + "#" + f.name); + } + } + } + } + } + + void wireUpTypes() { + for (TypeElement t : types.values()) { + for (FieldElement f : t.fields) { + TypeElement type = types.get(f.typeName); + if (f.struct) { + type.supportStruct = true; + } + f.type = type; + } + } + } + } + + static class EventElement extends TypeElement { + String representation; + boolean thread; + boolean stackTrace; + boolean startTime; + boolean periodic; + boolean cutoff; + } + + static class FieldElement { + final Metadata metadata; + TypeElement type; + String name; + String typeName; + boolean struct; + + FieldElement(Metadata metadata) { + this.metadata = metadata; + } + + String getParameterType() { + if (struct) { + return "const JfrStruct" + typeName + "&"; + } + XmlType xmlType = metadata.xmlTypes.get(typeName); + if (xmlType != null) { + return xmlType.parameterType; + } + return type != null ? "u8" : typeName; + } + + String getParameterName() { + return struct ? "value" : "new_value"; + } + + String getFieldType() { + if (struct) { + return "JfrStruct" + typeName; + } + XmlType xmlType = metadata.xmlTypes.get(typeName); + if (xmlType != null) { + return xmlType.fieldType; + } + return type != null ? "u8" : typeName; + } + } + + static class MetadataHandler extends DefaultHandler { + final Metadata metadata; + FieldElement currentField; + TypeElement currentType; + MetadataHandler(Metadata metadata) { + this.metadata = metadata; + } + @Override + public void error(SAXParseException e) throws SAXException { + throw e; + } + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + switch (qName) { + case "XmlType": + String name = attributes.getValue("name"); + String parameterType = attributes.getValue("parameterType"); + String fieldType = attributes.getValue("fieldType"); + metadata.xmlTypes.put(name, new XmlType(fieldType, parameterType)); + break; + case "Type": + currentType = new TypeElement(); + currentType.name = attributes.getValue("name"); + break; + case "Event": + EventElement eventtType = new EventElement(); + eventtType.name = attributes.getValue("name"); + eventtType.thread = getBoolean(attributes, "thread", false); + eventtType.stackTrace = getBoolean(attributes, "stackTrace", false); + eventtType.startTime = getBoolean(attributes, "startTime", true); + eventtType.periodic = attributes.getValue("period") != null; + eventtType.cutoff = getBoolean(attributes, "cutoff", false); + currentType = eventtType; + break; + case "Field": + currentField = new FieldElement(metadata); + currentField.struct = getBoolean(attributes, "struct", false); + currentField.name = attributes.getValue("name"); + currentField.typeName = attributes.getValue("type"); + break; + } + } + + private boolean getBoolean(Attributes attributes, String name, boolean defaultValue) { + String value = attributes.getValue(name); + return value == null ? defaultValue : Boolean.valueOf(value); + } + + @Override + public void endElement(String uri, String localName, String qName) { + switch (qName) { + case "Type": + case "Event": + metadata.types.put(currentType.name, currentType); + currentType = null; + break; + case "Field": + currentType.fields.add(currentField); + currentField = null; + break; + } + } + } + + static class Printer implements AutoCloseable { + final PrintStream out; + Printer(File outputDirectory, String filename) throws FileNotFoundException { + out = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(outputDirectory, filename)))); + write("/* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */"); + write(""); + } + + void write(String text) { + out.print(text); + out.print("\n"); // Don't use Windows line endings + } + + @Override + public void close() throws Exception { + out.close(); + } + } + + private static void printJfrPeriodicHpp(Metadata metadata, File outputDirectory) throws Exception { + try (Printer out = new Printer(outputDirectory, "jfrPeriodic.hpp")) { + out.write("#ifndef JFRFILES_JFRPERIODICEVENTSET_HPP"); + out.write("#define JFRFILES_JFRPERIODICEVENTSET_HPP"); + out.write(""); + out.write("#include \"utilities/macros.hpp\""); + out.write("#if INCLUDE_JFR"); + out.write("#include \"jfrfiles/jfrEventIds.hpp\""); + out.write("#include \"memory/allocation.hpp\""); + out.write(""); + out.write("class JfrPeriodicEventSet : public AllStatic {"); + out.write(" public:"); + out.write(" static void requestEvent(JfrEventId id) {"); + out.write(" switch(id) {"); + out.write(" "); + for (EventElement e : metadata.getPeriodicEvents()) { + out.write(" case Jfr" + e.name + "Event:"); + out.write(" request" + e.name + "();"); + out.write(" break;"); + out.write(" "); + } + out.write(" default:"); + out.write(" break;"); + out.write(" }"); + out.write(" }"); + out.write(""); + out.write(" private:"); + out.write(""); + for (EventElement e : metadata.getPeriodicEvents()) { + out.write(" static void request" + e.name + "(void);"); + out.write(""); + } + out.write("};"); + out.write(""); + out.write("#endif // INCLUDE_JFR"); + out.write("#endif // JFRFILES_JFRPERIODICEVENTSET_HPP"); + } + } + + private static void printJfrEventControlHpp(Metadata metadata, File outputDirectory) throws Exception { + try (Printer out = new Printer(outputDirectory, "jfrEventControl.hpp")) { + out.write("#ifndef JFRFILES_JFR_NATIVE_EVENTSETTING_HPP"); + out.write("#define JFRFILES_JFR_NATIVE_EVENTSETTING_HPP"); + out.write(""); + out.write("#include \"utilities/macros.hpp\""); + out.write("#if INCLUDE_JFR"); + out.write("#include \"jfrfiles/jfrEventIds.hpp\""); + out.write(""); + out.write("/**"); + out.write(" * Event setting. We add some padding so we can use our"); + out.write(" * event IDs as indexes into this."); + out.write(" */"); + out.write(""); + out.write("struct jfrNativeEventSetting {"); + out.write(" jlong threshold_ticks;"); + out.write(" jlong cutoff_ticks;"); + out.write(" u1 stacktrace;"); + out.write(" u1 enabled;"); + out.write(" u1 pad[6]; // Because GCC on linux ia32 at least tries to pack this."); + out.write("};"); + out.write(""); + out.write("union JfrNativeSettings {"); + out.write(" // Array version."); + out.write(" jfrNativeEventSetting bits[MaxJfrEventId];"); + out.write(" // Then, to make it easy to debug,"); + out.write(" // add named struct members also."); + out.write(" struct {"); + out.write(" jfrNativeEventSetting pad[NUM_RESERVED_EVENTS];"); + for (TypeElement t : metadata.getEventsAndStructs()) { + out.write(" jfrNativeEventSetting " + t.name + ";"); + } + out.write(" } ev;"); + out.write("};"); + out.write(""); + out.write("#endif // INCLUDE_JFR"); + out.write("#endif // JFRFILES_JFR_NATIVE_EVENTSETTING_HPP"); + } + } + + private static void printJfrEventIdsHpp(Metadata metadata, File outputDirectory) throws Exception { + try (Printer out = new Printer(outputDirectory, "jfrEventIds.hpp")) { + out.write("#ifndef JFRFILES_JFREVENTIDS_HPP"); + out.write("#define JFRFILES_JFREVENTIDS_HPP"); + out.write(""); + out.write("#include \"utilities/macros.hpp\""); + out.write("#if INCLUDE_JFR"); + out.write("#include \"jfrfiles/jfrTypes.hpp\""); + out.write(""); + out.write("/**"); + out.write(" * Enum of the event types in the JVM"); + out.write(" */"); + out.write("enum JfrEventId {"); + out.write(" _jfreventbase = (NUM_RESERVED_EVENTS-1), // Make sure we start at right index."); + out.write(" "); + out.write(" // Events -> enum entry"); + for (TypeElement t : metadata.getEventsAndStructs()) { + out.write(" Jfr" + t.name + "Event,"); + } + out.write(""); + out.write(" MaxJfrEventId"); + out.write("};"); + out.write(""); + out.write("/**"); + out.write(" * Struct types in the JVM"); + out.write(" */"); + out.write("enum JfrStructId {"); + for (TypeElement t : metadata.getNonEventsAndNonStructs()) { + out.write(" Jfr" + t.name + "Struct,"); + } + for (TypeElement t : metadata.getEventsAndStructs()) { + out.write(" Jfr" + t.name + "Struct,"); + } + out.write(""); + out.write(" MaxJfrStructId"); + out.write("};"); + out.write(""); + out.write("typedef enum JfrEventId JfrEventId;"); + out.write("typedef enum JfrStructId JfrStructId;"); + out.write(""); + out.write("#endif // INCLUDE_JFR"); + out.write("#endif // JFRFILES_JFREVENTIDS_HPP"); + } + } + + private static void printJfrTypesHpp(Metadata metadata, File outputDirectory) throws Exception { + List knownTypes = Arrays.asList(new String[] {"Thread", "StackTrace", "Class", "StackFrame"}); + try (Printer out = new Printer(outputDirectory, "jfrTypes.hpp")) { + out.write("#ifndef JFRFILES_JFRTYPES_HPP"); + out.write("#define JFRFILES_JFRTYPES_HPP"); + out.write(""); + out.write("#include \"utilities/macros.hpp\""); + out.write("#if INCLUDE_JFR"); + out.write(""); + out.write("enum JfrTypeId {"); + out.write(" TYPE_NONE = 0,"); + out.write(" TYPE_CLASS = 20,"); + out.write(" TYPE_STRING = 21,"); + out.write(" TYPE_THREAD = 22,"); + out.write(" TYPE_STACKTRACE = 23,"); + out.write(" TYPE_BYTES = 24,"); + out.write(" TYPE_EPOCHMILLIS = 25,"); + out.write(" TYPE_MILLIS = 26,"); + out.write(" TYPE_NANOS = 27,"); + out.write(" TYPE_TICKS = 28,"); + out.write(" TYPE_ADDRESS = 29,"); + out.write(" TYPE_PERCENTAGE = 30,"); + out.write(" TYPE_DUMMY,"); + out.write(" TYPE_DUMMY_1,"); + for (TypeElement type : metadata.getTypes()) { + if (!knownTypes.contains(type.name)) { + out.write(" TYPE_" + type.name.toUpperCase() + ","); + } + } + out.write(""); + out.write(" NUM_JFR_TYPES,"); + out.write(" TYPES_END = 255"); + out.write("};"); + out.write(""); + out.write("enum ReservedEvent {"); + out.write(" EVENT_METADATA,"); + out.write(" EVENT_CHECKPOINT,"); + out.write(" EVENT_BUFFERLOST,"); + out.write(" NUM_RESERVED_EVENTS = TYPES_END"); + out.write("};"); + out.write(""); + out.write("#endif // INCLUDE_JFR"); + out.write("#endif // JFRFILES_JFRTYPES_HPP"); + }; + } + + private static void printJfrEventClassesHpp(Metadata metadata, File outputDirectory) throws Exception { + try (Printer out = new Printer(outputDirectory, "jfrEventClasses.hpp")) { + out.write("#ifndef JFRFILES_JFREVENTCLASSES_HPP"); + out.write("#define JFRFILES_JFREVENTCLASSES_HPP"); + out.write(""); + out.write("#include \"oops/klass.hpp\""); + out.write("#include \"jfrfiles/jfrTypes.hpp\""); + out.write("#include \"jfr/utilities/jfrTypes.hpp\""); + out.write("#include \"utilities/macros.hpp\""); + out.write("#include \"utilities/ticks.hpp\""); + out.write("#if INCLUDE_JFR"); + out.write("#include \"jfr/recorder/service/jfrEvent.hpp\""); + out.write("/*"); + out.write(" * Each event class has an assert member function verify() which is invoked"); + out.write(" * just before the engine writes the event and its fields to the data stream."); + out.write(" * The purpose of verify() is to ensure that all fields in the event are initialized"); + out.write(" * and set before attempting to commit."); + out.write(" *"); + out.write(" * We enforce this requirement because events are generally stack allocated and therefore"); + out.write(" * *not* initialized to default values. This prevents us from inadvertently committing"); + out.write(" * uninitialized values to the data stream."); + out.write(" *"); + out.write(" * The assert message contains both the index (zero based) as well as the name of the field."); + out.write(" */"); + out.write(""); + printTypes(out, metadata, false); + out.write(""); + out.write(""); + out.write("#else // !INCLUDE_JFR"); + out.write(""); + out.write("class JfrEvent {"); + out.write(" public:"); + out.write(" JfrEvent() {}"); + out.write(" void set_starttime(const Ticks&) const {}"); + out.write(" void set_endtime(const Ticks&) const {}"); + out.write(" bool should_commit() const { return false; }"); + out.write(" static bool is_enabled() { return false; }"); + out.write(" void commit() {}"); + out.write("};"); + out.write(""); + printTypes(out, metadata, true); + out.write(""); + out.write(""); + out.write("#endif // INCLUDE_JFR"); + out.write("#endif // JFRFILES_JFREVENTCLASSES_HPP"); + } + } + + private static void printTypes(Printer out, Metadata metadata, boolean empty) { + for (TypeElement t : metadata.getStructs()) { + if (empty) { + out.write(""); + printEmptyType(out, t); + } else { + printType(out, t); + } + out.write(""); + } + for (EventElement e : metadata.getEvents()) { + if (empty) { + printEmptyEvent(out, e); + } else { + printEvent(out, e); + } + out.write(""); + } + } + + private static void printEmptyEvent(Printer out, EventElement event) { + out.write("class Event" + event.name + " : public JfrEvent"); + out.write("{"); + out.write(" public:"); + out.write(" Event" + event.name + "(EventStartTime ignore=TIMED) {}"); + if (event.startTime) { + StringJoiner sj = new StringJoiner(",\n "); + for (FieldElement f : event.fields) { + sj.add(f.getParameterType()); + } + out.write(" Event" + event.name + "("); + out.write(" " + sj.toString() + ") { }"); + } + for (FieldElement f : event.fields) { + out.write(" void set_" + f.name + "(" + f.getParameterType() + ") { }"); + } + out.write("};"); + } + + private static void printEmptyType(Printer out, TypeElement t) { + out.write("struct JfrStruct" + t.name); + out.write("{"); + out.write(" public:"); + for (FieldElement f : t.fields) { + out.write(" void set_" + f.name + "(" + f.getParameterType() + ") { }"); + } + out.write("};"); + } + + private static void printType(Printer out, TypeElement t) { + out.write("struct JfrStruct" + t.name); + out.write("{"); + out.write(" private:"); + for (FieldElement f : t.fields) { + printField(out, f); + } + out.write(""); + out.write(" public:"); + for (FieldElement f : t.fields) { + printTypeSetter(out, f); + } + out.write(""); + printWriteData(out, t.fields); + out.write("};"); + out.write(""); + } + + private static void printEvent(Printer out, EventElement event) { + out.write("class Event" + event.name + " : public JfrEvent"); + out.write("{"); + out.write(" private:"); + for (FieldElement f : event.fields) { + printField(out, f); + } + out.write(""); + out.write(" public:"); + out.write(" static const bool hasThread = " + event.thread + ";"); + out.write(" static const bool hasStackTrace = " + event.stackTrace + ";"); + out.write(" static const bool isInstant = " + !event.startTime + ";"); + out.write(" static const bool hasCutoff = " + event.cutoff + ";"); + out.write(" static const bool isRequestable = " + event.periodic + ";"); + out.write(" static const JfrEventId eventId = Jfr" + event.name + "Event;"); + out.write(""); + out.write(" Event" + event.name + "(EventStartTime timing=TIMED) : JfrEvent(timing) {}"); + out.write(""); + int index = 0; + for (FieldElement f : event.fields) { + out.write(" void set_" + f.name + "(" + f.getParameterType() + " " + f.getParameterName() + ") {"); + out.write(" this->_" + f.name + " = " + f.getParameterName() + ";"); + out.write(" DEBUG_ONLY(set_field_bit(" + index++ + "));"); + out.write(" }"); + } + out.write(""); + printWriteData(out, event.fields); + out.write(""); + out.write(" using JfrEvent::commit; // else commit() is hidden by overloaded versions in this class"); + printConstructor2(out, event); + printCommitMethod(out, event); + printVerify(out, event.fields); + out.write("};"); + } + + private static void printWriteData(Printer out, List fields) { + out.write(" template "); + out.write(" void writeData(Writer& w) {"); + for (FieldElement field : fields) { + if (field.struct) { + out.write(" _" + field.name + ".writeData(w);"); + } else { + out.write(" w.write(_" + field.name + ");"); + } + } + out.write(" }"); + } + + private static void printTypeSetter(Printer out, FieldElement field) { + out.write(" void set_" + field.name + "(" + field.getParameterType() + " new_value) { this->_" + field.name + " = new_value; }"); + } + + private static void printVerify(Printer out, List fields) { + out.write(""); + out.write("#ifdef ASSERT"); + out.write(" void verify() const {"); + int index = 0; + for (FieldElement f : fields) { + out.write(" assert(verify_field_bit(" + index++ + "), \"Attempting to write an uninitialized event field: " + f.name + "\");"); + } + out.write(" }"); + out.write("#endif"); + } + + private static void printCommitMethod(Printer out, EventElement event) { + if (event.startTime) { + StringJoiner sj = new StringJoiner(",\n "); + for (FieldElement f : event.fields) { + sj.add(f.getParameterType() + " " + f.name); + } + out.write(""); + out.write(" void commit(" + sj.toString() + ") {"); + out.write(" if (should_commit()) {"); + for (FieldElement f : event.fields) { + out.write(" set_" + f.name + "(" + f.name + ");"); + } + out.write(" commit();"); + out.write(" }"); + out.write(" }"); + } + out.write(""); + StringJoiner sj = new StringJoiner(",\n "); + if (event.startTime) { + sj.add("const Ticks& startTicks"); + sj.add("const Ticks& endTicks"); + } + for (FieldElement f : event.fields) { + sj.add(f.getParameterType() + " " + f.name); + } + out.write(" static void commit(" + sj.toString() + ") {"); + out.write(" Event" + event.name + " me(UNTIMED);"); + out.write(""); + out.write(" if (me.should_commit()) {"); + if (event.startTime) { + out.write(" me.set_starttime(startTicks);"); + out.write(" me.set_endtime(endTicks);"); + } + for (FieldElement f : event.fields) { + out.write(" me.set_" + f.name + "(" + f.name + ");"); + } + out.write(" me.commit();"); + out.write(" }"); + out.write(" }"); + } + + private static void printConstructor2(Printer out, EventElement event) { + if (!event.startTime) { + out.write(""); + out.write(""); + } + if (event.startTime) { + out.write(""); + out.write(" Event" + event.name + "("); + StringJoiner sj = new StringJoiner(",\n "); + for (FieldElement f : event.fields) { + sj.add(f.getParameterType() + " " + f.name); + } + out.write(" " + sj.toString() + ") : JfrEvent(TIMED) {"); + out.write(" if (should_commit()) {"); + for (FieldElement f : event.fields) { + out.write(" set_" + f.name + "(" + f.name + ");"); + } + out.write(" }"); + out.write(" }"); + } + } + + private static void printField(Printer out, FieldElement field) { + out.write(" " + field.getFieldType() + " _" + field.name + ";"); + } +}