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