diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java index 2eed7b918fd21..6d1d5cf793823 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java @@ -28,6 +28,7 @@ import jdk.jfr.internal.event.EventConfiguration; import jdk.jfr.internal.util.Bytecode; +import jdk.jfr.internal.util.Utils; /** * All upcalls from the JVM should go through this class. * @@ -59,7 +60,7 @@ final class JVMUpcalls { static byte[] onRetransform(long traceId, boolean dummy1, boolean dummy2, Class<?> clazz, byte[] oldBytes) throws Throwable { try { if (jdk.internal.event.Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) { - if (!JVMSupport.shouldInstrument(clazz.getClassLoader() == null, clazz.getName())) { + if (!JVMSupport.shouldInstrument(Utils.isJDKClass(clazz), clazz.getName())) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Skipping instrumentation for " + clazz.getName() + " since container support is missing"); return oldBytes; } @@ -70,9 +71,9 @@ static byte[] onRetransform(long traceId, boolean dummy1, boolean dummy2, Class< // Probably triggered by some other agent return oldBytes; } - boolean bootClassLoader = clazz.getClassLoader() == null; + boolean jdkClass = Utils.isJDKClass(clazz); Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform"); - EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId, bootClassLoader, false); + EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId, jdkClass, false); byte[] bytes = ei.buildInstrumented(); Bytecode.log(clazz.getName(), bytes); return bytes; 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 9a2bbfe4c6314..7031718cb284e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -204,7 +204,7 @@ private EventConfiguration makeConfiguration(Class<? extends jdk.internal.event. // 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) { + if (Utils.isJDKClass(eventClass)) { Name name = eventClass.getAnnotation(Name.class); if (name != null) { String n = name.value(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java index 35eadff40d129..e8a26fe425d14 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java @@ -48,6 +48,7 @@ import jdk.jfr.events.VirtualThreadSubmitFailedEvent; import jdk.jfr.events.X509CertificateEvent; import jdk.jfr.events.X509ValidationEvent; +import jdk.jfr.internal.util.Utils; /** * This class registers all mirror events. @@ -85,7 +86,7 @@ private static void register(String eventClassName, Class<? extends MirrorEvent> } static Class<? extends MirrorEvent> find(Class<? extends jdk.internal.event.Event> eventClass) { - return find(eventClass.getClassLoader() == null, eventClass.getName()); + return find(Utils.isJDKClass(eventClass), eventClass.getName()); } static Class<? extends MirrorEvent> find(boolean bootClassLoader, String name) { 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 cab6e7befe1aa..350bf55ccd4ee 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java @@ -166,7 +166,9 @@ public static synchronized AnnotationElement createAnnotation(Annotation annotat for (ValueDescriptor v : type.getFields()) { values.add(invokeAnnotation(annotation, v.getName())); } - return PrivateAccess.getInstance().newAnnotation(type, values, annotation.annotationType().getClassLoader() == null); + // Only annotation classes in the boot class loader can always be resolved. + boolean bootClassLoader = annotationType.getClassLoader() == null; + return PrivateAccess.getInstance().newAnnotation(type, values, bootClassLoader); } return null; } @@ -220,7 +222,7 @@ private static Type defineType(Class<?> clazz, String superType, boolean eventTy long id = Type.getTypeId(clazz); Type t; if (eventType) { - t = new PlatformEventType(typeName, id, clazz.getClassLoader() == null, true); + t = new PlatformEventType(typeName, id, Utils.isJDKClass(clazz), true); } else { t = new Type(typeName, superType, id); } @@ -283,7 +285,7 @@ public static synchronized Type createType(Class<?> clazz, List<AnnotationElemen } addAnnotations(clazz, type, dynamicAnnotations); - if (clazz.getClassLoader() == null) { + if (Utils.isJDKClass(clazz)) { type.log("Added", LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO); } else { type.log("Added", LogTag.JFR_METADATA, LogLevel.INFO); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/JDKEventTask.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/JDKEventTask.java index 73d4f5479eb04..a891b1c3775c1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/JDKEventTask.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/JDKEventTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -25,6 +25,7 @@ package jdk.jfr.internal.periodic; import jdk.internal.event.Event; +import jdk.jfr.internal.util.Utils; /** * Periodic task that runs trusted code that doesn't require an access control @@ -39,11 +40,11 @@ public JDKEventTask(Class<? extends Event> eventClass, Runnable runnable) { if (!getEventType().isJDK()) { throw new InternalError("Must be a JDK event"); } - if (eventClass.getClassLoader() != null) { - throw new SecurityException("Periodic task can only be registered for event classes that are loaded by the bootstrap class loader"); + if (!Utils.isJDKClass(eventClass)) { + throw new SecurityException("Periodic task can only be registered for event classes that belongs to the JDK"); } - if (runnable.getClass().getClassLoader() != null) { - throw new SecurityException("Runnable class must be loaded by the bootstrap class loader"); + if (!Utils.isJDKClass(runnable.getClass())) { + throw new SecurityException("Runnable class must belong to the JDK"); } } 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 53b3599f9d953..0049662e9a1f6 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 @@ -435,4 +435,12 @@ public static String format(String template, Map<String, String> parameters) { } return sb.toString(); } + + public static boolean isJDKClass(Class<?> type) { + return type.getClassLoader() == null; + // In the future we might want to also do: + // type.getClassLoader() == ClassLoader.getPlatformClassLoader(); + // but only if it is safe and there is a mechanism to register event + // classes in other modules besides jdk.jfr and java.base. + } }