26 package jdk.jfr.consumer; |
26 package jdk.jfr.consumer; |
27 |
27 |
28 import java.io.IOException; |
28 import java.io.IOException; |
29 import java.util.ArrayList; |
29 import java.util.ArrayList; |
30 import java.util.List; |
30 import java.util.List; |
31 import java.util.Objects; |
|
32 |
31 |
33 import jdk.jfr.EventType; |
32 import jdk.jfr.EventType; |
34 import jdk.jfr.ValueDescriptor; |
33 import jdk.jfr.ValueDescriptor; |
35 import jdk.jfr.internal.MetadataDescriptor; |
34 import jdk.jfr.internal.MetadataDescriptor; |
36 import jdk.jfr.internal.PrivateAccess; |
35 import jdk.jfr.internal.PrivateAccess; |
37 import jdk.jfr.internal.Type; |
36 import jdk.jfr.internal.Type; |
|
37 import jdk.jfr.internal.consumer.Parser; |
38 import jdk.jfr.internal.consumer.RecordingInput; |
38 import jdk.jfr.internal.consumer.RecordingInput; |
39 |
39 |
40 /** |
40 /** |
41 * Class that create parsers suitable for reading events and constant pools |
41 * Class that create parsers suitable for reading events and constant pools |
42 */ |
42 */ |
43 final class ParserFactory { |
43 final class ParserFactory { |
44 private final LongMap<Parser> parsers = new LongMap<>(); |
44 private final LongMap<Parser> parsers = new LongMap<>(); |
45 private final TimeConverter timeConverter; |
45 private final TimeConverter timeConverter; |
46 private final LongMap<Type> types = new LongMap<>(); |
46 private final LongMap<Type> types = new LongMap<>(); |
47 private final LongMap<ConstantMap> constantPools; |
47 private final LongMap<ConstantLookup> constantLookups; |
48 |
48 |
49 public ParserFactory(MetadataDescriptor metadata, TimeConverter timeConverter) throws IOException { |
49 public ParserFactory(MetadataDescriptor metadata, LongMap<ConstantLookup> constantLookups, TimeConverter timeConverter) throws IOException { |
50 this.constantPools = new LongMap<>(); |
50 this.constantLookups = constantLookups; |
51 this.timeConverter = timeConverter; |
51 this.timeConverter = timeConverter; |
52 for (Type t : metadata.getTypes()) { |
52 for (Type t : metadata.getTypes()) { |
53 types.put(t.getId(), t); |
53 types.put(t.getId(), t); |
54 } |
54 } |
55 for (Type t : types) { |
55 List<Type> typeList = new ArrayList<>(); |
|
56 types.forEach(typeList::add); |
|
57 for (Type t : typeList) { |
56 if (!t.getFields().isEmpty()) { // Avoid primitives |
58 if (!t.getFields().isEmpty()) { // Avoid primitives |
57 CompositeParser cp = createCompositeParser(t); |
59 CompositeParser cp = createCompositeParser(t, false); |
58 if (t.isSimpleType()) { // Reduce to nested parser |
60 if (t.isSimpleType()) { // Reduce to nested parser |
59 parsers.put(t.getId(), cp.parsers[0]); |
61 parsers.put(t.getId(), cp.parsers[0]); |
60 } |
62 } |
61 |
63 |
62 } |
64 } |
63 } |
65 } |
64 // Override event types with event parsers |
66 // Override event types with event parsers |
69 |
71 |
70 public LongMap<Parser> getParsers() { |
72 public LongMap<Parser> getParsers() { |
71 return parsers; |
73 return parsers; |
72 } |
74 } |
73 |
75 |
74 public LongMap<ConstantMap> getConstantPools() { |
|
75 return constantPools; |
|
76 } |
|
77 |
|
78 public LongMap<Type> getTypeMap() { |
76 public LongMap<Type> getTypeMap() { |
79 return types; |
77 return types; |
80 } |
78 } |
81 |
79 |
82 private EventParser createEventParser(EventType eventType) throws IOException { |
80 private EventParser createEventParser(EventType eventType) throws IOException { |
83 List<Parser> parsers = new ArrayList<Parser>(); |
81 List<Parser> parsers = new ArrayList<Parser>(); |
84 for (ValueDescriptor f : eventType.getFields()) { |
82 for (ValueDescriptor f : eventType.getFields()) { |
85 parsers.add(createParser(f)); |
83 parsers.add(createParser(f, true)); |
86 } |
84 } |
87 return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0])); |
85 return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0])); |
88 } |
86 } |
89 |
87 |
90 private Parser createParser(ValueDescriptor v) throws IOException { |
88 private Parser createParser(ValueDescriptor v, boolean event) throws IOException { |
91 boolean constantPool = PrivateAccess.getInstance().isConstantPool(v); |
89 boolean constantPool = PrivateAccess.getInstance().isConstantPool(v); |
92 if (v.isArray()) { |
90 if (v.isArray()) { |
93 Type valueType = PrivateAccess.getInstance().getType(v); |
91 Type valueType = PrivateAccess.getInstance().getType(v); |
94 ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null); |
92 ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null); |
95 return new ArrayParser(createParser(element)); |
93 return new ArrayParser(createParser(element, event)); |
96 } |
94 } |
97 long id = v.getTypeId(); |
95 long id = v.getTypeId(); |
98 Type type = types.get(id); |
96 Type type = types.get(id); |
99 if (type == null) { |
97 if (type == null) { |
100 throw new IOException("Type '" + v.getTypeName() + "' is not defined"); |
98 throw new IOException("Type '" + v.getTypeName() + "' is not defined"); |
101 } |
99 } |
102 if (constantPool) { |
100 if (constantPool) { |
103 ConstantMap pool = constantPools.get(id); |
101 ConstantLookup lookup = constantLookups.get(id); |
104 if (pool == null) { |
102 if (lookup == null) { |
105 pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName()); |
103 ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName()); |
106 constantPools.put(id, pool); |
104 lookup = new ConstantLookup(pool, type); |
107 } |
105 constantLookups.put(id, lookup); |
108 return new ConstantMapValueParser(pool); |
106 } |
|
107 if (event) { |
|
108 return new EventValueConstantParser(lookup); |
|
109 } |
|
110 return new ConstantValueParser(lookup); |
109 } |
111 } |
110 Parser parser = parsers.get(id); |
112 Parser parser = parsers.get(id); |
111 if (parser == null) { |
113 if (parser == null) { |
112 if (!v.getFields().isEmpty()) { |
114 if (!v.getFields().isEmpty()) { |
113 return createCompositeParser(type); |
115 return createCompositeParser(type, event); |
114 } else { |
116 } else { |
115 return registerParserType(type, createPrimitiveParser(type)); |
117 return registerParserType(type, createPrimitiveParser(type, constantPool)); |
116 } |
118 } |
117 } |
119 } |
118 return parser; |
120 return parser; |
119 } |
121 } |
120 |
122 |
121 private Parser createPrimitiveParser(Type type) throws IOException { |
123 private Parser createPrimitiveParser(Type type, boolean event) throws IOException { |
122 switch (type.getName()) { |
124 switch (type.getName()) { |
123 case "int": |
125 case "int": |
124 return new IntegerParser(); |
126 return new IntegerParser(); |
125 case "long": |
127 case "long": |
126 return new LongParser(); |
128 return new LongParser(); |
153 } |
156 } |
154 parsers.put(t.getId(), parser); |
157 parsers.put(t.getId(), parser); |
155 return parser; |
158 return parser; |
156 } |
159 } |
157 |
160 |
158 private CompositeParser createCompositeParser(Type type) throws IOException { |
161 private CompositeParser createCompositeParser(Type type, boolean event) throws IOException { |
159 List<ValueDescriptor> vds = type.getFields(); |
162 List<ValueDescriptor> vds = type.getFields(); |
160 Parser[] parsers = new Parser[vds.size()]; |
163 Parser[] parsers = new Parser[vds.size()]; |
161 CompositeParser composite = new CompositeParser(parsers); |
164 CompositeParser composite = new CompositeParser(parsers); |
162 // need to pre-register so recursive types can be handled |
165 // need to pre-register so recursive types can be handled |
163 registerParserType(type, composite); |
166 registerParserType(type, composite); |
164 |
167 |
165 int index = 0; |
168 int index = 0; |
166 for (ValueDescriptor vd : vds) { |
169 for (ValueDescriptor vd : vds) { |
167 parsers[index++] = createParser(vd); |
170 parsers[index++] = createParser(vd, event); |
168 } |
171 } |
169 return composite; |
172 return composite; |
170 } |
173 } |
171 |
174 |
172 private static final class BooleanParser extends Parser { |
175 private static final class BooleanParser extends Parser { |
173 @Override |
176 @Override |
174 public Object parse(RecordingInput input) throws IOException { |
177 public Object parse(RecordingInput input) throws IOException { |
175 return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE; |
178 return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE; |
176 } |
179 } |
|
180 |
|
181 @Override |
|
182 public void skip(RecordingInput input) throws IOException { |
|
183 input.skipBytes(1); |
|
184 } |
177 } |
185 } |
178 |
186 |
179 private static final class ByteParser extends Parser { |
187 private static final class ByteParser extends Parser { |
180 @Override |
188 @Override |
181 public Object parse(RecordingInput input) throws IOException { |
189 public Object parse(RecordingInput input) throws IOException { |
182 return Byte.valueOf(input.readByte()); |
190 return Byte.valueOf(input.readByte()); |
183 } |
191 } |
|
192 |
|
193 @Override |
|
194 public void skip(RecordingInput input) throws IOException { |
|
195 input.skipBytes(1); |
|
196 } |
184 } |
197 } |
185 |
198 |
186 private static final class LongParser extends Parser { |
199 private static final class LongParser extends Parser { |
187 @Override |
200 private Object lastLongObject = Long.valueOf(0); |
188 public Object parse(RecordingInput input) throws IOException { |
201 private long last = 0; |
189 return Long.valueOf(input.readLong()); |
202 |
|
203 @Override |
|
204 public Object parse(RecordingInput input) throws IOException { |
|
205 long l = input.readLong(); |
|
206 if (l != last) { |
|
207 last = l; |
|
208 lastLongObject = Long.valueOf(l); |
|
209 } |
|
210 return lastLongObject; |
|
211 } |
|
212 |
|
213 @Override |
|
214 public void skip(RecordingInput input) throws IOException { |
|
215 input.readLong(); |
190 } |
216 } |
191 } |
217 } |
192 |
218 |
193 private static final class IntegerParser extends Parser { |
219 private static final class IntegerParser extends Parser { |
194 @Override |
220 private Integer lastIntegergObject = Integer.valueOf(0); |
195 public Object parse(RecordingInput input) throws IOException { |
221 private int last = 0; |
196 return Integer.valueOf(input.readInt()); |
222 |
|
223 @Override |
|
224 public Object parse(RecordingInput input) throws IOException { |
|
225 int i = input.readInt(); |
|
226 if (i != last) { |
|
227 last = i; |
|
228 lastIntegergObject = Integer.valueOf(i); |
|
229 } |
|
230 return lastIntegergObject; |
|
231 } |
|
232 |
|
233 @Override |
|
234 public void skip(RecordingInput input) throws IOException { |
|
235 input.readInt(); |
197 } |
236 } |
198 } |
237 } |
199 |
238 |
200 private static final class ShortParser extends Parser { |
239 private static final class ShortParser extends Parser { |
201 @Override |
240 @Override |
202 public Object parse(RecordingInput input) throws IOException { |
241 public Object parse(RecordingInput input) throws IOException { |
203 return Short.valueOf(input.readShort()); |
242 return Short.valueOf(input.readShort()); |
204 } |
243 } |
|
244 |
|
245 @Override |
|
246 public void skip(RecordingInput input) throws IOException { |
|
247 input.readShort(); |
|
248 } |
205 } |
249 } |
206 |
250 |
207 private static final class CharacterParser extends Parser { |
251 private static final class CharacterParser extends Parser { |
208 @Override |
252 @Override |
209 public Object parse(RecordingInput input) throws IOException { |
253 public Object parse(RecordingInput input) throws IOException { |
210 return Character.valueOf(input.readChar()); |
254 return Character.valueOf(input.readChar()); |
211 } |
255 } |
|
256 |
|
257 @Override |
|
258 public void skip(RecordingInput input) throws IOException { |
|
259 input.readChar(); |
|
260 } |
212 } |
261 } |
213 |
262 |
214 private static final class FloatParser extends Parser { |
263 private static final class FloatParser extends Parser { |
215 @Override |
264 @Override |
216 public Object parse(RecordingInput input) throws IOException { |
265 public Object parse(RecordingInput input) throws IOException { |
217 return Float.valueOf(input.readFloat()); |
266 return Float.valueOf(input.readFloat()); |
218 } |
267 } |
|
268 |
|
269 @Override |
|
270 public void skip(RecordingInput input) throws IOException { |
|
271 input.skipBytes(Float.SIZE); |
|
272 } |
219 } |
273 } |
220 |
274 |
221 private static final class DoubleParser extends Parser { |
275 private static final class DoubleParser extends Parser { |
222 @Override |
276 @Override |
223 public Object parse(RecordingInput input) throws IOException { |
277 public Object parse(RecordingInput input) throws IOException { |
224 return Double.valueOf(input.readDouble()); |
278 return Double.valueOf(input.readDouble()); |
225 } |
279 } |
226 } |
280 |
227 |
281 @Override |
228 private static final class StringParser extends Parser { |
282 public void skip(RecordingInput input) throws IOException { |
229 private final ConstantMap stringConstantMap; |
283 input.skipBytes(Double.SIZE); |
230 private String last; |
|
231 |
|
232 StringParser(ConstantMap stringConstantMap) { |
|
233 this.stringConstantMap = stringConstantMap; |
|
234 } |
|
235 |
|
236 @Override |
|
237 public Object parse(RecordingInput input) throws IOException { |
|
238 String s = parseEncodedString(input); |
|
239 if (!Objects.equals(s, last)) { |
|
240 last = s; |
|
241 } |
|
242 return last; |
|
243 } |
|
244 |
|
245 private String parseEncodedString(RecordingInput input) throws IOException { |
|
246 byte encoding = input.readByte(); |
|
247 if (encoding == RecordingInput.STRING_ENCODING_CONSTANT_POOL) { |
|
248 long id = input.readLong(); |
|
249 return (String) stringConstantMap.get(id); |
|
250 } else { |
|
251 return input.readEncodedString(encoding); |
|
252 } |
|
253 } |
284 } |
254 } |
285 } |
255 |
286 |
256 private final static class ArrayParser extends Parser { |
287 private final static class ArrayParser extends Parser { |
257 private final Parser elementParser; |
288 private final Parser elementParser; |
284 for (int i = 0; i < values.length; i++) { |
323 for (int i = 0; i < values.length; i++) { |
285 values[i] = parsers[i].parse(input); |
324 values[i] = parsers[i].parse(input); |
286 } |
325 } |
287 return values; |
326 return values; |
288 } |
327 } |
289 } |
328 |
290 |
329 @Override |
291 private static final class ConstantMapValueParser extends Parser { |
330 public void skip(RecordingInput input) throws IOException { |
292 private final ConstantMap pool; |
331 for (int i = 0; i < parsers.length; i++) { |
293 |
332 parsers[i].skip(input); |
294 ConstantMapValueParser(ConstantMap pool) { |
333 } |
295 this.pool = pool; |
334 } |
296 } |
335 } |
297 |
336 |
298 @Override |
337 public static final class EventValueConstantParser extends Parser { |
299 public Object parse(RecordingInput input) throws IOException { |
338 private final ConstantLookup lookup; |
300 return pool.get(input.readLong()); |
339 private Object lastValue = 0; |
|
340 private long lastKey = -1; |
|
341 EventValueConstantParser(ConstantLookup lookup) { |
|
342 this.lookup = lookup; |
|
343 } |
|
344 |
|
345 @Override |
|
346 public Object parse(RecordingInput input) throws IOException { |
|
347 long key = input.readLong(); |
|
348 if (key == lastKey) { |
|
349 return lastValue; |
|
350 } |
|
351 lastKey = key; |
|
352 lastValue = lookup.getCurrentResolved(key); |
|
353 return lastValue; |
|
354 } |
|
355 |
|
356 @Override |
|
357 public void skip(RecordingInput input) throws IOException { |
|
358 input.readLong(); |
|
359 } |
|
360 } |
|
361 |
|
362 public static final class ConstantValueParser extends Parser { |
|
363 private final ConstantLookup lookup; |
|
364 ConstantValueParser(ConstantLookup lookup) { |
|
365 this.lookup = lookup; |
|
366 } |
|
367 |
|
368 @Override |
|
369 public Object parse(RecordingInput input) throws IOException { |
|
370 return lookup.getCurrent(input.readLong()); |
|
371 } |
|
372 |
|
373 @Override |
|
374 public void skip(RecordingInput input) throws IOException { |
|
375 input.readLong(); |
301 } |
376 } |
302 } |
377 } |
303 } |
378 } |