src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java
changeset 58863 c16ac7a2eba4
parent 52981 4eff16f47ae2
equal deleted inserted replaced
58861:2c3cc4b01880 58863:c16ac7a2eba4
     1 /*
     1 /*
     2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package jdk.jfr.consumer;
    26 package jdk.jfr.consumer;
    27 
    27 
       
    28 import java.io.IOException;
    28 import java.io.PrintWriter;
    29 import java.io.PrintWriter;
    29 import java.io.StringWriter;
    30 import java.io.StringWriter;
    30 import java.time.Duration;
    31 import java.time.Duration;
    31 import java.time.Instant;
    32 import java.time.Instant;
    32 import java.time.OffsetDateTime;
    33 import java.time.OffsetDateTime;
       
    34 import java.util.Comparator;
    33 import java.util.List;
    35 import java.util.List;
    34 import java.util.Objects;
    36 import java.util.Objects;
    35 
    37 
    36 import jdk.jfr.Timespan;
    38 import jdk.jfr.Timespan;
    37 import jdk.jfr.Timestamp;
    39 import jdk.jfr.Timestamp;
    38 import jdk.jfr.ValueDescriptor;
    40 import jdk.jfr.ValueDescriptor;
       
    41 import jdk.jfr.internal.consumer.JdkJfrConsumer;
       
    42 import jdk.jfr.internal.consumer.ObjectFactory;
    39 import jdk.jfr.internal.PrivateAccess;
    43 import jdk.jfr.internal.PrivateAccess;
       
    44 import jdk.jfr.internal.Type;
       
    45 import jdk.jfr.internal.consumer.ObjectContext;
    40 import jdk.jfr.internal.tool.PrettyWriter;
    46 import jdk.jfr.internal.tool.PrettyWriter;
    41 
    47 
    42 /**
    48 /**
    43  * A complex data type that consists of one or more fields.
    49  * A complex data type that consists of one or more fields.
    44  * <p>
    50  * <p>
    49  *
    55  *
    50  * @since 9
    56  * @since 9
    51  */
    57  */
    52 public class RecordedObject {
    58 public class RecordedObject {
    53 
    59 
       
    60     static{
       
    61         JdkJfrConsumer access = new JdkJfrConsumer() {
       
    62             public List<Type> readTypes(RecordingFile file) throws IOException {
       
    63                 return file.readTypes();
       
    64             }
       
    65 
       
    66             public boolean isLastEventInChunk(RecordingFile file) {
       
    67                 return file.isLastEventInChunk();
       
    68             }
       
    69 
       
    70             @Override
       
    71             public Object getOffsetDataTime(RecordedObject event, String name) {
       
    72                 return event.getOffsetDateTime(name);
       
    73             }
       
    74 
       
    75             @Override
       
    76             public RecordedClass newRecordedClass(ObjectContext objectContext, long id, Object[] values) {
       
    77                 return new RecordedClass(objectContext, id, values);
       
    78             }
       
    79 
       
    80             @Override
       
    81             public RecordedClassLoader newRecordedClassLoader(ObjectContext objectContext, long id, Object[] values) {
       
    82                 return new RecordedClassLoader(objectContext, id, values);
       
    83             }
       
    84 
       
    85             @Override
       
    86             public Comparator<? super RecordedEvent> eventComparator() {
       
    87                 return new Comparator<RecordedEvent>()  {
       
    88                     @Override
       
    89                     public int compare(RecordedEvent e1, RecordedEvent e2) {
       
    90                         return Long.compare(e1.endTimeTicks, e2.endTimeTicks);
       
    91                     }
       
    92                 };
       
    93             }
       
    94 
       
    95             @Override
       
    96             public RecordedStackTrace newRecordedStackTrace(ObjectContext objectContext, Object[] values) {
       
    97                 return new RecordedStackTrace(objectContext, values);
       
    98             }
       
    99 
       
   100             @Override
       
   101             public RecordedThreadGroup newRecordedThreadGroup(ObjectContext objectContext, Object[] values) {
       
   102                 return new RecordedThreadGroup(objectContext, values);
       
   103             }
       
   104 
       
   105             @Override
       
   106             public RecordedFrame newRecordedFrame(ObjectContext objectContext, Object[] values) {
       
   107                 return new RecordedFrame(objectContext, values);
       
   108             }
       
   109 
       
   110             @Override
       
   111             public RecordedThread newRecordedThread(ObjectContext objectContext, long id, Object[] values) {
       
   112                 return new RecordedThread(objectContext, id, values);
       
   113             }
       
   114 
       
   115             @Override
       
   116             public RecordedMethod newRecordedMethod(ObjectContext objectContext, Object[] values) {
       
   117                 return new RecordedMethod(objectContext, values);
       
   118             }
       
   119 
       
   120             @Override
       
   121             public RecordedEvent newRecordedEvent(ObjectContext objectContext, Object[] values, long startTimeTicks, long endTimeTicks) {
       
   122                 return new RecordedEvent(objectContext, values, startTimeTicks, endTimeTicks);
       
   123             }
       
   124 
       
   125             @Override
       
   126             public void setStartTicks(RecordedEvent event, long startTicks) {
       
   127                event.startTimeTicks = startTicks;
       
   128             }
       
   129 
       
   130             @Override
       
   131             public void setEndTicks(RecordedEvent event, long endTicks) {
       
   132                event.endTimeTicks = endTicks;
       
   133             }
       
   134 
       
   135             @Override
       
   136             public Object[] eventValues(RecordedEvent event) {
       
   137                 return event.objects;
       
   138             }
       
   139         };
       
   140         JdkJfrConsumer.setAccess(access);
       
   141     }
       
   142 
    54     private final static class UnsignedValue {
   143     private final static class UnsignedValue {
    55         private final Object o;
   144         private final Object o;
    56 
   145 
    57         UnsignedValue(Object o) {
   146         UnsignedValue(Object o) {
    58             this.o = o;
   147             this.o = o;
    61         Object value() {
   150         Object value() {
    62             return o;
   151             return o;
    63         }
   152         }
    64     }
   153     }
    65 
   154 
    66     private final Object[] objects;
   155     final Object[] objects;
    67     private final List<ValueDescriptor> descriptors;
   156     final ObjectContext objectContext;
    68     private final TimeConverter timeConverter;
       
    69 
   157 
    70     // package private, not to be subclassed outside this package
   158     // package private, not to be subclassed outside this package
    71     RecordedObject(List<ValueDescriptor> descriptors, Object[] objects, TimeConverter timeConverter) {
   159     RecordedObject(ObjectContext objectContext, Object[] objects) {
    72         this.descriptors = descriptors;
   160         this.objectContext = objectContext;
    73         this.objects = objects;
   161         this.objects = objects;
    74         this.timeConverter = timeConverter;
       
    75     }
   162     }
    76 
   163 
    77     // package private
   164     // package private
    78     final <T> T getTyped(String name, Class<T> clazz, T defaultValue) {
   165     final <T> T getTyped(String name, Class<T> clazz, T defaultValue) {
    79         // Unnecessary to check field presence twice, but this
   166         // Unnecessary to check field presence twice, but this
    99      *
   186      *
   100      * @see #getFields()
   187      * @see #getFields()
   101      */
   188      */
   102     public boolean hasField(String name) {
   189     public boolean hasField(String name) {
   103         Objects.requireNonNull(name);
   190         Objects.requireNonNull(name);
   104         for (ValueDescriptor v : descriptors) {
   191         for (ValueDescriptor v : objectContext.fields) {
   105             if (v.getName().equals(name)) {
   192             if (v.getName().equals(name)) {
   106                 return true;
   193                 return true;
   107             }
   194             }
   108         }
   195         }
   109         int dotIndex = name.indexOf(".");
   196         int dotIndex = name.indexOf(".");
   110         if (dotIndex > 0) {
   197         if (dotIndex > 0) {
   111             String structName = name.substring(0, dotIndex);
   198             String structName = name.substring(0, dotIndex);
   112             for (ValueDescriptor v : descriptors) {
   199             for (ValueDescriptor v : objectContext.fields) {
   113                 if (!v.getFields().isEmpty() && v.getName().equals(structName)) {
   200                 if (!v.getFields().isEmpty() && v.getName().equals(structName)) {
   114                     RecordedObject child = getValue(structName);
   201                     RecordedObject child = getValue(structName);
   115                     if (child != null) {
   202                     if (child != null) {
   116                         return child.hasField(name.substring(dotIndex + 1));
   203                         return child.hasField(name.substring(dotIndex + 1));
   117                     }
   204                     }
   167         @SuppressWarnings("unchecked")
   254         @SuppressWarnings("unchecked")
   168         T t = (T) getValue(name, false);
   255         T t = (T) getValue(name, false);
   169         return t;
   256         return t;
   170     }
   257     }
   171 
   258 
       
   259     protected Object objectAt(int index) {
       
   260         return objects[index];
       
   261     }
       
   262 
   172     private Object getValue(String name, boolean allowUnsigned) {
   263     private Object getValue(String name, boolean allowUnsigned) {
   173         Objects.requireNonNull(name);
   264         Objects.requireNonNull(name);
   174         int index = 0;
   265         int index = 0;
   175         for (ValueDescriptor v : descriptors) {
   266         for (ValueDescriptor v : objectContext.fields) {
   176             if (name.equals(v.getName())) {
   267             if (name.equals(v.getName())) {
   177                 Object object = objects[index];
   268                 Object object = objectAt(index);
   178                 if (object == null) {
   269                 if (object == null) {
   179                     // error or missing
   270                     // error or missing
   180                     return null;
   271                     return null;
   181                 }
   272                 }
   182                 if (v.getFields().isEmpty()) {
   273                 if (v.getFields().isEmpty()) {
   198                     if (v.isArray()) {
   289                     if (v.isArray()) {
   199                         // struct array
   290                         // struct array
   200                         return structifyArray(v, array, 0);
   291                         return structifyArray(v, array, 0);
   201                     }
   292                     }
   202                     // struct
   293                     // struct
   203                     return new RecordedObject(v.getFields(), (Object[]) object, timeConverter);
   294                     return new RecordedObject(objectContext.getInstance(v), (Object[]) object);
   204                 }
   295                 }
   205             }
   296             }
   206             index++;
   297             index++;
   207         }
   298         }
   208 
   299 
   209         int dotIndex = name.indexOf(".");
   300         int dotIndex = name.indexOf(".");
   210         if (dotIndex > 0) {
   301         if (dotIndex > 0) {
   211             String structName = name.substring(0, dotIndex);
   302             String structName = name.substring(0, dotIndex);
   212             for (ValueDescriptor v : descriptors) {
   303             for (ValueDescriptor v : objectContext.fields) {
   213                 if (!v.getFields().isEmpty() && v.getName().equals(structName)) {
   304                 if (!v.getFields().isEmpty() && v.getName().equals(structName)) {
   214                     RecordedObject child = getValue(structName);
   305                     RecordedObject child = getValue(structName);
   215                     String subName = name.substring(dotIndex + 1);
   306                     String subName = name.substring(dotIndex + 1);
   216                     if (child != null) {
   307                     if (child != null) {
   217                         return child.getValue(subName, allowUnsigned);
   308                         return child.getValue(subName, allowUnsigned);
   259     // This is to prevent a call to getString on a thread field, that is
   350     // This is to prevent a call to getString on a thread field, that is
   260     // null to succeed.
   351     // null to succeed.
   261     private <T> T getTypedValue(String name, String typeName) {
   352     private <T> T getTypedValue(String name, String typeName) {
   262         Objects.requireNonNull(name);
   353         Objects.requireNonNull(name);
   263         // Validate name and type first
   354         // Validate name and type first
   264         getValueDescriptor(descriptors, name, typeName);
   355         getValueDescriptor(objectContext.fields, name, typeName);
   265         return getValue(name);
   356         return getValue(name);
   266     }
   357     }
   267 
   358 
   268     private Object[] structifyArray(ValueDescriptor v, Object[] array, int dimension) {
   359     private Object[] structifyArray(ValueDescriptor v, Object[] array, int dimension) {
   269         if (array == null) {
   360         if (array == null) {
   270             return null;
   361             return null;
   271         }
   362         }
   272         Object[] structArray = new Object[array.length];
   363         Object[] structArray = new Object[array.length];
       
   364         ObjectContext objContext = objectContext.getInstance(v);
   273         for (int i = 0; i < structArray.length; i++) {
   365         for (int i = 0; i < structArray.length; i++) {
   274             Object arrayElement = array[i];
   366             Object arrayElement = array[i];
   275             if (dimension == 0) {
   367             if (dimension == 0) {
   276                 // No general way to handle structarrays
   368                 // No general way to handle structarrays
   277                 // without invoking ObjectFactory for every instance (which may require id)
   369                 // without invoking ObjectFactory for every instance (which may require id)
   278                 if (isStackFrameType(v.getTypeName())) {
   370                 if (isStackFrameType(v.getTypeName())) {
   279                     structArray[i] = new RecordedFrame(v.getFields(), (Object[]) arrayElement, timeConverter);
   371                     structArray[i] = new RecordedFrame(objContext, (Object[]) arrayElement);
   280                 } else {
   372                 } else {
   281                     structArray[i] = new RecordedObject(v.getFields(), (Object[]) arrayElement, timeConverter);
   373                     structArray[i] = new RecordedObject(objContext, (Object[]) arrayElement);
   282                 }
   374                 }
   283             } else {
   375             } else {
   284                 structArray[i] = structifyArray(v, (Object[]) arrayElement, dimension - 1);
   376                 structArray[i] = structifyArray(v, (Object[]) arrayElement, dimension - 1);
   285             }
   377             }
   286         }
   378         }
   301      * Returns an immutable list of the fields for this object.
   393      * Returns an immutable list of the fields for this object.
   302      *
   394      *
   303      * @return the fields, not {@code null}
   395      * @return the fields, not {@code null}
   304      */
   396      */
   305     public List<ValueDescriptor> getFields() {
   397     public List<ValueDescriptor> getFields() {
   306         return descriptors;
   398         return objectContext.fields;
   307     }
   399     }
   308 
   400 
   309     /**
   401     /**
   310      * Returns the value of a field of type {@code boolean}.
   402      * Returns the value of a field of type {@code boolean}.
   311      * <p>
   403      * <p>
   723         }
   815         }
   724         throw newIllegalArgumentException(name, "java,time.Duration");
   816         throw newIllegalArgumentException(name, "java,time.Duration");
   725     }
   817     }
   726 
   818 
   727     private Duration getDuration(long timespan, String name) throws InternalError {
   819     private Duration getDuration(long timespan, String name) throws InternalError {
   728         ValueDescriptor v = getValueDescriptor(descriptors, name, null);
   820         ValueDescriptor v = getValueDescriptor(objectContext.fields, name, null);
   729         if (timespan == Long.MIN_VALUE) {
   821         if (timespan == Long.MIN_VALUE) {
   730             return Duration.ofSeconds(Long.MIN_VALUE, 0);
   822             return Duration.ofSeconds(Long.MIN_VALUE, 0);
   731         }
   823         }
   732         Timespan ts = v.getAnnotation(Timespan.class);
   824         Timespan ts = v.getAnnotation(Timespan.class);
   733         if (ts != null) {
   825         if (ts != null) {
   739             case Timespan.MILLISECONDS:
   831             case Timespan.MILLISECONDS:
   740                 return Duration.ofMillis(timespan);
   832                 return Duration.ofMillis(timespan);
   741             case Timespan.NANOSECONDS:
   833             case Timespan.NANOSECONDS:
   742                 return Duration.ofNanos(timespan);
   834                 return Duration.ofNanos(timespan);
   743             case Timespan.TICKS:
   835             case Timespan.TICKS:
   744                 return Duration.ofNanos(timeConverter.convertTimespan(timespan));
   836                 return Duration.ofNanos(objectContext.convertTimespan(timespan));
   745             }
   837             }
   746             throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal timespan unit " + ts.value());
   838             throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal timespan unit " + ts.value());
   747         }
   839         }
   748         throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with missing @Timespan");
   840         throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with missing @Timespan");
   749     }
   841     }
   802         }
   894         }
   803         throw newIllegalArgumentException(name, "java.time.Instant");
   895         throw newIllegalArgumentException(name, "java.time.Instant");
   804     }
   896     }
   805 
   897 
   806     private Instant getInstant(long timestamp, String name) {
   898     private Instant getInstant(long timestamp, String name) {
   807         ValueDescriptor v = getValueDescriptor(descriptors, name, null);
   899         ValueDescriptor v = getValueDescriptor(objectContext.fields, name, null);
   808         Timestamp ts = v.getAnnotation(Timestamp.class);
   900         Timestamp ts = v.getAnnotation(Timestamp.class);
   809         if (ts != null) {
   901         if (ts != null) {
   810             if (timestamp == Long.MIN_VALUE) {
   902             if (timestamp == Long.MIN_VALUE) {
   811                 return Instant.MIN;
   903                 return Instant.MIN;
   812             }
   904             }
   813             switch (ts.value()) {
   905             switch (ts.value()) {
   814             case Timestamp.MILLISECONDS_SINCE_EPOCH:
   906             case Timestamp.MILLISECONDS_SINCE_EPOCH:
   815                 return Instant.ofEpochMilli(timestamp);
   907                 return Instant.ofEpochMilli(timestamp);
   816             case Timestamp.TICKS:
   908             case Timestamp.TICKS:
   817                 return Instant.ofEpochSecond(0, timeConverter.convertTimestamp(timestamp));
   909                 return Instant.ofEpochSecond(0, objectContext.convertTimestamp(timestamp));
   818             }
   910             }
   819             throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal timestamp unit " + ts.value());
   911             throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal timestamp unit " + ts.value());
   820         }
   912         }
   821         throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with missing @Timestamp");
   913         throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with missing @Timestamp");
   822     }
   914     }
   887         p.flush(true);
   979         p.flush(true);
   888         return s.toString();
   980         return s.toString();
   889     }
   981     }
   890 
   982 
   891     // package private for now. Used by EventWriter
   983     // package private for now. Used by EventWriter
   892     OffsetDateTime getOffsetDateTime(String name) {
   984     private OffsetDateTime getOffsetDateTime(String name) {
   893         Instant instant = getInstant(name);
   985         Instant instant = getInstant(name);
   894         if (instant.equals(Instant.MIN)) {
   986         if (instant.equals(Instant.MIN)) {
   895             return OffsetDateTime.MIN;
   987             return OffsetDateTime.MIN;
   896         }
   988         }
   897         return OffsetDateTime.ofInstant(getInstant(name), timeConverter.getZoneOffset());
   989         return OffsetDateTime.ofInstant(getInstant(name), objectContext.getZoneOffset());
   898     }
   990     }
   899 
   991 
   900     private static IllegalArgumentException newIllegalArgumentException(String name, String typeName) {
   992     private static IllegalArgumentException newIllegalArgumentException(String name, String typeName) {
   901         return new IllegalArgumentException("Attempt to get field \"" + name + "\" with illegal data type conversion " + typeName);
   993         return new IllegalArgumentException("Attempt to get field \"" + name + "\" with illegal data type conversion " + typeName);
   902     }
   994     }