Upload
danheidinga
View
408
Download
0
Embed Size (px)
Citation preview
Evolution of a Language Feature
Dan Heidinga, J9 VM Interpreter Lead
@DanHeidinga
26 October 2015
Invokedynamic
Brian Goetz, Java Language Architect
Oracle
Who am I?
I've been involved with virtual machine development at IBM
since 2007 and am now the J9 Virtual Machine Team Lead.
J9 is IBM's independent implementation of the JVM.
I've represented IBM on both the JSR 292 ('invokedynamic')
and JSR 335 ('lambda') expert groups and lead J9's
implementation of both JSRs.
I’ve also maintain the bytecode verifier and deal with various
other parts of the runtime.
2
Who am I?
Brian Goetz is the Java Language Architect at Oracle, and is
one of the leading authorities on the Java platform.
He is the author of the very successful 'Java Concurrency in
Practice', and has published over 75 articles on software
development.
He was the specification lead for JSR-335 (Lambda
Expressions for the Java Language) and has served on
numerous other JCP Expert Groups.
3
Important disclaimers
THE INFORMATION CONTAINED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL PURPOSES ONLY.
WHILST EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND ACCURACY OF THE INFORMATION
CONTAINED IN THIS PRESENTATION, IT IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED.
ALL PERFORMANCE DATA INCLUDED IN THIS PRESENTATION HAVE BEEN GATHERED IN A CONTROLLED
ENVIRONMENT. YOUR OWN TEST RESULTS MAY VARY BASED ON HARDWARE, SOFTWARE OR
INFRASTRUCTURE DIFFERENCES.
ALL DATA INCLUDED IN THIS PRESENTATION ARE MEANT TO BE USED ONLY AS A GUIDE.
IN ADDITION, THE INFORMATION CONTAINED IN THIS PRESENTATION IS BASED ON IBM’S CURRENT
PRODUCT PLANS AND STRATEGY, WHICH ARE SUBJECT TO CHANGE BY IBM, WITHOUT NOTICE.
IBM AND ITS AFFILIATED COMPANIES SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT
OF THE USE OF, OR OTHERWISE RELATED TO, THIS PRESENTATION OR ANY OTHER DOCUMENTATION.
NOTHING CONTAINED IN THIS PRESENTATION IS INTENDED TO, OR SHALL HAVE THE EFFECT OF:
– CREATING ANY WARRANT OR REPRESENTATION FROM IBM, ITS AFFILIATED COMPANIES OR ITS
OR THEIR SUPPLIERS AND/OR LICENSORS
4
Danger: highly technical talk!
This talk assumes you’re familiar with:
– JVM bytecode set
– java.lang.invoke.MethodHandle and related classes
– invokedynamic
5
Full bleed images preferredText over top of full bleed images would be in white or a color from the color palette that
would offer good contrast. Also, colored text in Arial Bold would have greater impact.
JVM Specification, first edition
7
JVM Specification, first edition
8
The JVM: a highly tuned performance machine
https://commons.wikimedia.org/wiki/File:Fernando_Alonso_2010_Jerez_test_14.jpg9
It’s fastest when you stay on the pathJVM optimized and tuned for the Java language.
As long as the language maps cleanly to Java’s semantics, good perf is likely
10
JVM invoke instructions
Prior to Java 7, there were 4 bytecodes to invoke methods:
– invokespecial: constructors, super calls, private methods
– invokevirtual: receiver based selection of instance methods
– invokestatic: static methods
– invokeinterface: interface based selection of instance methods
The semantics are tightly defined by the JVM spec
11
12
ResolutionAccess checkingType constraintsSelection
Ruby fib
Show Ruby fib and outline why it’s not the same as the Java version
13
def fib(x)
if x < 2
return x
end
return fib(x-2) + fib(x-1)
end
Ruby fib
6 method sends for Ruby vs 2 for Java
14
def fib(x)
if x < 2
return x
end
return fib(x-2) + fib(x-1)
end
JRuby: ~1.6 implementation
15
CachingCallSite DynamicMethod
@JRubyMethod(name = "+")
public IRubyObject op_plus(ThreadContext ctx, IRubyObject other)
{
if (other instanceof RubyFixnum) {
return addFixnum(ctx, (RubyFixnum)other);
}
return addOther(ctx, other);
}
Second class performance citizen: Dynamic languages
Simulation overheads:
– Inlining depth limits
– Inlining bytecode size limits
– Reflection overhead
– Non-inlinable caching / Hashtable lookups
– Type mismatches: sharp types vs IRubyObject
Complexity
– Generating invokers at build time based on annotations
– Need to ensure the cache is correct
16
JVM Specification, first edition
17
Birth of JSR 292 EG
18
New JVM instruction, invokedynamic, designed to support the implementation of dynamically typed object oriented languages.
… investigate support for hotswapping
The problem: linkage + typing
JVM invoke instructions are tightly tied to Java
– Linkage must match the JVM rules
My language uses different dispatch rules
– Metaclass
– Multiple dispatch
– Mixins
User’s need to control the linkage
19https://en.wikipedia.org/wiki/Burr_puzzle#/media/File:SixPartWoodKnot.jpg
RestartMethodException & VM method cache
Invokedynamic
– like invokevirtual except:
arguments not required to match the method’s signature
support for “doesNotUnderstand” handler
– recursive lookup for method exactly matching descriptor
else call handler, which can:
implement the method & return result
pick a method and return it (via RestartMethodException)
> VM can cache the “restart” method
20
From InvokeDynamic to target method
Invokedynamic Target method
21
User supplied
logic
Tell the VM what
method to link to
From InvokeDynamic to target method
Invokedynamic
Static data:
Caller
Method name
Descriptor
Other data
Target method
22
User supplied
logic
Tell the VM what
method to link to
BootstrapMethod
From InvokeDynamic to target method
Invokedynamic
java.lang.invoke.CallSite
Target method
23
User supplied
logic
Tell the VM what
method to link to
BootstrapMethod
From InvokeDynamic to target method
Invokedynamic
java.lang.invoke.CallSite
Target method
24
User supplied
logic
Tell the VM what
method to link to
BootstrapMethod
From InvokeDynamic to target method
Invokedynamic Target method
25
java.lang.invoke.CallSite
Indy is permanently linked to the CallSite (1 time)
Invocation of target method can occur many times
Anatomy of a CallSite
26
CallSite
type
target
MethodType
(String)V
MethodHandle
link(String)V
Anatomy of a CallSite
27
CallSite
type
target
MethodType
(String)V
MethodHandle
link(String)V
The link() handle does two things:1. It sets CallSite target2. Completes the call
Anatomy of a CallSite
28
CallSite
type
target
MethodType
(String)V
MethodHandle
link(String)V
GuardWithTest
test
target
fallback
MethodHandle
Guard()boolean
MethodHandle
Method(String)V
Invokedynamic: bytecode factory
Lazy constants
New semantics
New bytecodes
All these and more can be emulated using invokedynamic
– Bootstrap Method to link the CallSite
– Java code that implements the new operation
– Really the ultimate bytecode emulation tool
29
Interface injection
A Class implements all the methods for an interface
Doesn’t declare it implements it
– How can we allow the interface invocation to proceed?
30
Foo foo = new Foo();if (foo instanceof Injected) {
Injected i = (Injected) foo;System.out.println(i.m());
}
instanceof
checkcast
invokeinterface
Interface injection: 3 Bootstrap Methods
31
Interface injection: 2 helpers
32
Interface injection: bytecode
33
0: new #14 // class Foo
3: dup
4: invokespecial #15 // Method Foo."<init>":()V
7: astore_1
8: aload_1
9: invokedynamic #28, 0 // InvokeDynamic #0:instanceof:(LObject;)Z
14: ifeq 36
17: aload_1
18: invokedynamic #36, 0 // InvokeDynamic #1:checkcast:(LObject;)LInjected;
23: astore_2
24: getstatic #42 // Field System.out:LPrintStream;
27: aload_2
28: invokedynamic #50, 0 // InvokeDynamic #2:m:(LObject;)LString;
33: invokevirtual #56 // Method PrintStream.println:(LString;)V
36: return
BootstrapMethods:
0: #22 invokestatic Runtime.instanceOfBSM:(LLookup;LString;LMethodType;LClass;)LCallSite;
Method arguments:
#24 Injected
1: #32 invokestatic Runtime.checkcastBSM:(LLookup;LString;LMethodType;LClass;)LCallSite;
Method arguments:
#24 Injected
2: #46 invokestatic
Runtime.invokeinterfaceBSM:(LLookup;LString;LMethodType;Ljava/lang/Class;)LCallSite;
Method arguments:
#24 Injected
[jsr-292-eg] our package name 01/06/2011
Invokedynamic is more than dynamic languages!
Lambda can be built on top of invokedynamic and MethodHandles
(Painfully) renamed the package from java.dyn to java.lang.invoke at development cutoff
34
Birth of JSR 292 EG
35
New JVM instruction, invokedynamic, designed to support the implementation of dynamically typed object oriented languages.
… investigate support for hotswapping
Wait, what is a dyn language anyway?
Static Dynamic
36
Wait, what is a dyn language anyway?
Static Dynamic
37
Compile time
Runtime
Wait, what is a dyn language anyway?
Static Dynamic
38
Compile time
Runtime
Wait, what is a dyn language anyway?
Static
Typing
Dispatch
Dynamic
Binding
(Un)Loading
39
Its not just for dynamic languages anymore
Java 8 gave us Lambda expressions
– But how do we compile this lambda?
40
Predicate<Person> pred = p -> p.age < minAge;
Its not just for dynamic languages anymore
So, if indy is for dynamic languages, why is the Java compiler using it?
– All the types involved are static
– We can use indy to give us a dynamic code generation strategy
Generate inner classes?
Use method handles?
Use dynamic proxies?
Use VM-private APIs for constructing objects?
Indy lets us turn this choice into a pure implementation detail
– Separate from the binary representation
41
Desugaring lambdas to methods
First, we desugar the lambda to a method
– Signature matches functional interface method
– Plus captured arguments prepended
– Simplest lambdas desugar to static methods
But some need access to receiver, and so are instance methods
42
Predicate<Person> pred = p -> p.age < minAge;
private static boolean lambda$1(int minAge, Person p) {
return p.age < minAge;
}
Its not just for dynamic languages anymore
We use indy to embed a recipe for constructing a lambda, including
– The desugared implementation method (static)
– The functional interface we are converting to (static)
– Additional metadata, such as serialization information (static)
– Values captured from the lexical scope (dynamic)
The capture site is called the lambda factory
– Invoked with indy, returns an instance of the desired functional interface
– Subsequent captures bypass the (slow) linkage path
43
Factories and metafactories
We generate an indy call site which, when called, returns the lambda
– This is the lambda factory
– Bootstrap for the lambda factory
selects the translation strategy
Bootstrap is called the lambda metafactory
Part of Java runtime
– Captured args passed
to lambda factory
44
list.removeIf(p -> p.age < minAge);
private static boolean lambda$1(int minAge, Person p) {
return p.getAge() >= minAge;
}
Predicate $p = indy[bootstrap=LambdaMetafactory,
staticargs=[Predicate, lambda$1],
dynargs=[minAge])
list.removeIf($p);
Full bleed images preferredText over top of full bleed images would be in white or a color from the color palette that
would offer good contrast. Also, colored text in Arial Bold would have greater impact.
Optimized String concat (JEP tbd)
46
String m(String a, int b) {
return a + "(" + b + ")";
}
java.lang.String m(java.lang.String, int);
0: new #2 // class StringBuilder
3: dup
4: invokespecial #3 // Method StringBuilder.<init>:()V
7: aload_1
8: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;
11: ldc #5 // String (
13: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;
16: iload_2
17: invokevirtual #6 // Method StringBuilder.append:(I)LStringBuilder;
20: ldc #7 // String )
22: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;
25: invokevirtual #8 // Method StringBuilder.toString:()LString;
28: areturn
http://openjdk.java.net/jeps/8085796
Optimized String concat (JEP tbd)
47
String m(String a, int b) {
return a + "(" + b + ")";
}
java.lang.String m(java.lang.String, int);
0: aload_1
1: ldc #2 // String (
3: iload_2
4: ldc #3 // String )
6: invokedynamic #4, 0
// InvokeDynamic #0:stringConcat:(LString;LString;ILString;)LString;
11: areturn
BootstrapMethods:
0: #19 invokestatic StringConcatFactory.stringConcat:
(LMethodHandles$Lookup;LString;LMethodType;LString;[LObject;)LCallSite;
http://openjdk.java.net/jeps/8085796
48
Invoking Specialized Generic Static Methods
We need to capture the type argument at the callsite.
How does m access the type information at run-time?
class C {
static <any T> T m(T i) {…}
}
int i = C.<int>m(3);
Embed specialized type information in the invokedynamic Callsite
Invoking Specialized Static Methods (cont’d)
7: iconst_38: invokedynamic #4, 0 // InvokeDynamic #0:m:(LFoo;I)V
BootstrapMethods:0: #26 invokestatic GenericMethodSpecializer.metafactory:
(LMethodHandles$Lookup;LString;LMethodType;[LObject;)LCallSite;Method arguments:#27 LC;#28 invokevirtual C.m:(LObject;)V#29 I
51
52
Legal Notice
IBM and the IBM logo are trademarks or registered trademarks of IBM Corporation, in the United States, other
countries or both.
Java and all Java-based marks, among others, are trademarks or registered trademarks of Oracle in the United
States, other countries or both.
Other company, product and service names may be trademarks or service marks of others.
THE INFORMATION DISCUSSED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL
PURPOSES ONLY. WHILE EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND
ACCURACY OF THE INFORMATION, IT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, AND IBM SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT
OF THE USE OF, OR OTHERWISE RELATED TO, SUCH INFORMATION. ANY INFORMATION
CONCERNING IBM'S PRODUCT PLANS OR STRATEGY IS SUBJECT TO CHANGE BY IBM WITHOUT
NOTICE.