--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Fri Jul 11 09:14:21 2014 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Fri Jul 11 14:32:02 2014 -0700
@@ -777,11 +777,22 @@
// unneeded entries.
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
MetadataOnStackMark md_on_stack;
+ if (has_redefined_a_class) {
+ // purge_previous_versions also cleans weak method links. Because
+ // one method's MDO can reference another method from another
+ // class loader, we need to first clean weak method links for all
+ // class loaders here. Below, we can then free redefined methods
+ // for all class loaders.
+ while (data != NULL) {
+ if (data->is_alive(is_alive_closure)) {
+ data->classes_do(InstanceKlass::purge_previous_versions);
+ }
+ data = data->next();
+ }
+ }
+ data = _head;
while (data != NULL) {
if (data->is_alive(is_alive_closure)) {
- if (has_redefined_a_class) {
- data->classes_do(InstanceKlass::purge_previous_versions);
- }
data->free_deallocate_list();
prev = data;
data = data->next();
--- a/hotspot/src/share/vm/oops/methodData.cpp Fri Jul 11 09:14:21 2014 -0700
+++ b/hotspot/src/share/vm/oops/methodData.cpp Fri Jul 11 14:32:02 2014 -0700
@@ -1556,7 +1556,7 @@
public:
CleanExtraDataMethodClosure() {}
bool is_live(Method* m) {
- return m->on_stack();
+ return !m->is_old() || m->on_stack();
}
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/profiling/TestSpecTrapClassUnloading.java Fri Jul 11 14:32:02 2014 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, 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 8031752
+ * @summary speculative traps need to be cleaned up at GC
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx512M TestSpecTrapClassUnloading
+ *
+ */
+
+import java.lang.reflect.Method;
+
+public class TestSpecTrapClassUnloading {
+ static class B {
+ final public boolean m(Object o) {
+ if (o.getClass() == B.class) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ static class MemoryChunk {
+ MemoryChunk other;
+ long[] array;
+ MemoryChunk(MemoryChunk other) {
+ this.other = other;
+ array = new long[1024 * 1024 * 1024];
+ }
+ }
+
+ static void m1(B b, Object o) {
+ b.m(o);
+ }
+
+ static void m2(B b, Object o) {
+ b.m(o);
+ }
+
+ public static void main(String[] args) throws Exception {
+ Method m = B.class.getMethod("m", Object.class);
+ Object o = new Object();
+ B b = new B();
+
+ // add speculative trap in B.m() for m1
+ for (int i = 0; i < 20000; i++) {
+ m1(b, b);
+ }
+ m1(b, o);
+
+ // add speculative trap in B.m() for code generated by reflection
+ for (int i = 0; i < 20000; i++) {
+ m.invoke(b, b);
+ }
+ m.invoke(b, o);
+
+ m = null;
+
+ // add speculative trap in B.m() for m2
+ for (int i = 0; i < 20000; i++) {
+ m2(b, b);
+ }
+ m2(b, o);
+
+ // Exhaust memory which causes the code generated by
+ // reflection to be unloaded but B.m() is not.
+ MemoryChunk root = null;
+ try {
+ while (true) {
+ root = new MemoryChunk(root);
+ }
+ } catch(OutOfMemoryError e) {
+ root = null;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/profiling/spectrapredefineclass_classloaders/A.java Fri Jul 11 14:32:02 2014 -0700
@@ -0,0 +1,4 @@
+public class A {
+ void m() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/profiling/spectrapredefineclass_classloaders/Agent.java Fri Jul 11 14:32:02 2014 -0700
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, 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.security.*;
+import java.lang.instrument.*;
+import java.lang.reflect.*;
+import java.lang.management.ManagementFactory;
+import com.sun.tools.attach.VirtualMachine;
+import java.lang.reflect.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Paths;
+
+public class Agent implements ClassFileTransformer {
+ public static ClassLoader newClassLoader() {
+ try {
+ return new URLClassLoader(new URL[] {
+ Paths.get(System.getProperty("test.classes",".")).toUri().toURL(),
+ }, null);
+ } catch (MalformedURLException e){
+ throw new RuntimeException("Unexpected URL conversion failure", e);
+ }
+ }
+
+ static public Class Test_class;
+
+ static public void main(String[] args) throws Exception {
+
+ // loader2 must be first on the list so loader 1 must be used first
+ ClassLoader loader1 = newClassLoader();
+ Class dummy = loader1.loadClass("Test");
+
+ ClassLoader loader2 = newClassLoader();
+
+ Test_class = loader2.loadClass("Test");
+ Method m3 = Test_class.getMethod("m3", ClassLoader.class);
+ // Add speculative trap in m2() (loaded by loader1) that
+ // references m4() (loaded by loader2).
+ m3.invoke(Test_class.newInstance(), loader1);
+
+ String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
+ int p = nameOfRunningVM.indexOf('@');
+ String pid = nameOfRunningVM.substring(0, p);
+
+ // Make the nmethod go away
+ for (int i = 0; i < 10; i++) {
+ System.gc();
+ }
+
+ // Redefine class Test loaded by loader2
+ for (int i = 0; i < 2; i++) {
+ try {
+ VirtualMachine vm = VirtualMachine.attach(pid);
+ vm.loadAgent(System.getProperty("test.classes",".") + "/agent.jar", "");
+ vm.detach();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ // Will process loader2 first, find m4() is redefined and
+ // needs to be freed then process loader1, check the
+ // speculative trap in m2() and try to access m4() which was
+ // freed already.
+ for (int i = 0; i < 10; i++) {
+ System.gc();
+ }
+ }
+
+ public synchronized byte[] transform(final ClassLoader classLoader,
+ final String className,
+ Class<?> classBeingRedefined,
+ ProtectionDomain protectionDomain,
+ byte[] classfileBuffer) {
+ System.out.println("Transforming class " + className + " "+ classLoader);
+ return classfileBuffer;
+ }
+
+ public static void redefine(String agentArgs, Instrumentation instrumentation, Class to_redefine) {
+
+ try {
+ instrumentation.retransformClasses(to_redefine);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception {
+ Agent transformer = new Agent();
+ instrumentation.addTransformer(transformer, true);
+
+ redefine(agentArgs, instrumentation, Test_class);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/profiling/spectrapredefineclass_classloaders/B.java Fri Jul 11 14:32:02 2014 -0700
@@ -0,0 +1,5 @@
+public class B extends A {
+ void m() {
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java Fri Jul 11 14:32:02 2014 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, 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.PrintWriter;
+import com.oracle.java.testlibrary.*;
+
+/*
+ * @test
+ * @bug 8040237
+ * @library /testlibrary
+ * @build Agent Test A B
+ * @run main ClassFileInstaller Agent
+ * @run main Launcher
+ * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:ReservedCodeCacheSize=3M Agent
+ */
+public class Launcher {
+ public static void main(String[] args) throws Exception {
+
+ PrintWriter pw = new PrintWriter("MANIFEST.MF");
+ pw.println("Agent-Class: Agent");
+ pw.println("Can-Retransform-Classes: true");
+ pw.close();
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), "cmf", "MANIFEST.MF", System.getProperty("test.classes",".") + "/agent.jar", "Agent.class"});
+ pb.start().waitFor();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/profiling/spectrapredefineclass_classloaders/Test.java Fri Jul 11 14:32:02 2014 -0700
@@ -0,0 +1,50 @@
+import java.lang.reflect.*;
+
+public class Test {
+
+ public boolean m1(A a, Boolean early_return) {
+ if (early_return.booleanValue()) return true;
+ boolean res = m2(a);
+ return res;
+ }
+
+ public boolean m2(A a) {
+ boolean res = false;
+ if (a.getClass() == B.class) {
+ a.m();
+ } else {
+ res = true;
+ }
+ return res;
+ }
+
+ public void m3(ClassLoader loader) throws Exception {
+ Class Test_class = loader.loadClass("Test");
+ Object test = Test_class.newInstance();
+ Class A_class = loader.loadClass("A");
+ Object a = A_class.newInstance();
+ Class B_class = loader.loadClass("B");
+ Object b = B_class.newInstance();
+ Method m1 = Test_class.getMethod("m1", A_class, Boolean.class);
+
+ // So we don't hit uncommon trap in the next loop
+ for (int i = 0; i < 4000; i++) {
+ m4(m1, test, a, Boolean.TRUE);
+ m4(m1, test, b, Boolean.TRUE);
+ }
+ for (int i = 0; i < 20000; i++) {
+ m4(m1, test, a, Boolean.FALSE);
+ }
+ for (int i = 0; i < 4; i++) {
+ m4(m1, test, b, Boolean.FALSE);
+ }
+ }
+
+ public Object m4(Method m, Object test, Object a, Object early_return) throws Exception {
+ return m.invoke(test, a, early_return);
+ }
+
+ static public A a = new A();
+ static public B b = new B();
+}
+
--- a/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java Fri Jul 11 09:14:21 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2014, 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 8031752
- * @summary speculative traps need to be cleaned up at GC
- * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx512M TestSpecTrapClassUnloading
- *
- */
-
-import java.lang.reflect.Method;
-
-public class TestSpecTrapClassUnloading {
- static class B {
- final public boolean m(Object o) {
- if (o.getClass() == B.class) {
- return true;
- }
- return false;
- }
- }
-
- static class MemoryChunk {
- MemoryChunk other;
- long[] array;
- MemoryChunk(MemoryChunk other) {
- this.other = other;
- array = new long[1024 * 1024 * 1024];
- }
- }
-
- static void m1(B b, Object o) {
- b.m(o);
- }
-
- static void m2(B b, Object o) {
- b.m(o);
- }
-
- public static void main(String[] args) throws Exception {
- Method m = B.class.getMethod("m", Object.class);
- Object o = new Object();
- B b = new B();
-
- // add speculative trap in B.m() for m1
- for (int i = 0; i < 20000; i++) {
- m1(b, b);
- }
- m1(b, o);
-
- // add speculative trap in B.m() for code generated by reflection
- for (int i = 0; i < 20000; i++) {
- m.invoke(b, b);
- }
- m.invoke(b, o);
-
- m = null;
-
- // add speculative trap in B.m() for m2
- for (int i = 0; i < 20000; i++) {
- m2(b, b);
- }
- m2(b, o);
-
- // Exhaust memory which causes the code generated by
- // reflection to be unloaded but B.m() is not.
- MemoryChunk root = null;
- try {
- while (true) {
- root = new MemoryChunk(root);
- }
- } catch(OutOfMemoryError e) {
- root = null;
- }
- }
-}