8038636: speculative traps break when classes are redefined

Tue, 08 Apr 2014 09:51:25 +0200

author
roland
date
Tue, 08 Apr 2014 09:51:25 +0200
changeset 9183
f95c67788f18
parent 9182
0f31f18d2241
child 9184
fbcbfd2753b5

8038636: speculative traps break when classes are redefined
Summary: remove speculative traps that point to methods that are redefined
Reviewed-by: kvn, twisti

src/share/vm/oops/instanceKlass.cpp file | annotate | diff | comparison | revisions
src/share/vm/oops/methodData.cpp file | annotate | diff | comparison | revisions
src/share/vm/oops/methodData.hpp file | annotate | diff | comparison | revisions
test/compiler/profiling/spectrapredefineclass/Agent.java file | annotate | diff | comparison | revisions
test/compiler/profiling/spectrapredefineclass/Launcher.java file | annotate | diff | comparison | revisions
     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 +}

mercurial