Slide 1

Slide 1 text

Project Amber Rémi Forax Devoxx FR - April 2017 Project Amber Rémi Forax Devoxx FR - April 2017

Slide 2

Slide 2 text

Me, myself and I Father – 3 kids Assistant Prof – University Paris East Marne la Vallée 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 Two new Features – Value types – Generics over primitive and value types

Slide 6

Slide 6 text

What’s wrong with objects ? Every objects have an header – 64 bits (for hotspot) wasted for every objects Arrays of objects are array of references – Cache misses :( Too many references – Too much allocation → Slow the GC

Slide 7

Slide 7 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 8

Slide 8 text

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

Slide 9

Slide 9 text

Value types + Generics Problems :( Bytecode is not ready for that ! Specialization of the generic code at runtime ? By the JIT ! Generics over objects still erased for compatibility Wildcards / Boxing List> vs List vs List

Slide 10

Slide 10 text

Project Panama Java does not fear C anymore – Make the JIT generates the JNI Stub Need metadata to describe – C structs layout in memory – Calling convention Access C heap safely through interfaces

Slide 11

Slide 11 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 (defined by the JDK) – Intrinsics for the VM

Slide 12

Slide 12 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 13

Slide 13 text

so no new language feature in Java 10 ?

Slide 14

Slide 14 text

Amber !

Slide 15

Slide 15 text

Project Amber http://openjdk.java.net/projects/amber/ explore and incubate smaller, productivity-oriented language features – Local-Variable Type Inference – Enhanced Enums – Lambda Leftovers – ???

Slide 16

Slide 16 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 17

Slide 17 text

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

Slide 18

Slide 18 text

Lambda leftovers ‘_’ means unused parameter Map> map = ... map.computeIfAbsent(key, _ - > new HashSet<>()) .add(value); Lambda parameters open a new scope map.merge(key, value, (old, value) - > old + value); Better inference – Fix cases where overloading is obvious for a human

Slide 19

Slide 19 text

Pattern Matching

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Brain Dump mode

Slide 22

Slide 22 text

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

Slide 23

Slide 23 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 24

Slide 24 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 25

Slide 25 text

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

Slide 26

Slide 26 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 27

Slide 27 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 28

Slide 28 text

Closed Hierarchy

Slide 29

Slide 29 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 30

Slide 30 text

Data Class data Point(int x, int y); Provide a way to represent ‘dumb’ data – Abstraction ‘it’s a data class’ – Less boiler plate Generate (at runtime ?) – equals, hashCode, toString, getters ? – Value types also need that too !

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Encapsulation

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

De-constructor ? return switch(expr) { case Add(Value(v1), Value(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 { private final Expr left; private final Expr right; ... public Expr, Expr deconstructor() { return left, right; } ...

Slide 39

Slide 39 text

Under the hood

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

Use invokedynamic 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 43

Slide 43 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;

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 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 49

Slide 49 text

Idea ! Create only one object for the whole pattern expr == Add(Value(v1), Value(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 50

Slide 50 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); John Rose starts a prototype :)

Slide 51

Slide 51 text

Summary

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

Q & A

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

No content