1 /*
2  * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test UnloadInterfaceTest
26  * @requires vm.opt.final.ClassUnloading
27  * @modules java.base/jdk.internal.misc
28  * @library /runtime/testlibrary /test/lib
29  * @compile test/Interface.java
30  * @compile test/ImplementorClass.java
31  * @build sun.hotspot.WhiteBox
32  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
33  * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xlog:class+unload=trace UnloadInterfaceTest
34  */
35 import sun.hotspot.WhiteBox;
36 import test.Interface;
37 import java.lang.ClassLoader;
38 
39 /**
40  * Test that verifies that class unloaded removes the implementor from its the interface that it implements
41  * via logging.
42  * [1.364s][info][class,unload] unloading class test.ImplementorClass 0x00000008000a2840
43  * [1.366s][trace][class,unload] unlinking class (subclass): test.ImplementorClass
44  * [1.366s][trace][class,unload] unlinking class (implementor): test.ImplementorClass
45  */
46 public class UnloadInterfaceTest {
47     private static String className = "test.ImplementorClass";
48     private static String interfaceName = "test.Interface";
49 
50     static class LoaderToUnload extends ClassLoader {
51        ClassLoader myParent;
loadClass(String name)52         public Class loadClass(String name) throws ClassNotFoundException {
53             if (name.contains(className)) {
54               System.out.println("className found " + className);
55               byte[] data = ClassUnloadCommon.getClassData(name);
56               return defineClass(name, data, 0, data.length);
57             } else {
58               return myParent.loadClass(name);
59             }
60         }
LoaderToUnload(ClassLoader parent)61         public LoaderToUnload(ClassLoader parent) {
62             super();
63             myParent = parent;
64         }
65     }
66 
main(String... args)67     public static void main(String... args) throws Exception {
68        run();
69     }
70 
run()71     private static void run() throws Exception {
72         final WhiteBox wb = WhiteBox.getWhiteBox();
73 
74         ClassUnloadCommon.failIf(wb.isClassAlive(className), "is not expected to be alive yet");
75 
76         // Load interface Class with one class loader.
77         ClassLoader icl = ClassUnloadCommon.newClassLoader();
78         Class<?> ic = icl.loadClass(interfaceName);
79 
80         ClassLoader cl = new LoaderToUnload(icl);
81         Class<?> c = cl.loadClass(className);
82         Object o = c.newInstance();
83 
84         ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here");
85         ClassUnloadCommon.failIf(!wb.isClassAlive(interfaceName), "should be live here");
86 
87         cl = null; c = null; o = null;
88         ClassUnloadCommon.triggerUnloading();
89         ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded");
90         ClassUnloadCommon.failIf(!wb.isClassAlive(interfaceName), "should be live here");
91         System.out.println("We still have Interface referenced" + ic);
92     }
93 }
94 
95