Slide 1

Slide 1 text

History of a Value A glimpse into the future of the JVM

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

About me Edoardo Vacchi – @evacchi

Slide 4

Slide 4 text

About me ● Edoardo Vacchi – @evacchi – Language Implementation Frameworks @ UniMi (+Mate) – Distributed and High-Performance Streaming @ UniCredit R&D – Currently Drools & JBPM team @ Red Hat

Slide 5

Slide 5 text

Motivation

Slide 6

Slide 6 text

High Performance Streaming ● Market Prices ● Different from Reactive Streams ● Performance – e.g. cache locality ● X-Language Interop – Multi-lang analytics platform – Possibly, interface with HW

Slide 7

Slide 7 text

● Control over memory allocation ● Control over memory layout – for performance – for interop

Slide 8

Slide 8 text

Making a Point{} struct Point { double x; double y; }; auto p = Point{1.0, 2.0}; Point ps[] = { Point{1.0, 2.0}, Point{1.1, 2.1}, Point{2.0, 3.0} };

Slide 9

Slide 9 text

Making a new Point() public class Point { public double x; public double y; public Point(double x_, double y_) { x = x_; y = y_; } } var p = new Point(1.0, 2.0); Point[] ps = { new Point(1.0, 2.0), new Point(1.1, 2.1), new Point(2.0, 3.0), };

Slide 10

Slide 10 text

Making a new Point() public class Point { public double x; public double y; public Point(double x_, double y_) { x = x_; y = y_; } } var p = new Point(1.0, 2.0); Point[] ps = new Point[] { new Point(1.0, 2.0), new Point(1.1, 2.1), new Point(2.0, 3.0), }; http://bit.ly/java-struct

Slide 11

Slide 11 text

Memory Layout header header x1 y1 header x2 y2 header x3 y3 Point[] ps =

Slide 12

Slide 12 text

Memory Layout in C++ 1.0 2.0 1.1 2.1 2.0 3.0 1 Point ps[] = { Point{…}, … }; 2 double* pps = (double*) ps; 3 pps[0] // 1.0 4 pps[1] // 2.0 5 pps[2] // 1.1 6 //. ps[1] ps[2] ps[3]

Slide 13

Slide 13 text

Control over layout ● Objects are 8 bytes aligned in memory (address A is K aligned if A % K == 0) ● All felds are type-aligned (long/double is 8 aligned, integer/foat 4, short/char 2) ● Fields are packed in the order of their size, except for references (last) Nitsan Wakart - Know Thy Java Object Memory Layout http://psy-lob-saw.blogspot.it/2013/05/know-thy-java-object-memory-layout.html

Slide 14

Slide 14 text

Java Object Layout $ java -jar jol-cli/target/jol-cli.jar internals java.util.HashMap Running 64-bit HotSpot VM. Using compressed oop with 3-bit shift. Using compressed klass with 3-bit shift. Objects are 8 bytes aligned. Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] java.util.HashMap object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (0000 0101 0000 0000 0000 0000 0000 0000) 4 4 (object header) 00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000) 8 4 (object header) 8c 3b 00 f8 (1000 1100 0011 1011 0000 0000 1111 1000) 12 4 Set AbstractMap.keySet null 16 4 Collection AbstractMap.values null 20 4 int HashMap.size 0 24 4 int HashMap.modCount 0 28 4 int HashMap.threshold 0 32 4 float HashMap.loadFactor 0.75 36 4 Node[] HashMap.table null 40 4 Set HashMap.entrySet null 44 4 (loss due to the next object alignment) Instance size: 48 bytes (reported by Instrumentation API) Space losses: 0 bytes internal + 4 bytes external = 4 bytes total http://openjdk.java.net/projects/code-tools/jol/

Slide 15

Slide 15 text

Memory Layout header x1 y1 x2 y2 x3 y3 Point[] ps =

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

Projects ● Metropolis. Java-on-Java & AOT ● Loom. Lightweight Threads (Fibers) ● GC. ZGC, Shenandoah, EpsilonGC ● Valhalla. Value Types and Generic Specialization ● Amber. Data Classes and pattern matching ● Panama. Native Interop

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Loom

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Valhalla

Slide 22

Slide 22 text

Valhalla ● Codes like a class, works like an int ● Allow representation of ubiquitous types currently not well supported on the JVM, including complex numbers, vector values, and tuples. ● Avoid boxed types in generics

Slide 23

Slide 23 text

Value-based classes ● fnal and immutable ● equals, hashCode, and toString solely from the instance's state and not from its identity ● no use of identity-sensitive operations such as reference equality (==) between instances, identity hash code of instances, or synchronization on an instances's intrinsic lock; ● equal solely based on equals(), not based on reference equality (==); ● no accessible constructors, instead instantiated through factory methods which make no committment as to the identity of returned instances; ● freely substitutable when equal

Slide 24

Slide 24 text

OptionalInt

Slide 25

Slide 25 text

Values ● Pure data aggregates – Can’t extend other classes, cannot be extended – Can’t have felds of the type being declared (no recursion!) – Structural equality, not identity – No wait/notify – All fnal felds – Non-nullable

Slide 26

Slide 26 text

Values value Point { double x; double y; }

Slide 27

Slide 27 text

Recursion value Node { int value; Node next; }

Slide 28

Slide 28 text

Memory Layout header x1 y1 x2 y2 x3 y3 Point[] ps =

Slide 29

Slide 29 text

Monomorphization

Slide 30

Slide 30 text

List

Slide 31

Slide 31 text

List

Slide 32

Slide 32 text

class List { ... }

Slide 33

Slide 33 text

List xs = …

Slide 34

Slide 34 text

Minimal Value Types ● Let the VM derive a value class from a POJO – Annotated ● Generate bytecode ● Use MethodHandles to access the values

Slide 35

Slide 35 text

Making a Point() @jvm.internal.value.ValueCapableClass final class Point { final double x; final double y; public Point(double x_, double y_) { x = x_; y = y_; } }

Slide 36

Slide 36 text

Amber

Slide 37

Slide 37 text

var

Slide 38

Slide 38 text

The infamous bug 4459053

Slide 39

Slide 39 text

The infamous bug 4459053

Slide 40

Slide 40 text

But really List names = Collections.emptyList(); List names = new ArrayList/>(); Consumer consumer = s /> System.out.println(s); Consumer consumer = System.out/:println;

Slide 41

Slide 41 text

Pattern Matching String formatted = "unknown"; if (obj instanceof Integer) { int i = ((Integer) obj).intValue(); formatted = String.format("int %d", i); } if (obj matches Integer i) { formatted = String.format("int %d", i); }

Slide 42

Slide 42 text

Pattern Matching String formatted = exprswitch (obj) { case Integer i /> String.format("int %d", i); case Byte b /> String.format("byte %d", b); case Long l /> String.format("long %d", l); case Double d /> String.format(“double %f", d); default /> String.format("String %s", s); };

Slide 43

Slide 43 text

Data Classes

Slide 44

Slide 44 text

Data Classes record Point(int x, int y);

Slide 45

Slide 45 text

Data Classes record Point(int x, int y) { } // desugars to final class Point extends java.lang.DataClass { final int x; final int y; public Point(int x, int y) { this.x = x; this.y = y; } // destructuring pattern for Point(int x, int y) // state-based equals, hashCode, and toString // public read accessors x() and y() }

Slide 46

Slide 46 text

Data Classes interface Shape { } record Point(int x, int y); record Rect(Point p1, Point p2) implements Shape; record Circle(Point center, int radius) implements Shape;

Slide 47

Slide 47 text

Data Classes interface Node { } abstract record BinaryOpNode(Node left, Node right) implements Node; record PlusNode(Node left, Node right) extends BinaryOperatorNode(left, right); record MulNode(Node left, Node right) extends BinaryOperatorNode(left, right); record IntNode(int constant) implements Node;

Slide 48

Slide 48 text

Pattern Matching int eval(Node n) { return switch(n) { case IntNode(int i) /> i; case NegNode(Node n) /> -eval(n); case AddNode(Node left, Node right) /> eval(left) + eval(right); case MulNode(Node left, Node right) /> eval(left) * eval(right); default: throw new IllegalStateException(n); }; } // nesting case AddNode(IntNode(0), Node right) /> //.

Slide 49

Slide 49 text

Pattern Matching int eval(Node n) { return switch(n) { case IntNode(int i) /> i; case NegNode(var n) /> -eval(n); case AddNode(var left, var right) /> eval(left) + eval(right); case MulNode(var left, var right) /> eval(left) * eval(right); default /> throw new IllegalStateException(n); }; }

Slide 50

Slide 50 text

Bonus chatter case IntNode(int i): break i;

Slide 51

Slide 51 text

Panama

Slide 52

Slide 52 text

Going Native http://bit.ly/yt-going-native

Slide 53

Slide 53 text

Panama – Header fle extraction tools (Groveler) – Layout description language (LDL, Little Language) – Access to structured data on and off-heap – Native function calling from JVM to C/C++ – Intrinsic types to leverage CPU vector instructions

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

Q& A

Slide 57

Slide 57 text

Bonus the reason for diamond class Foo { Foo(X x) { } Foo get(X x) { return this; } } new Foo(1).get("");

Slide 58

Slide 58 text

public class X { public X(T t) {} public T get() { return null; } public static int f(String s) { return 1; } public static int f(Object o) { return 2; } public static void main(String[] args) { f(new X/>("").get()); // 1 f(new X("").get()); // 2 } } http://mail.openjdk.java.net/pipermail/coin-dev/2011-February/003082.html http://tronicek.blogspot.it/2011/03/do-we-really-need-in-diamond-operator.html

Slide 59

Slide 59 text

If we were to add reifed generics to Java, it is very likely that we will have to support runtime raw types (!!) for backwards compatibility – so the syntactic distinction between diamond and raw turns out to be quite sweet. http://mail.openjdk.java.net/pipermail/coin-dev/2011-February/003083.html