# HG changeset patch # User coleenp # Date 1367968663 25200 # Node ID a1cc1d1e7ce58c35498d03fce5f818524d8a1f75 # Parent 4674e409a9e66c0ee00e7a7849cef3cfec8654db# Parent 33bcd9ead1d519c826c594d4b36462948c7dc7de Merge diff -r 4674e409a9e6 -r a1cc1d1e7ce5 agent/src/os/bsd/ps_core.c --- a/agent/src/os/bsd/ps_core.c Tue May 07 18:51:31 2013 -0400 +++ b/agent/src/os/bsd/ps_core.c Tue May 07 16:17:43 2013 -0700 @@ -199,10 +199,10 @@ //--------------------------------------------------------------- // Part of the class sharing workaround: // -// With class sharing, pages are mapped from classes[_g].jsa file. +// With class sharing, pages are mapped from classes.jsa file. // The read-only class sharing pages are mapped as MAP_SHARED, // PROT_READ pages. These pages are not dumped into core dump. -// With this workaround, these pages are read from classes[_g].jsa. +// With this workaround, these pages are read from classes.jsa. // FIXME: !HACK ALERT! // The format of sharing achive file header is needed to read shared heap @@ -298,14 +298,12 @@ lib_info* lib = ph->libs; while (lib != NULL) { // we are iterating over shared objects from the core dump. look for - // libjvm[_g].so. + // libjvm.so. const char *jvm_name = 0; #ifdef __APPLE__ - if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0 || - (jvm_name = strstr(lib->name, "/libjvm_g.dylib")) != 0) + if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0) #else - if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 || - (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) + if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0) #endif // __APPLE__ { char classes_jsa[PATH_MAX]; @@ -389,7 +387,7 @@ } ph->core->classes_jsa_fd = fd; - // add read-only maps from classes[_g].jsa to the list of maps + // add read-only maps from classes.jsa to the list of maps for (m = 0; m < NUM_SHARED_MAPS; m++) { if (header._space[m]._read_only) { base = (uintptr_t) header._space[m]._base; diff -r 4674e409a9e6 -r a1cc1d1e7ce5 agent/src/os/linux/ps_core.c --- a/agent/src/os/linux/ps_core.c Tue May 07 18:51:31 2013 -0400 +++ b/agent/src/os/linux/ps_core.c Tue May 07 16:17:43 2013 -0700 @@ -195,10 +195,10 @@ //--------------------------------------------------------------- // Part of the class sharing workaround: // -// With class sharing, pages are mapped from classes[_g].jsa file. +// With class sharing, pages are mapped from classes.jsa file. // The read-only class sharing pages are mapped as MAP_SHARED, // PROT_READ pages. These pages are not dumped into core dump. -// With this workaround, these pages are read from classes[_g].jsa. +// With this workaround, these pages are read from classes.jsa. // FIXME: !HACK ALERT! // The format of sharing achive file header is needed to read shared heap @@ -284,10 +284,9 @@ lib_info* lib = ph->libs; while (lib != NULL) { // we are iterating over shared objects from the core dump. look for - // libjvm[_g].so. + // libjvm.so. const char *jvm_name = 0; - if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 || - (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) { + if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0) { char classes_jsa[PATH_MAX]; struct FileMapHeader header; size_t n = 0; @@ -371,7 +370,7 @@ } ph->core->classes_jsa_fd = fd; - // add read-only maps from classes[_g].jsa to the list of maps + // add read-only maps from classes.jsa to the list of maps for (m = 0; m < NUM_SHARED_MAPS; m++) { if (header._space[m]._read_only) { base = (uintptr_t) header._space[m]._base; diff -r 4674e409a9e6 -r a1cc1d1e7ce5 agent/src/os/solaris/proc/saproc.cpp --- a/agent/src/os/solaris/proc/saproc.cpp Tue May 07 18:51:31 2013 -0400 +++ b/agent/src/os/solaris/proc/saproc.cpp Tue May 07 16:17:43 2013 -0700 @@ -589,8 +589,7 @@ JNIEnv* env = dbg->env; jobject this_obj = dbg->this_obj; const char* jvm_name = 0; - if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL || - (jvm_name = strstr(obj_name, "libjvm_g.so")) != NULL) { + if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL) { jvm_name = obj_name; } else { return 0; @@ -598,7 +597,7 @@ struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID); - // initialize classes[_g].jsa file descriptor field. + // initialize classes.jsa file descriptor field. dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1); // check whether class sharing is on by reading variable "UseSharedSpaces" @@ -641,7 +640,7 @@ print_debug("looking for %s\n", classes_jsa); - // open the classes[_g].jsa + // open the classes.jsa int fd = libsaproc_open(classes_jsa, O_RDONLY); if (fd < 0) { char errMsg[ERR_MSG_SIZE]; @@ -651,7 +650,7 @@ print_debug("opened shared archive file %s\n", classes_jsa); } - // parse classes[_g].jsa + // parse classes.jsa struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader)); if (pheader == NULL) { close(fd); @@ -798,8 +797,8 @@ if (! isProcess) { /* * With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ. - * These pages are mapped from the file "classes[_g].jsa". MAP_SHARED pages are not dumped - * in Solaris core.To read shared heap pages, we have to read classes[_g].jsa file. + * These pages are mapped from the file "classes.jsa". MAP_SHARED pages are not dumped + * in Solaris core.To read shared heap pages, we have to read classes.jsa file. */ Pobject_iter(ph, init_classsharing_workaround, &dbg); exception = env->ExceptionOccurred(); diff -r 4674e409a9e6 -r a1cc1d1e7ce5 agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java --- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java Tue May 07 18:51:31 2013 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java Tue May 07 16:17:43 2013 -0700 @@ -24,20 +24,29 @@ package sun.jvm.hotspot; -import java.io.PrintStream; -import java.net.*; -import java.rmi.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.bsd.*; -import sun.jvm.hotspot.debugger.proc.*; -import sun.jvm.hotspot.debugger.remote.*; -import sun.jvm.hotspot.debugger.windbg.*; -import sun.jvm.hotspot.debugger.linux.*; -import sun.jvm.hotspot.memory.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.*; +import java.rmi.RemoteException; + +import sun.jvm.hotspot.debugger.Debugger; +import sun.jvm.hotspot.debugger.DebuggerException; +import sun.jvm.hotspot.debugger.JVMDebugger; +import sun.jvm.hotspot.debugger.MachineDescription; +import sun.jvm.hotspot.debugger.MachineDescriptionAMD64; +import sun.jvm.hotspot.debugger.MachineDescriptionIA64; +import sun.jvm.hotspot.debugger.MachineDescriptionIntelX86; +import sun.jvm.hotspot.debugger.MachineDescriptionSPARC32Bit; +import sun.jvm.hotspot.debugger.MachineDescriptionSPARC64Bit; +import sun.jvm.hotspot.debugger.NoSuchSymbolException; +import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal; +import sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal; +import sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal; +import sun.jvm.hotspot.debugger.remote.RemoteDebugger; +import sun.jvm.hotspot.debugger.remote.RemoteDebuggerClient; +import sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer; +import sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.types.TypeDataBase; +import sun.jvm.hotspot.utilities.PlatformInfo; +import sun.jvm.hotspot.utilities.UnsupportedPlatformException; /**

This class wraps much of the basic functionality and is the * highest-level factory for VM data structures. It makes it simple @@ -475,7 +484,7 @@ } private void setupJVMLibNamesSolaris() { - jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" }; + jvmLibNames = new String[] { "libjvm.so" }; } // @@ -507,7 +516,7 @@ } private void setupJVMLibNamesWin32() { - jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" }; + jvmLibNames = new String[] { "jvm.dll" }; } // @@ -547,7 +556,7 @@ } private void setupJVMLibNamesLinux() { - jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; + jvmLibNames = new String[] { "libjvm.so" }; } // @@ -572,7 +581,7 @@ } private void setupJVMLibNamesBsd() { - jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; + jvmLibNames = new String[] { "libjvm.so" }; } // @@ -595,7 +604,7 @@ } private void setupJVMLibNamesDarwin() { - jvmLibNames = new String[] { "libjvm.dylib", "libjvm_g.dylib" }; + jvmLibNames = new String[] { "libjvm.dylib" }; } /** Convenience routine which should be called by per-platform diff -r 4674e409a9e6 -r a1cc1d1e7ce5 agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java --- a/agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java Tue May 07 18:51:31 2013 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java Tue May 07 16:17:43 2013 -0700 @@ -24,9 +24,9 @@ package sun.jvm.hotspot; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.types.basic.*; +import sun.jvm.hotspot.debugger.SymbolLookup; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.basic.BasicVtblAccess; public class LinuxVtblAccess extends BasicVtblAccess { private String vt; @@ -35,8 +35,7 @@ String[] dllNames) { super(symbolLookup, dllNames); - if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null || - symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) { + if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null) { // old C++ ABI vt = "__vt_"; } else { diff -r 4674e409a9e6 -r a1cc1d1e7ce5 agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Tue May 07 18:51:31 2013 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Tue May 07 16:17:43 2013 -0700 @@ -24,17 +24,28 @@ package sun.jvm.hotspot.debugger.bsd; -import java.io.*; -import java.net.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.x86.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.utilities.*; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.DebuggerBase; +import sun.jvm.hotspot.debugger.DebuggerException; +import sun.jvm.hotspot.debugger.DebuggerUtilities; +import sun.jvm.hotspot.debugger.MachineDescription; +import sun.jvm.hotspot.debugger.NotInHeapException; +import sun.jvm.hotspot.debugger.OopHandle; +import sun.jvm.hotspot.debugger.ReadResult; +import sun.jvm.hotspot.debugger.ThreadProxy; +import sun.jvm.hotspot.debugger.UnalignedAddressException; +import sun.jvm.hotspot.debugger.UnmappedAddressException; +import sun.jvm.hotspot.debugger.cdbg.CDebugger; +import sun.jvm.hotspot.debugger.cdbg.ClosestSymbol; +import sun.jvm.hotspot.debugger.cdbg.LoadObject; +import sun.jvm.hotspot.runtime.JavaThread; +import sun.jvm.hotspot.runtime.Threads; import sun.jvm.hotspot.runtime.VM; -import sun.jvm.hotspot.runtime.Threads; -import sun.jvm.hotspot.runtime.JavaThread; -import java.lang.reflect.*; +import sun.jvm.hotspot.utilities.PlatformInfo; /**

An implementation of the JVMDebugger interface. The basic debug facilities are implemented through ptrace interface in the JNI code @@ -246,10 +257,8 @@ /* called from attach methods */ private void findABIVersion() throws DebuggerException { String libjvmName = isDarwin ? "libjvm.dylib" : "libjvm.so"; - String libjvm_gName = isDarwin? "libjvm_g.dylib" : "libjvm_g.so"; String javaThreadVt = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread"; - if (lookupByName0(libjvmName, javaThreadVt) != 0 || - lookupByName0(libjvm_gName, javaThreadVt) != 0) { + if (lookupByName0(libjvmName, javaThreadVt) != 0) { // old C++ ABI useGCC32ABI = false; } else { diff -r 4674e409a9e6 -r a1cc1d1e7ce5 agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java Tue May 07 18:51:31 2013 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java Tue May 07 16:17:43 2013 -0700 @@ -24,14 +24,25 @@ package sun.jvm.hotspot.debugger.linux; -import java.io.*; -import java.net.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.x86.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.utilities.*; -import java.lang.reflect.*; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.DebuggerBase; +import sun.jvm.hotspot.debugger.DebuggerException; +import sun.jvm.hotspot.debugger.DebuggerUtilities; +import sun.jvm.hotspot.debugger.MachineDescription; +import sun.jvm.hotspot.debugger.NotInHeapException; +import sun.jvm.hotspot.debugger.OopHandle; +import sun.jvm.hotspot.debugger.ReadResult; +import sun.jvm.hotspot.debugger.ThreadProxy; +import sun.jvm.hotspot.debugger.UnalignedAddressException; +import sun.jvm.hotspot.debugger.UnmappedAddressException; +import sun.jvm.hotspot.debugger.cdbg.CDebugger; +import sun.jvm.hotspot.debugger.cdbg.ClosestSymbol; +import sun.jvm.hotspot.debugger.cdbg.LoadObject; +import sun.jvm.hotspot.utilities.PlatformInfo; /**

An implementation of the JVMDebugger interface. The basic debug facilities are implemented through ptrace interface in the JNI code @@ -238,8 +249,7 @@ /* called from attach methods */ private void findABIVersion() throws DebuggerException { - if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 || - lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) { + if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0) { // old C++ ABI useGCC32ABI = false; } else { diff -r 4674e409a9e6 -r a1cc1d1e7ce5 src/share/vm/prims/jvmtiClassFileReconstituter.cpp --- a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Tue May 07 18:51:31 2013 -0400 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Tue May 07 16:17:43 2013 -0700 @@ -350,13 +350,13 @@ // u2 bootstrap_arguments[num_bootstrap_arguments]; // } bootstrap_methods[num_bootstrap_methods]; // } -void JvmtiClassFileReconstituter::write_boostrapmethod_attribute() { +void JvmtiClassFileReconstituter::write_bootstrapmethod_attribute() { Array* operands = cpool()->operands(); write_attribute_name_index("BootstrapMethods"); int num_bootstrap_methods = ConstantPool::operand_array_length(operands); // calculate length of attribute - int length = sizeof(u2); // num_boostrap_methods + int length = sizeof(u2); // num_bootstrap_methods for (int n = 0; n < num_bootstrap_methods; n++) { u2 num_bootstrap_arguments = cpool()->operand_argument_count_at(n); length += sizeof(u2); // bootstrap_method_ref @@ -657,7 +657,7 @@ write_annotations_attribute("RuntimeVisibleAnnotations", anno); } if (cpool()->operands() != NULL) { - write_boostrapmethod_attribute(); + write_bootstrapmethod_attribute(); } } diff -r 4674e409a9e6 -r a1cc1d1e7ce5 src/share/vm/prims/jvmtiClassFileReconstituter.hpp --- a/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Tue May 07 18:51:31 2013 -0400 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Tue May 07 16:17:43 2013 -0700 @@ -127,7 +127,7 @@ void write_signature_attribute(u2 generic_signaure_index); void write_attribute_name_index(const char* name); void write_annotations_attribute(const char* attr_name, AnnotationArray* annos); - void write_boostrapmethod_attribute(); + void write_bootstrapmethod_attribute(); address writeable_address(size_t size); void write_u1(u1 x); diff -r 4674e409a9e6 -r a1cc1d1e7ce5 test/runtime/ClassUnload/KeepAliveClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ClassUnload/KeepAliveClass.java Tue May 07 16:17:43 2013 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013, 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 KeepAliveClass + * @summary This test case uses a java.lang.Class instance to keep a class alive. + * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary + * @library classes + * @build KeepAliveClass test.Empty + * @build ClassUnloadCommon + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveClass + */ + +import java.lang.ref.SoftReference; +import sun.hotspot.WhiteBox; + +/** + * Test that verifies that classes are not unloaded when specific types of references are kept to them. + */ +public class KeepAliveClass { + private static final String className = "test.Empty"; + private static final WhiteBox wb = WhiteBox.getWhiteBox(); + public static Object escape = null; + + public static void main(String... args) throws Exception { + ClassLoader cl = ClassUnloadCommon.newClassLoader(); + Class c = cl.loadClass(className); + Object o = c.newInstance(); + o = null; cl = null; + escape = c; + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testClass (1) alive: " + isAlive); + + ClassUnloadCommon.failIf(!isAlive, "should be alive"); + } + + ClassUnloadCommon.triggerUnloading(); + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testClass (2) alive: " + isAlive); + + ClassUnloadCommon.failIf(!isAlive, "should be alive"); + } + c = null; + escape = null; + ClassUnloadCommon.triggerUnloading(); + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testClass (3) alive: " + isAlive); + ClassUnloadCommon.failIf(isAlive, "should be unloaded"); + } + + } +} diff -r 4674e409a9e6 -r a1cc1d1e7ce5 test/runtime/ClassUnload/KeepAliveClassLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ClassUnload/KeepAliveClassLoader.java Tue May 07 16:17:43 2013 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013, 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 KeepAliveClassLoader + * @summary This test case uses a java.lang.ClassLoader instance to keep a class alive. + * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary + * @library classes + * @build KeepAliveClassLoader test.Empty + * @build ClassUnloadCommon + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveClassLoader + */ + +import sun.hotspot.WhiteBox; + +/** + * Test that verifies that classes are not unloaded when specific types of references are kept to them. + */ +public class KeepAliveClassLoader { + private static final String className = "test.Empty"; + private static final WhiteBox wb = WhiteBox.getWhiteBox(); + public static Object escape = null; + + + public static void main(String... args) throws Exception { + ClassLoader cl = ClassUnloadCommon.newClassLoader(); + Class c = cl.loadClass(className); + Object o = c.newInstance(); + o = null; c = null; + escape = cl; + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testClassLoader (1) alive: " + isAlive); + + ClassUnloadCommon.failIf(!isAlive, "should be alive"); + } + ClassUnloadCommon.triggerUnloading(); + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testClassLoader (2) alive: " + isAlive); + + ClassUnloadCommon.failIf(!isAlive, "should be alive"); + } + cl = null; + escape = null; + ClassUnloadCommon.triggerUnloading(); + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testClassLoader (3) alive: " + isAlive); + ClassUnloadCommon.failIf(isAlive, "should be unloaded"); + } + + } +} diff -r 4674e409a9e6 -r a1cc1d1e7ce5 test/runtime/ClassUnload/KeepAliveObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ClassUnload/KeepAliveObject.java Tue May 07 16:17:43 2013 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013, 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 KeepAliveObject + * @summary This test case uses a class instance to keep the class alive. + * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary + * @library classes + * @build KeepAliveObject test.Empty + * @build ClassUnloadCommon + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveObject + */ + +import sun.hotspot.WhiteBox; + +/** + * Test that verifies that classes are not unloaded when specific types of references are kept to them. + */ +public class KeepAliveObject { + private static final String className = "test.Empty"; + private static final WhiteBox wb = WhiteBox.getWhiteBox(); + public static Object escape = null; + + public static void main(String... args) throws Exception { + ClassLoader cl = ClassUnloadCommon.newClassLoader(); + Class c = cl.loadClass(className); + Object o = c.newInstance(); + cl = null; c = null; + escape = o; + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testObject (1) alive: " + isAlive); + + ClassUnloadCommon.failIf(!isAlive, "should be alive"); + } + + ClassUnloadCommon.triggerUnloading(); + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testObject (2) alive: " + isAlive); + + ClassUnloadCommon.failIf(!isAlive, "should be alive"); + } + o = null; + escape = null; + ClassUnloadCommon.triggerUnloading(); + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testObject (3) alive: " + isAlive); + ClassUnloadCommon.failIf(isAlive, "should be unloaded"); + } + + } +} diff -r 4674e409a9e6 -r a1cc1d1e7ce5 test/runtime/ClassUnload/KeepAliveSoftReference.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ClassUnload/KeepAliveSoftReference.java Tue May 07 16:17:43 2013 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, 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 KeepAliveSoftReference + * @summary This test case uses a java.lang.ref.SoftReference referencing a class instance to keep a class alive. + * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary + * @library classes + * @build KeepAliveSoftReference test.Empty + * @build ClassUnloadCommon + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveSoftReference + */ + +import java.lang.ref.SoftReference; +import sun.hotspot.WhiteBox; + +/** + * Test that verifies that classes are not unloaded when specific types of references are kept to them. + */ +public class KeepAliveSoftReference { + private static final String className = "test.Empty"; + private static final WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String... args) throws Exception { + ClassLoader cl = ClassUnloadCommon.newClassLoader(); + Class c = cl.loadClass(className); + Object o = c.newInstance(); + SoftReference sr = new SoftReference(o); + o = null; c = null; cl = null; + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testSoftReference (1) alive: " + isAlive); + boolean cleared = (sr.get() == null); + boolean shouldBeAlive = !cleared; + ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive); + } + + ClassUnloadCommon.triggerUnloading(); + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testSoftReference (2) alive: " + isAlive); + boolean cleared = (sr.get() == null); + boolean shouldBeAlive = !cleared; + ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive); + } + sr.clear(); + ClassUnloadCommon.triggerUnloading(); + + { + boolean isAlive = wb.isClassAlive(className); + System.out.println("testSoftReference (3) alive: " + isAlive); + boolean cleared = (sr.get() == null); + boolean shouldBeAlive = !cleared; + ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive); + } + } +} diff -r 4674e409a9e6 -r a1cc1d1e7ce5 test/runtime/ClassUnload/UnloadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ClassUnload/UnloadTest.java Tue May 07 16:17:43 2013 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, 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 UnloadTest + * @library /runtime/testlibrary /testlibrary /testlibrary/whitebox + * @library classes + * @build ClassUnloadCommon test.Empty + * @build UnloadTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI UnloadTest + */ +import sun.hotspot.WhiteBox; + +/** + * Test that verifies that classes are unloaded when they are no longer reachable. + * + * The test creates a class loader, uses the loader to load a class and creates an instance + * of that class. The it nulls out all the references to the instance, class and class loader + * and tries to trigger class unloading. Then it verifies that the class is no longer + * loaded by the VM. + */ +public class UnloadTest { + private static String className = "test.Empty"; + + public static void main(String... args) throws Exception { + run(); + } + + private static void run() throws Exception { + final WhiteBox wb = WhiteBox.getWhiteBox(); + + ClassUnloadCommon.failIf(wb.isClassAlive(className), "is not expected to be alive yet"); + + ClassLoader cl = ClassUnloadCommon.newClassLoader(); + Class c = cl.loadClass(className); + Object o = c.newInstance(); + + ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here"); + + cl = null; c = null; o = null; + ClassUnloadCommon.triggerUnloading(); + ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded"); + } +} + diff -r 4674e409a9e6 -r a1cc1d1e7ce5 test/runtime/ClassUnload/classes/test/Empty.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ClassUnload/classes/test/Empty.java Tue May 07 16:17:43 2013 -0700 @@ -0,0 +1,5 @@ +package test; + +public class Empty { +public String toString() { return "nothing"; } +} diff -r 4674e409a9e6 -r a1cc1d1e7ce5 test/runtime/testlibrary/ClassUnloadCommon.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/testlibrary/ClassUnloadCommon.java Tue May 07 16:17:43 2013 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, 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.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Paths; +import java.util.ArrayList; + +public class ClassUnloadCommon { + public static class TestFailure extends RuntimeException { + TestFailure(String msg) { + super(msg); + } + } + + public static void failIf(boolean value, String msg) { + if (value) throw new TestFailure("Test failed: " + msg); + } + + private static volatile Object dummy = null; + private static void allocateMemory(int kilobytes) { + ArrayList l = new ArrayList<>(); + dummy = l; + for (int i = kilobytes; i > 0; i -= 1) { + l.add(new byte[1024]); + } + l = null; + dummy = null; + } + + public static void triggerUnloading() { + allocateMemory(16 * 1024); // yg size is 8m with cms, force young collection + System.gc(); + } + + public static ClassLoader newClassLoader() { + try { + return new URLClassLoader(new URL[] { + Paths.get(System.getProperty("test.classes",".") + File.separatorChar + "classes").toUri().toURL(), + }, null); + } catch (MalformedURLException e){ + throw new RuntimeException("Unexpected URL conversion failure", e); + } + } + +}