Tue, 08 Apr 2014 09:51:25 +0200
8038636: speculative traps break when classes are redefined
Summary: remove speculative traps that point to methods that are redefined
Reviewed-by: kvn, twisti
1.1 --- a/src/share/vm/oops/instanceKlass.cpp Thu Mar 22 21:47:01 2018 -0400 1.2 +++ b/src/share/vm/oops/instanceKlass.cpp Tue Apr 08 09:51:25 2014 +0200 1.3 @@ -3682,6 +3682,10 @@ 1.4 ("purge: %s(%s): prev method @%d in version @%d is alive", 1.5 method->name()->as_C_string(), 1.6 method->signature()->as_C_string(), j, i)); 1.7 + if (method->method_data() != NULL) { 1.8 + // Clean out any weak method links 1.9 + method->method_data()->clean_weak_method_links(); 1.10 + } 1.11 } 1.12 } 1.13 } 1.14 @@ -3691,6 +3695,14 @@ 1.15 ("purge: previous version stats: live=%d, deleted=%d", live_count, 1.16 deleted_count)); 1.17 } 1.18 + 1.19 + Array<Method*>* methods = ik->methods(); 1.20 + int num_methods = methods->length(); 1.21 + for (int index2 = 0; index2 < num_methods; ++index2) { 1.22 + if (methods->at(index2)->method_data() != NULL) { 1.23 + methods->at(index2)->method_data()->clean_weak_method_links(); 1.24 + } 1.25 + } 1.26 } 1.27 1.28 // External interface for use during class unloading.
2.1 --- a/src/share/vm/oops/methodData.cpp Thu Mar 22 21:47:01 2018 -0400 2.2 +++ b/src/share/vm/oops/methodData.cpp Tue Apr 08 09:51:25 2014 +0200 2.3 @@ -1559,9 +1559,35 @@ 2.4 } 2.5 } 2.6 2.7 -// Remove SpeculativeTrapData entries that reference an unloaded 2.8 -// method 2.9 -void MethodData::clean_extra_data(BoolObjectClosure* is_alive) { 2.10 +class CleanExtraDataClosure : public StackObj { 2.11 +public: 2.12 + virtual bool is_live(Method* m) = 0; 2.13 +}; 2.14 + 2.15 +// Check for entries that reference an unloaded method 2.16 +class CleanExtraDataKlassClosure : public CleanExtraDataClosure { 2.17 +private: 2.18 + BoolObjectClosure* _is_alive; 2.19 +public: 2.20 + CleanExtraDataKlassClosure(BoolObjectClosure* is_alive) : _is_alive(is_alive) {} 2.21 + bool is_live(Method* m) { 2.22 + return m->method_holder()->is_loader_alive(_is_alive); 2.23 + } 2.24 +}; 2.25 + 2.26 +// Check for entries that reference a redefined method 2.27 +class CleanExtraDataMethodClosure : public CleanExtraDataClosure { 2.28 +public: 2.29 + CleanExtraDataMethodClosure() {} 2.30 + bool is_live(Method* m) { 2.31 + return m->on_stack(); 2.32 + } 2.33 +}; 2.34 + 2.35 + 2.36 +// Remove SpeculativeTrapData entries that reference an unloaded or 2.37 +// redefined method 2.38 +void MethodData::clean_extra_data(CleanExtraDataClosure* cl) { 2.39 DataLayout* dp = extra_data_base(); 2.40 DataLayout* end = extra_data_limit(); 2.41 2.42 @@ -1572,7 +1598,7 @@ 2.43 SpeculativeTrapData* data = new SpeculativeTrapData(dp); 2.44 Method* m = data->method(); 2.45 assert(m != NULL, "should have a method"); 2.46 - if (!m->method_holder()->is_loader_alive(is_alive)) { 2.47 + if (!cl->is_live(m)) { 2.48 // "shift" accumulates the number of cells for dead 2.49 // SpeculativeTrapData entries that have been seen so 2.50 // far. Following entries must be shifted left by that many 2.51 @@ -1603,9 +1629,9 @@ 2.52 } 2.53 } 2.54 2.55 -// Verify there's no unloaded method referenced by a 2.56 +// Verify there's no unloaded or redefined method referenced by a 2.57 // SpeculativeTrapData entry 2.58 -void MethodData::verify_extra_data_clean(BoolObjectClosure* is_alive) { 2.59 +void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) { 2.60 #ifdef ASSERT 2.61 DataLayout* dp = extra_data_base(); 2.62 DataLayout* end = extra_data_limit(); 2.63 @@ -1615,7 +1641,7 @@ 2.64 case DataLayout::speculative_trap_data_tag: { 2.65 SpeculativeTrapData* data = new SpeculativeTrapData(dp); 2.66 Method* m = data->method(); 2.67 - assert(m != NULL && m->method_holder()->is_loader_alive(is_alive), "Method should exist"); 2.68 + assert(m != NULL && cl->is_live(m), "Method should exist"); 2.69 break; 2.70 } 2.71 case DataLayout::bit_data_tag: 2.72 @@ -1641,6 +1667,19 @@ 2.73 parameters->clean_weak_klass_links(is_alive); 2.74 } 2.75 2.76 - clean_extra_data(is_alive); 2.77 - verify_extra_data_clean(is_alive); 2.78 + CleanExtraDataKlassClosure cl(is_alive); 2.79 + clean_extra_data(&cl); 2.80 + verify_extra_data_clean(&cl); 2.81 } 2.82 + 2.83 +void MethodData::clean_weak_method_links() { 2.84 + for (ProfileData* data = first_data(); 2.85 + is_valid(data); 2.86 + data = next_data(data)) { 2.87 + data->clean_weak_method_links(); 2.88 + } 2.89 + 2.90 + CleanExtraDataMethodClosure cl; 2.91 + clean_extra_data(&cl); 2.92 + verify_extra_data_clean(&cl); 2.93 +}
3.1 --- a/src/share/vm/oops/methodData.hpp Thu Mar 22 21:47:01 2018 -0400 3.2 +++ b/src/share/vm/oops/methodData.hpp Tue Apr 08 09:51:25 2014 +0200 3.3 @@ -251,6 +251,9 @@ 3.4 3.5 // GC support 3.6 void clean_weak_klass_links(BoolObjectClosure* cl); 3.7 + 3.8 + // Redefinition support 3.9 + void clean_weak_method_links(); 3.10 }; 3.11 3.12 3.13 @@ -508,6 +511,9 @@ 3.14 // GC support 3.15 virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {} 3.16 3.17 + // Redefinition support 3.18 + virtual void clean_weak_method_links() {} 3.19 + 3.20 // CI translation: ProfileData can represent both MethodDataOop data 3.21 // as well as CIMethodData data. This function is provided for translating 3.22 // an oop in a ProfileData to the ci equivalent. Generally speaking, 3.23 @@ -2030,6 +2036,7 @@ 3.24 // 3.25 3.26 CC_INTERP_ONLY(class BytecodeInterpreter;) 3.27 +class CleanExtraDataClosure; 3.28 3.29 class MethodData : public Metadata { 3.30 friend class VMStructs; 3.31 @@ -2183,9 +2190,9 @@ 3.32 static bool profile_parameters_jsr292_only(); 3.33 static bool profile_all_parameters(); 3.34 3.35 - void clean_extra_data(BoolObjectClosure* is_alive); 3.36 + void clean_extra_data(CleanExtraDataClosure* cl); 3.37 void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false); 3.38 - void verify_extra_data_clean(BoolObjectClosure* is_alive); 3.39 + void verify_extra_data_clean(CleanExtraDataClosure* cl); 3.40 3.41 public: 3.42 static int header_size() { 3.43 @@ -2477,6 +2484,8 @@ 3.44 static bool profile_return_jsr292_only(); 3.45 3.46 void clean_method_data(BoolObjectClosure* is_alive); 3.47 + 3.48 + void clean_weak_method_links(); 3.49 }; 3.50 3.51 #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/compiler/profiling/spectrapredefineclass/Agent.java Tue Apr 08 09:51:25 2014 +0200 4.3 @@ -0,0 +1,142 @@ 4.4 +/* 4.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. 4.11 + * 4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.15 + * version 2 for more details (a copy is included in the LICENSE file that 4.16 + * accompanied this code). 4.17 + * 4.18 + * You should have received a copy of the GNU General Public License version 4.19 + * 2 along with this work; if not, write to the Free Software Foundation, 4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.21 + * 4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.23 + * or visit www.oracle.com if you need additional information or have any 4.24 + * questions. 4.25 + */ 4.26 + 4.27 +import java.security.*; 4.28 +import java.lang.instrument.*; 4.29 +import java.lang.reflect.*; 4.30 +import java.lang.management.ManagementFactory; 4.31 +import com.sun.tools.attach.VirtualMachine; 4.32 + 4.33 +class A { 4.34 + void m() { 4.35 + } 4.36 +} 4.37 + 4.38 +class B extends A { 4.39 + void m() { 4.40 + } 4.41 +} 4.42 + 4.43 +class C extends A { 4.44 + void m() { 4.45 + } 4.46 +} 4.47 + 4.48 +class Test { 4.49 + 4.50 + static public void m() throws Exception { 4.51 + for (int i = 0; i < 20000; i++) { 4.52 + m1(a); 4.53 + } 4.54 + for (int i = 0; i < 4; i++) { 4.55 + m1(b); 4.56 + } 4.57 + } 4.58 + 4.59 + static boolean m1(A a) { 4.60 + boolean res = Agent.m2(a); 4.61 + return res; 4.62 + } 4.63 + 4.64 + static public A a = new A(); 4.65 + static public B b = new B(); 4.66 + static public C c = new C(); 4.67 +} 4.68 + 4.69 +public class Agent implements ClassFileTransformer { 4.70 + 4.71 + 4.72 + static class MemoryChunk { 4.73 + MemoryChunk other; 4.74 + long[] array; 4.75 + MemoryChunk(MemoryChunk other) { 4.76 + other = other; 4.77 + array = new long[1024 * 1024 * 1024]; 4.78 + } 4.79 + } 4.80 + 4.81 + static public boolean m2(A a) { 4.82 + boolean res = false; 4.83 + if (a.getClass() == B.class) { 4.84 + a.m(); 4.85 + } else { 4.86 + res = true; 4.87 + } 4.88 + return res; 4.89 + } 4.90 + 4.91 + static public void main(String[] args) throws Exception { 4.92 + // Create speculative trap entries 4.93 + Test.m(); 4.94 + 4.95 + String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName(); 4.96 + int p = nameOfRunningVM.indexOf('@'); 4.97 + String pid = nameOfRunningVM.substring(0, p); 4.98 + 4.99 + // Make the nmethod go away 4.100 + for (int i = 0; i < 10; i++) { 4.101 + System.gc(); 4.102 + } 4.103 + 4.104 + // Redefine class 4.105 + try { 4.106 + VirtualMachine vm = VirtualMachine.attach(pid); 4.107 + vm.loadAgent(System.getProperty("test.classes",".") + "/agent.jar", ""); 4.108 + vm.detach(); 4.109 + } catch (Exception e) { 4.110 + throw new RuntimeException(e); 4.111 + } 4.112 + 4.113 + Test.m(); 4.114 + // GC will hit dead method pointer 4.115 + for (int i = 0; i < 10; i++) { 4.116 + System.gc(); 4.117 + } 4.118 + } 4.119 + 4.120 + public synchronized byte[] transform(final ClassLoader classLoader, 4.121 + final String className, 4.122 + Class<?> classBeingRedefined, 4.123 + ProtectionDomain protectionDomain, 4.124 + byte[] classfileBuffer) { 4.125 + System.out.println("Transforming class " + className); 4.126 + return classfileBuffer; 4.127 + } 4.128 + 4.129 + public static void redefine(String agentArgs, Instrumentation instrumentation, Class to_redefine) { 4.130 + 4.131 + try { 4.132 + instrumentation.retransformClasses(to_redefine); 4.133 + } catch (Exception e) { 4.134 + e.printStackTrace(); 4.135 + } 4.136 + 4.137 + } 4.138 + 4.139 + public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception { 4.140 + Agent transformer = new Agent(); 4.141 + instrumentation.addTransformer(transformer, true); 4.142 + 4.143 + redefine(agentArgs, instrumentation, Test.class); 4.144 + } 4.145 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/compiler/profiling/spectrapredefineclass/Launcher.java Tue Apr 08 09:51:25 2014 +0200 5.3 @@ -0,0 +1,47 @@ 5.4 +/* 5.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + */ 5.26 +import java.io.PrintWriter; 5.27 +import com.oracle.java.testlibrary.*; 5.28 + 5.29 +/* 5.30 + * @test 5.31 + * @bug 8038636 5.32 + * @library /testlibrary 5.33 + * @build Agent 5.34 + * @run main ClassFileInstaller Agent 5.35 + * @run main Launcher 5.36 + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -Xmx1M -XX:ReservedCodeCacheSize=3M Agent 5.37 + */ 5.38 +public class Launcher { 5.39 + public static void main(String[] args) throws Exception { 5.40 + 5.41 + PrintWriter pw = new PrintWriter("MANIFEST.MF"); 5.42 + pw.println("Agent-Class: Agent"); 5.43 + pw.println("Can-Retransform-Classes: true"); 5.44 + pw.close(); 5.45 + 5.46 + ProcessBuilder pb = new ProcessBuilder(); 5.47 + pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), "cmf", "MANIFEST.MF", System.getProperty("test.classes",".") + "/agent.jar", "Agent.class"}); 5.48 + pb.start().waitFor(); 5.49 + } 5.50 +}