1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * The contents of this file are subject to the terms of either the Universal Permissive License 7 * v 1.0 as shown at http://oss.oracle.com/licenses/upl 8 * 9 * or the following license: 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are permitted 12 * provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions 15 * and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 18 * conditions and the following disclaimer in the documentation and/or other materials provided with 19 * the distribution. 20 * 21 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 22 * endorse or promote products derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 26 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 31 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 package org.openjdk.jmc.flightrecorder.parser.synthetic; 34 35 import static org.openjdk.jmc.common.item.Attribute.attr; 36 import static org.openjdk.jmc.flightrecorder.JfrAttributes.EVENT_STACKTRACE; 37 import static org.openjdk.jmc.flightrecorder.JfrAttributes.EVENT_THREAD; 38 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.List; 42 43 import org.openjdk.jmc.common.IMCFrame; 44 import org.openjdk.jmc.common.IMCModule; 45 import org.openjdk.jmc.common.IMCPackage; 46 import org.openjdk.jmc.common.IMCStackTrace; 47 import org.openjdk.jmc.common.IMCThread; 48 import org.openjdk.jmc.common.item.IAttribute; 49 import org.openjdk.jmc.common.unit.UnitLookup; 50 import org.openjdk.jmc.common.util.LabeledIdentifier; 51 import org.openjdk.jmc.flightrecorder.JfrAttributes; 52 import org.openjdk.jmc.flightrecorder.internal.util.JfrInternalConstants; 53 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes; 54 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs; 55 import org.openjdk.jmc.flightrecorder.parser.IEventSink; 56 import org.openjdk.jmc.flightrecorder.parser.IEventSinkFactory; 57 import org.openjdk.jmc.flightrecorder.parser.IParserExtension; 58 import org.openjdk.jmc.flightrecorder.parser.ValueField; 59 60 public class SyntheticAttributeExtension implements IParserExtension { 61 62 private static final IAttribute<IMCStackTrace> EXECUTION_SAMPLES_STACKTRACE = attr("stackTrace", //$NON-NLS-1$ 63 Messages.getString(Messages.SyntheticAttributeExtension_EXECUTION_SAMPLES_STACKTRACE), 64 EVENT_STACKTRACE.getContentType()); 65 private static final IAttribute<IMCThread> EXECUTION_SAMPLES_THREAD = attr("sampledThread", //$NON-NLS-1$ 66 Messages.getString(Messages.SyntheticAttributeExtension_EXECUTION_SAMPLES_THREAD), 67 EVENT_THREAD.getContentType()); 68 private static final IAttribute<IMCThread> ALLOC_STATISTICS_THREAD = attr("thread", //$NON-NLS-1$ 69 Messages.getString(Messages.SyntheticAttributeExtension_ALLOC_STATISTICS_THREAD), 70 EVENT_THREAD.getContentType()); 71 // FIXME: Break out constant 72 static final IAttribute<LabeledIdentifier> REC_SETTING_EVENT_ID_ATTRIBUTE = attr("id", //$NON-NLS-1$ 73 Messages.getString(Messages.SyntheticAttributeExtension_REC_SETTING_EVENT_ID_ATTRIBUTE), 74 UnitLookup.LABELED_IDENTIFIER); 75 76 @Override 77 public IEventSinkFactory getEventSinkFactory(final IEventSinkFactory sf) { 78 return SettingsTransformer.wrapSinkFactory(new IEventSinkFactory() { 79 80 @Override 81 public IEventSink create( 82 String identifier, String label, String[] category, String description, 83 List<ValueField> dataStructure) { 84 if (JdkTypeIDs.EXECUTION_SAMPLE.equals(identifier)) { 85 ValueField[] struct = new ValueField[dataStructure.size()]; 86 for (int i = 0; i < struct.length; i++) { 87 ValueField vf = dataStructure.get(i); 88 if (vf.matches(EXECUTION_SAMPLES_STACKTRACE)) { 89 vf = new ValueField(EVENT_STACKTRACE); 90 } else if (vf.matches(EXECUTION_SAMPLES_THREAD)) { 91 vf = new ValueField(EVENT_THREAD); 92 } 93 struct[i] = vf; 94 } 95 dataStructure = Arrays.asList(struct); 96 } else if (JdkTypeIDs.THREAD_ALLOCATION_STATISTICS.equals(identifier)) { 97 ValueField[] struct = new ValueField[dataStructure.size()]; 98 for (int i = 0; i < struct.length; i++) { 99 ValueField vf = dataStructure.get(i); 100 if (vf.matches(ALLOC_STATISTICS_THREAD)) { 101 vf = new ValueField(EVENT_THREAD); 102 } 103 struct[i] = vf; 104 } 105 dataStructure = Arrays.asList(struct); 106 } else if (JdkTypeIDs.EXCEPTIONS_THROWN.equals(identifier)) { 107 for (int i = 0; i < dataStructure.size(); i++) { 108 final int stacktraceIndex = i; 109 if (dataStructure.get(i).matches(JfrAttributes.EVENT_STACKTRACE)) { 110 final IEventSink subSink = sf.create(identifier, label, category, description, 111 dataStructure); 112 return new IEventSink() { 113 114 @Override 115 public void addEvent(Object[] values) { 116 IMCStackTrace st = (IMCStackTrace) values[stacktraceIndex]; 117 /* 118 * NOTE: Filters out JavaExceptionThrow events created from the 119 * Error constructor to avoid constructed errors being 120 * represented both with a JavaErrorThrow and two 121 * JavaExceptionThrow. 122 */ 123 if (st == null || st.getFrames().size() < 2 124 || !isError(st.getFrames().get(0)) && !isError(st.getFrames().get(1))) { 125 subSink.addEvent(values); 126 } 127 } 128 129 private boolean isError(IMCFrame frame) { 130 return frame.getMethod().getType().getFullName().equals("java.lang.Error"); //$NON-NLS-1$ 131 } 132 }; 133 } 134 } 135 } else if (JdkTypeIDs.RECORDING_SETTING.equals(identifier)) { 136 ValueField[] struct = new ValueField[dataStructure.size()]; 137 for (int i = 0; i < struct.length; i++) { 138 ValueField vf = dataStructure.get(i); 139 if (vf.matches(REC_SETTING_EVENT_ID_ATTRIBUTE)) { 140 vf = new ValueField(JdkAttributes.REC_SETTING_FOR); 141 } 142 struct[i] = vf; 143 } 144 dataStructure = Arrays.asList(struct); 145 } else if (JdkTypeIDs.MODULE_EXPORT.equals(identifier)) { 146 // Unwrapping the exporting module field from the exported package as a separate attribute in the event type. 147 int packageIndex = -1; 148 for (int i = 0; i < dataStructure.size(); i++) { 149 ValueField vf = dataStructure.get(i); 150 if (vf.matches(JdkAttributes.EXPORTED_PACKAGE)) { 151 packageIndex = i; 152 break; 153 } 154 } 155 if (packageIndex != -1) { 156 List<ValueField> newDataStructure = new ArrayList<>(dataStructure); 157 newDataStructure.add(new ValueField(JdkAttributes.EXPORTING_MODULE)); 158 IEventSink subSink = sf.create(identifier, label, category, description, newDataStructure); 159 IEventSink moduleExportSink = new ModuleExportSink(subSink, packageIndex); 160 return moduleExportSink; 161 } 162 } 163 return sf.create(identifier, label, category, description, dataStructure); 164 } 165 166 @Override 167 public void flush() { 168 sf.flush(); 169 } 170 }); 171 } 172 173 @Override 174 public String getValueInterpretation(String eventTypeId, String fieldId) { 175 if (REC_SETTING_EVENT_ID_ATTRIBUTE.getIdentifier().equals(fieldId) 176 && (JdkTypeIDsPreJdk11.RECORDING_SETTING.equals(eventTypeId) || 177 JdkTypeIDsPreJdk11.JDK9_RECORDING_SETTING.equals(eventTypeId) || 178 JdkTypeIDs.RECORDING_SETTING.equals(eventTypeId))) { 179 return JfrInternalConstants.TYPE_IDENTIFIER_VALUE_INTERPRETATION; 180 } 181 return null; 182 } 183 184 private static class ModuleExportSink implements IEventSink { 185 private final IEventSink subSink; 186 private final int packageFieldIndex; 187 188 public ModuleExportSink(IEventSink subSink, int packageFieldIndex) { 189 this.subSink = subSink; 190 this.packageFieldIndex = packageFieldIndex; 191 } 192 193 @Override 194 public void addEvent(Object[] values) { 195 IMCPackage thePackage = (IMCPackage) values[packageFieldIndex]; 196 IMCModule exportingModule = thePackage.getModule(); 197 Object[] newValues = new Object[values.length + 1]; 198 System.arraycopy(values, 0, newValues, 0, values.length); 199 newValues[values.length] = exportingModule; 200 subSink.addEvent(newValues); 201 } 202 } 203 }