From 278db0b944beb42b81aaf09df954399828e5f058 Mon Sep 17 00:00:00 2001 From: Larry Cable Date: Fri, 3 Oct 2025 13:24:58 -0700 Subject: [PATCH] JDK-8365400: add JFR event to capture location (if available) of class files loaded --- .../java/security/SecureClassLoader.java | 30 +++++++++---- .../internal/event/ClassFileDefineEvent.java | 35 +++++++++++++++ .../jdk/jfr/events/ClassFileDefineEvent.java | 45 +++++++++++++++++++ .../classes/jdk/jfr/internal/JDKEvents.java | 2 + .../jdk/jfr/internal/MirrorEvents.java | 2 + src/jdk.jfr/share/conf/jfr/default.jfc | 4 ++ 6 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/event/ClassFileDefineEvent.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/events/ClassFileDefineEvent.java diff --git a/src/java.base/share/classes/java/security/SecureClassLoader.java b/src/java.base/share/classes/java/security/SecureClassLoader.java index b398d7332d717..94791f30ed56d 100644 --- a/src/java.base/share/classes/java/security/SecureClassLoader.java +++ b/src/java.base/share/classes/java/security/SecureClassLoader.java @@ -30,6 +30,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import jdk.internal.event.ClassFileDefineEvent; + /** * This class extends {@code ClassLoader} with additional support for defining * classes with an associated code source and permissions. @@ -137,11 +139,16 @@ protected SecureClassLoader(String name, ClassLoader parent) { * a different set of certificates than this class, or if * the class name begins with "java.". */ - protected final Class defineClass(String name, - byte[] b, int off, int len, - CodeSource cs) - { - return defineClass(name, b, off, len, getProtectionDomain(cs)); + protected final Class defineClass(String name, byte[] b, int off, int len, CodeSource cs) { + final var cls = defineClass(name, b, off, len, getProtectionDomain(cs)); + + final var evt = new ClassFileDefineEvent(); + + evt.definedClass = cls; + evt.path = cs.getLocation().toExternalForm(); + evt.commit(); + + return cls; } /** @@ -170,10 +177,17 @@ protected final Class defineClass(String name, * * @since 1.5 */ - protected final Class defineClass(String name, java.nio.ByteBuffer b, - CodeSource cs) + protected final Class defineClass(String name, java.nio.ByteBuffer b, CodeSource cs) { - return defineClass(name, b, getProtectionDomain(cs)); + final var cls = defineClass(name, b, getProtectionDomain(cs)); + + final var evt = new ClassFileDefineEvent(); + + evt.definedClass = cls; + evt.path = cs.getLocation().toExternalForm(); + evt.commit(); + + return cls; } /** diff --git a/src/java.base/share/classes/jdk/internal/event/ClassFileDefineEvent.java b/src/java.base/share/classes/jdk/internal/event/ClassFileDefineEvent.java new file mode 100644 index 0000000000000..b83e7f5748c62 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/event/ClassFileDefineEvent.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +import java.net.URL; + +/** + * Event recording that a Class has been loaded and defined by a ClassLoader. + */ +public final class ClassFileDefineEvent extends Event { + public Class definedClass; + public String path; +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/ClassFileDefineEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/ClassFileDefineEvent.java new file mode 100644 index 0000000000000..d592edf9767c7 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ClassFileDefineEvent.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.events; + +import jdk.jfr.Category; +import jdk.jfr.Description; +import jdk.jfr.Label; +import jdk.jfr.Name; +import jdk.jfr.internal.MirrorEvent; +import jdk.jfr.internal.Type; + +@Category("Java Virtual Machine, Class Loading") +@Label("ClassFile Define") +@Name("jdk.ClassFileDefine") +public final class ClassFileDefineEvent extends MirrorEvent { + @Label("Defined Class Name") + public Class definedClass; + + @Label("Path") + @Description("The path/url location of the classfile loaded") + public String path; +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java index 503a7955e0022..d048fb95274cf 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java @@ -35,6 +35,7 @@ import jdk.jfr.Event; import jdk.jfr.events.ActiveRecordingEvent; import jdk.jfr.events.ActiveSettingEvent; +import jdk.jfr.events.ClassFileDefineEvent; import jdk.jfr.events.ContainerCPUThrottlingEvent; import jdk.jfr.events.ContainerCPUUsageEvent; import jdk.jfr.events.ContainerConfigurationEvent; @@ -56,6 +57,7 @@ public final class JDKEvents { ActiveRecordingEvent.class, // jdk.internal.event.* classes need their mirror // event class to be listed in the MirrorEvents class. + jdk.internal.event.ClassFileDefineEvent.class, jdk.internal.event.DeserializationEvent.class, jdk.internal.event.ErrorThrownEvent.class, jdk.internal.event.ExceptionStatisticsEvent.class, 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 48dc0d22cea3a..4a6bd2713d1a8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import jdk.jfr.events.ClassFileDefineEvent; import jdk.jfr.events.DeserializationEvent; import jdk.jfr.events.ErrorThrownEvent; import jdk.jfr.events.ExceptionStatisticsEvent; @@ -57,6 +58,7 @@ final class MirrorEvents { // Add mirror event mapping here. See MirrorEvent class for details. static { + register("jdk.internal.event.ClassFileDefineEvent", ClassFileDefineEvent.class); register("jdk.internal.event.DeserializationEvent", DeserializationEvent.class); register("jdk.internal.event.FileForceEvent", FileForceEvent.class); register("jdk.internal.event.FileReadEvent", FileReadEvent.class); diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index eb3b8626722c0..113175ca24833 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -166,6 +166,10 @@ true + + false + + true true