From d29cefb6ebfd03638e1ca880ff20a0489e4e4fa5 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 29 Feb 2024 20:18:17 +0000 Subject: [PATCH] 8326838: JFR: Native mirror events Reviewed-by: mgronlun --- .../jdk/jfr/internal/MetadataRepository.java | 43 ++++++++++++++++--- .../share/classes/jdk/jfr/internal/Type.java | 6 ++- .../classes/jdk/jfr/internal/TypeLibrary.java | 4 +- .../classes/jdk/jfr/internal/util/Utils.java | 16 ++++++- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java index 4b54150e5bb..29267803009 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,12 +35,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import jdk.jfr.AnnotationElement; import jdk.jfr.Event; import jdk.jfr.EventType; +import jdk.jfr.Name; import jdk.jfr.Period; import jdk.jfr.StackTrace; import jdk.jfr.Threshold; @@ -54,8 +56,8 @@ public final class MetadataRepository { private static final MetadataRepository instance = new MetadataRepository(); - private final List nativeEventTypes = new ArrayList<>(150); - private final List nativeControls = new ArrayList(nativeEventTypes.size()); + private final Map nativeEventTypes = LinkedHashMap.newHashMap(150); + private final Map nativeControls = LinkedHashMap.newHashMap(150); private final SettingsManager settingsManager = new SettingsManager(); private Constructor cachedEventConfigurationConstructor; private boolean staleMetadata = true; @@ -83,8 +85,9 @@ public final class MetadataRepository { PeriodicEvents.addJVMEvent(pEventType); } } - nativeControls.add(new EventControl(pEventType)); - nativeEventTypes.add(eventType); + String name = eventType.getName(); + nativeControls.put(name, new EventControl(pEventType)); + nativeEventTypes.put(name,eventType); } } } @@ -101,7 +104,7 @@ public final class MetadataRepository { eventTypes.add(ec.getEventType()); } } - for (EventType t : nativeEventTypes) { + for (EventType t : nativeEventTypes.values()) { if (PrivateAccess.getInstance().isVisible(t)) { eventTypes.add(t); } @@ -200,6 +203,32 @@ public final class MetadataRepository { if (pEventType == null) { pEventType = (PlatformEventType) TypeLibrary.createType(eventClass, dynamicAnnotations, dynamicFields); } + // Check for native mirror. + // Note, defining an event in metadata.xml is not a generic mechanism to emit + // native data in Java. For example, calling JVM.getStackTraceId(int, long) + // and assign the result to a long field is not enough to always get a proper + // stack trace. Purpose of the mechanism is to transfer metadata, such as + // native type IDs, without specialized Java logic for each type. + if (eventClass.getClassLoader() == null) { + Name name = eventClass.getAnnotation(Name.class); + if (name != null) { + String n = name.value(); + EventType nativeType = nativeEventTypes.get(n); + if (nativeType != null) { + var nativeFields = nativeType.getFields(); + var eventFields = pEventType.getFields(); + var comparator = Comparator.comparing(ValueDescriptor::getName); + if (!Utils.compareLists(nativeFields, eventFields, comparator)) { + throw new InternalError("Field for native mirror event " + n + " doesn't match Java event"); + } + nativeEventTypes.remove(n); + nativeControls.remove(n); + TypeLibrary.removeType(nativeType.getId()); + pEventType.setAnnotations(nativeType.getAnnotationElements()); + pEventType.setFields(nativeType.getFields()); + } + } + } EventType eventType = PrivateAccess.getInstance().newEventType(pEventType); EventControl ec = new EventControl(pEventType, eventClass); EventConfiguration configuration = newEventConfiguration(eventType, ec); @@ -226,7 +255,7 @@ public final class MetadataRepository { public synchronized List getEventControls() { List> eventClasses = JVM.getAllEventClasses(); ArrayList controls = new ArrayList<>(eventClasses.size() + nativeControls.size()); - controls.addAll(nativeControls); + controls.addAll(nativeControls.values()); for (Class clazz : eventClasses) { EventConfiguration eh = JVMSupport.getConfiguration(clazz); if (eh != null) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java index 277b28505e6..bc949b8c7ff 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -222,6 +222,10 @@ public class Type implements Comparable { return id < JVM.RESERVED_CLASS_ID_LIMIT; } + public void setFields(List fields) { + this.fields = List.copyOf(fields); + } + public void add(ValueDescriptor valueDescriptor) { Objects.requireNonNull(valueDescriptor); fields.add(valueDescriptor); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java index 4663ead6838..19c83b3dc1c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -322,7 +322,7 @@ public final class TypeLibrary { ValueDescriptor vd = dynamicFieldSet.get(field.getName()); if (vd != null) { if (!vd.getTypeName().equals(field.getType().getName())) { - throw new InternalError("Type expected to match for field " + vd.getName() + " expected " + field.getName() + " but got " + vd.getName()); + throw new InternalError("Type expected to match for field " + vd.getName() + " expected " + field.getType().getName() + " but got " + vd.getTypeName()); } for (AnnotationElement ae : vd.getAnnotationElements()) { newTypes.add(PrivateAccess.getInstance().getType(ae)); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java index 1b739712985..96a2de5b7b9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.nio.file.Path; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -176,6 +177,19 @@ public final class Utils { return map; } + public static boolean compareLists(List a, List b, Comparator c) { + int size = a.size(); + if (size != b.size()) { + return false; + } + for (int i = 0; i < size; i++) { + if (c.compare(a.get(i), b.get(i)) != 0) { + return false; + } + } + return true; + } + public static List sanitizeNullFreeList(List elements, Class clazz) { List sanitized = new ArrayList<>(elements.size()); for (T element : elements) {