Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6610906

inexplicable IncompatibleClassChangeError

    XMLWordPrintable

    Details

    • Subcomponent:
    • Introduced In Build:
      b05
    • Introduced In Version:
    • Resolved In Build:
      b02
    • CPU:
      generic, x86
    • OS:
      generic, linux, solaris
    • Verification:
      Not verified

      Backports

        Description

        Following test case is failing from JDK7 build 20

        <testcase>
        import java.util.*;

        public class VectorIntegerTest {
            static Random rnd = new Random();
            public static void main(String[] args) throws Exception {
        List<Integer> list1 = new Vector<Integer>();
        AddRandoms(list1, 400);
        List<Integer> list2 = new Vector<Integer>();
        AddRandoms(list2, 400);

        List<Integer> copyofs2 = new Vector<Integer>();
        copyofs2.addAll(list2);

        if (!list2.equals(copyofs2))
        throw new Exception("Exception");

        list1.clear();
        list1.addAll(0,list2);

        if (!(list1.equals(list2) && list2.equals(list1)))
        throw new Exception ("Exception");

        if (!(list1.equals(list2) && list2.equals(list1)))
        throw new Exception("Exception");

        List<Integer> l = new Vector<Integer>();
        AddRandoms(l,400);
        Integer [] ia = l.toArray(new Integer[0]);
        if (!l.equals(Arrays.asList(ia)))
        throw new Exception("Exception");
            }

            static void AddRandoms(List<Integer> s, int n) throws Exception {
        for (int i=0; i<n; i++) {
        int r = rnd.nextInt() % n;
        Integer e = new Integer(r < 0 ? -r : r);
        s.add(e);
        }
           }
        }
        </testcase>

        <output>
        bash-3.00$ /net/sqindia/export/disk09/jdk/7/b17/binaries/solsparc/bin/java VectorIntegerTest
        bash-3.00$ /net/sqindia/export/disk09/jdk/7/b18/binaries/solsparc/bin/java VectorIntegerTest
        bash-3.00$ /net/sqindia/export/disk09/jdk/7/b19/binaries/solsparc/bin/java VectorIntegerTest

        **** failing from build 20 ******

        bash-3.00$ /net/sqindia/export/disk09/jdk/7/b20/binaries/solsparc/bin/java VectorIntegerTest
        Exception in thread "main" java.lang.IncompatibleClassChangeError
                at java.util.AbstractList.equals(AbstractList.java:522)
                at java.util.Vector.equals(Vector.java:953)
                at VectorIntegerTest.VectorIntegerTestTest01(VectorIntegerTest.java:63)
                at VectorIntegerTest.main(VectorIntegerTest.java:9)
        bash-3.00$ /net/sqindia/export/disk09/jdk/7/b21/binaries/solsparc/bin/java VectorIntegerTest
        Exception in thread "main" java.lang.IncompatibleClassChangeError
                at java.util.AbstractList.equals(AbstractList.java:522)
                at java.util.Vector.equals(Vector.java:953)
                at VectorIntegerTest.VectorIntegerTestTest01(VectorIntegerTest.java:63)
                at VectorIntegerTest.main(VectorIntegerTest.java:9)
        </output>
        Additional comments and test case from Christian Wimmer (###@###.###) from the C1 collaborative research project (also on the bugs.sun.com public database):

        I get a similar bug: the "eclipse" benchmark of the DaCapo benchmark suite fails with the latest JDK 7 builds (starting with build b20 which changed the handling of dependencies). In debug builds, a message is printed that a method should have been marked for deoptimization, but was not marked by the optimized dependency checking code.

        I could reduce the problem to the small testcase that is attached. The Interface has two implementations: the classes Impl1 and Impl2. At first, only Impl1 is loaded, so the method of the interface call can be inlined because there is only one implementation. When the second implementation is loaded, the method must be deoptimized.

        The second class Impl2 implements the Interface, but the method is already defined in the base class BaseImpl2. The optimized dependency checking code only looks at the methods defined in Impl2, does not see the method, and therefore does not trigger deoptimization. The slow verification code of the debug build detects the inconsistency and prints an error (I would prefer an assertion in such cases).



        A possible fix would be to also look at methods defined in superclasses. When the line 753 in the file dependencies.cpp is changed from

          methodOop m = instanceKlass::cast(k)->find_method(_name, _signature);
           
        to

          methodOop m = instanceKlass::cast(k)->uncached_lookup_method(_name, _signature);
          
        the dependency checking is correct in my example. However, I do not know if this change causes other problems (it could detect too many conflicts) or is too slow.

        [Follow-up from Christian: My nightly benchmarks revealed that my possible fix of the bug is too conservative. It literally kills the performance of some benchmarks, e.g. _227_mtrt is more than 50% slower because many accessor methods are no longer inlined. So just forget my suggestion...]

        public class DependencyBug {

          public static interface Interface {
            public void method();
          }
          
          public static class Impl1 implements Interface {
            public void method() {
              // Nothing to do here
            }
          }
          
          public static class BaseImpl2 {
            public void method() {
              System.out.print("#");
            }
          }

          public static class Impl2 extends BaseImpl2 implements Interface {
            // Interface method already implemented in base class.
          }

          
         
          public static void callMethod(Interface obj) {
            // method() is inlined as long as only class Impl1() is loaded.
            obj.method();
          }
          
          public static void main(String[] args) throws Exception {
            
            Interface obj = new Impl1();
            for (int i = 0; i < 2000; i++) {
              // Force compilation of the method callMethod()
              callMethod(obj);
            }
            
            System.out.println("**** Initiating class loading of Impl2 ****");
            
            obj = new Impl2();
            callMethod(obj);
          }
        }
        JDK: 7, 6u10 b09
        testbase: /net/cady/export/dtf/unified/knight-ws/suites/6.0_cady/libs
        Failing testcases:
        java_util/generics/list/LinkedListDoubleTest
        java_util/generics/list/LinkedListIntegerTest
        failing cases:
        java_util/generics/list/VectorIntegerTest
        java_util/generics/list/VectorDoubleTest
        java_util/generics/list/ArrayListDoubleTest
        java_util/generics/list/ArrayListIntegerTest
        java_util/generics/list/StackDoubleTest
        java_util/generics/list/StackIntegerTest

          Attachments

            Issue Links

              Activity

                People

                Assignee:
                jrose John Rose
                Reporter:
                savadhansunw Seetharama Avadhanam (Inactive)
                Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                  Dates

                  Created:
                  Updated:
                  Resolved:
                  Imported:
                  Indexed: