Bug 232487 - [1.5][compiler] Casting mode of JDT compiler is different to Suns javac
Summary: [1.5][compiler] Casting mode of JDT compiler is different to Suns javac
Status: VERIFIED INVALID
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.4 RC2   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-05-16 08:36 EDT by Roland CLA
Modified: 2008-05-30 08:08 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Roland CLA 2008-05-16 08:36:49 EDT
Build ID: I20080502-0100

Steps To Reproduce:
Compile any source like:

Source Code:
  ArrayList<ContingentDAO> contingentDAOs = new ArrayList<ContingentDAO>();
  for (IContingentDAO contingentDAO : contingentDAOs) {

Tested under Eclipse 3.3 and 3.4 and jdk 1.5

More information:
Source Code:
  ArrayList<ContingentDAO> contingentDAOs = new ArrayList<ContingentDAO>();
  for (IContingentDAO contingentDAO : contingentDAOs) {

results in compiled code:

Sun javac code:
  Iterator i$ = contingentDAOs.iterator();
  do {
    if(!i$.hasNext())
      break;
      IContingentDAO contingentDAO = (ContingentDAO)i$.next();

Eclipse compiler code:
  if(contingentDAOs.size() > 0) {
    for(Iterator iterator1 = contingentDAOs.iterator(); iterator1.hasNext();) {
      IContingentDAO contingentDAO = (IContingentDAO)iterator1.next();

as you see Sunn casts to the type given by the ArrayList and
eclipse casts to the type given in the for (...)
Comment 1 Philipe Mulet CLA 2008-05-16 12:24:36 EDT
Maxime - pls make some investigation if this would have been a recent change in javac.

On such code, I am noticing strange behavior from javac:
import java.util.*;

public class X implements Runnable {
	public void run() {/**/}
	void foo() {
		  List<X> runnables = new ArrayList<X>();
		  for (Runnable r : runnables) {
			  r.run();
		  }
		  Object o = runnables.get(0);//#1
		  X x = runnables.get(1);//#2
	}
}

It doesn't insert a cast to Object for (#1), but it does for (#2).

  void foo();
     0  new ArrayList [2]
     3  dup
     4  invokespecial ArrayList() [3]
     7  astore_1
     8  aload_1
     9  invokeinterface List.iterator() : Iterator [4] [nargs: 1]
    14  astore_2
    15  aload_2
    16  invokeinterface Iterator.hasNext() : boolean [5] [nargs: 1]
    21  ifeq 43
    24  aload_2
    25  invokeinterface Iterator.next() : Object [6] [nargs: 1]
    30  checkcast X [7]
    33  astore_3
    34  aload_3
    35  invokeinterface Runnable.run() : void [8] [nargs: 1]
    40  goto 15
    43  aload_1
    44  iconst_0
    45  invokeinterface List.get(int) : Object [9] [nargs: 2]
    50  astore_2
    51  aload_1
    52  iconst_1
    53  invokeinterface List.get(int) : Object [9] [nargs: 2]
    58  checkcast X [7]
    61  astore_3
    62  return

Our implementation does only insert the minimal cast required to match expectation. In these cases, no cast is needed for cast to Object, and for matching Runnable, no need to cast to X.
Comment 2 Philipe Mulet CLA 2008-05-16 12:28:16 EDT
We do produce:

  void foo();
     0  new ArrayList [18]
     3  dup
     4  invokespecial ArrayList() [20]
     7  astore_1 [runnables]
     8  aload_1 [runnables]
     9  invokeinterface List.iterator() : Iterator [21] [nargs: 1]
    14  astore_3
    15  goto 34
    18  aload_3
    19  invokeinterface Iterator.next() : Object [27] [nargs: 1]
    24  checkcast Runnable [5]
    27  astore_2 [r]
    28  aload_2 [r]
    29  invokeinterface Runnable.run() : void [33] [nargs: 1]
    34  aload_3
    35  invokeinterface Iterator.hasNext() : boolean [35] [nargs: 1]
    40  ifne 18
    43  aload_1 [runnables]
    44  iconst_0
    45  invokeinterface List.get(int) : Object [39] [nargs: 2]
    50  pop
    51  aload_1 [runnables]
    52  iconst_1
    53  invokeinterface List.get(int) : Object [39] [nargs: 2]
    58  checkcast X [1]
    61  pop
    62  return
Comment 3 Philipe Mulet CLA 2008-05-16 12:33:47 EDT
Oops - my previous testcase was wrong.
Trying again.

import java.util.*;

public class X implements Runnable {
	public void run() {/**/}
	void foo() {
		  List<X> runnables = new ArrayList<X>();
		  for (Runnable r : runnables) {
			  r.run();
		  }
		  Object o = runnables.get(0);
		  Runnable r = runnables.get(1);
	}
} 

JAVAC (1.6.0_10-beta) produces:
  void foo();
     0  new ArrayList [2]
     3  dup
     4  invokespecial ArrayList() [3]
     7  astore_1
     8  aload_1
     9  invokeinterface List.iterator() : Iterator [4] [nargs: 1]
    14  astore_2
    15  aload_2
    16  invokeinterface Iterator.hasNext() : boolean [5] [nargs: 1]
    21  ifeq 43
    24  aload_2
    25  invokeinterface Iterator.next() : Object [6] [nargs: 1]
    30  checkcast X [7]
    33  astore_3
    34  aload_3
    35  invokeinterface Runnable.run() : void [8] [nargs: 1]
    40  goto 15
    43  aload_1
    44  iconst_0
    45  invokeinterface List.get(int) : Object [9] [nargs: 2]
    50  astore_2
    51  aload_1
    52  iconst_1
    53  invokeinterface List.get(int) : Object [9] [nargs: 2]
    58  checkcast Runnable [10]
    61  astore_3
    62  return


where ECJ 3.4RC1 produces:
  void foo();
     0  new ArrayList [18]
     3  dup
     4  invokespecial ArrayList() [20]
     7  astore_1 [runnables]
     8  aload_1 [runnables]
     9  invokeinterface List.iterator() : Iterator [21] [nargs: 1]
    14  astore_3
    15  goto 34
    18  aload_3
    19  invokeinterface Iterator.next() : Object [27] [nargs: 1]
    24  checkcast Runnable [5]
    27  astore_2 [r]
    28  aload_2 [r]
    29  invokeinterface Runnable.run() : void [33] [nargs: 1]
    34  aload_3
    35  invokeinterface Iterator.hasNext() : boolean [35] [nargs: 1]
    40  ifne 18
    43  aload_1 [runnables]
    44  iconst_0
    45  invokeinterface List.get(int) : Object [39] [nargs: 2]
    50  pop
    51  aload_1 [runnables]
    52  iconst_1
    53  invokeinterface List.get(int) : Object [39] [nargs: 2]
    58  checkcast Runnable [5]
    61  pop
    62  return

i.e. we agree except for the foreach loop.

I could only explain the difference by the fact Javac misses the assignment conversion in for the current element in iteration !? i.e. their bug !

Comment 4 Philipe Mulet CLA 2008-05-16 12:41:11 EDT
I believe our behavior is the right one. Closing as Javac bug.
Hence marking as invalid.

Added GenericTypeTest#test1332
Comment 5 Maxime Daniel CLA 2008-05-19 03:39:38 EDT
Could find no matching javac bug (which is not that surprising given the fact that both strategies lead to runnable code). While the runtime behavior tolerates some interpretation, the specification puts more constraints on what should be done. The following test case leverages the definition of the foreach loop in the spec:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public abstract class X {
  public static void main(String... args) {
	List<Y> elements = new ArrayList<Y>();
	// foreach loop
	for (I element: elements) {
	  element.foo();
	}
	// translation of the foreach loop according to JLS 3 ยง 14.14.2
	for (Iterator<Y> i = elements.iterator(); i.hasNext(); ) {
	  I element = i.next();
	  element.foo();
	}
  }
}
interface I {
  void foo();
}
class Y implements I {
  public void foo() {
  }
  void bar() {
  }
}

Looking at the generated code, we are doing the same cast in both cases, while javac generates a cast to Y in the first loop, hence generating different code for two sources fragments deemed equivalent by the spec. While we will leave javac's people decide for themselves whether they have a bug or not, the equivalence argument proves our conforming to the spec.
Comment 6 Maxime Daniel CLA 2008-05-23 05:49:08 EDT
Verified for 3.4 RC2 using build I20080523-0100.
(Checked that the byte code of comment #5 still had the expected characteristics.)
Comment 7 Maxime Daniel CLA 2008-05-30 08:08:40 EDT
This must be a duplicate of bug 209779 indeed, which led to the same conclusions by a similar path. Following links from there, found out that javac bug has been identified since as http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500701.