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("class JfrEvent {");
481             out.write(" public:");
482             out.write("  JfrEvent() {}");
483             out.write("  void set_starttime(const Ticks&) const {}");
484             out.write("  void set_endtime(const Ticks&) const {}");
485             out.write("  bool should_commit() const { return false; }");
486             out.write("  static bool is_enabled() { return false; }");
487             out.write("  void commit() {}");
488             out.write("};");
489             out.write("");
490             printTypes(out, metadata, true);
491             out.write("");
492             out.write("");
493             out.write("#endif // INCLUDE_JFR");
494             out.write("#endif // JFRFILES_JFREVENTCLASSES_HPP");
495         }
496     }
497 
498     private static void printTypes(Printer out, Metadata metadata, boolean empty) {
499         for (TypeElement t : metadata.getStructs()) {
500             if (empty) {
501                 out.write("");
502                 printEmptyType(out, t);
503             } else {
504                 printType(out, t);
505             }
506             out.write("");
507         }
508         for (EventElement e : metadata.getEvents()) {
509             if (empty) {
510                 printEmptyEvent(out, e);
511             } else {
512                 printEvent(out, e);
513             }
514             out.write("");
515         }
516     }
517 
518     private static void printEmptyEvent(Printer out, EventElement event) {
519         out.write("class Event" + event.name + " : public JfrEvent");
520         out.write("{");
521         out.write(" public:");
522         out.write("  Event" + event.name + "(EventStartTime ignore=TIMED) {}");
523         if (event.startTime) {
524             StringJoiner sj = new StringJoiner(",\n    ");
525             for (FieldElement f : event.fields) {
526                 sj.add(f.getParameterType());
527             }
528             out.write("  Event" + event.name + "(");
529             out.write("    " + sj.toString() + ") { }");
530         }
531         for (FieldElement f : event.fields) {
532             out.write("  void set_" + f.name + "(" + f.getParameterType() + ") { }");
533         }
534         out.write("  using JfrEvent::commit; // else commit() is hidden by overloaded versions in this class");
535         printCommitMethod(out, event, true);
536         out.write("};");
537     }
538 
539     private static void printEmptyType(Printer out, TypeElement t) {
540         out.write("struct JfrStruct" + t.name);
541         out.write("{");
542         out.write(" public:");
543         for (FieldElement f : t.fields) {
544             out.write("  void set_" + f.name + "(" + f.getParameterType() + ") { }");
545         }
546         out.write("};");
547     }
548 
549     private static void printType(Printer out, TypeElement t) {
550         out.write("struct JfrStruct" + t.name);
551         out.write("{");
552         out.write(" private:");
553         for (FieldElement f : t.fields) {
554             printField(out, f);
555         }
556         out.write("");
557         out.write(" public:");
558         for (FieldElement f : t.fields) {
559             printTypeSetter(out, f);
560         }
561         out.write("");
562         printWriteData(out, t.fields);
563         out.write("};");
564         out.write("");
565     }
566 
567     private static void printEvent(Printer out, EventElement event) {
568         out.write("class Event" + event.name + " : public JfrEvent<Event" + event.name + ">");
569         out.write("{");
570         out.write(" private:");
571         for (FieldElement f : event.fields) {
572             printField(out, f);
573         }
574         out.write("");
575         out.write(" public:");
576         out.write("  static const bool hasThread = " + event.thread + ";");
577         out.write("  static const bool hasStackTrace = " + event.stackTrace + ";");
578         out.write("  static const bool isInstant = " + !event.startTime + ";");
579         out.write("  static const bool hasCutoff = " + event.cutoff + ";");
580         out.write("  static const bool isRequestable = " + event.periodic + ";");
581         out.write("  static const JfrEventId eventId = Jfr" + event.name + "Event;");
582         out.write("");
583         out.write("  Event" + event.name + "(EventStartTime timing=TIMED) : JfrEvent<Event" + event.name + ">(timing) {}");
584         out.write("");
585         int index = 0;
586         for (FieldElement f : event.fields) {
587             out.write("  void set_" + f.name + "(" + f.getParameterType() + " " + f.getParameterName() + ") {");
588             out.write("    this->_" + f.name + " = " + f.getParameterName() + ";");
589             out.write("    DEBUG_ONLY(set_field_bit(" + index++ + "));");
590             out.write("  }");
591         }
592         out.write("");
593         printWriteData(out, event.fields);
594         out.write("");
595         out.write("  using JfrEvent<Event" + event.name + ">::commit; // else commit() is hidden by overloaded versions in this class");
596         printConstructor2(out, event);
597         printCommitMethod(out, event, false);
598         printVerify(out, event.fields);
599         out.write("};");
600     }
601 
602     private static void printWriteData(Printer out, List<FieldElement> fields) {
603         out.write("  template <typename Writer>");
604         out.write("  void writeData(Writer& w) {");
605         for (FieldElement field : fields) {
606             if (field.struct) {
607                 out.write("    _" + field.name + ".writeData(w);");
608             } else {
609                 out.write("    w.write(_" + field.name + ");");
610             }
611         }
612         out.write("  }");
613     }
614 
615     private static void printTypeSetter(Printer out, FieldElement field) {
616         out.write("  void set_" + field.name + "(" + field.getParameterType() + " new_value) { this->_" + field.name + " = new_value; }");
617     }
618 
619     private static void printVerify(Printer out, List<FieldElement> fields) {
620         out.write("");
621         out.write("#ifdef ASSERT");
622         out.write("  void verify() const {");
623         int index = 0;
624         for (FieldElement f : fields) {
625             out.write("    assert(verify_field_bit(" + index++ + "), \"Attempting to write an uninitialized event field: %s\", \"_" + f.name + "\");");
626         }
627         out.write("  }");
628         out.write("#endif");
629     }
630 
631     private static void printCommitMethod(Printer out, EventElement event, boolean emptyBody) {
632         if (event.startTime) {
633             StringJoiner sj = new StringJoiner(",\n              ");
634             for (FieldElement f : event.fields) {
635                 sj.add(f.getParameterType() + " " + f.name);
636             }
637             out.write("");
638             out.write("  void commit(" + sj.toString() + ") {");
639             if (!emptyBody) {
640                 out.write("    if (should_commit()) {");
641                 for (FieldElement f : event.fields) {
642                     out.write("      set_" + f.name + "(" + f.name + ");");
643                 }
644                 out.write("      commit();");
645                 out.write("    }");
646             }
647             out.write("  }");
648         }
649         out.write("");
650         StringJoiner sj = new StringJoiner(",\n                     ");
651         if (event.startTime) {
652             sj.add("const Ticks& startTicks");
653             sj.add("const Ticks& endTicks");
654         }
655         for (FieldElement f : event.fields) {
656             sj.add(f.getParameterType() + " " + f.name);
657         }
658         out.write("  static void commit(" + sj.toString() + ") {");
659         if (!emptyBody) {
660             out.write("    Event" + event.name + " me(UNTIMED);");
661             out.write("");
662             out.write("    if (me.should_commit()) {");
663             if (event.startTime) {
664                 out.write("      me.set_starttime(startTicks);");
665                 out.write("      me.set_endtime(endTicks);");
666             }
667             for (FieldElement f : event.fields) {
668                 out.write("      me.set_" + f.name + "(" + f.name + ");");
669             }
670             out.write("      me.commit();");
671             out.write("    }");
672         }
673         out.write("  }");
674     }
675 
676     private static void printConstructor2(Printer out, EventElement event) {
677         if (!event.startTime) {
678             out.write("");
679             out.write("");
680         }
681         if (event.startTime) {
682             out.write("");
683             out.write("  Event" + event.name + "(");
684             StringJoiner sj = new StringJoiner(",\n    ");
685             for (FieldElement f : event.fields) {
686                 sj.add(f.getParameterType() + " " + f.name);
687             }
688             out.write("    " + sj.toString() + ") : JfrEvent<Event" + event.name + ">(TIMED) {");
689             out.write("    if (should_commit()) {");
690             for (FieldElement f : event.fields) {
691                 out.write("      set_" + f.name + "(" + f.name + ");");
692             }
693             out.write("    }");
694             out.write("  }");
695         }
696     }
697 
698     private static void printField(Printer out, FieldElement field) {
699         out.write("  " + field.getFieldType() + " _" + field.name + ";");
700     }
701 }