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

qualifying types for Object methods from interfaces

    Details

    • Subcomponent:
    • Understanding:
      Cause Known
    • CPU:
      generic
    • OS:
      solaris_8

      Description

      Date: Sat, 03 Jan 2004 08:32:36 -0700
      Wrom: EXCAXZOWCONEUQZAAFXI
      Subject: [Java Spec Report] JLS 13.1 and qualifying types of method
      Sender: ###@###.###

      Jikes and javac 1.4.2 disagree about the qualifying type of Object methods
      emitted in classfiles. I argue that javac has a bug. According to JLS
      13.1, "a method named m declared in a (possibly distinct) class or interface
      D, we define the qualifying type of the method invocation as follows:
      If D is Object then the qualifying type of the expression is Object."

      interface I {}
      interface J extends I {
         String toString();
      }
      class A {}
      class B extends A implements J {
         public String toString() { return null; }
      }
      class C extends B {
         public static void main(String[] args) {
           C c = new C();
           A a = c;
           B b = c;
           I i = c;
           J j = c;
            // A does not declare toString, declaration is found in Object
            // since Object declares, emit Object
           a.toString(); // invokevirtual Object.toString
            // B declares toString
            // since Object does not declare, emit qualifying type (B)
           b.toString(); // invokevirtual B.toString
            // C does not declare toString, declaration is found in B
            // since Object does not declare, emit qualifying type (C)
           c.toString(); // invokevirtual C.toString
            // I does not declare toString, declaration implicit from Object
            // since Object declares, emit Object
           i.toString(); // invokevirtual Object.toString
            // J declares toString
            // javac: since toString is also declared in Object, emit Object
            // jikes: since Object does not declare, emit qualifying type (J)
           j.toString(); // ???
         }
      }

      Both jikes and javac have the same behavior for b and c. But javac emits
      'invokevirtual Object.toString' for j, while jikes emits 'invokeinterface
      J.toString'. According to my reading of the JLS, J declares toString, so
      javac is in error because the declaration of j.toString was not found in
      Object. Javac is inconsistent between its treatment of b and j.

      I do agree that invokeinterface is slower than invokevirtual, which is why
      javac would prefer to emit invokevirtual rather than invokeinterface. But
      if that is the case, the JLS needs to be reworded to accurately convey this
      desire. It should read something along the lines of "if method m has the
      same signature (ignoring throws clauses) as a method declared in Object,
      then the qualifying type of the expression is Object". And if this is the
      case, then both compilers should also emit Object.toString for b and c,
      rather than B.toString and C.toString.

      The following example shows that the qualifying type is detectable to binary
      compatibility, so there is either a bug in javac or in the specification
      (the point of JLS 13 is to make all compilers give the same behavior):
      First, compile these types:
      class Foo {
         public static void main(String[] args) {
           // neither compiler emits checkcast I, because C implements I
           // javac emits Object.toString, jikes emits I.toString
           System.out.println(((I) new C()).toString());
         }
      }
      interface I {
         String toString();
      }
      class C implements I {}

      Now, recompile just C:
      class C {}

      When done by javac, the program executes and prints C@107077e (or similar):
      because Foo has no reference to I, the fact that C no longer implements I is
      irrelevant. But when done by jikes, an IncompatibleClassChangeError is
      thrown, because the VM detects that Foo's reference to I is no longer valid
      for an object of type C.

        Attachments

          Activity

            People

            • Assignee:
              dlsmith Dan Smith
              Reporter:
              gafter Neal Gafter
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Imported:
                Indexed: