Slide 1

Slide 1 text

Project Amber Rémi Forax - April 2017

Slide 2

Slide 2 text

Me, myself and I Father 3 kids Assistant Prof University Paris East Marne la Vallée / ESIPE Java Champion / Developer OpenJDK, ASM, Pro, etc Expert for the JCP invokedynamic, lambda, module

Slide 3

Slide 3 text

Lies lies lies lies lies lies lies lies lies lies lies damn lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies lies damn lies lies lies lies lies lies lies lies lies lies lies lies

Slide 4

Slide 4 text

Release of Java 9 27 / 7 / 2017

Slide 5

Slide 5 text

Project Valhalla OpenJDK project Started July 2014 Provide uniform data access model Value types + Generics specialization

Slide 6

Slide 6 text

Value types Code like a class, works like an int value class complex { private final double re; private final double im; ... } No identity Must be immutable (avoid stack aliasing)

Slide 7

Slide 7 text

Generics of value types class ArrayList implements List { private E[] elements; ... } List list= new ArrayList(); The JIT will generate the specialization ! Will work with primitive types too List list = new ArrayList();

Slide 8

Slide 8 text

Project Panama Java does not fear C anymore – Make the JIT generates the JNI Stubs – Make unsafe offheap access safe Need metadata to describe – C structs layout in memory – Calling conventions Access C heap safely through interfaces

Slide 9

Slide 9 text

Project Panama The VM is already able to do restricted auto- vectorisation of loop over arrays of primitives Add API to access to SIMD/AVX ops – Need to define 128/256/512 bits int/double ? Use value types (but defined in JDK) – Intrinsics for the VM

Slide 10

Slide 10 text

Current plan Java 10 – panama C without JNI + SIMD/AVX – stealth valhalla: Value types in the VM let JRuby, Groovy, Scala, etc play with it first Java 11 – full valhalla: Value types + Specialized Generics

Slide 11

Slide 11 text

so no new language feature in Java 10 ?

Slide 12

Slide 12 text

Amber !

Slide 13

Slide 13 text

Project Amber http://openjdk.java.net/projects/amber/ explore and incubate smaller, productivity-oriented language features – Local-Variable Type Inference, Lambda Leftovers – Augment use-site Variance with declaration-site defaults – Enhanced Constant Folding – Enhanced Enums – ???

Slide 14

Slide 14 text

Local Variable Type Inference simple var a = 3; var list = new ArrayList(); use super type: var anonymous = new Object() { int x; }; not supported: var lambda = x -> x + 2; var ref = String::length;

Slide 15

Slide 15 text

Misc ... ‘_’ means unused parameter public static void main(String[] _) { ... Lambda parameters open a new scope var cache = new HashMap(); var name = ... var info = cache.computeIfAbsent(name, name -> new Info(name));

Slide 16

Slide 16 text

Pattern Matching

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Brain Dump mode

Slide 19

Slide 19 text

Example { or [{ "username": "remi", "user": "remi", ... ... } }, ... v1 v2 Extracting a user name from a JSON document

Slide 20

Slide 20 text

If instanceof … { or [{ "username": "remi", "user": "remi", ... ... } }, ... Object json = ... if (json instanceof JSObject) { return ((JSObject)json).getValue("username"); } if (json instanceof JSArray) { return ((JSArray)json).get(0).getValue("user"); } ...

Slide 21

Slide 21 text

Enhanced Switch Switch on types Object json = ... switch(json) { case JSObject: return ((JSObject)json).getValue("username"); case JSArray: return ((JSArray)json).get(0).getValue("user"); default: ... }

Slide 22

Slide 22 text

Smart cast / type flow Fuse instanceof/cast + declare a variable Object json = ... switch(json) { case JSObject object: return return object.getValue("username"); case JSArray array: return array.get(0).getValue("user"); default: ... }

Slide 23

Slide 23 text

Pattern Matching with Expression “break” is so 1970 ! Object json = ... return switch(json) { case JSObject object -> object.getValue("username") case JSArray array -> array.get(0).getValue("user") default: ... };

Slide 24

Slide 24 text

Default ? We need a default because ... Object json = ... return switch(json) { case JSObject object -> object.getValue("username") case JSArray array -> array.get(0).getValue("user") default: ... };

Slide 25

Slide 25 text

Closed Hierarchy

Slide 26

Slide 26 text

Algebraic Data Type Enumerate allowed subtypes closed interface Expr { data Value(int x) data Add(Expr left, Expr right) } 2 + (3 + 5) new Add(new Value(2), new Add(…, …)) or Add(Value(2), Add(Value(3), Value(5)))

Slide 27

Slide 27 text

Data Class data Add(Expr left, Expr right) Provide a way to represent ‘structured’ data – Abstraction “it’s just a data class” – Less boiler plate Generate (at runtime ?) – equals, hashCode, toString, getters ? – Value types also need that too !

Slide 28

Slide 28 text

Destructured Pattern Matching Data class fields can be extracted public Expr simplify(Expr expr) { return switch(expr) { case Add(var e1, var e2) -> ... case Value(var value) -> ... }; } Look ‘ma, no default

Slide 29

Slide 29 text

Destructured Pattern Matching Match part of the subtree public Expr simplify(Expr expr) { return switch(expr) { case Add(Value(var v1), Value(var v2)) -> ... case Add(var e1, var e2) -> ... case Value(var value) -> ... }; }

Slide 30

Slide 30 text

Destructured Pattern Matching With the implementations public Expr simplify(Expr expr) { return switch(expr) { case Add(Value(var v1), Value(var v2)) -> new Value(v1 + v2)) case Add(var e1, var e2) -> simplify(...) case Value value -> value }; }

Slide 31

Slide 31 text

‘_’ means unused/anything Use _ in patterns return switch(expr) { case Add(Value(_), Value(var v2)) -> case Add(_, _) -> case Value _ -> };

Slide 32

Slide 32 text

Destructured Pattern Matching You can not change a local variable ! public Expr simplify(Expr expr) { return switch(expr) { case Add(Value(var v1), Value(var v2)) -> new Value(v1 + v2)) case Add(var e1, var e2) -> simplify(...) case Value _ -> expr }; } Use of local variable (non final)

Slide 33

Slide 33 text

Encapsulation

Slide 34

Slide 34 text

Destructured vs Encapsulation return switch(expr) { case Add(Value(var v1), ...) -> ... ... }; if (expr instanceof Add) { Add add = (Add)expr; Expr left = add.getLeft(); if (left instanceof Value) { Value v1 = (Value)left; … } } data class Add { ... public Expr getLeft() { return left; } public Expr getRight() { return right; } }

Slide 35

Slide 35 text

De-constructor ? return switch(expr) { case Add(Value(var v1), Value(var v2)) -> ... ... }; if (expr instanceof Add) { Add add = (Add)expr; Expr left, right = add.deconstructor(); if (left instanceof Value) { Value v1 = (Value)left; … } } data class Add { ... public Expr, Expr deconstructor() { return left, right; }

Slide 36

Slide 36 text

Under the hood

Slide 37

Slide 37 text

Implementation Troubles Problems – If instanceof … else – De-constructor / Scala unapply – Sharing, zero allocation Goal Pattern matching on types == as fast as method calls ?

Slide 38

Slide 38 text

If instanceof … else instanceof == dynamic suite of typechecks – Instanceof itself creates a series of if … else Linearly checks all patterns is slooooooow

Slide 39

Slide 39 text

Use invokedynamic invokedynamic(expr); recipe […] The recipe is an array of pairs Pattern / Action ● A text transformed as an automata at runtime ● Action: a static method to call if the pattern match No instanceof guardWithTest is a typecheck on runtime classes

Slide 40

Slide 40 text

Sharing Some patterns starts with the same pattern Several classes may match the same pattern switch(expr) { case Iadd(IValue(var v1), IValue(var v2)) -> // 1 case Iadd(var e1, var e2) -> // 2 IAdd IValue IValue extract expr v1 v2 action1 action2

Slide 41

Slide 41 text

At runtime (1/4) switch(expr) { case Iadd(IValue(var v1), IValue(var v2)) -> ... case Iadd(var e1, var e2) - > ... IAdd IValue IValue extract expr v1 v2 action1 action2 Add Add Value Value Value Create the matching data structure at runtime

Slide 42

Slide 42 text

At runtime (2/4) switch(expr) { case Iadd(IValue(var v1), IValue(var v2)) -> ... case Iadd(var e1, var e2) - > ... IAdd IValue IValue extract expr v1 v2 action1 action2 Add Add Value Value Value Add extract

Slide 43

Slide 43 text

At runtime (3/4) switch(expr) { case Iadd(IValue(var v1), IValue(var v2)) -> ... case Iadd(var e1, var e2) - > ... IAdd IValue IValue extract expr v1 v2 action1 action2 Add Add Value Value Value Add extract Add v1 action2

Slide 44

Slide 44 text

At runtime (4/4) switch(expr) { case Iadd(IValue(var v1), IValue(var v2)) -> ... case Iadd(var e1, var e2) - > ... IAdd IValue IValue extract expr v1 v2 action1 action2 Add Value Value Add extract Add v1 action2 Value v1 action1 Value v2

Slide 45

Slide 45 text

Guard or map ? switch(expr) { case Iadd(IValue(var v1), IValue(var v2)) -> ... case Iadd(var e1, var e2) - > ... Add extract Add v1 action2 Value v1 action1 Value v2 After N guards, use java.lang.ClassValue instead

Slide 46

Slide 46 text

De-constructor / unapply Scala unapply is slow (Tuple and Optional are objects) data class Add { private final Expr left; private final Expr right; ... public Optional> unapply() { return Some((left, right)); } } Extract the values => 2 object creations

Slide 47

Slide 47 text

Idea ! Create only one object for the whole pattern expr == Add(Value(var v1), Value(var v2)) <=> var foo = new $Foo$(); (expr as Add).deconstructor(foo::args1, foo::args2); (foo.args1 as Value).deconstructor(foo:args3); (foo args2 as Value).deconstructor(foo::args4); action(args3, args4); /* runtime */ class $Foo$ { Expr arg1; Expr arg2; int arg3; int arg4; } args1 args2 args3 args4

Slide 48

Slide 48 text

Magic ! Avoid the creation of the $Foo$ object, with the help of the VM Reify the stackframe as an object var frame = StackFrame.alloc(LExpr;LExpr;II) add.deconstructor(frame.refAt(0), frame.refAt(1)); … action.invokeWithStackFrame(frame, 2); a prototype is currently developed :)

Slide 49

Slide 49 text

Summary

Slide 50

Slide 50 text

Java 10 – Speculative planning Panama Stealh Valhalla – Value types in the VM Amber – A lot of small improvements – Pattern Matching

Slide 51

Slide 51 text

Q & A

Slide 52

Slide 52 text

More slides !!

Slide 53

Slide 53 text

Pizza into Java: translating theory into practice Martin Odersky, Philip Wadler POPL 97

Slide 54

Slide 54 text

Pizza Java + generics + lambdas + pattern matching Generics → Java 5 Lambdas → Java 8 Pattern Matching → Java 10 ??

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

Use-site Variance Wildcard are use-site Variance @FunctionalInterface interface Function { U apply(T t) } interface Stream { Stream map( Function super T, ? extends U> mapper) } Stream s1 = … Stream s2 =s1.map((Object o) - > 3);

Slide 57

Slide 57 text

Declaration-site Variance vs Use-site Variance Declaration site Variance @FunctionalInterface interface Function { U apply(T t) } interface Stream { Stream map( Function super T, ? extends U> mapper) } Stream s1 = … Stream s2 =s1.map((Object o) - > 3);

Slide 58

Slide 58 text

Enhanced Constant Folding You can not emit an invokedynamic in Java – Testing is not fun :( The Java compiler is not able to propagate constants – Macro ? => add Intrinisics.ldc/invokedynamic + a mechanism to propagate constant (Constable?)

Slide 59

Slide 59 text

Enhanced Enum Generics in enum enum ChronoField { YEAR, MONTH, DAY_OF_MONTH, DAY_OF_WEEK, } Frankenstenum in my opinion

Slide 60

Slide 60 text

And switch with statements ? If limited to switch on types, use the double switch trick ! String s; int index = invokedynamic(expr); recipe […] switch(index) { case 0: s = "JSObject"; break; case 1: s = "JSArray"; break; default: s = "other"; } return s;