More Related Content Similar to Invokedynamic / JSR-292 Similar to Invokedynamic / JSR-292 (20) Invokedynamic / JSR-2922. • invokedynamic
• Java7 invokedynamic
Java VM
•
• JVM
•
• Java platform
2
3. Program Agenda
• JVM to Multi-language VM
• Invoke bytecodes
• InvokeDynamic
• JSR-292 API
• Examples
3
4. Program Agenda
• JVM to Multi-language VM
• Invoke bytecodes
• InvokeDynamic
• JSR-292 API
• Examples
4
5. JVM to Multi-Language VM
Many languages are already available on JVM
• Programming languages for Java Virtual Machine
• http://www.is-research.de/info/vmlanguages/category/jvm-language/
BeanShell, Clojure, Groovy, JRuby, Mirah,
JavaFX, Rhino, Nashorn, Kawa, Smalltalk,
Jython, Scala, Ceylon, Kotlin,...
•
5
6. JVM to Multi-Language VM
The Da Vinci Machine Project
• a multi-language renaissance for the JVM
• http://openjdk.java.net/projects/mlvm/
• mailing list http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
• sub-projects
Dynamic Invocation Lightweight method objects
Lightweight bytecode loading Interface Injection
Continuations and stack introspection Tail calls and tail recursion
Tuples and value-oriented types Immediate wrapper types
Runtime support for closures Runtime support for multimethods
Faster interface invocation Faster reflection
Symbolic freedom
6
7. JVM to Multi-Language VM
JSR-292
• Dynamic Invocation
• invokedynamic
VM
bootstrap
• Lightweight method objects
• MethodHandle
invokedynamic bootstrap CallSite
MethodHandle function pointer
7
8. JVM to Multi-Language VM
JVM Language Summit
•
VM
• http://openjdk.java.net/projects/mlvm/jvmlangsummit/
• Wiki page invokedynamic
• http://www.wiki.jvmlangsummit.com/Main_Page
• 2011
• http://medianetwork.oracle.com/media/show/16998 - 17017
• 17014 Method Handles and Beyond / John Rose
• 17008 JSR 292 Cookbook / Rémi Forax
• 17016 Adding invokedynamic Support to JRuby / Charles Nutter
8
9. JVM to Multi-Language VM
Other resources
• JSR-292 Cookbook
• http://code.google.com/p/jsr292-cookbook/
• JSR-292 API
• https://github.com/headius/invokebinder
• MethodHandle
•
• https://github.com/ytoshima/indy-samples
• git clone https://github.com/ytoshima/indy-samples.git
9
10. JVM to Multi-Language VM
Other resources
• JRuby
• invokedynamic
git clone http://github.com/jruby/jruby.git
export JAVA_HOME=<path to jdk7>
See
cd jruby
InvokeDynamicSupport.java
ant
for bootstrap method
bin/jruby --bytecode test/fib.rb
implementation
:
ALOAD 1
INVOKEDYNAMIC getFixnum (Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyFixnum;
[org/jruby/runtime/invokedynamic/InvokeDynamicSupport.getFixnumBootstrap(Ljava/lang/
invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;J)Ljava/
lang/invoke/CallSite; (6), 0]
10
11. Program Agenda
• JVM to Multi-language VM
• Invoke bytecodes
• InvokeDynamic
• JSR-292 API
• Examples
11
12. Invoke bytecodes
Java6 invoke*
opcode description
182 0xb6 invokevirtual
183 0xb7 invokespecial private, super.*
184 0xb8 invokestatic
185 0xb9 invokeinterface
186 0xba xxxunusedxxx -> invokedynamic from java7
187 0xbb new
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html
12
13. Invoke bytecodes
invokevirtual -- javap -private -verbose output
public static void main(String[] args) {System.out.println("hello");}
$ javap -c <class>
...
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #6; //String hello
5: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/
lang/String;)V
invokevirtual receiver ( this) ( PrintStream)
receiver method virtual table
invokedynamic
13
14. Program Agenda
• JVM to Multi-language VM
• Invoke bytecodes
• InvokeDynamic
• JSR-292 API
• Examples
14
15. InvokeDynamic
invokedynamic, MethodHandle
• invokedynamic bytecode boot strap method
CallSite
• CallSite target MethodHandle
• MutableCallSite target
• MethodHandle bind ( )
• MethodHandle
15
16. InvokeDynamic
invokedynamic
Bootstrap method
...
invokedynamic (unlinked) CallSite
... CallSite target
1 CallSite return
...
invokedynamic (linked) CallSite target MethodHandle
...
• invokedynamic java ASM
• http://asm.ow2.org/ asm4 *-asm4
• http://forge.ow2.org/projects/asm/
16
18. InvokeDynamic
invokedynamic -- javap -private -verbose output
invokedynamic javap
0: invokedynamic #22, 0 // InvokeDynamic #0:_:()Ljava/math
/BigDecimal; bsm index : name : type
5: areturn
// constant pool entry name, type bsm
#21 = NameAndType #20:#10 // _:()Ljava/math/BigDecimal;
#22 = InvokeDynamic #0:#21 // #0:_:()Ljava/math/BigDecimal;
BootstrapMethods:
0: #17 invokestatic DynamicIndyTest.bsm:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/
lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
Method arguments:
#19 1234567890.1234567890
18
19. InvokeDynamic
ASM 4.0 invokedynamic
Link to a Sample
import org.objectweb.asm.MethodVisitor;
:
Class<?> bsmClass = ... // bootstrap method
String bsmName = “bsm” // bootstrap method
MethodType bsmType = ... //
MethodVisitor mv = ... Byte[]
// invokedynamic javap
mv.visitInvokeDynamicInsn(name /* passed to bsm */,
descriptor, /* target method type as string */
new Handle(H_INVOKESTATIC,
bsmClass.getName().replace('.', '/'),
bsmName,
bsmType.toMethodDescriptorString()),
bsmArgs);
19
20. InvokeDynamic
ASM 4.0 invokedynamic
• ClassWriter Gen + <N>
• MethodVisitor <init>
• MethodVisitor invokedynamic static method
• MethodType
• MethodVisitor visitInvokeDynamicInsn invokedynamic
• visitInvokeDynamicInsn Object... bsmArgs
Integer, Float, Long, Double, String, Type, Handle
20
21. Program Agenda
• JVM to Multi-language VM
• Invoke bytecodes
• InvokeDynamic
• JSR-292 API
• Examples
21
22. JSR-292 API
Package java.lang.invoke http://download.oracle.com/javase/7/docs/api/
CallSite MethodHandle target
ConstantCallSite target CallSite
MethodHandle
MethodHandleProxies MethodHandle interface
MethodHandles MethodHandle static method
MethodHandles.Lookup MethodHandle factory object
MethodType MethodHandle
MutableCallSite target CallSite
SwitchPoint state MH
VolatileCallSite target volatile CallSite
22
24. JSR-292 API
// Lookup
MethodType mt; MethodHandle mh;
MethodHandles.Lookup lookup = MethodHandles.lookup();
// String.class public String replace(char, char)
// MethodType mt is (char,char)String
mt = MethodType.methodType(/* rtype */ String.class,
/* ptype0 */ char.class, /* ptype1 */ char.class);
// MethodHandle
mh = lookup.findVirtual(/* refc */String.class,
"replace", mt);
// receiver
s = (String) mh.invokeExact("daddy",'d','n');
// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
// -> “nanny”, same as: “daddy”.replace(‘d’,’n’)
24
25. JSR-292 API
MethodHandles.Lookup
• MethodHandles nested class
• findVirtual, findStatic
MethodHandle
• MethodHandles.lookup()
• Lookup object
• MethodHandles.publicLookup()
• public lookup Lookup object
• bootstramp method lookup
• invokedynamic
Lookup
• lookupClass()
• lookupModes() (PUBLIC, PROTECTED, ...)
25
26. JSR-292 API
insertArguments, bindTo
import java.lang.invoke.*;
public class BindEx {
public static void main(String[] main) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh_replace = lookup.findVirtual(String.class, "replace",
MethodType.methodType(String.class, char.class, char.class));
D((String)mh_replace.invokeExact("daddy", 'd', 'n')
+ " // " + mh_replace.type());
D(mh_replace.invoke("daddy", 'd', 'n'));
MethodHandle mh_bound = mh_replace.bindTo("daddy");
D("mh_bound: " + (String)mh_bound.invokeExact('d', 'n')
+ " // " + mh_bound.type());
mh_bound = MethodHandles.insertArguments(mh_replace, 0, "daddy");
D("mh_bound: " + (String)mh_bound.invokeExact('d', 'n')
+ " // " + mh_bound.type());
MethodHandle mh_bound_all = MethodHandles.insertArguments(mh_bound,
0, 'd', 'n');
D((String)mh_bound_all.invokeExact()
+ " // " + mh_bound_all.type());
}
public static void D(Object o) { System.out.println("D: " + o); }
}
26
27. JSR-292 API
insertArguments, bindTo
mh_replace
(String,char,char)String
bindTo
mh_bound
(char,char)String
insertArguments
output:
mh_bound_all D: nanny // (String,char,char)String
()String D: nanny
D: mh_bound: nanny // (char,char)String
D: mh_bound: nanny // (char,char)String
D: nanny // ()String
27
28. JSR-292 API
dropArguments:
import java.lang.invoke.*;
import java.util.*;
public class DropEx {
public static void main(String[] main) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh_replace = lookup.findVirtual(String.class, "replace",
MethodType.methodType(String.class, char.class, char.class));
MethodHandle mh_drop = MethodHandles.dropArguments(mh_replace,
1, Map.class, Set.class);
D("mh_drop: "
+ (String)mh_drop.invokeExact("daddy",
(Map)new HashMap(), (Set)new TreeSet(), 'd', 'n')
+ " // " + mh_drop.type());
D("mh_drop: "
+ (String)mh_drop.invoke("daddy", new HashMap(),
new TreeSet(), 'd', 'n')
+ " // " + mh_drop.type());
}
public static void D(Object o) { System.out.println("D: " + o);}
}
28
29. JSR-292 API
dropArguments:
mh_replace
(String,char,char)String
dropArguments
mh_drop
(String,Map,Set,char,char)String output:
D: mh_drop: nanny //
(String,Map,Set,char,char)String
D: mh_drop: nanny //
(String,Map,Set,char,char)String
29
30. JSR-292 API
asType, asCollector:
public class AsCollectorEx {
public static void main(String[] args) throws Throwable {
Lookup lookup = lookup();
MethodHandle m0 = lookup.findStatic(AsCollectorEx.class, "printAll",
methodType(void.class, Object[].class));
P("m0 : " + m0);
MethodHandle mcoll = m0.asCollector(Object[].class, 4);
mcoll.invoke("Foo", "Bar", "Fizz", "Buzz");
mcoll = mcoll.asType(methodType(void.class,
String.class, String.class, String.class, String.class));
P("mcoll: " + mcoll);
mcoll.invokeExact("Foo", "Bar", "Fizz", "Buzz");
Object[] params = new Object[] {"Foo", "Bar", "Fizz", "Buzz"};
MethodHandle mspr = mcoll.asSpreader(Object[].class, 4);
P("mspr: " + mspr);
mspr.invokeExact(params);
}
public static void printAll(Object[] args) { ... }
30
31. JSR-292 API
asType, asCollector:
m0 mspr
(Object[])void (Object[])void
asCollector
mcoll 1 asSpreader
(Object,Object,Object,Object)void
output:
asType m0 : MethodHandle(Object[])void
mcoll 1: MethodHandle(Object,Object,Object,Object)void
mcoll 2 (Foo Bar Fizz Buzz )
mcoll 2: MethodHandle(String,String,String,String)void
(String,String,String,String)void (Foo Bar Fizz Buzz )
mspr: MethodHandle(Object[])void
(Foo Bar Fizz Buzz )
31
32. JSR-292 API
foldArguments:
public class FoldEx {
public static void main(String[] main) throws Throwable {
Lookup lookup = lookup();
MethodHandle mh_replace = lookup.findVirtual(String.class,
"replace",
methodType(String.class, char.class, char.class));
MethodHandle mh_hdr = lookup.findStatic(FoldEx.class,
"printHeader",
methodType(String.class, char.class, char.class));
MethodHandle mh_folded = foldArguments(mh_replace, mh_hdr);
D("mh_folded type: " + mh_folded.type());
D("mh_fold call: " + mh_folded.invoke('d', 'n'));
}
public static void D(Object o) { System.out.println("D: " + o);}
public static String printHeader(char fromC, char toC) {
System.out.println("* params: " + fromC + ", " + toC);
return "daddy";
}
32
33. JSR-292 API
foldArguments:
target: mh_replace combiner: mh_hdr
(String, char, char)String (String, char, char)String
foldArguments
mh_folded
(char,char)String
33
34. JSR-292 API
filterReturnValue:
public class FilterReturnEx {
public static void main(String[] main) throws Throwable {
Lookup lookup = lookup();
MethodHandle mh_d2s = lookup.findStatic(FilterReturnEx.class,
"double2String", methodType(String.class, double.class));
MethodHandle mh_s2bi = lookup.findStatic(FilterReturnEx.class,
"string2BigDecimal", methodType(BigDecimal.class, String.class));
MethodHandle mh_filtered = filterReturnValue(mh_d2s, mh_s2bi);
D("mh_filtered type: " + mh_filtered.type());
D("mh_filtered call: " + (BigDecimal)mh_filtered.invokeExact(123.456));
}
public static String double2String(double dval) {
return Double.toString(dval);
}
public static BigDecimal string2BigDecimal(String str) {
return new BigDecimal(str);
}
34
35. JSR-292 API
filterReturnValue:
target: mh_d2s rv filter: mh_s2bi
(double)String (String)BigDecimal
filterReturnValue
target String
mh_filtered
(double)BigDecimal
BigDecimal filter
35
36. JSR-292 API
filterArguments:
public class FilterEx {
public static void main(String[] main) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh_domatch = lookup.findStatic(FilterEx.class, "domatch",
MethodType.methodType(Matcher.class, String.class, Pattern.class));
MethodHandle mh_getPtn = lookup.findStatic(FilterEx.class, "getPtn",
MethodType.methodType(Pattern.class, String.class));
MethodHandle mh_filtered = MethodHandles.filterArguments(mh_domatch, 1,
mh_getPtn);
D("mh_filtered type: " + mh_filtered.type());
D("mh_filtered call: " + mh_filtered.invoke("daddy", ".*dd.*"));
}
public static Matcher domatch(String str, Pattern ptn) {
Matcher matcher = ptn.matcher(str);
if (matcher.matches()) {
System.out.println("matched: str: " + str + " ptn: " + ptn);
} else {
System.out.println("Did not match: str: " + str + " ptn: " + ptn);
}
return matcher;
}
public static Pattern getPtn(String sptn) { return Pattern.compile(sptn); }
36
37. JSR-292 API
filterArguments:
target: mh_domatch filters: mh_getPtn [...]
(String,Pattern)Matcher (String)Pattern
filterArguments
mh_filtered target
(String,String)Matcher
output:
D: mh_filtered type: (String,String)Matcher
matched: str: daddy ptn: .*dd.*
D: mh_filtered call: java.util.regex.Matcher[pattern=.*dd.*
region=0,5 lastmatch=daddy]
37
38. JSR-292 API
guardWithTest:
public class GWTEx {
public static void main(String[] args) throws Throwable {
Lookup lookup = lookup();
MethodHandle test = lookup.findStatic(GWTEx.class, "isString",
methodType(boolean.class, Object.class));
MethodHandle target = lookup.findStatic(GWTEx.class, "printString",
methodType(void.class, Object.class, long.class));
MethodHandle fallback = lookup.findStatic(GWTEx.class, "printObject",
methodType(void.class, Object.class, long.class, long.class));
MethodHandle test1 = dropArguments(test, 1, long.class);
MethodHandle fallback1 = insertArguments(fallback, 2, 99);
MethodHandle mh = guardWithTest(test1, target, fallback1);
mh.invoke("This is a String", -1L); mh.invoke(new Integer(10), -1L);
D("test : " + test); D("test1 : " + test1);
D("target : " + target); D("fallback : " + fallback);
D("fallback1: " + fallback1); D("mh : " + mh);
}
static boolean isString(Object o) { return (o instanceof String); }
static void printString(Object o, long t) {
System.out.println("printString: " + (String)o + " t: " + t);
}
static void printObject(Object o, long t, long t2) {
System.out.println("printObject: " + o + " t: " + t + " t2: " + t2);
}
38
39. JSR-292 API
guardWithTest:
test target fallback
(Object)boolean (Object,long)void (Object,long,long)void
dropArguments
insertArguments
test1 true
(Object,long)boolean fallback1
(Object,long)void
guardWithTest
fallback CallSite false output:
false mh printString: This is a String t: -1
printObject: 10 t: -1 t2: 99
(Object,long)void :
CallSite
39
40. Program Agenda
• JVM to Multi-language VM
• Invoke bytecodes
• InvokeDynamic
• JSR-292 API
• Examples
40
41. Examples
Inline Cache Link to the sample
• JSR-292 Cookbook inlining-cache
• guardWithTest test, target, fallback
receiver test true
target false
fallback
•
target
41
42. Examples
invokedynamic (Pet.java main)
DynamicIndy dynamicIndy = new DynamicIndy();
MethodHandle mh = dynamicIndy.invokeDynamic("talk",
MethodType.methodType(void.class, Object.class),
Pet.class, "bsm",
MethodType.methodType(CallSite.class,
Lookup.class, String.class, MethodType.class,
Object.class),
"dummy");
Object[] pets = new Object[] {new Cat(), new Dog(), new Cat(),
new Dog()};
for (Object pet : pets) {
for (int i = 0; i < 4; i++) {
mh.invokeExact(pet);
}
}
42
43. Examples
bootstrap method
public static CallSite bsm(Lookup lookup, String name,
MethodType type, Object arg) throws Throwable {
D("bsm: type: " + type);
InlineCacheCallSite site =
new InlineCacheCallSite(lookup, name, type);
MethodHandle fallback = FALLBACK_MH.bindTo(site);
fallback = fallback.asCollector(Object[].class,
type.parameterCount());
D("bsm: fallback: " + fallback);
fallback = fallback.asType(type);
D("bsm: fallback: " + fallback);
site.setTarget(fallback);
return site;
}
// lookup, name, type MutableCallSite
// fallback bind CallSite target
// fallback CallSite
43
44. Examples
fallback method
public static void fallback(InlineCacheCallSite site, Object[] args) throws
Throwable {
MethodType type = site.type();
Object receiver = args[0];
Class<?> receiverClass = receiver.getClass();
MethodHandle target = site.lookup.findVirtual(receiverClass,
site.name, type.dropParameterTypes(0, 1));
target = target.asType(site.getTarget().type());
MethodHandle test = CHECK_CLASS_MH.bindTo(receiverClass);
test = test.asType(test.type().changeParameterType(0, type.parameterType
(0)));
MethodHandle fallback = FALLBACK_MH.bindTo(site);
fallback = fallback.asCollector(Object[].class, type.parameterCount());
fallback = fallback.asType(type);
MethodHandle guard = MethodHandles.guardWithTest(test, target, fallback);
site.setTarget(guard);
target.invokeWithArguments(args);
}
44
45. Examples
test method
public static boolean isCachedClass(Class<?> cls,
Object receiver) {
if (cls != receiver.getClass()) D("isCachedClass
false !");
else D("isCachedClass true.");
return cls == receiver.getClass();
}
45
47. Examples
SwitchPoint example link to the sample
• Inline
• SwitchPoint guardWithTest target, fallback
SwitchPoint valid target
invalidate fallback
• SwitchPoint invalidate
SwitchPoint invalidate
47
48. Examples
bootstrap method
public static CallSite bsm(Lookup lookup, String name,
MethodType type, Object arg) throws Throwable {
AmethystConstantCallSite site =
new AmethystConstantCallSite(type, "site1");
MethodType fallbackType =
type.insertParameterTypes(0,
AmethystConstantCallSite.class);
MethodHandle myFallback = insertArguments(
lookup.findStatic(SwitchPointEx.class,
"constantFallback",fallbackType),
0,
site);
site.setTarget(myFallback);
return site;
}
48
49. Examples
fallback method
public static IAmethystObject constantFallback(AmethystConstantCallSite site,
MyThreadContext context) {
IAmethystObject value = context.getConstant(site.name());
if (value != null) {
MethodHandle valueHandle = constant(IAmethystObject.class, value);
valueHandle = dropArguments(valueHandle, 0, MyThreadContext.class);
MethodHandle fallback = insertArguments(
findStatic(SwitchPointEx.class, "constantFallback",
methodType(IAmethystObject.class, AmethystConstantCallSite.class,
MyThreadContext.class)),
0,
site);
SwitchPoint switchPoint = (SwitchPoint)context.runtime.getConstantInvalidator
().getData();
MethodHandle gwt = switchPoint.guardWithTest(valueHandle, fallback);
site.setTarget(gwt);
} else {
D("In constantFallback value=null");
value = new IAmethystObject("(null)");
}
return value;
}
49
50. • %
invokedynamic/JSR-292 API
• java
• Java 8 Closure invokedynamic, MethodHandle
50