Java Valhalla Project

Introduction

In this article, we’ll cover the Valhalla project - the reasons for its history, the current state of development, and what it has brought to everyday Java developers since its release.

Motivation and reasons.

The Valhalla Project

Brian Goetz, Oracle’s Java language architect, said in a talk that one of the main motivations for the Valhalla Project was the desire to adapt the Java language and runtime to modern hardware. When the Java language was created (about 25 years ago when this article was written), the cost of acquiring memory and arithmetic operations was roughly the same.

Today, this has changed, with memory fetch operations costing 200 to 1000 times more than arithmetic operations. In terms of language design, this means that the indirect operations that lead to pointer fetching can have a detrimental effect on overall performance.

Since most Java data structures in an application are objects, we can think of Java as a pointer-intensive language (even though we don’t usually see or manipulate them directly). This pointer-based object implementation is used to enable object identification, which itself is used for language features such as polymorphism, mutability, and locking. By default, these features apply to every object, whether they are actually needed or not.

Following the chain of identifiers that lead to pointers and the chain of pointers that lead to indirection, indirection suffers from performance deficiencies and the logical conclusion is to remove those data structures that do not need them. This is where the value types come into play.

Value Types

The concept of value types is to represent pure data aggregation. This removes the functionality of regular objects. So, we have pure data, no identity. Of course, this means that we also lose the functionality that can be achieved using object identities. Therefore, equality comparisons can only be made based on state. Therefore, we cannot use representations of polymorphism and we cannot use objects that are immutable or not null.

Since we no longer have object identifiers, we can drop pointers and change the general memory layout of value types instead of objects. Let’s compare the memory layout between a point of class and the corresponding point of value type.

The code for the regular Point class and the corresponding memory layout is

final class Point {
  final int x;
  final int y;
}

Java Valhalla Project

On the other hand, the code for the value type Point and the corresponding memory layout would be

value class Point {
  int x;
  int y
}

Java Valhalla Project

This allows the JVM to spread value types into arrays and objects, as well as other value types. In the following figure we show the negative effects of using Point class time joins in arrays.

Java Valhalla Project|952x717

On the other hand, here we see the corresponding memory structure for the value type Point[]: !

Java Valhalla Project|160x497

It also enables the JVM to pass value types on the stack without having to allocate them on the heap. Finally, this means that we get data aggregation with runtime behavior similar to that of the original Java language, such as int or float.

However, unlike the original language, value types can have methods and fields. We can also implement interfaces and use them as generic types. Thus, we can look at value types from two different perspectives.

  • Faster objects
  • User-defined primitives

As an extra icing on the cake, we can use value types as generic types without the need to box. This leads us directly to another feature of the larger Valhalla project: specialized generics.

Specialized Generics

We currently use boxed types when we want to generalize a language primitive, such as the integer representation Integer or the floating point representation Float. Such boxing creates an extra layer of indirection, thus defeating the purpose of using the original language to improve performance in the first place.

As a result, we see many specializations for primitive types in existing frameworks and libraries, such as IntStream <T> or ToIntFunction <T>. This is done to maintain the performance improvement of using the primitive language.

Thus, specializing generics is an attempt to eliminate the need for these “hacks”. Instead, the Java language strives to enable generic types for basically everything: object references, primitives, value types, and possibly even void.

Conclusion

We have taken a preliminary look at the changes that the Valhalla project will bring to the Java language. Two of the main goals are to improve performance and reduce leaky abstractions.

Performance enhancements are addressed by spreading the object graph and removing indirections. This will lead to more efficient memory layout and less allocation and garbage collection.

When used as a generic type, primitives and objects have more similar behavior, which is better abstraction.

We can find more information about the Valhalla project in the corresponding project page and in the JEP at

Project Valhalla: https://wiki.openjdk.org/display/valhalla/Main

JEP 169: Value Objects: https://openjdk.org/jeps/169

JEP 218: Generics over Primitive Types: https://openjdk.org/jeps/218