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