amber.pdf

5ce0156bc2f1864459fd77229eff3fe3?s=47 forax
April 19, 2017
11

 amber.pdf

5ce0156bc2f1864459fd77229eff3fe3?s=128

forax

April 19, 2017
Tweet

Transcript

  1. Project Amber Rémi Forax - April 2017

  2. 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
  3. 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
  4. Release of Java 9 27 / 7 / 2017

  5. Project Valhalla OpenJDK project Started July 2014 Provide uniform data

    access model Value types + Generics specialization
  6. 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)
  7. Generics of value types class ArrayList<any E> implements List<E> {

    private E[] elements; ... } List<complex> list= new ArrayList<complex>(); The JIT will generate the specialization ! Will work with primitive types too List<int> list = new ArrayList<int>();
  8. 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
  9. 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
  10. 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
  11. so no new language feature in Java 10 ?

  12. Amber !

  13. 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 – ???
  14. Local Variable Type Inference simple var a = 3; var

    list = new ArrayList<String>(); use super type: var anonymous = new Object() { int x; }; not supported: var lambda = x -> x + 2; var ref = String::length;
  15. Misc ... ‘_’ means unused parameter public static void main(String[]

    _) { ... Lambda parameters open a new scope var cache = new HashMap<String, Info>(); var name = ... var info = cache.computeIfAbsent(name, name -> new Info(name));
  16. Pattern Matching

  17. None
  18. Brain Dump mode

  19. Example { or [{ "username": "remi", "user": "remi", ... ...

    } }, ... v1 v2 Extracting a user name from a JSON document
  20. 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"); } ...
  21. 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: ... }
  22. 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: ... }
  23. 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: ... };
  24. 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: ... };
  25. Closed Hierarchy

  26. 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)))
  27. 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 !
  28. 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
  29. 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) -> ... }; }
  30. 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 }; }
  31. ‘_’ means unused/anything Use _ in patterns return switch(expr) {

    case Add(Value(_), Value(var v2)) -> case Add(_, _) -> case Value _ -> };
  32. 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)
  33. Encapsulation

  34. 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; } }
  35. 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; }
  36. Under the hood

  37. Implementation Troubles Problems – If instanceof … else – De-constructor

    / Scala unapply – Sharing, zero allocation Goal Pattern matching on types == as fast as method calls ?
  38. If instanceof … else instanceof == dynamic suite of typechecks

    – Instanceof itself creates a series of if … else Linearly checks all patterns is slooooooow
  39. 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
  40. 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
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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<Tuple<Expr, Expr>> unapply() { return Some((left, right)); } } Extract the values => 2 object creations
  47. 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
  48. 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 :)
  49. Summary

  50. Java 10 – Speculative planning Panama Stealh Valhalla – Value

    types in the VM Amber – A lot of small improvements – Pattern Matching
  51. Q & A

  52. More slides !!

  53. Pizza into Java: translating theory into practice Martin Odersky, Philip

    Wadler POPL 97
  54. Pizza Java + generics + lambdas + pattern matching Generics

    → Java 5 Lambdas → Java 8 Pattern Matching → Java 10 ??
  55. None
  56. Use-site Variance Wildcard are use-site Variance @FunctionalInterface interface Function<T, U>

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

    Function<super T, extends U> { U apply(T t) } interface Stream<T> { <U> Stream<U> map( Function<? super T, ? extends U> mapper) } Stream<String> s1 = … Stream<Number> s2 =s1.map((Object o) - > 3);
  58. 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?)
  59. Enhanced Enum Generics in enum enum ChronoField<X extends IntValueish> {

    YEAR<Year>, MONTH<Month>, DAY_OF_MONTH<Integer>, DAY_OF_WEEK<DayOfWeek>, } Frankenstenum in my opinion
  60. 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;