+{"files":[{"patch":"@@ -27,1 +27,1 @@\n-#include \"cds\/dumpTimeClassInfo.hpp\"\n+#include \"cds\/dumpTimeClassInfo.inline.hpp\"\n","filename":"src\/hotspot\/share\/cds\/dumpTimeClassInfo.cpp","additions":1,"deletions":1,"binary":false,"changes":2,"status":"modified"},{"patch":"@@ -171,1 +171,1 @@\n-class DumpTimeSharedClassTable: public ResourceHashtable<\n+using DumpTimeSharedClassTableBaseType = ResourceHashtable<\n@@ -177,1 +177,3 @@\n- &DumpTimeSharedClassTable_hash>\n+ &DumpTimeSharedClassTable_hash>;\n+\n+class DumpTimeSharedClassTable: public DumpTimeSharedClassTableBaseType\n@@ -197,0 +199,5 @@\n+\n+ \/\/ Overrides ResourceHashtable<>::iterate(ITER*)\n+ template<class ITER> void iterate(ITER* iter) const;\n+private:\n+ template<class ITER> class IterationHelper;\n","filename":"src\/hotspot\/share\/cds\/dumpTimeClassInfo.hpp","additions":9,"deletions":2,"binary":false,"changes":11,"status":"modified"},{"patch":"@@ -0,0 +1,74 @@\n+\n+\/*\n+ * Copyright (c) 2021, Oracle and\/or its affiliates. All rights reserved.\n+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n+ *\n+ * This code is free software; you can redistribute it and\/or modify it\n+ * under the terms of the GNU General Public License version 2 only, as\n+ * published by the Free Software Foundation.\n+ *\n+ * This code is distributed in the hope that it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n+ * version 2 for more details (a copy is included in the LICENSE file that\n+ * accompanied this code).\n+ *\n+ * You should have received a copy of the GNU General Public License version\n+ * 2 along with this work; if not, write to the Free Software Foundation,\n+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n+ *\n+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n+ * or visit www.oracle.com if you need additional information or have any\n+ * questions.\n+ *\n+ *\/\n+\n+#ifndef SHARED_CDS_DUMPTIMESHAREDCLASSINFO_INLINE_HPP\n+#define SHARED_CDS_DUMPTIMESHAREDCLASSINFO_INLINE_HPP\n+\n+#include \"cds\/dumpTimeClassInfo.hpp\"\n+#include \"classfile\/systemDictionaryShared.hpp\"\n+#include \"classfile\/classLoaderData.inline.hpp\"\n+#include \"oops\/instanceKlass.hpp\"\n+#include \"oops\/klass.inline.hpp\"\n+#include \"runtime\/safepoint.hpp\"\n+\n+#if INCLUDE_CDS\n+\n+\/\/ For safety, only iterate over a class if it loader is alive.\n+\/\/ IterationHelper and DumpTimeSharedClassTable::iterate\n+\/\/ must be used only inside a safepoint, where the value of\n+\/\/ k->is_loader_alive() will not change.\n+template<class ITER>\n+class DumpTimeSharedClassTable::IterationHelper {\n+ ITER* _iter;\n+public:\n+ IterationHelper(ITER* iter) {\n+ _iter = iter;\n+ }\n+ bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {\n+ assert(SafepointSynchronize::is_at_safepoint(), \"invariant\");\n+ assert_lock_strong(DumpTimeTable_lock);\n+ if (k->is_loader_alive()) {\n+ bool result = _iter->do_entry(k, info);\n+ assert(k->is_loader_alive(), \"must not change\");\n+ return result;\n+ } else {\n+ if (!SystemDictionaryShared::is_excluded_class(k)) {\n+ SystemDictionaryShared::warn_excluded(k, \"Class loader not alive\");\n+ SystemDictionaryShared::set_excluded_locked(k);\n+ }\n+ return true;\n+ }\n+ }\n+};\n+\n+template<class ITER>\n+void DumpTimeSharedClassTable::iterate(ITER* iter) const {\n+ IterationHelper<ITER> helper(iter);\n+ DumpTimeSharedClassTableBaseType::iterate(&helper);\n+}\n+\n+#endif \/\/ INCLUDE_CDS\n+\n+#endif \/\/ SHARED_CDS_DUMPTIMESHAREDCLASSINFO_INLINE_HPP\n","filename":"src\/hotspot\/share\/cds\/dumpTimeClassInfo.inline.hpp","additions":74,"deletions":0,"binary":false,"changes":74,"status":"added"},{"patch":"@@ -118,0 +118,6 @@\n+ if (SystemDictionaryShared::is_dumptime_table_empty()) {\n+ log_warning(cds, dynamic)(\"There is no class to be included in the dynamic archive.\");\n+ SystemDictionaryShared::stop_dumping();\n+ return;\n+ }\n+\n@@ -174,0 +180,1 @@\n+ SystemDictionaryShared::stop_dumping();\n@@ -345,4 +352,0 @@\n- if (SystemDictionaryShared::is_dumptime_table_empty()) {\n- log_warning(cds, dynamic)(\"There is no class to be included in the dynamic archive.\");\n- return;\n- }\n","filename":"src\/hotspot\/share\/cds\/dynamicArchive.cpp","additions":7,"deletions":4,"binary":false,"changes":11,"status":"modified"},{"patch":"@@ -34,1 +34,1 @@\n-#include \"cds\/dumpTimeClassInfo.hpp\"\n+#include \"cds\/dumpTimeClassInfo.inline.hpp\"\n@@ -190,0 +190,5 @@\n+void SystemDictionaryShared::stop_dumping() {\n+ assert_lock_strong(DumpTimeTable_lock);\n+ _dump_in_progress = false;\n+}\n+\n@@ -1531,0 +1536,1 @@\n+ assert_lock_strong(DumpTimeTable_lock);\n","filename":"src\/hotspot\/share\/classfile\/systemDictionaryShared.cpp","additions":7,"deletions":1,"binary":false,"changes":8,"status":"modified"},{"patch":"@@ -303,0 +303,1 @@\n+ static void stop_dumping() NOT_CDS_RETURN;\n","filename":"src\/hotspot\/share\/classfile\/systemDictionaryShared.hpp","additions":1,"deletions":0,"binary":false,"changes":1,"status":"modified"},{"patch":"@@ -0,0 +1,82 @@\n+\/*\n+ * Copyright (c) 2021, Oracle and\/or its affiliates. All rights reserved.\n+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n+ *\n+ * This code is free software; you can redistribute it and\/or modify it\n+ * under the terms of the GNU General Public License version 2 only, as\n+ * published by the Free Software Foundation.\n+ *\n+ * This code is distributed in the hope that it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n+ * version 2 for more details (a copy is included in the LICENSE file that\n+ * accompanied this code).\n+ *\n+ * You should have received a copy of the GNU General Public License version\n+ * 2 along with this work; if not, write to the Free Software Foundation,\n+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n+ *\n+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n+ * or visit www.oracle.com if you need additional information or have any\n+ * questions.\n+ *\n+ *\/\n+\n+\/*\n+ * @test\n+ * @bug 8278602\n+ * @summary Lots of classes being unloaded while we try to dump a dynamic archive\n+ * @requires vm.cds\n+ * @library \/test\/lib \/test\/hotspot\/jtreg\/runtime\/cds\/appcds\n+ * \/test\/hotspot\/jtreg\/runtime\/cds\/appcds\/dynamicArchive\/test-classes\n+ * @build sun.hotspot.WhiteBox\n+ * @build LotsUnloadApp\n+ * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox\n+ * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar LotsUnloadApp.jar LotsUnloadApp DefinedAsHiddenKlass\n+ * @run main\/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath\/a:. LotsUnloadTest\n+ *\/\n+\n+\/\/ Note: for https:\/\/bugs.openjdk.java.net\/browse\/JDK-8278602, this test case does NOT\n+\/\/ reliably reproduce the problem. Reproduction requires patching ZGC. Please see\n+\/\/ the bug report for instructions.\n+\/\/\n+\/\/ This test case is included so that it may find a similar bug under stress conditions\n+\/\/ in the CI runs.\n+import jdk.test.lib.helpers.ClassFileInstaller;\n+\n+public class LotsUnloadTest extends DynamicArchiveTestBase {\n+ public static void main(String[] args) throws Exception {\n+ runTest(LotsUnloadTest::test);\n+ }\n+\n+ static void test() throws Exception {\n+ String topArchiveName = getNewArchiveName();\n+ String appJar = ClassFileInstaller.getJarPath(\"LotsUnloadApp.jar\");\n+ String mainClass = \"LotsUnloadApp\";\n+ String logging;\n+\n+ if (Boolean.getBoolean(\"verbose.LotsUnloadTest\")) {\n+ \/\/ class+unload logs may change GC timing and cause the bug to be\n+ \/\/ less reproducible.\n+ logging = \"-Xlog:cds,class+unload\";\n+ } else {\n+ logging = \"-Xlog:cds\";\n+ }\n+\n+ dump(topArchiveName,\n+ logging,\n+ \"-Xmx64m\", \"-Xms32m\",\n+ \"-cp\", appJar, mainClass)\n+ .assertNormalExit(output -> {\n+ output.shouldHaveExitValue(0);\n+ });\n+\n+ run(topArchiveName,\n+ logging,\n+ \"-Xmx64m\", \"-Xms32m\",\n+ \"-cp\", appJar, mainClass)\n+ .assertNormalExit(output -> {\n+ output.shouldHaveExitValue(0);\n+ });\n+ }\n+}\n","filename":"test\/hotspot\/jtreg\/runtime\/cds\/appcds\/dynamicArchive\/LotsUnloadTest.java","additions":82,"deletions":0,"binary":false,"changes":82,"status":"added"},{"patch":"@@ -0,0 +1,84 @@\n+\/*\n+ * Copyright (c) 2021, Oracle and\/or its affiliates. All rights reserved.\n+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n+ *\n+ * This code is free software; you can redistribute it and\/or modify it\n+ * under the terms of the GNU General Public License version 2 only, as\n+ * published by the Free Software Foundation.\n+ *\n+ * This code is distributed in the hope that it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n+ * version 2 for more details (a copy is included in the LICENSE file that\n+ * accompanied this code).\n+ *\n+ * You should have received a copy of the GNU General Public License version\n+ * 2 along with this work; if not, write to the Free Software Foundation,\n+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n+ *\n+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n+ * or visit www.oracle.com if you need additional information or have any\n+ * questions.\n+ *\n+ *\/\n+\n+import java.lang.invoke.MethodType;\n+import java.lang.invoke.MethodHandles;\n+import java.lang.invoke.MethodHandles.Lookup;\n+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;\n+\n+public class LotsUnloadApp implements Runnable {\n+ static byte[] classdata;\n+ static int exitAfterNumClasses = 1024;\n+\n+ public static void main(String args[]) throws Throwable {\n+ String resname = DefinedAsHiddenKlass.class.getName() + \".class\";\n+ classdata = LotsUnloadApp.class.getClassLoader().getResourceAsStream(resname).readAllBytes();\n+\n+ int numThreads = 4;\n+ try {\n+ numThreads = Integer.parseInt(args[0]);\n+ } catch (Throwable t) {}\n+\n+ try {\n+ exitAfterNumClasses = Integer.parseInt(args[1]);\n+ } catch (Throwable t) {}\n+\n+ for (int i = 0; i < numThreads; i++) {\n+ Thread t = new Thread(new LotsUnloadApp());\n+ t.start();\n+ }\n+ }\n+\n+ public void run() {\n+ while (true) {\n+ try {\n+ Lookup lookup = MethodHandles.lookup();\n+ Class<?> cl = lookup.defineHiddenClass(classdata, false, NESTMATE).lookupClass();\n+ cl.newInstance();\n+ add();\n+ } catch (Throwable t) {\n+ t.printStackTrace();\n+ }\n+ }\n+ }\n+\n+ static int n;\n+ static synchronized void add() {\n+ n++;\n+ if (n >= exitAfterNumClasses) {\n+ System.exit(0);\n+ }\n+ }\n+}\n+\n+class DefinedAsHiddenKlass {\n+ \/\/ ZGC region size is always a multiple of 2MB on x64.\n+ \/\/ Make this slightly smaller than that.\n+ static byte[] array = new byte[2 * 1024 * 1024 - 8 * 1024];\n+ static String x;\n+ public DefinedAsHiddenKlass() {\n+ \/\/ This will generate some lambda forms hidden classes for string concat.\n+ x = \"array size is \" + array.length + \" bytes \";\n+ }\n+}\n","filename":"test\/hotspot\/jtreg\/runtime\/cds\/appcds\/dynamicArchive\/test-classes\/LotsUnloadApp.java","additions":84,"deletions":0,"binary":false,"changes":84,"status":"added"}]}
0 commit comments