
https://horstmann.com/presentations/2024/valhalla
Slide navigation: Forward with space bar, →, or swipe left. Backwards with ← or swipe right. Switch slides with PgDn and PgUp.


byte short int long float double boolean char== compares primitives by value, not identitynull ⭐false) ⭐

Codes like a class, acts like an int== semantics:
Point p = ... if (p == origin)
Function<Integer, Boolean> vs. Predicate<Integer> vs. IntFunction<Boolean> vs. IntPredicate
==, hashCode derived from fields, not addressfinal:
public value class Point {
private double x; // final
private double y; // final
...
}
public value record Point(double x, double y) {
public Point moveBy(Point other) { return new Point(x + other.x, y + other.x); }
}

x == y tests whether x and y are references to the identical objectPoint p, q; ... if (p == q) // Checks p.x == q.x && p.y == q.y
value record Circle(double radius, Point center) {}
Circle c, d;
...
if (c == d) // Checks c.radius = d.radius, c.center == d.center
equals in recordscompare, not ==, different for ±0, NaNObject does not check reference identity:
Point p = new Point(3, 4), q = new Point(3, 4); p == q // true Object op = p, oq = q; op == oq // true

long and double, short float, unsigned, complex numbersOptional, Either, Try
abstract value class JSONValue { ... }
abstract value class JSONPrimitive extends JSONValue { ... }
value record JSONNumber(double value) extends JSONPrimitive { ... }
class JSONObject extends JSONValue { ... } // identity class
Object is an identity class, but value classes extend it
super(...)super()super possible for arbitrary classessuper call:
public value class LocalizedMessage extends Localized {
private String message;
public LocalizedMessage(String message, Locale locale) {
this.message = message;
super(locale);
}
...
}

null: Point target = null;
null:
Point! origin = new Point(0, 0); // Syntax may change
null assignment:
origin = null; // Compile-time error
Point![] path = new Point![NPOINTS]; Object[] objs = path; objs[0] = null; // NullPointerException

T! is not a subtype of T, but conversions are ok in both directions.Point! origin = new Point(0, 0); Point p = origin; // Widening conversion Object o = origin; // Ok, also widening conversion p = null; // Ok, doesn't change origin
origin = p; // NullPointerException origin = (Point!) o; // Narrowing conversion. maybe NPE origin = (Point) o; // Same
Point![] path = new Point![NPOINTS]; Object[] objs = path; // Ok, even if unsound objs[0] = "Fred"; // ArrayStoreException objs[0] = null; // NullPointerException

public value class Node {
private Object data;
private Node next;
public Node(Object data, Node next) { this.data = data; this.next = next; }
...
}private Node! next;

Point!.classvar path = new Point![100];
CheckedType type = Array.getComponentType(path);
type.cast("Fred"); // ClassCastException
type.cast(null); // NullPointerException
var cloud = (Point[]) Array.newInstance(type, NPOINT); cloud[0] = null; // NullPointerException

null) value typeLocalDatevalue record Point(double x, double y) {
public implicit Point();
}
T! when T has implicit constructor 
int n = 42; String hex = n.toHexString(); // i.e. Integer.valueOf(n).toHexString() var signs = Stream.of(1, -4, 0).map(0::compareTo).toList(); // i.e. Integer.valueOf(0)::compareTo
int.MAX_VALUE // i.e. Integer.MAX_VALUE "Hello 🇧🇬".codePoints().map(char::charCount).toArray() // i.e. Character::charCount

int and Integer!, what about arrays?
Integer! digits = new Integer![]{ 3, 1, 4, 1, 5, 9}; // A flattened array
int[] intDigits = digits; // The same array, but accessed with different byte codes
Object[] objs = digits; // An array of references objs = intDigits; // used to be illegal
int to be Integer!class Die extends Supplier<Integer> {
int get() { return 1 + (int) (6 * Math.random()); }
// i.e. Integer get() { ... }
}
class Die extends Supplier<int> // i.e. Supplier<Integer!>
List<int> still uses boxing.
long, double may tearvalue record Point(double x, double y)
implements LooselyConsistentValue {}
volatile fields
Integer, Double, etc.OptionalRecordOptional are deemed to have an implicit constructor== and hashCode reflect field-based value semanticssynchronized
ArrayList<int> use int or Object bytecodes?int[] or Integer![] is different than for Object[]List<int> a subtype of the raw List or wildcard List<?> type?Optional<T!>)get method of Map<String, int> can't return null static <T extends Comparable<? super T>> void sort(T[] a) static void sort(int[] a)

L and values Q—no morewithfield and defaultvalue—no moreinline classesvalue class seems here to stayPoint! for null-restricted typesT!, T?, T*
git clone https://github.com/openjdk/valhalla/ cd valhalla bash configure
make images
valhalla/build/linux-x86_64-server-release/images/jdk
value class syntax is supportedjavac --enable-preview --source 23 ... java --enable-preview ... jshell --enable-preview
jdk.internal.vm.annotation package for “phase 2” features@NullRestricted on a field (instead of !)@ImplicitlyConstructible on a value type (instead of implicit constructor)@LooselyConsistentValue on a value type (instead of marker interface)jdk.internal.value.ValueClass lets you construct null-restricted arraysjavac -add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED \ --add-exports java.base/jdk.internal.value=ALL-UNNAMED ... java --add-exports java.base/jdk.internal.value=ALL-UNNAMED ...
Point by random amount (Code)
mvn archetype:generate \ -DinteractiveMode=false \ -DarchetypeGroupId=org.openjdk.jmh \ -DarchetypeArtifactId=jmh-java-benchmark-archetype \ -DgroupId=com.horstmann \ -DartifactId=valhalla-benchmark \ -Dversion=1.0
configuration of maven-compiler-plugin:
<compilerArgs> <arg>-verbose</arg> <arg>--enable-preview</arg> <arg>-proc:full</arg> <arg>--add-exports</arg> <arg>java.base/jdk.internal.vm.annotation=ALL-UNNAMED</arg> </compilerArgs>
mvn clean install java --enable-preview -jar target/benchmarks.jar
Benchmark Mode Cnt Score Error Units c.h.novalhalla.Benchmark1.work avgt 25 34819.177 ± 4295.566 us/op c.h.withvalhalla.Benchmark1.work avgt 25 0.004 ± 0.001 us/op
Benchmark Mode Cnt Score Error Units c.h.novalhalla.Benchmark3.work avgt 25 47725.264 ± 6597.810 us/op c.h.withvalhalla.Benchmark3.work avgt 25 24847.389 ± 3120.296 us/op

hsdis-amd64.so from https://www.chriswhocodes.com/hsdis/ into lib directoryexport LD_LIBRARY_PATH=lib
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly \ -XX:+LogCompilation -XX:LogFile=logfilename
java --enable-preview -jar jitwatch-ui-1.4.9-shaded-linux-x64.jar

Point[] path = (Point[]) ValueClass.newNullRestrictedArray(Point.class, 100_000_000);
for (int i = 1; i < path.length; i++) {
path[i] = path[i - 1].transform();
}
System.out.println(path[path.length - 1]);
Thread.sleep(60_000);
jcmd withvalhalla.Points GC.class_histogram | head
num #instances #bytes class name (module) ------------------------------------------------------- 1: 1 1600000016 [Lwithvalhalla.Point;
double

List<int> is backed by an int[]