Invokedynamic / JSR-292

  • 1,184 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,184
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
19
Comments
0
Likes
10

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. InvokeDynamic @ytoshima
  • 2. • invokedynamic • Java7 invokedynamic Java VM • • JVM • • Java platform2
  • 3. Program Agenda • JVM to Multi-language VM • Invoke bytecodes • InvokeDynamic • JSR-292 API • Examples3
  • 4. Program Agenda • JVM to Multi-language VM • Invoke bytecodes • InvokeDynamic • JSR-292 API • Examples4
  • 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 freedom6
  • 7. JVM to Multi-Language VM JSR-292 • Dynamic Invocation • invokedynamic VM bootstrap • Lightweight method objects • MethodHandle invokedynamic bootstrap CallSite MethodHandle function pointer7
  • 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 Nutter8
  • 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.git9
  • 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 • Examples11
  • 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.html12
  • 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 invokedynamic13
  • 14. Program Agenda • JVM to Multi-language VM • Invoke bytecodes • InvokeDynamic • JSR-292 API • Examples14
  • 15. InvokeDynamic invokedynamic, MethodHandle • invokedynamic bytecode boot strap method CallSite • CallSite target MethodHandle • MutableCallSite target • MethodHandle bind ( ) • MethodHandle15
  • 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
  • 17. InvokeDynamic invokedynamic17
  • 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.123456789018
  • 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, Handle20
  • 21. Program Agenda • JVM to Multi-language VM • Invoke bytecodes • InvokeDynamic • JSR-292 API • Examples21
  • 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 CallSite22
  • 23. JSR-292 API23
  • 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 // ()String27
  • 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)String29
  • 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)String33
  • 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 filter35
  • 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 : CallSite39
  • 40. Program Agenda • JVM to Multi-language VM • Invoke bytecodes • InvokeDynamic • JSR-292 API • Examples40
  • 41. Examples Inline Cache Link to the sample • JSR-292 Cookbook inlining-cache • guardWithTest test, target, fallback receiver test true target false fallback • target41
  • 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 CallSite43
  • 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
  • 46. Examples Inline Cache46
  • 47. Examples SwitchPoint example link to the sample • Inline • SwitchPoint guardWithTest target, fallback SwitchPoint valid target invalidate fallback • SwitchPoint invalidate SwitchPoint invalidate47
  • 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, MethodHandle50