-
Bug
-
Resolution: Fixed
-
P3
-
repo-valhalla
javac is inserting an useless checkcast when accessing fields of a primitive object through its reference projection.
Heres' an example:
public class CheckcastGetfieldTest {
static primitive class Point {
int x = 0, y = 0;
}
public static void main(String[] args) {
Point p0 = new Point();
int x0 = p0.x;
Point.ref p1 = null;
int x1 = p1.x;
}
}
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=5, args_size=1
0: invokestatic #7 // Method CheckcastGetfieldTest$Point."<init>":()QCheckcastGetfieldTest$Point;
3: astore_1
4: aload_1
5: getfield #12 // Field CheckcastGetfieldTest$Point.x:I
8: istore_2
9: aconst_null
10: astore_3
11: aload_3
12: checkcast #16 // class "QCheckcastGetfieldTest$Point;"
15: getfield #12 // Field CheckcastGetfieldTest$Point.x:I
18: istore 4
20: return
LineNumberTable:
line 7: 0
line 8: 4
line 9: 9
line 10: 11
line 11: 20
This checkcast was required when the value projection and the reference projection of a primitive object were two different classes. The class of the reference projection had no fields, so the reference had to be down casted to the value projection where the fields were declared.
But with a L/Q model, where there's single class for both projections, such checkcast is not required anymore. This is visible on the field reference of the getfield: "CheckcastGetfieldTest$Point.x:I" where only the class is specified, not the projection (nor LCheckcastGetfieldTest$Point.x:I; or QCheckcastGetfieldTest$Point.x:I;).
In case the reference projection is the null reference, gtefield will throw a NullPointerException as it always do for null receivers (same behavior as for identity classes).
This doesn't change the requirement to insert a checkcast when casting from one projection to the other (especially when casting the reference projection to the value projection as a null check is required).
An open question is: should withfield be allowed to operate on the reference projection too, and include a null check on the receiver?
Heres' an example:
public class CheckcastGetfieldTest {
static primitive class Point {
int x = 0, y = 0;
}
public static void main(String[] args) {
Point p0 = new Point();
int x0 = p0.x;
Point.ref p1 = null;
int x1 = p1.x;
}
}
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=5, args_size=1
0: invokestatic #7 // Method CheckcastGetfieldTest$Point."<init>":()QCheckcastGetfieldTest$Point;
3: astore_1
4: aload_1
5: getfield #12 // Field CheckcastGetfieldTest$Point.x:I
8: istore_2
9: aconst_null
10: astore_3
11: aload_3
12: checkcast #16 // class "QCheckcastGetfieldTest$Point;"
15: getfield #12 // Field CheckcastGetfieldTest$Point.x:I
18: istore 4
20: return
LineNumberTable:
line 7: 0
line 8: 4
line 9: 9
line 10: 11
line 11: 20
This checkcast was required when the value projection and the reference projection of a primitive object were two different classes. The class of the reference projection had no fields, so the reference had to be down casted to the value projection where the fields were declared.
But with a L/Q model, where there's single class for both projections, such checkcast is not required anymore. This is visible on the field reference of the getfield: "CheckcastGetfieldTest$Point.x:I" where only the class is specified, not the projection (nor LCheckcastGetfieldTest$Point.x:I; or QCheckcastGetfieldTest$Point.x:I;).
In case the reference projection is the null reference, gtefield will throw a NullPointerException as it always do for null receivers (same behavior as for identity classes).
This doesn't change the requirement to insert a checkcast when casting from one projection to the other (especially when casting the reference projection to the value projection as a null check is required).
An open question is: should withfield be allowed to operate on the reference projection too, and include a null check on the receiver?