Since JDK-8374639, the following test starts failing when archived in dynamic CDS archive
class ArraySuperApp implements Predicate {
static volatile Object array;
public boolean test(Object o) {
return true;
}
static void main(String args[]) {
array = new ArraySuperApp[1];
if (args.length > 0) {
Predicate[] p = new Predicate[0];
System.out.println(p.getClass().isInstance(array)); // prints false, should be true
p = (Predicate[])array; // checked cast exception
p[0] = new ArraySuperApp();
System.out.println("All tests passed");
}
}
}
In the dynamic archive, we archive ArraySuperApp[] because ArraySuperApp is also in the dynamic archive. However, in the Klass::_secondary_supers for ArraySuperApp[], we have an ArrayKlass of Predicate[].
However, the InstanceKlass of Predicate is in the static array and does not have an archived Predicate[]. When InstanceKlass::array_klass() is called on the Predicate class, it allocates a different array ArrayKlass of Predicate[].
As a result, the Klass::_secondary_supers for ArraySuperApp[] does not contain the actually used version of Predicate[]. As a result, the checkcast bytecode fails.
***************
Proposed fix -- exclude all ArrayKlasses from the dynamic archive. ArrayKlasses are easy to allocate at runtime, so it's not with the complexity for making the above test case work while still archive some ArrayKlasses in the dynamic archive.
(Note: ArrayKlasses are required in the static archive (or AOT cache) which has the ability of caching Java heap objects. An archived Java array would require its klass to also be cached. Since the dynamic archive doesn't cache Java heap objects, there is no such requirement).
class ArraySuperApp implements Predicate {
static volatile Object array;
public boolean test(Object o) {
return true;
}
static void main(String args[]) {
array = new ArraySuperApp[1];
if (args.length > 0) {
Predicate[] p = new Predicate[0];
System.out.println(p.getClass().isInstance(array)); // prints false, should be true
p = (Predicate[])array; // checked cast exception
p[0] = new ArraySuperApp();
System.out.println("All tests passed");
}
}
}
In the dynamic archive, we archive ArraySuperApp[] because ArraySuperApp is also in the dynamic archive. However, in the Klass::_secondary_supers for ArraySuperApp[], we have an ArrayKlass of Predicate[].
However, the InstanceKlass of Predicate is in the static array and does not have an archived Predicate[]. When InstanceKlass::array_klass() is called on the Predicate class, it allocates a different array ArrayKlass of Predicate[].
As a result, the Klass::_secondary_supers for ArraySuperApp[] does not contain the actually used version of Predicate[]. As a result, the checkcast bytecode fails.
***************
Proposed fix -- exclude all ArrayKlasses from the dynamic archive. ArrayKlasses are easy to allocate at runtime, so it's not with the complexity for making the above test case work while still archive some ArrayKlasses in the dynamic archive.
(Note: ArrayKlasses are required in the static archive (or AOT cache) which has the ability of caching Java heap objects. An archived Java array would require its klass to also be cached. Since the dynamic archive doesn't cache Java heap objects, there is no such requirement).
- caused by
-
JDK-8374639 Static archive with AOTClassLinking breaks dynamic archive
-
- Resolved
-
- links to
-
Commit(master)
openjdk/jdk/7f2aa59f
-
Review(master)
openjdk/jdk/29356