-
Bug
-
Resolution: Fixed
-
P2
-
repo-valhalla
The substitutability check is currently broken when null-restricted are not flat.
Here's an example:
import jdk.internal.vm.annotation.ImplicitlyConstructible;
import jdk.internal.vm.annotation.NullRestricted;
import jdk.internal.value.ValueClass;
public class EQTest {
@ImplicitlyConstructible
static value class EmptyValue {
}
@ImplicitlyConstructible
static value class EmptyContainer {
@NullRestricted
EmptyValue ev = new EmptyValue();
}
public static void main(String[] args) {
EmptyContainer ec0 = new EmptyContainer();
EmptyContainer ec1 = new EmptyContainer();
System.out.println(ec0 == ec1);
EmptyContainer[] array = (EmptyContainer[])ValueClass.newNullRestrictedArray(EmptyContainer.class, 10);
System.out.println(ec0 == array[0]);
System.out.println(ec0.ev == array[0].ev);
}
}
When executing with field flattening:
$ ./build/lworld/images/jdk/bin/java --enable-preview --add-exports java.base/jdk.internal.value=ALL-UNNAMED -XX:+UseFieldFlattening EQTest
true
true
true
When executing without field flattening:
$ ./build/lworld/images/jdk/bin/java --enable-preview --add-exports java.base/jdk.internal.value=ALL-UNNAMED -XX:-UseFieldFlattening EQTest
true
false
true
The issue is in the handling of the null-restricted non-flat ev. When an instance of EmptyContainer is created through a constructor, this field is initialized with a reference to a heap buffered value. However, when a null-free array of EmptyContainer values is created, the elements are initialized with the all-zero instance, meaning the ev field contains the null reference. The VM used to detect this situation and substitute the null reference with the default value of the field's class.
This behavior is likely to have been removed byJDK-8348904. The complete removal of the concept of default value cannot be performed until all the pieces of the replacement feature (guaranteed initialization though strict fields and new array factories) have been pushed into the repo.
Here's an example:
import jdk.internal.vm.annotation.ImplicitlyConstructible;
import jdk.internal.vm.annotation.NullRestricted;
import jdk.internal.value.ValueClass;
public class EQTest {
@ImplicitlyConstructible
static value class EmptyValue {
}
@ImplicitlyConstructible
static value class EmptyContainer {
@NullRestricted
EmptyValue ev = new EmptyValue();
}
public static void main(String[] args) {
EmptyContainer ec0 = new EmptyContainer();
EmptyContainer ec1 = new EmptyContainer();
System.out.println(ec0 == ec1);
EmptyContainer[] array = (EmptyContainer[])ValueClass.newNullRestrictedArray(EmptyContainer.class, 10);
System.out.println(ec0 == array[0]);
System.out.println(ec0.ev == array[0].ev);
}
}
When executing with field flattening:
$ ./build/lworld/images/jdk/bin/java --enable-preview --add-exports java.base/jdk.internal.value=ALL-UNNAMED -XX:+UseFieldFlattening EQTest
true
true
true
When executing without field flattening:
$ ./build/lworld/images/jdk/bin/java --enable-preview --add-exports java.base/jdk.internal.value=ALL-UNNAMED -XX:-UseFieldFlattening EQTest
true
false
true
The issue is in the handling of the null-restricted non-flat ev. When an instance of EmptyContainer is created through a constructor, this field is initialized with a reference to a heap buffered value. However, when a null-free array of EmptyContainer values is created, the elements are initialized with the all-zero instance, meaning the ev field contains the null reference. The VM used to detect this situation and substitute the null reference with the default value of the field's class.
This behavior is likely to have been removed by
- links to
-
Commit(lworld) openjdk/valhalla/ca409f88
-
Review(lworld) openjdk/valhalla/1383