diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 0b25b1bb137b2..350d47435ad2c 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1354,11 +1354,29 @@ bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeShare return info->is_excluded(); } +// Check if a class or any of its supertypes has been redefined. +bool SystemDictionaryShared::has_been_redefined(InstanceKlass* k) { + if (k->has_been_redefined()) { + return true; + } + if (k->java_super() != NULL && has_been_redefined(k->java_super())) { + return true; + } + Array* interfaces = k->local_interfaces(); + int len = interfaces->length(); + for (int i = 0; i < len; i++) { + if (has_been_redefined(interfaces->at(i))) { + return true; + } + } + return false; +} + bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { if (k->is_in_error_state()) { return warn_excluded(k, "In error state"); } - if (k->has_been_redefined()) { + if (has_been_redefined(k)) { return warn_excluded(k, "Has been redefined"); } if (!k->is_hidden() && k->shared_classpath_index() < 0 && is_builtin(k)) { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 227d69304cfab..ff369b2546a2f 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -215,6 +215,7 @@ class SystemDictionaryShared: public SystemDictionary { static bool is_registered_lambda_proxy_class(InstanceKlass* ik); static bool warn_excluded(InstanceKlass* k, const char* reason); static bool check_for_exclusion_impl(InstanceKlass* k); + static bool has_been_redefined(InstanceKlass* k); static bool _dump_in_progress; DEBUG_ONLY(static bool _no_class_loading_should_happen;) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/JFRDynamicCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/JFRDynamicCDS.java new file mode 100644 index 0000000000000..354401cf49494 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/JFRDynamicCDS.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021, 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. + * + * 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. + * + */ + +/* + * @test + * @bug 8268470 + * @summary Test dynamic CDS with JFR recording. + * Dynamic dump should skip the class such as jdk/jfr/events/FileReadEvent + * if one of its super classes has been redefined during JFR startup. + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes + * @build JFRDynamicCDSApp sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar jfr_dynamic_cds_app.jar JFRDynamicCDSApp JFRDynamicCDSApp$StressEvent + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. JFRDynamicCDS + */ + +import jdk.test.lib.helpers.ClassFileInstaller; + +public class JFRDynamicCDS extends DynamicArchiveTestBase { + public static void main(String[] args) throws Exception { + runTest(JFRDynamicCDS::test); + } + + static void test() throws Exception { + String topArchiveName = getNewArchiveName(); + String appJar = ClassFileInstaller.getJarPath("jfr_dynamic_cds_app.jar"); + String mainClass = "JFRDynamicCDSApp"; + // 0 : without JFR recording + // 4 : with JFR recording + int[] modes = {0, 4}; + + for (int mode : modes) { + dump(topArchiveName, + "-Xlog:class+load,cds=debug", + "-cp", appJar, mainClass, String.valueOf(mode)) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0); + if (mode == 4) { + output.shouldMatch("Skipping.jdk/jfr/events.*Has.been.redefined"); + } + }); + + run(topArchiveName, + "-Xlog:class+load=info", + "-cp", appJar, mainClass, String.valueOf(mode)) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain("[class,load] JFRDynamicCDSApp source: shared objects file (top)"); + if (mode == 4) { + output.shouldMatch(".class.load. jdk.jfr.events.*source:.*jrt:/jdk.jfr"); + } + }); + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/JFRDynamicCDSApp.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/JFRDynamicCDSApp.java new file mode 100644 index 0000000000000..95a76663e07ca --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/JFRDynamicCDSApp.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021, 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. + * + * 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. + * + */ +import java.nio.file.Paths; +import jdk.jfr.Configuration; +import jdk.jfr.Description; +import jdk.jfr.Label; +import jdk.jfr.Name; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingStream; + +public class JFRDynamicCDSApp { + public static void main(String args[]) throws Exception { + int mode = 4; + try { + mode = Integer.parseInt(args[0]); + } catch (Throwable t) {} + + if (mode > 0) { + RecordingStream rs = new RecordingStream(); + if (mode > 1) { + rs.enable("JFRDynamicCDS.StressEvent"); + rs.startAsync(); + + if (mode > 2) { + Recording recording = startRecording(); + if (mode > 3) { + loop(); + } + recording.stop(); + recording.close(); + } + } + + rs.close(); + } + } + + static Recording startRecording() throws Exception { + Configuration configuration = Configuration.getConfiguration("default"); + Recording recording = new Recording(configuration); + + recording.setName("internal"); + recording.enable(StressEvent.class); + recording.setDestination(Paths.get("JFRDynamicCDS.jfr")); + recording.start(); + return recording; + } + + + static void loop() { + for (int i=0; i<100; i++) { + StressEvent event = new StressEvent(); + event.iteration = i; + event.description = "Stressful Event, take it easy!"; + event.customClazz = StressEvent.class; + event.value = i; + event.commit(); + } + } + + + /** + * Internal StressEvent class. + */ + @Label("Stress Event") + @Description("A duration event with 4 entries") + @Name("JFRDynamicCDS.StressEvent") + public static class StressEvent extends jdk.jfr.Event { + public Class customClazz; + public String description; + public int iteration; + public double value; + } +}