Project Valhalla has been an in-development OpenJDK project for many years now. It is probably the most ambitious project ever conducted within OpenJDK. The tagline is deceptively modest: "To align JVM memory layout behavior with the cost model of modern hardware." However, Valhalla touches the innermost workings of the Java data model - it is effectively open-heart surgery on the JVM.
In currently extant versions of Java there are two separate kinds of data - primitives, which are bit patterns that represent int, long, boolean, etc - and reference types, which are pointers that target specific memory locations in the Java heap and are required to point at the start of a Java object header (which is mandatory for all objects).
One consequence of this is that the primitives do not have any form of identity - one bit pattern representing the number 42 is indistinguishable from another bit pattern that also represents 42. However, it is entirely possible for two references to point at different memory locations that contain objects that have all their fields equal - and despite this field-equality, in the Java memory model, these are considered separate objects with different identities.
Valhalla's starting position is - "What if there was a new kind of data - one which represented composite or user-defined data types, but which did not have identity?" This seemingly-simple idea cuts to the deepest level of the Java platform. Implementing it requires changes to the virtual machine, libraries, language and everything above it.
Some of the most immediate consequences are that such objects can avoid paying the overhead of a header and that the defining value class must be final, so that all targets for method calls can be known at class loading time. Example use cases for value classes include:
- New kinds of primitives, such as unsigned bytes, 128-bit integers, and 16-bit floats
- Complex numbers, quaternions, colours and 3-d vectors
- Numbers with units: sizes, temperatures, cashflow amounts
- Immutable cursors, subarrays, intermediate streams, and other data structure view abstractions
It has long been a goal that some existing JDK types could be retrofitted and evolve to become represented as value classes. As of JDK 28 EA, 30 classes have been migrated to be value types (provided the --enable-preview flag is set) - this includes the wrapper classes (Integer, Long, Float, Double, Byte, Short, Character and Boolean) as well as Optional and its primitive variants and LocalDate, LocalTime, LocalDateTime, ZonedDateTime and Duration from java.time
Additionally, although records are not, per se, related to value classes, it is very likely that many record classes will be aggregates that do not require identity, so value records may well become a very useful and common pattern.
Going even further, Valhalla opens the possibility that the Java language designers can use this singular opportunity to undertake work that was previously believed to be intractable (or even impossible) - such as revisiting generics, closing the language syntax gap between primitives and objects, and adding nullability markers to the type system.
Much can (and, indeed, has been) written about Valhalla - but in this post I want to focus on the practicalities: The first pieces of Valhalla have, at long last, landed on OpenJDK main as Preview Features. This is a huge milestone, reflecting vast amounts of work by the OpenJDK developers at Oracle - and other companies - and it opens the door for testing to be done by a much wider group of Java developers than previously.
As of right now, I've been trying out the Adoptium nightly builds for JDK 28, which support value types and have a few observations that I've distilled from my attempts to build various OSS projects (e.g. Quarkus, Hibernate):
- Core Maven 3.9.9 seems to work fine with 28 EA.
- Gradle 9.7.0 (latest) does not support JDKs beyond 26 yet. Gradle projects just will not build yet.
- Kotlin projects that utilize the kapt annotation processor do not work. Each JDK release seems to affect the access to javac internals that kapt requires. Kotlin 2.5.0 (est. release date: Dec 2026) will hopefully introduce a new mode for this annotation processor that does not require internals access. Thanks to Ilmir Usmanov & Anton Arhipov @ JetBrains for helping track this failure down.
- Additionally, Kotlin does not support -ea suffix on Java version numbers, and will not work with JDK builds that don't report a production Java version number.
- ASM does not support Java 28 yet. Support is being discussed here and I note that Remi Forax is actively engaged there.
As these issues are resolved, or betas are made available that address them, then we should as a community be able to enable a much broader set of testing and possible failures. I'm going to start with the suggestion of building an ASM jar from the current branch Remi indicated. Watch this space for updates.