JDK-8343218 : Add option to disable allocating interface and abstract classes in non-class metaspace
  • Type: Sub-task
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 24,25
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2024-10-29
  • Updated: 2025-08-21
  • Resolved: 2025-08-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 25 JDK 26
25.0.2Fixed 26 b10Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
There have been bugs and suspected C2 bugs in allocating interface and abstract classes in non-class metaspace.  This RFE adds an option to disable this feature.  Testing has been done with the feature on, so the new option UseClassMetaspaceForAllClasses is added with the initial default value (false) to maintain the status quo. We may still want to reduce the number of Klass stored in class-metaspace so nobody add new code to assume that it's ok to decode interface and abstract classes.  Or we might remove this feature altogether.
Comments
A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk25u/pull/123 Date: 2025-08-21 12:32:05 +0000
21-08-2025

Fix Request: This fix should be backported to JDK 25 update releases so that a customer can use this option to turn off the feature where interface and abstract classes in non-class metaspace cause C2 to generate incorrect code. It's a stop-gap until this feature is removed.
21-08-2025

I don't really understand why 25.01 is closed for pushes before 25 GA but can request a critical request for 25.01. That seems like a decent plan. We're opting for sanity and not trying to push this change on the last day as the C2 bug hasn't manifested itself in 24 and 25 testing. Could get the flag in 25.01 and removing feature in 26, backported to a subsequent 25.
06-08-2025

Well, the goal for the flag was to allow users to opt-out if we/they suspect the problem, right? So we want to get the flag ahead of the actual fix/disabling the feature. If we end up not backporting the flag to 25 GA, and just remove the feature in 25.0.1, then we expose users to potential bug in JDK 25 GA without an escape hatch. That might be a sane course of action at this time, but not the most user-friendly one. I also see that 25.0.1 have been closed for pushes on July 22: https://mail.openjdk.org/pipermail/jdk-updates-dev/2025-July/045556.html -- which is still fine if we planning to request critical fix for 25.0.1 to get it for Oct 2025. Otherwise this flag would end up in 25.0.2 (Jan 2026), which is IMO way too late. Same goes for the feature disabling. So, what's the new plan?
05-08-2025

I'm retracting this late feature request. We'll remove this feature for JDK 25u1. Testing hasn't found the bug in all of JDK 24 and 25 testing and while the possible presence of this bug is worrying, we should be able to fix the problem before any code fails because of it.
04-08-2025

Late feature request for JDK 25. We should integrate this change to add the `UseClassMetaspaceForAllClasses` for JDK 25. It's a low risk workaround for a potentially severe compiler bug where the compiler may generate incorrect code. The default value of this option is `false` matching current and tested JDK 25 behavior, but can be set to workaround any bugs that are suspected for this optimization. The optimization that this turns off would not harm performance. The change has been tested with tier1-10 with the value of the option off and on.
04-08-2025

Changeset: da3a5da8 Branch: master Author: Coleen Phillimore <coleenp@openjdk.org> Date: 2025-08-04 20:13:03 +0000 URL: https://git.openjdk.org/jdk/commit/da3a5da81bc1d6fe1e47e3a4e65bf390ee1d39a0
04-08-2025

> I've seen some Java code where for each implementation class there's an interface class, so storing the interface classes also in the Class Metaspace would be 2x the number of classes. Is that not normal? [~coleenp] This should still be fine. We have enough address space in class space for roughly 3.5..4 million classes even in Lilliput. I have very rarely seen customers with more than 100k classes.
01-08-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/26579 Date: 2025-07-31 18:13:30 +0000
31-07-2025

Draft PR https://github.com/openjdk/jdk/pull/26579
31-07-2025

Re-ILW: ILW=H (might generate bad code) L (no current sightings) H (can find offending code and not compile it, maybe that's a High) = P2 Edit: Maybe this ILW should apply to JDK-8361211 also?
31-07-2025

I've seen some Java code where for each implementation class there's an interface class, so storing the interface classes also in the Class Metaspace would be 2x the number of classes. Is that not normal? I'm fine with removing the feature, especially if it complicates C2. We don't need that. It's probably a simple patch to remove. The C2 bug above is a P3 but the workaround should be High because turning off CompressedClassPointers is something we really never want to do. A month ago would have been better. Need to check the JDK 25 schedule.
31-07-2025

I am fine with disabling the feature and removing it forever. It is one of the compatible outcomes with the plan above. At this point, we need feature flag to de-risk JDK 25 and avoid making rash decisions, especially those that would invalidate pre-release JDK 25 testing. If we did discover this earlier in JDK 25 timeframe (= if I realized this is a more generic problem that just a simple overlook in dusty corner of C2 back when I found JDK-8361211, and started pushing a month ago, mea culpa), we could have just went with original Coleen's patch that disables it unconditionally. But oh well, hindsight is 20/20.
31-07-2025

I have been doubtful on JDK-8338526 recently myself, since the benefits (fewer Klass structures in class space) are not urgently needed, even with Lilliput, and it made a number of things more complex - not only in existing code, but also e.g. in the KLUTE stuff I proposed at FOSDEM earlier this year. Having a simple rule like "all Klass live in class space and are encodable via nKlass" has certain merits. We want to disable this quickly, if we do so, to get enough testing coverage in JDK 26 for the upcoming Lilliput-by-default change. I am fine with your proposed timeline, [~shade], my fear would only be that with such a feature flag, we add another never-tested configuration to the zoo of configurations. I'd be perfectly fine with removing this feature altogether. If nobody got time, I can take care of (1) - (3).
31-07-2025

I think the code moved but I might have one cycle later today. I won't mix your C2 patch in though because I'm far from knowledgeable in that area. Also, It should be a diagnostic flag. I'll reopen this. Also, this seems like it should be backported to JDK 25, but only P1 and P2s can be checked in now. We can backport it or put it in the update release later. ILW=H (might generate bad code) L (no current sightings) M (can find offending code and not compile it, maybe that's a High) = P3
31-07-2025

Coleen, do you have cycles to do this? You already had a good version in PR, maybe "just" gate it with an experimental flag, and turn that flag off? I think we want to do this in JDK 25 as well. Mixing in my patch would be a bonus: https://github.com/openjdk/jdk/compare/master...shipilev:jdk:JDK-8343218-disable-abstract-interface -- provided compiler folks are happy with it.
31-07-2025

Yes, it would make sense to me if both ciKlass::is_in_encoding_range() and CompressedKlassPointers::is_encodeable(addr) always return "true" when interface/abstract classes are back in compressed class space. If they return "false", that sounds like a major bug to me, as we expect all classes to be encodeable with feature flag off. Right? Unfortunate timing for JDK 25. So how about this plan: 1. The feature flag goes into mainline without behavior change. 2. The feature flag is backported to JDK 25 GA. The justification is that users need to have an escape hatch if the problem is wide-spread. 3. We flip the feature flag "off" by default in mainline. 4. We backport the feature flag "off" to 25.0.1/2. The justification is that we want to provide a stable 25u to users, without any extra action. 5. We do more C2-level checks for potential problems, like my patch, in mainline. This ticket fits (3), and can be used for (4). For (2), it is probably worth filing the new RFE related to JDK-8338526.
31-07-2025

Unfortunately, this has leaked into several places, so it's not as simple as the patch here. edit: maybe not, maybe only a couple of places. in ciKlass.hpp bool is_in_encoding_range() { Klass* k = get_Klass(); bool is_in_encoding_range = CompressedKlassPointers::is_encodable(k); assert(is_in_encoding_range || k->is_interface() || k->is_abstract(), "sanity"); return is_in_encoding_range; } and then // Returns whether the pointer is in the memory region used for encoding compressed // class pointers. This includes CDS. static inline bool is_encodable(const void* addr) { // An address can only be encoded if: // // 1) the address lies within the klass range. // 2) It is suitably aligned to 2^encoding_shift. This only really matters for // +UseCompactObjectHeaders, since the encoding shift can be large (max 10 bits -> 1KB). return (address)addr >= _klass_range_start && (address)addr < _klass_range_end && is_aligned(addr, klass_alignment_in_bytes()); } So the assert won't fail if interfaces and abstract classes end up in the encoding range.
31-07-2025

> Also, at *very least* we should have had the feature flag that disables this optimization. Right now we have no recourse if VM misbehaves due to this. Seems reasonable.
30-07-2025

Also, at *very least* we should have had the feature flag that disables this optimization. Right now we have no recourse if VM misbehaves due to this.
30-07-2025

Take the patch from here: https://github.com/openjdk/jdk/compare/master...shipilev:jdk:JDK-8343218-disable-abstract-interface ...and run this to see it fail all over the place: $ CONF=linux-x86_64-server-fastdebug make images test TEST=applications/ctw/modules
30-07-2025

Er. Um... So, when working on JDK-8361211, I got very surprised to see that C2 routinely generates ConN and TypeNarrowKlass with unencodeable classes. Are we relying on later idealizations to strip those away, and I have only caught one of those red-handed? That sounds very fragile. IMO, we should not be generating these constants to begin with. I suspect JDK-8338526 is way too optimistic about C2. Example from parser, which AFAICS just does the load off the klass-offset and then IGVN constant-folds to the load of abstract class, which produces TypeNarrowKlass and ConN with unencodable klass. # Internal Error (/home/shade/trunks/jdk/src/hotspot/share/oops/compressedKlass.inline.hpp:80), pid=973926, tid=973959 # assert(is_encodable(addr)) failed: Address 0x0000705cc041fbd8 is not encodable (Klass range: [0x0000000032000000 - 0x0000000073000000), (1090519040 bytes), klass alignment: 8) Current CompileTask: C2:9735 479 b 4 javax.annotation.processing.AbstractProcessor::getSupportedOptions (39 bytes) Stack: [0x000071d8a7200000,0x000071d8a7300000], sp=0x000071d8a72fbbf0, free space=1006k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) V [libjvm.so+0x494862] CompressedKlassPointers::check_encodable(void const*)+0x118 (compressedKlass.inline.hpp:80) V [libjvm.so+0x1b93718] TypeNarrowKlass::TypeNarrowKlass(TypePtr const*)+0xb2 (type.hpp:2085) V [libjvm.so+0x1b8db12] TypeNarrowKlass::make(TypePtr const*)+0x32 (type.cpp:5321) V [libjvm.so+0xbbfb6f] Type::make_narrowklass() const+0x4f (type.hpp:2419) V [libjvm.so+0x15ecf5b] LoadNKlassNode::Value(PhaseGVN*) const+0x5b (memnode.cpp:2590) V [libjvm.so+0x17781a4] PhaseGVN::transform(Node*)+0x18a (phaseX.cpp:703) V [libjvm.so+0x15ec494] LoadKlassNode::make(PhaseGVN&, Node*, Node*, TypePtr const*, TypeKlassPtr const*)+0x192 (memnode.cpp:2407) V [libjvm.so+0x101be6b] GraphKit::load_object_klass(Node*)+0xd7 (graphKit.cpp:1218) V [libjvm.so+0x148cdf0] LibraryCallKit::inline_native_getClass()+0x58 (library_call.cpp:4859) V [libjvm.so+0x14741c8] LibraryCallKit::try_to_inline(int)+0x1da (library_call.cpp:240) V [libjvm.so+0x14731e6] LibraryIntrinsic::generate(JVMState*)+0x236 (library_call.cpp:119) V [libjvm.so+0xe22423] Parse::do_call()+0xd25 (doCall.cpp:677) V [libjvm.so+0x1760001] Parse::do_one_bytecode()+0x41d5 (parse2.cpp:2723) V [libjvm.so+0x174d1be] Parse::do_one_block()+0x6e6 (parse1.cpp:1586) V [libjvm.so+0x1748b90] Parse::do_all_blocks()+0x42e (parse1.cpp:724) V [libjvm.so+0x1748674] Parse::Parse(JVMState*, ciMethod*, float)+0xfc4 (parse1.cpp:628) V [libjvm.so+0xa49445] ParseGenerator::generate(JVMState*)+0x19f (callGenerator.cpp:97)
30-07-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/21769 Date: 2024-10-29 17:15:44 +0000
29-10-2024