8210094: Better loading of classloader classes
authorcoleenp
Mon, 10 Sep 2018 16:49:01 -0400
changeset 53322 8ba5b3c76857
parent 53321 2cdf4a989ee7
child 53323 bc9faf59936d
8210094: Better loading of classloader classes Reviewed-by: acorn, hseigel, ahgross, rhalade
src/hotspot/share/classfile/classFileParser.cpp
src/hotspot/share/classfile/classLoaderDataGraph.cpp
src/hotspot/share/classfile/dictionary.cpp
src/hotspot/share/classfile/dictionary.hpp
src/hotspot/share/classfile/systemDictionary.cpp
src/hotspot/share/classfile/verificationType.cpp
src/hotspot/share/classfile/verifier.cpp
src/hotspot/share/oops/constantPool.cpp
src/hotspot/share/prims/jvm.cpp
test/hotspot/jtreg/runtime/ClassUnload/ConstantPoolDependsTest.java
test/hotspot/jtreg/runtime/ClassUnload/DictionaryDependsTest.java
test/hotspot/jtreg/runtime/ClassUnload/MyDiffClassLoader.java
test/hotspot/jtreg/runtime/ClassUnload/SuperDependsTest.java
test/hotspot/jtreg/runtime/ClassUnload/p2/c2.java
--- a/src/hotspot/share/classfile/classFileParser.cpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Mon Sep 10 16:49:01 2018 -0400
@@ -4484,33 +4484,6 @@
   }
 }
 
-// Attach super classes and interface classes to class loader data
-static void record_defined_class_dependencies(const InstanceKlass* defined_klass,
-                                              TRAPS) {
-  assert(defined_klass != NULL, "invariant");
-
-  ClassLoaderData* const defining_loader_data = defined_klass->class_loader_data();
-  if (defining_loader_data->is_the_null_class_loader_data()) {
-      // Dependencies to null class loader data are implicit.
-      return;
-  } else {
-    // add super class dependency
-    Klass* const super = defined_klass->super();
-    if (super != NULL) {
-      defining_loader_data->record_dependency(super);
-    }
-
-    // add super interface dependencies
-    const Array<InstanceKlass*>* const local_interfaces = defined_klass->local_interfaces();
-    if (local_interfaces != NULL) {
-      const int length = local_interfaces->length();
-      for (int i = 0; i < length; i++) {
-        defining_loader_data->record_dependency(local_interfaces->at(i));
-      }
-    }
-  }
-}
-
 // utility methods for appending an array with check for duplicates
 
 static void append_interfaces(GrowableArray<InstanceKlass*>* result,
@@ -5717,9 +5690,6 @@
     }
   }
 
-  // Update the loader_data graph.
-  record_defined_class_dependencies(ik, CHECK);
-
   ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
 
   if (!is_internal()) {
--- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp	Mon Sep 10 16:49:01 2018 -0400
@@ -561,11 +561,6 @@
 
   ClassLoaderData* data = _head;
   while (data != NULL) {
-    // Remove entries in the dictionary of live class loader that have
-    // initiated loading classes in a dead class loader.
-    if (data->dictionary() != NULL) {
-      data->dictionary()->do_unloading();
-    }
     // Walk a ModuleEntry's reads, and a PackageEntry's exports
     // lists to determine if there are modules on those lists that are now
     // dead and should be removed.  A module's life cycle is equivalent
--- a/src/hotspot/share/classfile/dictionary.cpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/classfile/dictionary.cpp	Mon Sep 10 16:49:01 2018 -0400
@@ -233,40 +233,6 @@
   }
 }
 
-
-void Dictionary::do_unloading() {
-  assert_locked_or_safepoint(SystemDictionary_lock);
-
-  // The NULL class loader doesn't initiate loading classes from other class loaders
-  if (loader_data() == ClassLoaderData::the_null_class_loader_data()) {
-    return;
-  }
-
-  // Remove unloaded entries and classes from this dictionary
-  DictionaryEntry* probe = NULL;
-  for (int index = 0; index < table_size(); index++) {
-    for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
-      probe = *p;
-      InstanceKlass* ik = probe->instance_klass();
-      ClassLoaderData* k_def_class_loader_data = ik->class_loader_data();
-
-      // If the klass that this loader initiated is dead,
-      // (determined by checking the defining class loader)
-      // remove this entry.
-      if (k_def_class_loader_data->is_unloading()) {
-        assert(k_def_class_loader_data != loader_data(),
-               "cannot have live defining loader and unreachable klass");
-        *p = probe->next();
-        free_entry(probe);
-        continue;
-      }
-      // Clean pd_set
-      clean_cached_protection_domains(probe);
-      p = probe->next_addr();
-    }
-  }
-}
-
 //   Just the classes from defining class loaders
 void Dictionary::classes_do(void f(InstanceKlass*)) {
   for (int index = 0; index < table_size(); index++) {
--- a/src/hotspot/share/classfile/dictionary.hpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/classfile/dictionary.hpp	Mon Sep 10 16:49:01 2018 -0400
@@ -74,9 +74,6 @@
 
   void unlink();
 
-  // Unload classes whose defining loaders are unloaded
-  void do_unloading();
-
   // Protection domains
   InstanceKlass* find(unsigned int hash, Symbol* name, Handle protection_domain);
   bool is_valid_protection_domain(unsigned int hash,
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Mon Sep 10 16:49:01 2018 -0400
@@ -861,8 +861,15 @@
         check_constraints(d_hash, k, class_loader, false, THREAD);
 
         // Need to check for a PENDING_EXCEPTION again; check_constraints
-        // can throw and doesn't use the CHECK macro.
+        // can throw but we may have to remove entry from the placeholder table below.
         if (!HAS_PENDING_EXCEPTION) {
+          // Record dependency for non-parent delegation.
+          // This recording keeps the defining class loader of the klass (k) found
+          // from being unloaded while the initiating class loader is loaded
+          // even if the reference to the defining class loader is dropped
+          // before references to the initiating class loader.
+          loader_data->record_dependency(k);
+
           { // Grabbing the Compile_lock prevents systemDictionary updates
             // during compilations.
             MutexLocker mu(Compile_lock, THREAD);
@@ -2177,6 +2184,7 @@
     InstanceKlass* sd_check = find_class(d_hash, name, dictionary);
     if (sd_check == NULL) {
       dictionary->add_klass(d_hash, name, k);
+
       notice_modification();
     }
   #ifdef ASSERT
--- a/src/hotspot/share/classfile/verificationType.cpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/classfile/verificationType.cpp	Mon Sep 10 16:49:01 2018 -0400
@@ -50,7 +50,6 @@
   Klass* this_class = SystemDictionary::resolve_or_fail(
       name, Handle(THREAD, klass->class_loader()),
       Handle(THREAD, klass->protection_domain()), true, CHECK_false);
-  klass->class_loader_data()->record_dependency(this_class);
   if (log_is_enabled(Debug, class, resolve)) {
     Verifier::trace_class_resolution(this_class, klass);
   }
@@ -68,7 +67,6 @@
     Klass* from_class = SystemDictionary::resolve_or_fail(
         from_name, Handle(THREAD, klass->class_loader()),
         Handle(THREAD, klass->protection_domain()), true, CHECK_false);
-    klass->class_loader_data()->record_dependency(from_class);
     if (log_is_enabled(Debug, class, resolve)) {
       Verifier::trace_class_resolution(from_class, klass);
     }
--- a/src/hotspot/share/classfile/verifier.cpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/classfile/verifier.cpp	Mon Sep 10 16:49:01 2018 -0400
@@ -2015,7 +2015,6 @@
     true, THREAD);
 
   if (kls != NULL) {
-    current_class()->class_loader_data()->record_dependency(kls);
     if (log_is_enabled(Debug, class, resolve)) {
       Verifier::trace_class_resolution(kls, current_class());
     }
--- a/src/hotspot/share/oops/constantPool.cpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/oops/constantPool.cpp	Mon Sep 10 16:49:01 2018 -0400
@@ -504,10 +504,6 @@
     }
   }
 
-  // Make this class loader depend upon the class loader owning the class reference
-  ClassLoaderData* this_key = this_cp->pool_holder()->class_loader_data();
-  this_key->record_dependency(k);
-
   // logging for class+resolve.
   if (log_is_enabled(Debug, class, resolve)){
     trace_class_resolution(this_cp, k);
--- a/src/hotspot/share/prims/jvm.cpp	Tue Aug 28 13:22:57 2018 +0530
+++ b/src/hotspot/share/prims/jvm.cpp	Mon Sep 10 16:49:01 2018 -0400
@@ -872,7 +872,6 @@
   if (result != NULL) {
     oop mirror = JNIHandles::resolve_non_null(result);
     Klass* to_class = java_lang_Class::as_Klass(mirror);
-    ClassLoaderData::class_loader_data(h_loader())->record_dependency(to_class);
   }
 
   if (log_is_enabled(Debug, class, resolve) && result != NULL) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/ClassUnload/ConstantPoolDependsTest.java	Mon Sep 10 16:49:01 2018 -0400
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018, 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 ConstantPoolDependsTest
+ * @bug 8210094
+ * @summary Create ClassLoader dependency from initiating loader to class loader through constant pool reference
+ * @modules java.base/jdk.internal.misc
+ *          java.compiler
+ * @library /runtime/testlibrary /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @compile p2/c2.java MyDiffClassLoader.java
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+PrintSystemDictionaryAtExit -Xlog:class+unload=trace -XX:+WhiteBoxAPI ConstantPoolDependsTest
+ */
+
+import sun.hotspot.WhiteBox;
+
+
+public class ConstantPoolDependsTest {
+    public static WhiteBox wb = WhiteBox.getWhiteBox();
+    public static final String MY_TEST = "ConstantPoolDependsTest$c1c";
+
+    public static class c1c {
+        private void test() throws Exception {
+            // ConstantPool.klass_at_impl loads through constant pool and creates dependency
+            p2.c2 c2_obj = new p2.c2();
+            c2_obj.method2();
+        }
+
+        public c1c () throws Exception {
+            test();
+            ClassUnloadCommon.triggerUnloading();  // should not unload anything
+            test();
+            ClassUnloadCommon.triggerUnloading();  // should not unload anything
+        }
+    }
+
+    static void test() throws Throwable {
+
+        // now use the same loader to load class MyTest
+        Class MyTest_class = new MyDiffClassLoader(MY_TEST).loadClass(MY_TEST);
+
+        try {
+            // Call MyTest to load p2.c2 twice and call p2.c2.method2
+            MyTest_class.newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException("Test FAILED if NoSuchMethodException is thrown");
+        }
+        ClassUnloadCommon.triggerUnloading();  // should not unload anything
+        ClassUnloadCommon.failIf(!wb.isClassAlive(MY_TEST), "should not be unloaded");
+        ClassUnloadCommon.failIf(!wb.isClassAlive("p2.c2"), "should not be unloaded");
+        // Unless MyTest_class is referenced here, the compiler can unload it.
+        System.out.println("Should not unload anything before here because " + MyTest_class + " is still alive.");
+    }
+
+    public static void main(String args[]) throws Throwable {
+        test();
+        ClassUnloadCommon.triggerUnloading();  // should unload
+        System.gc();
+        System.out.println("Should unload p2.c2 just now");
+        ClassUnloadCommon.failIf(wb.isClassAlive(MY_TEST), "should be unloaded");
+        ClassUnloadCommon.failIf(wb.isClassAlive("p2.c2"), "should be unloaded");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/ClassUnload/DictionaryDependsTest.java	Mon Sep 10 16:49:01 2018 -0400
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018, 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 DictionaryDependsTest
+ * @bug 8210094
+ * @summary Create ClassLoader dependency from initiating loader to class loader through reflection
+ * @modules java.base/jdk.internal.misc
+ *          java.compiler
+ * @library /runtime/testlibrary /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @compile p2/c2.java MyDiffClassLoader.java
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -Xlog:class+unload=trace -XX:+WhiteBoxAPI DictionaryDependsTest
+ */
+import sun.hotspot.WhiteBox;
+import java.lang.reflect.Method;
+
+public class DictionaryDependsTest {
+    public static WhiteBox wb = WhiteBox.getWhiteBox();
+    public static final String MY_TEST = "DictionaryDependsTest$c1r";
+
+    static public class c1r {
+
+        private void test() throws Exception {
+            // forName loads through reflection and doesn't create dependency
+            Class<?> x = Class.forName("p2.c2", true, c1r.class.getClassLoader());
+            Method m = x.getMethod("method2");
+            java.lang.Object t = x.newInstance();
+            m.invoke(t);
+        }
+
+        public c1r () throws Exception {
+            test();
+            ClassUnloadCommon.triggerUnloading();  // should unload p2.c2
+            test();
+            ClassUnloadCommon.triggerUnloading();  // should unload p2.c2
+        }
+    }
+
+    public void test() throws Throwable {
+
+        // now use the same loader to load class MyTest
+        Class MyTest_class = new MyDiffClassLoader(MY_TEST).loadClass(MY_TEST);
+
+        try {
+            // Call MyTest to load p2.c2 twice and call p2.c2.method2
+            MyTest_class.newInstance();
+        } catch (Exception e) {
+            System.out.println("Not expected NSME");
+            throw new RuntimeException("Not expecting NSME");
+        }
+        ClassUnloadCommon.triggerUnloading();  // should not unload anything
+        ClassUnloadCommon.failIf(!wb.isClassAlive(MY_TEST), "should not be unloaded");
+        ClassUnloadCommon.failIf(!wb.isClassAlive("p2.c2"), "should not be unloaded");
+        // Unless MyTest_class is referenced here, the compiler can unload it.
+        System.out.println("Should not unload anything before here because " + MyTest_class + " is still alive.");
+    }
+
+    public static void main(String args[]) throws Throwable {
+        DictionaryDependsTest d = new DictionaryDependsTest();
+        d.test();
+        ClassUnloadCommon.triggerUnloading();  // should not unload anything
+        System.out.println("Should unload MyTest and p2.c2 just now");
+        ClassUnloadCommon.failIf(wb.isClassAlive(MY_TEST), "should be unloaded");
+        ClassUnloadCommon.failIf(wb.isClassAlive("p2.c2"), "should be unloaded");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/ClassUnload/MyDiffClassLoader.java	Mon Sep 10 16:49:01 2018 -0400
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, 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.io.*;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+public class MyDiffClassLoader extends ClassLoader {
+
+    public String loaderName;
+    public static boolean switchClassData = false;
+
+    MyDiffClassLoader(String name) {
+        this.loaderName = name;
+    }
+
+    public Class loadClass(String name) throws ClassNotFoundException {
+        if (!name.contains("c1r") &&
+            !name.contains("c1c") &&
+            !name.contains("c1s") &&
+            !name.equals("p2.c2")) {
+                return super.loadClass(name);
+        }
+
+        // new loader loads p2.c2
+        if  (name.equals("p2.c2") && !loaderName.equals("C2Loader")) {
+            Class<?> c = new MyDiffClassLoader("C2Loader").loadClass(name);
+            switchClassData = true;
+            return c;
+        }
+
+        byte[] data = switchClassData ? getNewClassData(name) : getClassData(name);
+        System.out.println("name is " + name);
+        return defineClass(name, data, 0, data.length);
+    }
+    byte[] getClassData(String name) {
+        try {
+           String TempName = name.replaceAll("\\.", "/");
+           String currentDir = System.getProperty("test.classes");
+           String filename = currentDir + File.separator + TempName + ".class";
+           FileInputStream fis = new FileInputStream(filename);
+           byte[] b = new byte[5000];
+           int cnt = fis.read(b, 0, 5000);
+           byte[] c = new byte[cnt];
+           for (int i=0; i<cnt; i++) c[i] = b[i];
+             return c;
+        } catch (IOException e) {
+           return null;
+        }
+    }
+
+    // Return p2.c2 with everything removed
+    byte[] getNewClassData(String name) {
+        return InMemoryJavaCompiler.compile("p2.c2", "package p2; public class c2 { }");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/ClassUnload/SuperDependsTest.java	Mon Sep 10 16:49:01 2018 -0400
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018, 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 SuperDependsTest
+ * @bug 8210094
+ * @summary Create ClassLoader dependency from initiating loader to class loader through subclassing
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.compiler
+ * @library /runtime/testlibrary /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @compile p2/c2.java MyDiffClassLoader.java
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+PrintSystemDictionaryAtExit -Xlog:class+unload=trace -XX:+WhiteBoxAPI SuperDependsTest
+ */
+import sun.hotspot.WhiteBox;
+import p2.*;
+
+public class SuperDependsTest {
+    public static WhiteBox wb = WhiteBox.getWhiteBox();
+    public static final String MY_TEST = "SuperDependsTest$c1s";
+
+
+    // p2.c2 loads through super class and creates dependency
+    public static class c1s extends p2.c2 {
+
+        private void test() throws Exception {
+            method2();
+        }
+
+        public c1s () throws Exception {
+            test();
+            ClassUnloadCommon.triggerUnloading();  // should not unload anything
+            test();
+        }
+    }
+
+    public void test() throws Throwable {
+
+        // now use the same loader to load class MyTest
+        Class MyTest_class = new MyDiffClassLoader(MY_TEST).loadClass(MY_TEST);
+
+        // Call MyTest to load p2.c2 twice and call p2.c2.method2
+        MyTest_class.newInstance();
+        ClassUnloadCommon.triggerUnloading();  // should not unload anything
+        ClassUnloadCommon.failIf(!wb.isClassAlive(MY_TEST), "should not be unloaded");
+        ClassUnloadCommon.failIf(!wb.isClassAlive("p2.c2"), "should not be unloaded");
+        // Unless MyTest_class is referenced here, the compiler can unload it.
+        System.out.println("Should not unload anything before here because " + MyTest_class + " is still alive.");
+    }
+
+    public static void main(String args[]) throws Throwable {
+        SuperDependsTest d = new SuperDependsTest();
+        d.test();
+        ClassUnloadCommon.triggerUnloading();  // should not unload anything
+        System.out.println("Should unload MyTest and p2.c2 just now");
+        ClassUnloadCommon.failIf(wb.isClassAlive(MY_TEST), "should be unloaded");
+        ClassUnloadCommon.failIf(wb.isClassAlive("p2.c2"), "should be unloaded");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/ClassUnload/p2/c2.java	Mon Sep 10 16:49:01 2018 -0400
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+package p2;
+
+public class c2 {
+    int i;
+    public void method2() { i = 5; System.out.println("c2 method2 called"); }
+}