JDK 27 Emergency Rollback: P1 C2 Compiler Bug Forces Last-Minute Revert

Days before JDK 27's scheduled release, OpenJDK developers emergency-reverted a P1-level C2 compiler intrinsic memory alias bug (JDK-8390590) that caused incorrect optimization of EncodeISOArray, choosing a clean backout over risky patching to ensure release stability.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
JDK 27 Emergency Rollback: P1 C2 Compiler Bug Forces Last-Minute Revert

JDK 27 Release Context

JDK 27 GA was planned for September 15, 2026, with nine JEPs including G1 as default GC (JEP 523), TLS 1.3 post-quantum KEM (JEP 527), lazy constants (JEP 531), primitive types in patterns (JEP 532), structured concurrency (JEP 533), compact object headers (JEP 534), JFR in-process masking (JEP 536), Vector API 12th incubator (JEP 537), and cryptographic PEM encoding (JEP 538).

The Bug: JDK-8390590

On August 18, 2026, OpenJDK core compiler developer Vladimir Kozlov filed an emergency fix request JDK-8390590 titled "[BACKOUT] C2: Fix the memory around some intrinsics nodes." This was a full backout of prior change JDK-8373591, which had introduced a regression JDK-8390546 in JDK 27 EA. The regression caused the C2 compiler to use an incorrect memory alias for certain intrinsic methods. The bug was marked P1 (highest priority) with tags regression and jdk-rc-fix, and the fix was backported to JDK 27 builds b35, b07, 27.0.1, 27.0.2 and JDK 28 mainline within hours.

What Is an Intrinsic?

In HotSpot JVM, an Intrinsic is a special compiler optimization where the JIT (especially C2, the Server Compiler) replaces specific method calls with highly optimized machine code or special IR nodes instead of generating regular bytecode invocation sequences. Examples include EncodeISOArray (in sun.nio.cs.ISO_8859_1$Encoder for efficient char[] to ISO-8859-1 byte[] encoding), System.arraycopy, Math.log, String.indexOf, and hundreds of others.

C2 Memory Model and Alias Analysis

C2 builds a complex Memory Graph during optimization. Every memory access (Load, Store, ArrayCopy) must declare which memory region it touches — this region classification is Memory Alias. If the compiler incorrectly judges two memory operations as aliasing the same region, it can cause: (1) incorrect instruction reordering breaking program semantics; (2) missing memory barriers causing visibility issues in multithreaded code; (3) incorrect dead store elimination removing stores deemed redundant. For intrinsic nodes that directly manipulate arrays, correctly declaring their read/write memory aliases is a prerequisite for safe optimization.

Root Cause Analysis

Original Intent of JDK-8373591

JDK-8373591

(same title) aimed to fix legacy memory modeling issues in some intrinsic nodes, addressing two problems:

AryEqNode adr_type error: AryEqNode (array comparison intrinsic) inherited StrIntrinsicNode 's TypeAryPtr::BYTES type, but it actually also accepts char[] input.

Missing anti-dependencies in StrInflatedCopyNode etc.: Certain intrinsic nodes (e.g., string inflated copy node) did not correctly declare which memory states they "kill" when consuming memory, preventing the scheduler from correctly computing anti-dependencies.

The fix introduced finer-grained memory slices and MergeMem nodes, touching 6 files and 274 lines of code.

EncodeISOArray's Wrong Alias

During JDK 27 EA testing, developers discovered EncodeISOArray intrinsic used an incorrect destination memory alias. EncodeISOArray reads a source char[] and writes a destination byte[]. After JDK-8373591, the intrinsic node's declaration of the target memory region in C2's IR graph became inaccurate, causing the compiler to fail to correctly identify dependencies between this intrinsic and other memory operations in later optimization phases (global code motion, loop optimization, scalar replacement, etc.).

Why This Error Is Dangerous

The wrong memory alias can lead to: (1) incorrect reordering of EncodeISOArray with unrelated memory ops, causing data races or wrong results; (2) false assumptions in loop optimization (e.g., believing an array is unmodified in a loop, enabling aggressive vectorization/unrolling); (3) broken escape analysis and scalar replacement because the compiler cannot accurately judge whether an object is referenced by the intrinsic. Such bugs are highly latent — they only trigger under specific code patterns, C2 Tier 4 compilation, and particular data flows, manifesting as intermittent wrong results or hard-to-reproduce crashes in production.

Why Rollback Instead of Patch?

Facing a P1 regression with the JDK 27 GA deadline looming, OpenJDK chose the safest path: full backout of all JDK-8373591 changes . Advantages:

High determinism: Reverting a known change carries controllable risk.

Fast turnaround: From bug report to fix commit ( changeset 4b77534a) took under 10 hours.

No new regressions: Local patches on complex compiler code during a tight release window could trigger cascading failures.

Kozlov explicitly labeled it a "Clean backout" and noted it passed "A lot of testing."

Follow-up: REDO Plan

Rollback does not mean abandonment. The team created JDK-8390617 titled "[REDO] C2: Fix the memory around some intrinsics nodes" to redesign and reimplement the intrinsic memory model fix in a more relaxed timeframe. They also created JDK-8390591 to add a regression test for this specific failure, preventing recurrence.

Takeaways

Compiler optimization is a double-edged sword: C2 intrinsics give Java stellar performance, but their complexity demands extremely rigorous validation for any memory model change.

Rollback is wisdom: In software engineering, "daring to roll back" often takes more courage and professionalism than "pushing through with a patch."

Community collaboration power: From bug report ( JDK-8390546) to backout decision ( JDK-8390590), regression test ( JDK-8390591), and redo ( JDK-8390617), the entire cycle completed in under 24 hours, showcasing OpenJDK's efficient collaboration.

For everyday Java developers, the lesson is pragmatic: new JDK versions will ship when ready; sticking with Java 8 or a slightly older LTS is perfectly fine.

References

https://bugs.openjdk.org/browse/JDK-8390590
https://bugs.openjdk.org/browse/JDK-8390546
https://bugs.openjdk.org/browse/JDK-8373591
https://bugs.openjdk.org/browse/JDK-8390617
https://git.openjdk.org/jdk
https://jdk.java.net/27/release-notes
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

regressionintrinsicOpenJDKJDK 27backoutC2 compilerEncodeISOArraymemory alias
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.