The current implementation of the CDS archive doesn't support flat arrays (instances of FlatArrayKlass).
The limitation can easily be observed when applying the following patch which enables use of flat arrays by default, causing some migrated value classes to use flat arrays instead of reference arrays.
diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp
index a346d55f016..e5daa8b3aee 100644
--- a/src/hotspot/share/cds/filemap.hpp
+++ b/src/hotspot/share/cds/filemap.hpp
@@ -107,7 +107,8 @@ class FileMapRegion: private CDSFileMapRegion {
f(InlineTypeReturnedAsFields) \
f(UseNonAtomicValueFlattening) \
f(UseAtomicValueFlattening) \
- f(UseNullableValueFlattening)
+ f(UseNullableValueFlattening) \
+ f(UseFlatArrayByDefault)
class CDSMustMatchFlags {
diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp
index 9f69f634175..14bf5c5ede1 100644
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp
@@ -291,8 +291,22 @@ JRT_END
JRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* current, ConstantPool* pool, int index, jint size))
Klass* klass = pool->klass_at(index, CHECK);
- arrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
- current->set_vm_result(obj);
+ if (!klass->is_inline_klass()) {
+ arrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
+ current->set_vm_result(obj);
+ return;
+ }
+ // Inline klasses case
+ klass->initialize(CHECK);
+ InlineKlass* vk = InlineKlass::cast(klass);
+ oop array = nullptr;
+ if (UseArrayFlattening && UseFlatArrayByDefault && vk->has_nullable_atomic_layout()) {
+ array = oopFactory::new_flatArray(vk, size, LayoutKind::NULLABLE_ATOMIC_FLAT, CHECK);
+ } else {
+ array = oopFactory::new_objArray(vk, size, CHECK);
+ }
+ current->set_vm_result(array);
+
JRT_END
JRT_ENTRY(void, InterpreterRuntime::flat_array_load(JavaThread* current, arrayOopDesc* array, int index))
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index 3bc4ad8720d..fe6fe057d6f 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -821,12 +821,15 @@ const int ObjectAlignmentInBytes = 8;
product(bool, UseNonAtomicValueFlattening, true, \
"Allow the JVM to flatten some non-atomic null-free values") \
\
- product(bool, UseNullableValueFlattening, false, \
+ product(bool, UseNullableValueFlattening, true, \
"Allow the JVM to flatten some nullable values") \
\
product(bool, UseAtomicValueFlattening, false, \
"Allow the JVM to flatten some atomic values") \
\
+ product(bool, UseFlatArrayByDefault, true, \
+ "Allow anewarray to allocate flat array") \
+ \
product(intx, FlatArrayElementMaxOops, 4, \
"Max nof embedded object references in an inline type to flatten, <0 no limit") \
When building the JDK with this patch, the creation of CDS archive fails with this error:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (valhalla/open/src/hotspot/share/cds/archiveBuilder.cpp:
810), pid=2132230, tid=2132351
# assert(k->is_instance_klass()) failed: must be
#
# JRE version: Java(TM) SE Runtime Environment (25.0) (fastdebug build 25-lworld5ea-LTS-2025-04-14-1221043.fred...)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (fastdebug 25-lworld5ea-LTS-2025-04-14-1221043.fred..., interpreted mod
e, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# V [libjvm.so+0x678c7d] ArchiveBuilder::make_klasses_shareable()+0x99d
#
The stack trace is:
Current thread (0x00007a29c81a9920): VMThread "VM Thread" [id=2132351, stack(0x00007a29b42f0000,0x00007a29b43f0000) (1024K)]
Stack: [0x00007a29b42f0000,0x00007a29b43f0000], sp=0x00007a29b43ee650, free space=1017k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so+0x678c7d] ArchiveBuilder::make_klasses_shareable()+0x99d (archiveBuilder.cpp:810)
V [libjvm.so+0x162c93e] VM_PopulateDumpSharedSpace::doit()+0x2ae (metaspaceShared.cpp:657)
V [libjvm.so+0x1bbcc9f] VM_Operation::evaluate()+0x18f (vmOperations.cpp:74)
V [libjvm.so+0x1bd83e6] VMThread::evaluate_operation(VM_Operation*)+0x156 (vmThread.cpp:282)
V [libjvm.so+0x1bd9363] VMThread::inner_execute(VM_Operation*)+0x423 (vmThread.cpp:426)
V [libjvm.so+0x1bd9504] VMThread::loop()+0x84 (vmThread.cpp:492)
V [libjvm.so+0x1bd9614] VMThread::run()+0x94 (vmThread.cpp:176)
V [libjvm.so+0x1ac5d06] Thread::call_run()+0xb6 (thread.cpp:231)
V [libjvm.so+0x174b438] thread_native_entry(Thread*)+0x128 (os_linux.cpp:877)
C [libc.so.6+0x9caa4]
Registers:
RAX=0x00007a29d2aae000, RBX=0x00007a287c2331f8, RCX=0x00007a29d1f2df85, RDX=0x00007a29d1f98e70
RSP=0x00007a29b43ee650, RBP=0x00007a29b43ee7b0, RSI=0x000000000000032a, RDI=0x00007a29d1fa2480
R8 =0x00007a29c81a9f50, R9 =0x0000000000000001, R10=0x0000000000000000, R11=0x0000000000000017
R12=0x00007a29d25bb5a4, R13=0x00007a29d1f25162, R14=0x00007a29d01fc7a0, R15=0x0000000000000099
RIP=0x00007a29d0878c7d, EFLAGS=0x0000000000010202, CSGSFS=0x002b000000000033, ERR=0x0000000000000006
TRAPNO=0x000000000000000e
Looking at the archive builder, here's the logic involved in make_klasses_shareable():
if (k->is_objArray_klass()) {
// InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
// on their array classes.
num_obj_array_klasses ++;
type = "array";
} else if (k->is_typeArray_klass()) {
num_type_array_klasses ++;
type = "array";
k->remove_unshareable_info();
} else {
assert(k->is_instance_klass(), " must be");
The logic handles objArrayKlasses, typeArrayKlasses, InstanceKlasses but not FlatArrayKlasses.
The limitation can easily be observed when applying the following patch which enables use of flat arrays by default, causing some migrated value classes to use flat arrays instead of reference arrays.
diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp
index a346d55f016..e5daa8b3aee 100644
--- a/src/hotspot/share/cds/filemap.hpp
+++ b/src/hotspot/share/cds/filemap.hpp
@@ -107,7 +107,8 @@ class FileMapRegion: private CDSFileMapRegion {
f(InlineTypeReturnedAsFields) \
f(UseNonAtomicValueFlattening) \
f(UseAtomicValueFlattening) \
- f(UseNullableValueFlattening)
+ f(UseNullableValueFlattening) \
+ f(UseFlatArrayByDefault)
class CDSMustMatchFlags {
diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp
index 9f69f634175..14bf5c5ede1 100644
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp
@@ -291,8 +291,22 @@ JRT_END
JRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* current, ConstantPool* pool, int index, jint size))
Klass* klass = pool->klass_at(index, CHECK);
- arrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
- current->set_vm_result(obj);
+ if (!klass->is_inline_klass()) {
+ arrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
+ current->set_vm_result(obj);
+ return;
+ }
+ // Inline klasses case
+ klass->initialize(CHECK);
+ InlineKlass* vk = InlineKlass::cast(klass);
+ oop array = nullptr;
+ if (UseArrayFlattening && UseFlatArrayByDefault && vk->has_nullable_atomic_layout()) {
+ array = oopFactory::new_flatArray(vk, size, LayoutKind::NULLABLE_ATOMIC_FLAT, CHECK);
+ } else {
+ array = oopFactory::new_objArray(vk, size, CHECK);
+ }
+ current->set_vm_result(array);
+
JRT_END
JRT_ENTRY(void, InterpreterRuntime::flat_array_load(JavaThread* current, arrayOopDesc* array, int index))
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index 3bc4ad8720d..fe6fe057d6f 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -821,12 +821,15 @@ const int ObjectAlignmentInBytes = 8;
product(bool, UseNonAtomicValueFlattening, true, \
"Allow the JVM to flatten some non-atomic null-free values") \
\
- product(bool, UseNullableValueFlattening, false, \
+ product(bool, UseNullableValueFlattening, true, \
"Allow the JVM to flatten some nullable values") \
\
product(bool, UseAtomicValueFlattening, false, \
"Allow the JVM to flatten some atomic values") \
\
+ product(bool, UseFlatArrayByDefault, true, \
+ "Allow anewarray to allocate flat array") \
+ \
product(intx, FlatArrayElementMaxOops, 4, \
"Max nof embedded object references in an inline type to flatten, <0 no limit") \
When building the JDK with this patch, the creation of CDS archive fails with this error:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (valhalla/open/src/hotspot/share/cds/archiveBuilder.cpp:
810), pid=2132230, tid=2132351
# assert(k->is_instance_klass()) failed: must be
#
# JRE version: Java(TM) SE Runtime Environment (25.0) (fastdebug build 25-lworld5ea-LTS-2025-04-14-1221043.fred...)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (fastdebug 25-lworld5ea-LTS-2025-04-14-1221043.fred..., interpreted mod
e, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# V [libjvm.so+0x678c7d] ArchiveBuilder::make_klasses_shareable()+0x99d
#
The stack trace is:
Current thread (0x00007a29c81a9920): VMThread "VM Thread" [id=2132351, stack(0x00007a29b42f0000,0x00007a29b43f0000) (1024K)]
Stack: [0x00007a29b42f0000,0x00007a29b43f0000], sp=0x00007a29b43ee650, free space=1017k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so+0x678c7d] ArchiveBuilder::make_klasses_shareable()+0x99d (archiveBuilder.cpp:810)
V [libjvm.so+0x162c93e] VM_PopulateDumpSharedSpace::doit()+0x2ae (metaspaceShared.cpp:657)
V [libjvm.so+0x1bbcc9f] VM_Operation::evaluate()+0x18f (vmOperations.cpp:74)
V [libjvm.so+0x1bd83e6] VMThread::evaluate_operation(VM_Operation*)+0x156 (vmThread.cpp:282)
V [libjvm.so+0x1bd9363] VMThread::inner_execute(VM_Operation*)+0x423 (vmThread.cpp:426)
V [libjvm.so+0x1bd9504] VMThread::loop()+0x84 (vmThread.cpp:492)
V [libjvm.so+0x1bd9614] VMThread::run()+0x94 (vmThread.cpp:176)
V [libjvm.so+0x1ac5d06] Thread::call_run()+0xb6 (thread.cpp:231)
V [libjvm.so+0x174b438] thread_native_entry(Thread*)+0x128 (os_linux.cpp:877)
C [libc.so.6+0x9caa4]
Registers:
RAX=0x00007a29d2aae000, RBX=0x00007a287c2331f8, RCX=0x00007a29d1f2df85, RDX=0x00007a29d1f98e70
RSP=0x00007a29b43ee650, RBP=0x00007a29b43ee7b0, RSI=0x000000000000032a, RDI=0x00007a29d1fa2480
R8 =0x00007a29c81a9f50, R9 =0x0000000000000001, R10=0x0000000000000000, R11=0x0000000000000017
R12=0x00007a29d25bb5a4, R13=0x00007a29d1f25162, R14=0x00007a29d01fc7a0, R15=0x0000000000000099
RIP=0x00007a29d0878c7d, EFLAGS=0x0000000000010202, CSGSFS=0x002b000000000033, ERR=0x0000000000000006
TRAPNO=0x000000000000000e
Looking at the archive builder, here's the logic involved in make_klasses_shareable():
if (k->is_objArray_klass()) {
// InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
// on their array classes.
num_obj_array_klasses ++;
type = "array";
} else if (k->is_typeArray_klass()) {
num_type_array_klasses ++;
type = "array";
k->remove_unshareable_info();
} else {
assert(k->is_instance_klass(), " must be");
The logic handles objArrayKlasses, typeArrayKlasses, InstanceKlasses but not FlatArrayKlasses.