1 package build.tools.jfr;
   2 
   3 import java.io.BufferedOutputStream;
   4 import java.io.File;
   5 import java.io.FileNotFoundException;
   6 import java.io.FileOutputStream;
   7 import java.io.IOException;
   8 import java.io.PrintStream;
   9 import java.util.ArrayList;
  10 import java.util.HashMap;
  11 import java.util.LinkedHashMap;
  12 import java.util.List;
  13 import java.util.Map;
  14 import java.util.StringJoiner;
  15 import java.util.function.Predicate;
  16 
  17 import javax.xml.XMLConstants;
  18 import javax.xml.parsers.ParserConfigurationException;
  19 import javax.xml.parsers.SAXParser;
  20 import javax.xml.parsers.SAXParserFactory;
  21 import javax.xml.validation.SchemaFactory;
  22 
  23 import org.xml.sax.Attributes;
  24 import org.xml.sax.SAXException;
  25 import org.xml.sax.SAXParseException;
  26 import org.xml.sax.helpers.DefaultHandler;
  27 
  28 public class GenerateJfrFiles {
  29 
  30     public static void main(String... args) throws Exception {
  31         if (args.length != 3) {
  32             System.err.println("Incorrect number of command line arguments.");
  33             System.err.println("Usage:");
  34             System.err.println("java GenerateJfrFiles[.java] <path-to-metadata.xml> <path-to-metadata.xsd> <output-directory>");
  35             System.exit(1);
  36         }
  37         try {
  38             File metadataXml = new File(args[0]);
  39             File metadataSchema = new File(args[1]);
  40             File outputDirectory = new File(args[2]);
  41 
  42             Metadata metadata = new Metadata(metadataXml, metadataSchema);
  43             metadata.verify();
  44             metadata.wireUpTypes();
  45 
  46             printJfrPeriodicHpp(metadata, outputDirectory);
  47             printJfrEventIdsHpp(metadata, outputDirectory);
  48             printJfrEventControlHpp(metadata, outputDirectory);
  49             printJfrTypesHpp(metadata, outputDirectory);
  50             printJfrEventClassesHpp(metadata, outputDirectory);
  51 
  52         } catch (Exception e) {
  53             e.printStackTrace();
  54             System.exit(1);
  55         }
  56     }
  57 
  58     static class XmlType {
  59         final String fieldType;
  60         final String parameterType;
  61         XmlType(String fieldType, String parameterType) {
  62             this.fieldType = fieldType;
  63             this.parameterType = parameterType;
  64         }
  65     }
  66 
  67     static class TypeElement {
  68         List<FieldElement> fields = new ArrayList<>();
  69         String name;
  70         String fieldType;
  71         String parameterType;
  72         boolean supportStruct;
  73     }
  74 
  75     static class Metadata {
  76         final Map<String, TypeElement> types = new LinkedHashMap<>();
  77         final Map<String, XmlType> xmlTypes = new HashMap<>();
  78         Metadata(File metadataXml, File metadataSchema) throws ParserConfigurationException, SAXException, FileNotFoundException, IOException {
  79             SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
  80             SAXParserFactory factory = SAXParserFactory.newInstance();
  81             factory.setSchema(schemaFactory.newSchema(metadataSchema));
  82             SAXParser sp = factory.newSAXParser();
  83             sp.parse(metadataXml, new MetadataHandler(this));
  84         }
  85 
  86         List<EventElement> getEvents() {
  87             return getList(t -> t.getClass() == EventElement.class);
  88         }
  89 
  90         List<TypeElement> getEventsAndStructs() {
  91             return getList(t -> t.getClass() == EventElement.class || t.supportStruct);
  92         }
  93 
  94         List<TypeElement> getTypesAndStructs() {
  95             return getList(t -> t.getClass() == TypeElement.class || t.supportStruct);
  96         }
  97 
  98         @SuppressWarnings("unchecked")
  99         <T> List<T> getList(Predicate<? super TypeElement> pred) {
 100             List<T> result = new ArrayList<>(types.size());
 101             for (TypeElement t : types.values()) {
 102                 if (pred.test(t)) {
 103                     result.add((T) t);
 104                 }
 105             }
 106             return result;
 107         }
 108 
 109         List<EventElement> getPeriodicEvents() {
 110             return getList(t -> t.getClass() == EventElement.class && ((EventElement) t).periodic);
 111         }
 112 
 113         List<TypeElement> getNonEventsAndNonStructs() {
 114             return getList(t -> t.getClass() != EventElement.class && !t.supportStruct);
 115         }
 116 
 117         List<TypeElement> getTypes() {
 118             return getList(t -> t.getClass() == TypeElement.class && !t.supportStruct);
 119         }
 120 
 121         List<TypeElement> getStructs() {
 122             return getList(t -> t.getClass() == TypeElement.class && t.supportStruct);
 123         }
 124 
 125         void verify()  {
 126             for (TypeElement t : types.values()) {
 127                 for (FieldElement f : t.fields) {
 128                     if (!xmlTypes.containsKey(f.typeName)) { // ignore primitives
 129                         if (!types.containsKey(f.typeName)) {
 130                             throw new IllegalStateException("Could not find definition of type '" + f.typeName + "' used by " + t.name + "#" + f.name);
 131                         }
 132                     }
 133                 }
 134             }
 135         }
 136 
 137         void wireUpTypes() {
 138             for (TypeElement t : types.values()) {
 139                 for (FieldElement f : t.fields) {
 140                     TypeElement type = types.get(f.typeName);
 141                     if (f.struct) {
 142                         type.supportStruct = true;
 143                     }
 144                     f.type = type;
 145                 }
 146             }
 147         }
 148     }
 149 
 150     static class EventElement extends TypeElement {
 151         String representation;
 152         boolean thread;
 153         boolean stackTrace;
 154         boolean startTime;
 155         boolean periodic;
 156         boolean cutoff;
 157     }
 158 
 159     static class FieldElement {
 160         final Metadata metadata;
 161         TypeElement type;
 162         String name;
 163         String typeName;
 164         boolean struct;
 165 
 166         FieldElement(Metadata metadata) {
 167             this.metadata = metadata;
 168         }
 169 
 170         String getParameterType() {
 171             if (struct) {
 172                 return "const JfrStruct" + typeName + "&";
 173             }
 174             XmlType xmlType = metadata.xmlTypes.get(typeName);
 175             if (xmlType != null) {
 176                 return xmlType.parameterType;
 177             }
 178             return type != null ? "u8" : typeName;
 179         }
 180 
 181         String getParameterName() {
 182             return struct ? "value" : "new_value";
 183         }
 184 
 185         String getFieldType() {
 186             if (struct) {
 187                 return "JfrStruct" + typeName;
 188             }
 189             XmlType xmlType = metadata.xmlTypes.get(typeName);
 190             if (xmlType != null) {
 191                 return xmlType.fieldType;
 192             }
 193             return type != null ? "u8" : typeName;
 194         }
 195     }
 196 
 197     static class MetadataHandler extends DefaultHandler {
 198         final Metadata metadata;
 199         FieldElement currentField;
 200         TypeElement currentType;
 201         MetadataHandler(Metadata metadata) {
 202             this.metadata = metadata;
 203         }
 204         @Override
 205         public void error(SAXParseException e) throws SAXException {
 206           throw e;
 207         }
 208         @Override
 209         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
 210             switch (qName) {
 211             case "XmlType":
 212                 String name = attributes.getValue("name");
 213                 String parameterType = attributes.getValue("parameterType");
 214                 String fieldType = attributes.getValue("fieldType");
 215                 metadata.xmlTypes.put(name, new XmlType(fieldType, parameterType));
 216                 break;
 217             case "Type":
 218                 currentType = new TypeElement();
 219                 currentType.name = attributes.getValue("name");
 220                 break;
 221             case "Event":
 222                 EventElement eventtType = new EventElement();
 223                 eventtType.name = attributes.getValue("name");
 224                 eventtType.thread = getBoolean(attributes, "thread", false);
 225                 eventtType.stackTrace = getBoolean(attributes, "stackTrace", false);
 226                 eventtType.startTime = getBoolean(attributes, "startTime", true);
 227                 eventtType.periodic = attributes.getValue("period") != null;
 228                 eventtType.cutoff = getBoolean(attributes, "cutoff", false);
 229                 currentType = eventtType;
 230                 break;
 231             case "Field":
 232                 currentField = new FieldElement(metadata);
 233                 currentField.struct = getBoolean(attributes, "struct", false);
 234                 currentField.name = attributes.getValue("name");
 235                 currentField.typeName = attributes.getValue("type");
 236                 break;
 237             }
 238         }
 239 
 240         private boolean getBoolean(Attributes attributes, String name, boolean defaultValue) {
 241             String value = attributes.getValue(name);
 242             return value == null ? defaultValue : Boolean.valueOf(value);
 243         }
 244 
 245         @Override
 246         public void endElement(String uri, String localName, String qName) {
 247             switch (qName) {
 248             case "Type":
 249             case "Event":
 250                 metadata.types.put(currentType.name, currentType);
 251                 currentType = null;
 252                 break;
 253             case "Field":
 254                 currentType.fields.add(currentField);
 255                 currentField = null;
 256                 break;
 257             }
 258         }
 259     }
 260 
 261     static class Printer implements AutoCloseable {
 262         final PrintStream out;
 263         Printer(File outputDirectory, String filename) throws FileNotFoundException {
 264             out = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(outputDirectory, filename))));
 265             write("/* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */");
 266             write("");
 267         }
 268 
 269         void write(String text) {
 270             out.print(text);
 271             out.print("\n"); // Don't use Windows line endings
 272         }
 273 
 274         @Override
 275         public void close() throws Exception {
 276             out.close();
 277         }
 278     }
 279 
 280     private static void printJfrPeriodicHpp(Metadata metadata, File outputDirectory) throws Exception {
 281         try (Printer out = new Printer(outputDirectory, "jfrPeriodic.hpp")) {
 282             out.write("#ifndef JFRFILES_JFRPERIODICEVENTSET_HPP");
 283             out.write("#define JFRFILES_JFRPERIODICEVENTSET_HPP");
 284             out.write("");
 285             out.write("#include \"utilities/macros.hpp\"");
 286             out.write("#if INCLUDE_JFR");
 287             out.write("#include \"jfrfiles/jfrEventIds.hpp\"");
 288             out.write("#include \"memory/allocation.hpp\"");
 289             out.write("");
 290             out.write("class JfrPeriodicEventSet : public AllStatic {");
 291             out.write(" public:");
 292             out.write("  static void requestEvent(JfrEventId id) {");
 293             out.write("    switch(id) {");
 294             out.write("  ");
 295             for (EventElement e : metadata.getPeriodicEvents()) {
 296                 out.write("      case Jfr" + e.name + "Event:");
 297                 out.write("        request" + e.name + "();");
 298                 out.write("        break;");
 299                 out.write("  ");
 300             }
 301             out.write("      default:");
 302             out.write("        break;");
 303             out.write("      }");
 304             out.write("    }");
 305             out.write("");
 306             out.write(" private:");
 307             out.write("");
 308             for (EventElement e : metadata.getPeriodicEvents()) {
 309                 out.write("  static void request" + e.name + "(void);");
 310                 out.write("");
 311             }
 312             out.write("};");
 313             out.write("");
 314             out.write("#endif // INCLUDE_JFR");
 315             out.write("#endif // JFRFILES_JFRPERIODICEVENTSET_HPP");
 316         }
 317     }
 318 
 319     private static void printJfrEventControlHpp(Metadata metadata, File outputDirectory) throws Exception {
 320         try (Printer out = new Printer(outputDirectory, "jfrEventControl.hpp")) {
 321             out.write("#ifndef JFRFILES_JFR_NATIVE_EVENTSETTING_HPP");
 322             out.write("#define JFRFILES_JFR_NATIVE_EVENTSETTING_HPP");
 323             out.write("");
 324             out.write("#include \"utilities/macros.hpp\"");
 325             out.write("#if INCLUDE_JFR");
 326             out.write("#include \"jfrfiles/jfrEventIds.hpp\"");
 327             out.write("");
 328             out.write("/**");
 329             out.write(" * Event setting. We add some padding so we can use our");
 330             out.write(" * event IDs as indexes into this.");
 331             out.write(" */");
 332             out.write("");
 333             out.write("struct jfrNativeEventSetting {");
 334             out.write("  jlong  threshold_ticks;");
 335             out.write("  jlong  cutoff_ticks;");
 336             out.write("  u1     stacktrace;");
 337             out.write("  u1     enabled;");
 338             out.write("  u1     pad[6]; // Because GCC on linux ia32 at least tries to pack this.");
 339             out.write("};");
 340             out.write("");
 341             out.write("union JfrNativeSettings {");
 342             out.write("  // Array version.");
 343             out.write("  jfrNativeEventSetting bits[MaxJfrEventId];");
 344             out.write("  // Then, to make it easy to debug,");
 345             out.write("  // add named struct members also.");
 346             out.write("  struct {");
 347             out.write("    jfrNativeEventSetting pad[NUM_RESERVED_EVENTS];");
 348             for (TypeElement t : metadata.getEventsAndStructs()) {
 349                 out.write("    jfrNativeEventSetting " + t.name + ";");
 350             }
 351             out.write("  } ev;");
 352             out.write("};");
 353             out.write("");
 354             out.write("#endif // INCLUDE_JFR");
 355             out.write("#endif // JFRFILES_JFR_NATIVE_EVENTSETTING_HPP");
 356         }
 357     }
 358 
 359     private static void printJfrEventIdsHpp(Metadata metadata, File outputDirectory) throws Exception {
 360         try (Printer out = new Printer(outputDirectory, "jfrEventIds.hpp")) {
 361             out.write("#ifndef JFRFILES_JFREVENTIDS_HPP");
 362             out.write("#define JFRFILES_JFREVENTIDS_HPP");
 363             out.write("");
 364             out.write("#include \"utilities/macros.hpp\"");
 365             out.write("#if INCLUDE_JFR");
 366             out.write("#include \"jfrfiles/jfrTypes.hpp\"");
 367             out.write("");
 368             out.write("/**");
 369             out.write(" * Enum of the event types in the JVM");
 370             out.write(" */");
 371             out.write("enum JfrEventId {");
 372             out.write("  _jfreventbase = (NUM_RESERVED_EVENTS-1), // Make sure we start at right index.");
 373             out.write("  ");
 374             out.write("  // Events -> enum entry");
 375             for (TypeElement t : metadata.getEventsAndStructs()) {
 376                 out.write("  Jfr" + t.name + "Event,");
 377             }
 378             out.write("");
 379             out.write("  MaxJfrEventId");
 380             out.write("};");
 381             out.write("");
 382             out.write("/**");
 383             out.write(" * Struct types in the JVM");
 384             out.write(" */");
 385             out.write("enum JfrStructId {");
 386             for (TypeElement t : metadata.getNonEventsAndNonStructs()) {
 387                 out.write("  Jfr" + t.name + "Struct,");
 388             }
 389             for (TypeElement t : metadata.getEventsAndStructs()) {
 390                 out.write("  Jfr" + t.name + "Struct,");
 391             }
 392             out.write("");
 393             out.write("  MaxJfrStructId");
 394             out.write("};");
 395             out.write("");
 396             out.write("typedef enum JfrEventId JfrEventId;");
 397             out.write("typedef enum JfrStructId JfrStructId;");
 398             out.write("");
 399             out.write("#endif // INCLUDE_JFR");
 400             out.write("#endif // JFRFILES_JFREVENTIDS_HPP");
 401         }
 402     }
 403 
 404     private static void printJfrTypesHpp(Metadata metadata, File outputDirectory) throws Exception {
 405         List<String> knownTypes = List.of("Thread", "StackTrace", "Class", "StackFrame");
 406         try (Printer out = new Printer(outputDirectory, "jfrTypes.hpp")) {
 407             out.write("#ifndef JFRFILES_JFRTYPES_HPP");
 408             out.write("#define JFRFILES_JFRTYPES_HPP");
 409             out.write("");
 410             out.write("#include \"utilities/macros.hpp\"");
 411             out.write("#if INCLUDE_JFR");
 412             out.write("");
 413             out.write("enum JfrTypeId {");
 414             out.write("  TYPE_NONE             = 0,");
 415             out.write("  TYPE_CLASS            = 20,");
 416             out.write("  TYPE_STRING           = 21,");
 417             out.write("  TYPE_THREAD           = 22,");
 418             out.write("  TYPE_STACKTRACE       = 23,");
 419             out.write("  TYPE_BYTES            = 24,");
 420             out.write("  TYPE_EPOCHMILLIS      = 25,");
 421             out.write("  TYPE_MILLIS           = 26,");
 422             out.write("  TYPE_NANOS            = 27,");
 423             out.write("  TYPE_TICKS            = 28,");
 424             out.write("  TYPE_ADDRESS          = 29,");
 425             out.write("  TYPE_PERCENTAGE       = 30,");
 426             out.write("  TYPE_DUMMY,");
 427             out.write("  TYPE_DUMMY_1,");
 428             for (TypeElement type : metadata.getTypes()) {
 429                 if (!knownTypes.contains(type.name)) {
 430                     out.write("  TYPE_" + type.name.toUpperCase() + ",");
 431                 }
 432             }
 433             out.write("");
 434             out.write("  NUM_JFR_TYPES,");
 435             out.write("  TYPES_END             = 255");
 436             out.write("};");
 437             out.write("");
 438             out.write("enum ReservedEvent {");
 439             out.write("  EVENT_METADATA,");
 440             out.write("  EVENT_CHECKPOINT,");
 441             out.write("  EVENT_BUFFERLOST,");
 442             out.write("  NUM_RESERVED_EVENTS = TYPES_END");
 443             out.write("};");
 444             out.write("");
 445             out.write("#endif // INCLUDE_JFR");
 446             out.write("#endif // JFRFILES_JFRTYPES_HPP");
 447           };
 448     }
 449 
 450     private static void printJfrEventClassesHpp(Metadata metadata, File outputDirectory) throws Exception {
 451         try (Printer out = new Printer(outputDirectory, "jfrEventClasses.hpp")) {
 452             out.write("#ifndef JFRFILES_JFREVENTCLASSES_HPP");
 453             out.write("#define JFRFILES_JFREVENTCLASSES_HPP");
 454             out.write("");
 455             out.write("#include \"oops/klass.hpp\"");
 456             out.write("#include \"jfrfiles/jfrTypes.hpp\"");
 457             out.write("#include \"jfr/utilities/jfrTypes.hpp\"");
 458             out.write("#include \"utilities/macros.hpp\"");
 459             out.write("#include \"utilities/ticks.hpp\"");
 460             out.write("#if INCLUDE_JFR");
 461             out.write("#include \"jfr/recorder/service/jfrEvent.hpp\"");
 462             out.write("/*");
 463             out.write(" * Each event class has an assert member function verify() which is invoked");
 464             out.write(" * just before the engine writes the event and its fields to the data stream.");
 465             out.write(" * The purpose of verify() is to ensure that all fields in the event are initialized");
 466             out.write(" * and set before attempting to commit.");
 467             out.write(" *");
 468             out.write(" * We enforce this requirement because events are generally stack allocated and therefore");
 469             out.write(" * *not* initialized to default values. This prevents us from inadvertently committing");
 470             out.write(" * uninitialized values to the data stream.");
 471             out.write(" *");
 472             out.write(" * The assert message contains both the index (zero based) as well as the name of the field.");
 473             out.write(" */");
 474             out.write("");
 475             printTypes(out, metadata, false);
 476             out.write("");
 477             out.write("");
 478             out.write("#else // !INCLUDE_JFR");
 479             out.write("");
 480             out.write("template <typename T>");
 481             out.write("class JfrEvent {");
 482             out.write(" public:");
 483             out.write("  JfrEvent() {}");
 484             out.write("  void set_starttime(const Ticks&) const {}");
 485             out.write("  void set_endtime(const Ticks&) const {}");
 486             out.write("  bool should_commit() const { return false; }");
 487             out.write("  static bool is_enabled() { return false; }");
 488             out.write("  void commit() {}");
 489             out.write("};");
 490             out.write("");
 491             printTypes(out, metadata, true);
 492             out.write("");
 493             out.write("");
 494             out.write("#endif // INCLUDE_JFR");
 495             out.write("#endif // JFRFILES_JFREVENTCLASSES_HPP");
 496         }
 497     }
 498 
 499     private static void printTypes(Printer out, Metadata metadata, boolean empty) {
 500         for (TypeElement t : metadata.getStructs()) {
 501             if (empty) {
 502                 out.write("");
 503                 printEmptyType(out, t);
 504             } else {
 505                 printType(out, t);
 506             }
 507             out.write("");
 508         }
 509         for (EventElement e : metadata.getEvents()) {
 510             if (empty) {
 511                 printEmptyEvent(out, e);
 512             } else {
 513                 printEvent(out, e);
 514             }
 515             out.write("");
 516         }
 517     }
 518 
 519     private static void printEmptyEvent(Printer out, EventElement event) {
 520         out.write("class Event" + event.name + " : public JfrEvent<Event" + event.name + ">");
 521         out.write("{");
 522         out.write(" public:");
 523         out.write("  Event" + event.name + "(EventStartTime ignore=TIMED) {}");
 524         if (event.startTime) {
 525             StringJoiner sj = new StringJoiner(",\n    ");
 526             for (FieldElement f : event.fields) {
 527                 sj.add(f.getParameterType());
 528             }
 529             out.write("  Event" + event.name + "(");
 530             out.write("    " + sj.toString() + ") { }");
 531         }
 532         for (FieldElement f : event.fields) {
 533             out.write("  void set_" + f.name + "(" + f.getParameterType() + ") { }");
 534         }
 535         out.write("");
 536         out.write("  using JfrEvent<Event" + event.name + ">::commit; // else commit() is hidden by overloaded versions in this class");
 537         if (event.startTime) {
 538             StringJoiner sj = new StringJoiner(",\n              ");
 539             for (FieldElement f : event.fields) {
 540                 sj.add(f.getParameterType() + " " + f.name);
 541             }
 542             out.write("");
 543             out.write("  void commit(" + sj.toString() + ") { }");
 544         }
 545         out.write("");
 546         StringJoiner sj = new StringJoiner(",\n                     ");
 547         if (event.startTime) {
 548             sj.add("const Ticks& startTicks");
 549             sj.add("const Ticks& endTicks");
 550         }
 551         for (FieldElement f : event.fields) {
 552             sj.add(f.getParameterType() + " " + f.name);
 553         }
 554         out.write("  static void commit(" + sj.toString() + ") { }");
 555         out.write("};");
 556     }
 557 
 558     private static void printEmptyType(Printer out, TypeElement t) {
 559         out.write("struct JfrStruct" + t.name);
 560         out.write("{");
 561         out.write(" public:");
 562         for (FieldElement f : t.fields) {
 563             out.write("  void set_" + f.name + "(" + f.getParameterType() + ") { }");
 564         }
 565         out.write("};");
 566     }
 567 
 568     private static void printType(Printer out, TypeElement t) {
 569         out.write("struct JfrStruct" + t.name);
 570         out.write("{");
 571         out.write(" private:");
 572         for (FieldElement f : t.fields) {
 573             printField(out, f);
 574         }
 575         out.write("");
 576         out.write(" public:");
 577         for (FieldElement f : t.fields) {
 578             printTypeSetter(out, f);
 579         }
 580         out.write("");
 581         printWriteData(out, t.fields);
 582         out.write("};");
 583         out.write("");
 584     }
 585 
 586     private static void printEvent(Printer out, EventElement event) {
 587         out.write("class Event" + event.name + " : public JfrEvent<Event" + event.name + ">");
 588         out.write("{");
 589         out.write(" private:");
 590         for (FieldElement f : event.fields) {
 591             printField(out, f);
 592         }
 593         out.write("");
 594         out.write(" public:");
 595         out.write("  static const bool hasThread = " + event.thread + ";");
 596         out.write("  static const bool hasStackTrace = " + event.stackTrace + ";");
 597         out.write("  static const bool isInstant = " + !event.startTime + ";");
 598         out.write("  static const bool hasCutoff = " + event.cutoff + ";");
 599         out.write("  static const bool isRequestable = " + event.periodic + ";");
 600         out.write("  static const JfrEventId eventId = Jfr" + event.name + "Event;");
 601         out.write("");
 602         out.write("  Event" + event.name + "(EventStartTime timing=TIMED) : JfrEvent<Event" + event.name + ">(timing) {}");
 603         out.write("");
 604         int index = 0;
 605         for (FieldElement f : event.fields) {
 606             out.write("  void set_" + f.name + "(" + f.getParameterType() + " " + f.getParameterName() + ") {");
 607             out.write("    this->_" + f.name + " = " + f.getParameterName() + ";");
 608             out.write("    DEBUG_ONLY(set_field_bit(" + index++ + "));");
 609             out.write("  }");
 610         }
 611         out.write("");
 612         printWriteData(out, event.fields);
 613         out.write("");
 614         out.write("  using JfrEvent<Event" + event.name + ">::commit; // else commit() is hidden by overloaded versions in this class");
 615         printConstructor2(out, event);
 616         printCommitMethod(out, event);
 617         printVerify(out, event.fields);
 618         out.write("};");
 619     }
 620 
 621     private static void printWriteData(Printer out, List<FieldElement> fields) {
 622         out.write("  template <typename Writer>");
 623         out.write("  void writeData(Writer& w) {");
 624         for (FieldElement field : fields) {
 625             if (field.struct) {
 626                 out.write("    _" + field.name + ".writeData(w);");
 627             } else {
 628                 out.write("    w.write(_" + field.name + ");");
 629             }
 630         }
 631         out.write("  }");
 632     }
 633 
 634     private static void printTypeSetter(Printer out, FieldElement field) {
 635         out.write("  void set_" + field.name + "(" + field.getParameterType() + " new_value) { this->_" + field.name + " = new_value; }");
 636     }
 637 
 638     private static void printVerify(Printer out, List<FieldElement> fields) {
 639         out.write("");
 640         out.write("#ifdef ASSERT");
 641         out.write("  void verify() const {");
 642         int index = 0;
 643         for (FieldElement f : fields) {
 644             out.write("    assert(verify_field_bit(" + index++ + "), \"Attempting to write an uninitialized event field: %s\", \"_" + f.name + "\");");
 645         }
 646         out.write("  }");
 647         out.write("#endif");
 648     }
 649 
 650     private static void printCommitMethod(Printer out, EventElement event) {
 651         if (event.startTime) {
 652             StringJoiner sj = new StringJoiner(",\n              ");
 653             for (FieldElement f : event.fields) {
 654                 sj.add(f.getParameterType() + " " + f.name);
 655             }
 656             out.write("");
 657             out.write("  void commit(" + sj.toString() + ") {");
 658             out.write("    if (should_commit()) {");
 659             for (FieldElement f : event.fields) {
 660                 out.write("      set_" + f.name + "(" + f.name + ");");
 661             }
 662             out.write("      commit();");
 663             out.write("    }");
 664             out.write("  }");
 665         }
 666         out.write("");
 667         StringJoiner sj = new StringJoiner(",\n                     ");
 668         if (event.startTime) {
 669             sj.add("const Ticks& startTicks");
 670             sj.add("const Ticks& endTicks");
 671         }
 672         for (FieldElement f : event.fields) {
 673             sj.add(f.getParameterType() + " " + f.name);
 674         }
 675         out.write("  static void commit(" + sj.toString() + ") {");
 676         out.write("    Event" + event.name + " me(UNTIMED);");
 677         out.write("");
 678         out.write("    if (me.should_commit()) {");
 679         if (event.startTime) {
 680             out.write("      me.set_starttime(startTicks);");
 681             out.write("      me.set_endtime(endTicks);");
 682         }
 683         for (FieldElement f : event.fields) {
 684             out.write("      me.set_" + f.name + "(" + f.name + ");");
 685         }
 686         out.write("      me.commit();");
 687         out.write("    }");
 688         out.write("  }");
 689     }
 690 
 691     private static void printConstructor2(Printer out, EventElement event) {
 692         if (!event.startTime) {
 693             out.write("");
 694             out.write("");
 695         }
 696         if (event.startTime) {
 697             out.write("");
 698             out.write("  Event" + event.name + "(");
 699             StringJoiner sj = new StringJoiner(",\n    ");
 700             for (FieldElement f : event.fields) {
 701                 sj.add(f.getParameterType() + " " + f.name);
 702             }
 703             out.write("    " + sj.toString() + ") : JfrEvent<Event" + event.name + ">(TIMED) {");
 704             out.write("    if (should_commit()) {");
 705             for (FieldElement f : event.fields) {
 706                 out.write("      set_" + f.name + "(" + f.name + ");");
 707             }
 708             out.write("    }");
 709             out.write("  }");
 710         }
 711     }
 712 
 713     private static void printField(Printer out, FieldElement field) {
 714         out.write("  " + field.getFieldType() + " _" + field.name + ";");
 715     }
 716 }