
byte short int long float double boolean charint”
final==, hashCode derived from fields, not addresspublic value record Point(double x, double y) {
public Point moveBy(double dx, double dy) { return new Point(x + dx, y + dy); }
}

git clone https://github.com/openjdk/valhalla/ cd valhalla bash configure
make images
valhalla/build/linux-x86_64-server-release/images/jdksdk install java valhalla /path/to/valhalla/build/linux-x86_64-server-release/images/jdk

value class syntax is supported in current Valhalla buildjavac --enable-preview --source 26 ... java --enable-preview ... jshell --enable-preview
Point p = new Point(0, 0);
for (int i = 0; i < ITERATIONS; i++)
p = p.moveBy(Math.random() - 0.5, Math.random() - 0.5);
IO.println(p);
time java --enable-preview withvalhalla.Brownian Point[x=619.9117803091456, y=2227.141928668786] real 0m7.806s
0m8.178s
doubles: 16 bytesPoint heap objectjava --enable-preview -XX:StartFlightRecording=filename=novalhalla.jfr novalhalla.Brownian
novalhalla.jfr into Java Mission ControlPoint objects (close to 3GiB), busy GC
hsdis-amd64.so from https://www.chriswhocodes.com/hsdis/ into current directory, then
export LD_LIBRARY_PATH=. java --enable-preview -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly \ -XX:+LogCompilation -XX:LogFile=novalhalla.log novalhalla.Brownian
export GDK_SCALE=2 java --enable-preview -jar jitwatch-ui-1.4.9-shaded-linux-x64.jar

javac generates bytecodesjava interprets bytecodes...Point.moveBy in Brownian.main, novalhalla doesn’tMath.random is much more expensive 😞 
mvn archetype:generate \ -DinteractiveMode=false \ -DarchetypeGroupId=org.openjdk.jmh \ -DarchetypeArtifactId=jmh-java-benchmark-archetype \ -DgroupId=com.horstmann \ -DartifactId=valhalla-benchmark \ -Dversion=1.0
javac.target to 26 and add this inside 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>
cd benchmark mvn clean install java --enable-preview -jar target/benchmarks.jar Benchmark1

transform tweaks and swaps x and y:
/* value */ record Point(double x, double y) {
...
public Point transform() { return new Point(y + 1, 0.5 - x); }
}
p = p.transform() 10_000_000 timesBenchmark Mode Cnt Score Error Units c.h.novalhalla.Benchmark1.work avgt 25 69213.839 ± 1526.112 us/op c.h.withvalhalla.Benchmark1.work avgt 25 0.006 ± 0.001 us/op

transform unrolls loopp.transform().transform().transform().transform() equals p!transformBenchmark Mode Cnt Score Error Units c.h.novalhalla.Benchmark2.work avgt 25 47725.264 ± 6597.810 us/op c.h.withvalhalla.Benchmark2.work avgt 25 24847.389 ± 3120.296 us/op
null: Point target = null // Ok;
null, escape analysis can often optimize locallynull:
Point! origin = new Point(0, 0); // Syntax may change
null assignment:
origin = null; // Compile-time error
Point![] path = ...; Object[] objs = path; objs[0] = null; // NullPointerException

LocalDate!super(...), or with initializer expression, or assigned in object initializerString![] labels;
labels = new String![]{ "x", "y", "z" };
labels = new String![100]{ "" }; // strawman syntax
labels = new String![100]{ i -> "x"+i }; // strawman syntax
super possible for arbitrary classes
value modifier)! will come in phase 2jdk.internal.vm.annotation package for phase 2 features@NullRestricted on a field (instead of !)@Strict on a field that is strictly initialized@LooselyConsistentValue to allow tearingjdk.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 ...

value record Point(double x, double y)
implements LooselyConsistentValue {}
volatile, lockstime java --add-exports java.base/jdk.internal.value=ALL-UNNAMED --enable-preview withtearing.Main Point[x=7.0, y=6.0] Point[x=13.0, y=14.0] ... real 0m0.367s time java --add-exports java.base/jdk.internal.value=ALL-UNNAMED --enable-preview notearing.Main real 0m27.675s

Point[] path = (Point[]) ValueClass.newNullRestrictedNonAtomicArray(Point.class, NPOINTS, new Point(0, 0));
for (int i = 1; i < path.length; i++) {
path[i] = path[i - 1].transform();
}
IO.println(path[path.length - 1]);
Thread.sleep(60_000);
Value type must have single field or be loosely consistent
javac --add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED \
--add-exports java.base/jdk.internal.value=ALL-UNNAMED --enable-preview --source 26 \
withflattening/Points.java
java --add-exports java.base/jdk.internal.value=ALL-UNNAMED --enable-preview withflattening.Points
Run jcmd:
jcmd withflattening.Points GC.class_histogram | head
double 🎉
num #instances #bytes class name (module) ------------------------------------------------------- 1: 1 1600000016 [Lwithflattening.Point;
num #instances #bytes class name (module) ------------------------------------------------------- 1: 100000000 3200000000 noflattening.Point 2: 1 400000016 [Lwithvalhalla.Point;

value modifier! syntaxInteger, Double, etc.Optional, OptionalInt, etc.java.time classes LocalDate, Instant, etc.
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)

inline classesL and values Q—no morewithfield and defaultvalue—no more

List<int> is backed by an int[]