state of java.lang.invoke implementation in...
TRANSCRIPT
1 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
State of java.lang.invoke Implementation in OpenJDK
Vladimir Ivanov HotSpot JVM Compile r Oracle Corp. JVM Language Summit 2015
2 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Safe Harbor Statement
The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle.
3 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
2005
JSR 292 Support for Dynamically Typed Languages in the JVM
Method Handle API (Early Draft Review)
Java 7 Release
JSR 292 Expert Group
formed
Initial design sketch Expert Group reboot
API refinement (e.g., CONSTANT_MethodHandle)
API refinement (e.g., BootstrapMethods)
2006 2007 2008 2009 2010 2011
4 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Method Handles in JDK 7 GA § Good
– Flexible and powerful. – MH graphs are aggressively inlined and optimized.
§ Not-so-good – “Performance cliff” when inlining does not occur – MH.invoke() is slow – NoClassDefFoundError in large applications
§ Ugly – No general fast path for compiled code – JVM is entangled in MH operations
5 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Quest for a Better IR
§ Root problem: MH chains are wrong IR for the JVM
§ Lambda Forms for the rescue – Mostly-native moves into Java – Decouple representation decisions from the JVM – Meshes better with the JVM execution engine
§ translates to bytecode § Interprets and/or compiles
– Erases types, avoiding NCDFE issues
2012: Lambda Forms in 7u40
6 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
MHs vs LFs
MH
LF
n:1 .form
public
internal “ [A lambda form is a] … symbolic, non-executable form of a method handle's invocation semantics.”
“A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values.”
javadoc
7 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
The Grand Plan MH
CS MT
public n:1
.type
.target
MH = MethodHandle MT = MethodType CS = CallSite
n:1
JDK
8 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
The Grand Plan MH
CS
LF
MN
MT
MTF
DMH
n:1 .form
n:1 .vmentry
public
internal
n:1
.type
.target
MH = MethodHandle MT = MethodType CS = CallSite LF = LambdaForm DMH = DirectMethodHandle BMH = BoundMethodHandle MN = MemberName MTF = MethodTypeForm
n:1
n:1
VM anon classes
BMH extends
JDK
9 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
The Grand Plan MH
CS
LF
MN
JVM
MT
MTF
DMH
n:1 .form
n:1 .vmentry
n:1 .vmtarget
public
internal
n:1
.type
.target
MH = MethodHandle MT = MethodType CS = CallSite LF = LambdaForm DMH = DirectMethodHandle BMH = BoundMethodHandle MN = MemberName MTF = MethodTypeForm MHN = MethodHandleNative
n:1
n:1
JVM_Method
MH::linkTo* MH::invokeBasic
native stubs linkCallSite linkMethod
etc
Upcalls
MH::init/resolve setCallSiteTarget*
etc
VM calls
MHN
resolved_references[]
appendix
VM anon classes
BMH extends
methodHandles*.cpp
JDK
10 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form
putObjectFieldCast_000=Lambda(a0:L,a1:L,a2:L)=>{ t3:J=DMH.fieldOffset (a0:L); t4:L=DMH.checkBase (a1:L); t5:L=DMH.checkCast (a0:L,a2:L); t6:V=Unsafe.putObject((Unsafe@...),t4:L,t3:J,t5:L);void}
Example: putfield / Lookup.findSetter
11 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form
putObjectFieldCast_000=Lambda(a0:L,a1:L,a2:L)=>{ t3:J=DMH.fieldOffset (a0:L); t4:L=DMH.checkBase (a1:L); t5:L=DMH.checkCast (a0:L,a2:L); t6:V=Unsafe.putObject((Unsafe@...),t4:L,t3:J,t5:L);void} § Basic value type is one of { ref, int, long, float, double } + void
– represented as signature letters "LIJFD” + “V”
Example: putfield / Lookup.findSetter
12 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form
putObjectFieldCast_000=Lambda(a0:L,a1:L,a2:L)=>{ t3:J=DMH.fieldOffset (a0:L); t4:L=DMH.checkBase (a1:L); t5:L=DMH.checkCast (a0:L,a2:L); t6:V=Unsafe.putObject((Unsafe@...),t4:L,t3:J,t5:L);void}
Example: putfield / Lookup.findSetter LF.names[7]
Name.function Name.arguments[]
Name.type Name.index
LF.debugName
LF.result = -1
LF.arity = 3
13 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form
putObjectFieldCast_000=Lambda(a0:L,a1:L,a2:L)=>{ t3:J=DMH.fieldOffset (a0:L); t4:L=DMH.checkBase (a1:L); t5:L=DMH.checkCast (a0:L,a2:L); t6:V=Unsafe.putObject((Unsafe@...),t4:L,t3:J,t5:L);void}
Execution
14 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form
Entry point: LambdaForm::vmentry Can point to:
– LambdaForm Interpreter – compiled bytecode
Execution
.form
MH
LF
MN
JVM_Method
.vmentry
.vmtarget
.from_interpreted .from_compiled
interpreter compiled code
MH
LF
class (VM anon)
?
15 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Interpreter
16 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Compiled Form static void putObjectFieldCast_000( Object, Object, Object ); 0: aload_0 1: invokestatic #16 // DMH.fieldOffset:... 4: lstore_3 5: aload_1 6: invokestatic #20 // DMH.checkBase:... 9: astore 5 11: aload_0 12: aload_2 13: invokestatic #24 // DMH.checkCast:... 16: astore 6 18: ldc #26 // <<sun.misc.Unsafe@3830f1c0>> 20: checkcast #28 // class sun/misc/Unsafe 23: aload 5 25: lload_3 26: aload 6 28: invokevirtual #32 // Unsafe.putObject:(Object;Object;)V 31: return
RuntimeVisibleAnnotations:
LambdaForm$Hidden, LambdaForm$Compiled, ForceInline
t3:J
t4:L
t5:L
t6:V
a0:L a1:L a2:L putObjectFieldCast_000=Lambda(a0:L,a1:L,a2:L)=>{
t3:J=DMH.fieldOffset (a0:L);
t4:L=DMH.checkBase (a1:L);
t5:L=DMH.checkCast (a0:L,a2:L);
t6:V=Unsafe.putObject((Unsafe@...),t4:L,t3:J,t5:L);void}
17 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
VM Anonymous Classes Constant Pool Patching static void putObjectFieldCast_000(…); ... 18: ldc #26
// String “CONSTANT_PLACEHOLDER_0“ 20: checkcast #28
// class sun/misc/Unsafe 23: aload 5 25: lload_3 26: aload 6 28: invokevirtual #32 // Unsafe.putObject(...) 31: return
t6:V
putObjectFieldCast_000=Lambda(a0:L,a1:L,a2:L)=>{
t3:J=DMH.fieldOffset (a0:L);
t4:L=DMH.checkBase (a1:L);
t5:L=DMH.checkCast (a0:L,a2:L);
t6:V=Unsafe.putObject((Unsafe@...),t4:L,t3:J,t5:L);void}
ConstantPool
#26 = Utf8 “...”
...
resolved_references[] { ..., unsafeObj , ...}
Unsafe.defineAnonymousClass( LambdaForm.class, byte[] {…}, Object[] { …, unsafeObj, …})
#26
18 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
MHs vs LFs
§ Shared Lambda Form – many method handles share a
single LF instance
§ Customized Lambda Form – LF instance is customized for
some particular method handle
Sharing vs Customization
LF
LF
MH
MH
19 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
MHs vs LFs
putObjectFieldCast_000=Lambda(a0:L,a1:L,a2:L)=>{
t3:J=DMH.fieldOffset (a0:L);
t4:L=DMH.checkBase (a1:L);
t5:L=DMH.checkCast (a0:L,a2:L);
t6:V=Unsafe.putObject((Unsafe@...),t4:L,t3:J,t5:L);void}
Example: putfield / Lookup.findSetter
LF
MH
.form
LOOKUP.findSetter( MyClass1.class, “f1", Field1.class);
MT Field2.class
offset2
(MyClass2,Field2)void (MyClass1,Field1)void
Field1.class offset1
LOOKUP.findSetter( MyClass2.class, “f2", Field2.class);
… constructs …
(L,L,L)void .form LF
MH
20 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
MHs vs LFs
putIntField_000=Lambda(a0:L,a1:L,a2:I)=>{
t3:J=DMH.fieldOffset (a0:L);
t4:L=DMH.checkBase (a1:L);
t5:V=Unsafe.putInt((Unsafe@...),t4:L,t3:J,a2:I);void}
Example: putfield / Lookup.findSetter
LF
MH
.form
LOOKUP.findSetter( MyClass1.class, “i1", int.class);
MT long.class
offset2
(MyClass2,long)void (MyClass1,int)void
int.class offset1
LOOKUP.findSetter( MyClass2.class, “l2", long.class);
… constructs …
(L,L,I)void .form LF
MH
putLongField_000=Lambda(a0:L,a1:L,a2:J)=>{
t3:J=DMH.fieldOffset (a0:L);
t4:L=DMH.checkBase (a1:L);
t5:V=Unsafe.putLong((Unsafe@...),t4:L,t3:J,a2:J);void}
(L,L,J)void
21 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
7 GA 8 GA 7u40 8u20 8u40
Lambda Forms j.l.i enhancements Type speculation in C2 Math.exact*() intrinsics
Nashorn Project Lambda
JSR 292 Released Lambda Form Sharing
22 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
23 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Caching 8u40: JEP 210
LF
MH
LF
MH ~106
~106 ~103
~104 ~103
classes classes
24 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Sharing vs Customization Example: MHs.guardWithTest()
T guard(A... a, B... b) { if (test(a...)) return target(a..., b...); else return fallback(a..., b...); }
guard=Lambda(a0:L, a…, b…) => { t1:I =<<test>>(a…); t2:L=MHI.selectAlternative( t1:I, <<target>>, <<fallback>>); t3:?=MH.invokeBasic(t2:L, a…, b…);t3}
25 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Sharing vs Customization Example: Customized version
guard_000=Lambda(a0:L)=>{ t1:I =(MH()boolean@...); t2:L=MHI.selectAlternative( t1:I,(MH()void@...),(MH()void@...)); t3:V=MH.invokeBasic(t2:L);void}
static void guard_000(Object); ldc ... // <<MethodHandle()boolean>> checkcast ... // class MethodHandle invokevirtual ... // MethodHandle.invokeBasic:()I … if_icmpne … ldc ... // <<MethodHandle()void>> checkcast ... // class MethodHandle astore_2 aload_2 invokevirtual ... // MethodHandle.invokeBasic:()V goto … ldc ... // <<MethodHandle()void>> checkcast ... // class MethodHandle astore_2 aload_2 invokevirtual ... // MethodHandle.invokeBasic:()V return
t1:I
test: MethodHandle target: MethodHandle fallback: MethodHandle
t2:L +
t3:V
26 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Sharing vs Customization Example: Shareable version
guard_000=Lambda(a0:L)=>{ t3:L=BMH$Species_L3.argL0(a0:L); // test t4:L=BMH$Species_L3.argL1(a0:L); // target t5:L=BMH$Species_L3.argL2(a0:L); // fallback t6:I =MethodHandle.invokeBasic(t3:L); t7:L=MethodHandleImpl.selectAlternative(t6:I,t4:L,t5:L); t8:V=MethodHandle.invokeBasic(t7:L);void}
27 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Sharing
§ Smaller dynamic footprint – # of loaded classes, Metaspace size
§ Faster startup/warmup – less LFs to instantiate, less classes to load, less code to compile
§ Enables new optimizations – Lambda Form precompilation – Improves worst case stack consumption
Pros
28 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Sharing Dynamic Footprint
1
2
4
8
16
metaspace
classes
Measurements by Sergey Kuksenko 8u40: b05 vs b21, Nashorn
ratio
Octane
higher/better
29 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Sharing Startup / Warmup
-80
-30
20
70
120
8u40: b05 vs b21, Nashorn
354%
%
1st iteration duration higher/better
30 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Precompilation
§ Before: – first 30 invocations go through LF interpreter – then compiled to bytecode
§ After: – Lambda Form is precompiled during creation – completely bypasses LF interpreter
31 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Stack Consumption
jdk.nashorn.internal.scripts.Script$Recompilation$2$test.f1(test.js:1) j.l.i.LambdaForm$DMH/804581391.invokeStatic_LL_L
j.l.i.LambdaForm$DMH/1854778591.invokeSpecial_L3_L
j.l.i.LambdaForm$NamedFunction.invoke_LLL_L
j.l.i.LambdaForm$DMH/804581391.invokeStatic_LL_L
j.l.i.LambdaForm$NamedFunction.invokeWithArguments
j.l.i.LambdaForm.interpretName
j.l.i.LambdaForm.interpretWithArguments
j.l.i.LambdaForm.interpret_L
j.l.i.LambdaForm$DMH/1854778591.invokeSpecial_L3_L
j.l.i.LambdaForm$NamedFunction.invoke_LLL_L
j.l.i.LambdaForm$DMH/804581391.invokeStatic_LL_L
j.l.i.LambdaForm$NamedFunction.invokeWithArguments
j.l.i.LambdaForm.interpretName
j.l.i.LambdaForm.interpretWithArguments
j.l.i.LambdaForm.interpret_L
j.l.i.LambdaForm$MH/2142080121.linkToCallSite
jdk.nashorn.internal.scripts.Script$Recompilation$1$test.:program(test.js:2)
Lambda Form Interpreter
reinvoke
exactInvoker
test.js: 1: function f1() {} 2: f1()
32 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Stack Consumption
jdk.nashorn.internal.scripts.Script$Recompilation$2$test.f1(test.js:1) j.l.i.LambdaForm$DMH/804581391.invokeStatic_LL_L j.l.i.LambdaForm$BMH/921760190.reinvoke j.l.i.LambdaForm$MH/1690254271.exactInvoker j.l.i.LambdaForm$MH/206835546.linkToCallSite
jdk.nashorn.internal.scripts.Script$Recompilation$1$test.:program(test.js:9)
Compiled Form
33 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Sharing Peak Performance
-20
-10
0
10
20
30
40
Measurements by Sergey Kuksenko 8u40: b05 vs b21, Nashorn
125%
%
higher/better
34 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lambda Form Sharing
§ Profile pollution – peak performance suffers
§ Non-constant MH calls became slower – JIT can’t inline through them – less optimized machine code
Problems in 8u40
35 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution
Customization vs Sharing
36 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution Customized version
static void guard_000(Object); ldc ... // <<test>> checkcast ... // class MethodHandle invokevirtual ... // MethodHandle.invokeBasic:()I … if_icmpne … ldc ... // <<target>> checkcast ... // class MethodHandle astore_2 aload_2 invokevirtual ... // MH.invokeBasic:()V goto … ldc ... // <<fallback>> checkcast ... // class MethodHandle astore_2 aload_2 invokevirtual ... // MethodHandle.invokeBasic:()V return
t1:I
t2:L +
t3:V guard_000=Lambda(a0:L)=>{ t1:I =<<test>>(); t2:L=MethodHandleImpl.selectAlternative( t1:I,<<target>>,<<fallback>>); t3:V=MethodHandle.invokeBasic(t2:L);void}
37 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution Customized version
static void guard_000(Object); ldc ... // <<alwaysTrue>> checkcast ... // class MethodHandle invokevirtual ... // MH.invokeBasic:()I … if_icmpne … ldc ... // <<target>> checkcast ... // class MethodHandle astore_2 aload_2 invokevirtual ... // MH.invokeBasic:()V goto … ldc ... // <<fallback>> checkcast ... // class MethodHandle astore_2 aload_2 invokevirtual ... // MH.invokeBasic:()V return
t1:I
t2:L +
t3:V
0%
guard_000=Lambda(a0:L)=>{ t1:I =<<alwaysTrue>>(); t2:L=MethodHandleImpl.selectAlternative( t1:I,<<target>>,<<fallback>>); t3:V=MethodHandle.invokeBasic(t2:L);void}
38 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution Customized version
static void guard_001(Object); ldc ... // <<alwaysFalse>> checkcast ... // class MethodHandle invokevirtual ... // MH.invokeBasic:()I … if_icmpne … ldc ... // <<target>> checkcast ... // class MethodHandle astore_2 aload_2 invokevirtual ... // MH.invokeBasic:()V goto … ldc ... // <<fallback>> checkcast ... // class MethodHandle astore_2 aload_2 invokevirtual ... // MH.invokeBasic:()V return
t1:I
t2:L +
t3:V
100%
guard_001=Lambda(a0:L)=>{ t1:I =<<alwaysFalse>>; t2:L=MethodHandleImpl.selectAlternative( t1:I,<<target>>,<<fallback>>); t3:V=MethodHandle.invokeBasic(t2:L);void}
39 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution Shared version
static void guard_000(Object); aload_0 checkcast … // BMH$Species_L3 getfield ... // BMH$Species_L3.argL0:Object invokevirtual ... // MH.invokeBasic:()I … if_icmpne … aload_2 checkcast ... // class MethodHandle astore_5 aload_5 invokevirtual ... // MH.invokeBasic:()V goto … aload_3 checkcast ... // class MethodHandle astore_5 aload_5 invokevirtual ... // MH.invokeBasic:()V return
???%
40 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution How to fix
static void guard_000(Object); aload_0 checkcast … // BMH$Species_L3 getfield ... // BMH$Species_L3.argL0:Object invokevirtual ... // MH.invokeBasic:()I … if_icmpne … aload_2 checkcast ... // class MethodHandle astore_5 aload_5 invokevirtual ... // MH.invokeBasic:()V goto … aload_3 checkcast ... // class MethodHandle astore_5 aload_5 invokevirtual ... // MH.invokeBasic:()V return
?%
§ Idea: customized profiling – collect per-MethodHandle profile
during warm-up – inject profile into the JVM when
warm-up is over
41 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution Custom Branch Profiling
guard_000=Lambda(a0:L)=>{ t1:L=BMH$Species_L4.argL0(a0:L); // test t2:L=BMH$Species_L4.argL1(a0:L); // target t3:L=BMH$Species_L4.argL2(a0:L); // fallback t4:L=BMH$Species_L4.argL3(a0:L); // counts (int[2]) t5:I =MethodHandle.invokeBasic(t1:L); t6:I =MethodHandleImpl.profileBoolean(t5:I,t4:L); t7:L=MethodHandleImpl.selectAlternative(t6:I,t2:L,t3:L); t8:V=MethodHandle.invokeBasic(t7:L);void}
42 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution Custom Branch Profiling Logic
§ profiling / warm-up – interpreter / C1 – C2 when counts array is unknown
§ per-LambdaForm compiled method
§ optimized – C2 intrinsic – injects per-MH counts into IR
43 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution Custom Branch Profiling Logic
§ profiling / warm-up – interpreter / C1 – C2 when counts array is unknown
§ per-LambdaForm compiled method
§ optimized – C2 intrinsic – injects per-MH counts into IR
44 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution
§ Type profile – not a problem – Type speculation (by Roland Westrelin in 8u20)
§ -XX:+UseTypeProfile -XX:TypeProfileLevel=[012]{3}
§ Deoptimization counts – no generic solution yet – fixed some manifestations of the problem
§ JDK-8074551: GWT can be marked non-compilable due to deopt count pollution
Other cases
45 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Non-Constant Method Handle
Invocation
MH.invokeExact() et al
46 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Non-Constant Method Handle Invocation Non-constant method handle
@ 105 jsr292.GWT::run1 (7 bytes) inline (hot) @ 3 java.lang.invoke.LambdaForm$MH/789451787::invokeExact_MT (13 bytes) inline (hot) @ 2 java.lang.invoke.Invokers::checkExactType (30 bytes) inline (hot) @ 11 java.lang.invoke.MethodHandle::type (5 bytes) accessor @ 9 java.lang.invoke.MethodHandle::invokeBasic()V (0 bytes) receiver not constant
47 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Non-Constant Method Handle Invocation Customized version java.lang.invoke.LambdaForm$MH/1510467688::guard (56 bytes)
@ 5 java.lang.invoke.LambdaForm$DMH/1581781576::invokeStatic__I (13 bytes) inline (hot) @ 1 java.lang.invoke.DirectMethodHandle::internalMemberName (8 bytes) inline (hot) @ 9 jsr292.GWT::test1 (12 bytes) inline (hot) @ 31 java.lang.invoke.LambdaForm$DMH/1581781576::invokeStatic__V (13 bytes) inline (hot) @ 1 java.lang.invoke.DirectMethodHandle::internalMemberName (8 bytes) inline (hot) @ 9 jsr292.GWT::f1 (2 bytes) inline (hot) @ 52 java.lang.invoke.LambdaForm$DMH/1581781576::invokeStatic__V (13 bytes) inline (hot) @ 1 java.lang.invoke.DirectMethodHandle::internalMemberName (8 bytes) inline (hot) @ 9 jsr292.GWT::f2 (2 bytes) inline (hot)
48 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Non-Constant Method Handle Invocation Shared version java.lang.invoke.LambdaForm$MH/1252585652::guard (68 bytes)
@ 24 java.lang.invoke.MethodHandle::invokeBasic()I (0 bytes) receiver not constant @ 47 java.lang.invoke.MethodHandle::invokeBasic()V (0 bytes) receiver not constant @ 64 java.lang.invoke.MethodHandle::invokeBasic()V (0 bytes) receiver not constant
49 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
§ Customized Lambda Form – single compiled method per
MH chain / root LF
§ Shared Lambda Form – compiled method per MH/LF
Non-Constant Method Handle Invocation
nmethod
50 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Non-Constant Method Handle Invocation
nmethod Solution: Optional Customization § Original (shared) guard_000=Lambda(a0:L)=>{ t1:L=BMH$Species_L4.argL0(a0:L); … § Customized (a0 is overridden by t1:L) guard_000=Lambda(a0:L)=>{ t1:L=<<MethodHandle …>> t2:L=BMH$Species_L4.argL0(t1:L); …
51 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
7 GA 8 GA 9+
Timeline
7u40 8u20 8u40
λ-form sharing
Performance fixes
(e.g. per-MH profiling, LF customization)
λ-forms catchException λ-form sharing
type speculation Math.exact*() intrinsics
Now
8u60
Nashorn Project Lambda
Aug, 2015
52 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Future work
• Ultimate Sharing • MH.asType() Optimization • Reduce Stack Consumption • Lightweight Code Loading • Profile Pollution
53 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Ultimate Sharing
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ I , J , L , … , F ]
...
Currently: Lambda Form instance per erased signature
Goal: Single Lambda Form instance per unit of behavior
call site
LF
LF
target
54 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Ultimate Sharing
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ L , L , L , … , L ]
[ L , L , L , … , L ]
...
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ I , J , L , … , F ]
...
call site
LF
LF
target
No conversions Boxing
55 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Ultimate Sharing
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ L , L , L , … , L ]
[ L , L , L , … , L ]
...
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ I , J , L , … , F ]
...
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ L ]
[ L ]
call site
LF
LF
target
No conversions Boxing Boxing + VarArgs
56 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Ultimate Sharing
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ ]
[ ]
§ JVM support is needed – reliable box/unbox elimination – array explosion
[ I , J , L , … , F ]
[ I , J , L , … , F ]
[ L ]
[ L ]
57 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
MethodHandle.asType()
§ Improve caching/sharing of MH.asType() transformations – type adaptations are expensive to construct
§ Single-element per-MH cache – subject to profile pollution
§ MH.invoke() on shared MH doesn’t work well – (w.r.t. peak performance)
Better Caching / Sharing
58 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Reduce stack consumption
jdk.nashorn.internal.scripts.Script$Recompilation$2$test.f1(test.js:1) j.l.i.LambdaForm$DMH/804581391.invokeStatic_LL_L j.l.i.LambdaForm$BMH/921760190.reinvoke j.l.i.LambdaForm$MH/1690254271.exactInvoker j.l.i.LambdaForm$MH/206835546.linkToCallSite
jdk.nashorn.internal.scripts.Script$Recompilation$1$test.:program(test.js:9)
Precompiled Lambda Forms
59 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Reduce stack consumption
jdk.nashorn.internal.scripts.Script$Recompilation$2$test.f1(test.js:1) j.l.i.LambdaForm$DMH/804581391.invokeStatic_LL_L j.l.i.LambdaForm$BMH/921760190.reinvoke j.l.i.LF$MH/….customized j.l.i.LambdaForm$MH/1690254271.exactInvoker j.l.i.LambdaForm$MH/206835546.linkToCallSite
jdk.nashorn.internal.scripts.Script$Recompilation$1$test.:program(test.js:9)
(1) Lambda Form Inlining
60 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Reduce stack consumption
jdk.nashorn.internal.scripts.Script$Recompilation$2$test.f1(test.js:1) j.l.i.LambdaForm$MH/483294845.customized j.l.i.LambdaForm$MH/206835546.linkToCallSite
jdk.nashorn.internal.scripts.Script$Recompilation$1$test.:program(test.js:9)
(1) Lambda Form Inlining
61 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Reduce stack consumption
§ Pros – easy to implement – doesn’t require any JVM extensions
§ Cons – defeats Lambda Form sharing
§ too many indy call sites to specialize for § VM anonymous classes are too heavyweight
(1) Lambda Form Inlining
62 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Reduce stack consumption
jdk.nashorn.internal.scripts.Script$Recompilation$2$test.f1(test.js:1) (*)
jdk.nashorn.internal.scripts.Script$Recompilation$1$test.:program(test.js:9) (*) during invocation: linkToCallSite =tail-call=> reinvoke =tail-call=> exactInvoker =tail-call=> invokeStatic_LL_L =tail-call=> …$test.f1
(2) Tail Calls
63 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lightweight Code Loading VM Anonymous Classes
Class<?> Unsafe.defineAnonymousClass( Class<?> hostClass, byte[] code, Object[] cpPatches)
64 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lightweight Code Loading VM Anonymous Classes
Class<?> Unsafe.defineAnonymousClass( Class<?> hostClass, byte[] code, Object[] cpPatches)
65 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Lightweight Code Loading
MethodHandle Lookup.loadCode( /*Class<?> hostClass,*/ byte[] code, Object[] cpPatches)
66 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Profile Pollution
LF
MH
class
67 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Future Extensions
• Variable Handles • Small API Enhancements • Native Calls
68 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
JEP 193: Variable Handles
§ Safe, performant, enhanced atomics – access to fields and array elements
§ VarHandles are like method handles for data – Abstracts over location – static fields, instance fields, arrays, off heap – Supports explicit fences and atomic operation
§ Safer than Unsafe, as fast as MethodHandles
JEP-193 “Variable Handles” by Doug Lea, Paul Sandoz http://openjdk.java.net/jeps/193
69 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
API Enhancements
§ Candidates – MHs.tryFinally() – MHs.*Loop() – Lookup.lookupClass()/findSuperConstructor() – Additional combinators for argument handling
§ e.g. MHs.spreadArguments(MH target, int pos, int count)
[email protected] discussion http://mail.openjdk.java.net/pipermail/mlvm-dev/2015-February/006288.html
70 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Native Calls Project Panama: FFI
Java Native
Construction Lookup.findVirtual() et al Lookup.findNative()
Reference (typed) DirectMethodHandle NativeMethodHandle
Reference (direct) MemberName NativeEntryPoint
Linker MH.linkToVirtual() et al MH.linkToNative()
Invocation indy, MH.invoke(), MH.invokeExact()
“Making native calls from the JVM” by John Rose http://cr.openjdk.java.net/~jrose/panama/native-call-primitive.html
71 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Thank you!
@iwan0www
72 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Materials
§ Implementation Notes:– http://cr.openjdk.java.net/~vlivanov/talks/2015-Indy_Deep_Dive.pdf
§ https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic § https://wiki.openjdk.java.net/display/HotSpot/Bound+method+handles § https://wiki.openjdk.java.net/display/HotSpot/Direct+method+handles § https://wiki.openjdk.java.net/display/HotSpot/Method+handle+invocation § "Deconstructing MethodHandles” by Paul Sandoz
– https://wiki.openjdk.java.net/display/HotSpot/Deconstructing+MethodHandles § "Lambda Forms” by John Rose, JVMLS'12
– http://cr.openjdk.java.net/~jrose/pres/201207-LF-Tutorial.pdf
§ “J9's MethodHandle Compilation Pipeline” by Dan Heidinga, Jfocus VM Summit’15 – http://www.jfokus.se/jfokus15/preso/J9%20MethodHandle%20Compilation%20Pipeline.pdf
73 Copyright © 2015, Oracle and/or its affiliates. All rights reserved
Graphic Section Divider