jdart - oraclecr.openjdk.java.net/~forax/jvmsummit2012/jvmsummit12.pdf · use a linear*...
TRANSCRIPT
JDart
https://github.com/Geozz/DartRuntime
Rémi ForaxJVM Summit'12
Dart in one slide
Dynamic Language2 runtimes : DartVM / Dart2js
Less dynamic than Java ?
Better JavaScriptScope done right,
classes, no_such_method, mirrors
Optionally typestypes are mostly for documentation
checked modeIntegers are nullable and infinite
DartVM
Derived from V8
Not a production VM (yet!)
Client VM / 32 bits only
Two tiers compiler
Use tagged pointer (small integer/reference)
Far better than Java boxing !
Example on Fibonacci
int fibo(n) { if (n < 2) return 1; return fibo(n-1) + fibo(n-2);}
main() { fibo(7);}
In assembler – simple code
0xf3108f0a push [ebp+0x8]0xf3108f0d push 0x20xf3108f12 mov ecx,0xf31b8f11 'ICData target:-'0xf3108f17 mov edx,0xf331d279 Array[2, 2, null]0xf3108f1c call 0xf3100230 [stub: TwoArgsCheckInlineCache]0xf3108f21 add esp,0x80xf3108f24 push eax0xf3108f25 mov ecx,0xf31b8ca1 'Function 'fibo': static.'0xf3108f2a mov edx,0xf31a1ba9 Array[1, 1, null]0xf3108f2f call 0xf5600420 [stub: CallStaticFunction]0xf3108f34 add esp,0x40xf3108f37 push eax
0xf3108f38 push [ebp+0x8]0xf3108f3b push 0x4... ; same code again !0xf3108f66 mov ecx,0xf31b8fd1 'ICData target:+'0xf3108f6b mov edx,0xf331d279 Array[2, 2, null]0xf3108f70 call 0xf3100230 [stub: TwoArgsCheckInlineCache]0xf3108f75 add esp,0x80xf3108f78 push eax0xf3108f79 pop eax0xf3108f7a mov ebx,0xf31b8ca1 'Function 'fibo': static.'0xf3108f7f inc [ebx+0x43]0xf3108f82 cmp [ebx+0x43],0x7d00xf3108f89 jng 0xf3108f9e
In assembler - optimized
0xf3109005 mov eax,[ebp+0x8]0xf3109008 mov edx,0x20xf310900d mov ecx,eax0xf310900f test al,0x10xf3109011 jnz 0xf31090830xf3109017 sub eax,edx0xf3109019 jo 0xf31090830xf310901f push eax0xf3109020 mov ecx,0xf31b8ca1 'Function 'fibo': static.'0xf3109025 mov edx,0xf31a1ba9 Array[1, 1, null]0xf310902a call 0xf5600420 [stub: CallStaticFunction]0xf310902f add esp,0x40xf3109032 push eax
0xf3109033 mov eax,[ebp+0x8]0xf3109036 mov edx,0x4... ; same code again0xf310905b mov ecx,eax0xf310905d or eax,edx0xf310905f test al,0x10xf3109061 jnz 0xf310909b0xf3109067 mov eax,ecx0xf3109069 add eax,edx0xf310906b jo 0xf310909b0xf3109071 mov esp,ebp0xf3109073 pop ebp0xf3109074 ret
Dart on the JVM
Dart on server
uses invokedynamic !
but avoid useless boxing● precise static type analysis
(done offline currently)● split-path trick
JDart static analysis
Use a linear* interprocedural type flow analysis before generating bytecode
Don't use declared type by default
Can be used in rare cases in checked mode
Works with an horizon, try to share/reuse analysis
Analysis not done more than K times by method (actually K=4)
* almost :)
Example on Fibonacci
int fibo(n [7]) { if (n < 2) return 1; return fibo(n -1 [6]) + fibo(n-2);}
main() { fibo(7);}
Example on Fibonacci
int fibo(n [7]) { if (n < 2) return 1; return fibo(n -1 [6]) + fibo(n-2);}
int fibo(n [0, +inf]) { if (n < 2) return 1; // return type [1] return fibo(n [2, +inf] -1) + fibo(n-2);}
main() { fibo(7);}
Example on Fibonacci
int fibo(n [7]) { if (n < 2) return 1; return fibo(n -1 [6]) + fibo(n-2);}
int fibo(n [0, +inf]) { if (n < 2) return 1; // return type = [1] return [-inf, +inf]? + fibo(n-2 [0, +inf]); // return type = [-inf, +inf]}
main() { fibo(7);}
Example on Fibonacci
int fibo(n [7]) { if (n < 2) return 1; return fibo(n -1 [6]) [-inf, +inf] + fibo(n-2 [5]) [-inf, +inf];}
[-inf, +inf] int fibo(n [0, +inf]) { if (n < 2) return 1; // return type = [1] return [-inf, +inf]? + fibo(n-2 [0, +inf]); // return type = [-inf, +inf]}
main() { fibo(7);}
Example on Fibonacci
[-inf, +inf] int fibo(n [7]) { if (n < 2) return 1; return fibo(n -1 [6]) [-inf, +inf] + fibo(n-2) [-inf, +inf];}
[-inf, +inf] int fibo(n [0, +inf]) { if (n < 2) return 1; // return type = [1] return [-inf, +inf]? + fibo(n-2 [0, +inf]); // return type = [-inf, +inf]}
main() { fibo(7);} We can remove the first fibo because
fibo([7]) doesn't offer a more precise return type
Split-path generation
Methods that takes an int > int32 are compiled in two methods
If return type is int, int32 will be used and overflow values will use a thread local exception
In the method, ints are compiled using two variables (int32 and BigInt) if BigInt is null, value is int32
Overflow detection is added where neededusing the profile
Fibo in pseudo Java
private static int fibo(int n) { if (n < 2) return 1; int r1; BigInt _r1; try { r1 = invokedynamic fibo(n -1); _r1 = null; } catch(ControlFlowException e) { r1 = 0; _r1 = e.value; } int r2; BigInt _r2; try { r2 = invokedynamic fibo(n -2); _r2 = null; } catch(ControlFlowException e) { r2 = 0; _r2 = e.value; } int r3; BigInt _r3; if (_r1 == null && _r2 == null) try { r3 = RT.addExact(r1, r2); _r3 = null; } catch(ArithmeticException e) { _r3 = invokedynamic addOverflowed(r1, r2); r3 = 0; } else _r3 = invokedynamic addBig(r1, _r1, r2, _r2); r3 = 0; if (_r3 == null) return r3; throw ControlFlowException.valueOf(_r3); }
In assembler
...fd4c: mov %esi,(%rsp)
...fd4f: cmp $0x2,%esi
...fd52: jl ...fda1 ;*if_icmpge
...fd54: dec %esi ;*isub
...fd57: callq 0x00007f6459038060 ;*invokestatic fibo
...fd5c: mov %eax,0x4(%rsp)
...fd60: mov (%rsp),%esi
...fd63: add $0xfffffffffffffffe,%esi ;*isub
...fd67: callq 0x00007f6459038060 ;*invokestatic fibo
...fd6c: mov %eax,%r9d
...fd6f: mov 0x4(%rsp),%eax
...fd73: add %r9d,%eax
...fd76: mov 0x4(%rsp),%r11d
...fd7b: xor %eax,%r11d
...fd7e: mov %r9d,%r8d
...fd81: xor %eax,%r8d
...fd84: and %r8d,%r11d
...fd87: test %r11d,%r11d
...fd8a: jge ...fda6 ;inline RT.addExact
...fd8c: mov $0xa5,%esi
...fd91: mov %r9d,(%rsp)
...fd95: xchg %ax,%ax
...fd97: callq 0x00007f6459039020 ; deoptimization
...fda1: mov $0x1,%eax
fast path ??
Execution time !Fibo(40) in second
DartVM Java boxing JDart (no inline) JDart Java (int only)0
2
4
6
8
10
12
14
16
18
1.65
15.26
0.93 0.69 0.73
Smaller is better
Questions ?
Image Credits
Phone booth by Louis du Monshttp://www.flickr.com/photos/2create/4433423854/
Overflow by James Whitesmithhttp://www.flickr.com/photos/jwhitesmith/7430605966/