JRuby on Steroids
why invokedynamic is a game changer
JUDCon 2012:Boston
stack-based
Virtual Machine
OO
taken to the next level
writing this in Java
IRubyObject +(IRubyObject o){}
Java
Y U NO OPERATOR OVERLOADING
Java (language) is
limited
(and that's ok)
writing this in Java
IRubyObject op_plus(IRubyObject o){}
requires
ALL THE TYPES
during compilation
it's all about
method invocation
1 + 2
IRubyObject x = // 1
IRubyObject y = // 2
x.op_plus(y);
bytecode
ALOAD 0
CHECKCAST org/jruby/RubyFixnum
ALOAD 1
INVOKEVIRTUAL org/jruby/RubyFixnum.op_plus
summary
invokestatic |
for static methods |
invokevirtual |
for instance methods |
invokespecial |
for super() and constructors |
invokeinterface |
for calling against an interface |
what about this ruby code?
class Car
def honk
puts "beep!"
end
end
this honk method becomes a
DynamicMethod
object!
that will be stored at
private volatile Map<String, DynamicMethod> methods = Collections.EMPTY_MAP;
yeah, a simple HashMap
let's call it
IRubyObject car = //;
car.honk(); // fails
car.callMethod(context, "honk"); // works
steps
- gets the object
- hash lookup
- context lookup
- actual invocation
- profit?
we could teach
the JVM
on how to reach the DynamicMethod instance we want?
we could give
the JVM
more hints about the code it runs?
mlvm
invokedynamic
(and friends)
Method Handles
int (*foo)(int)
Method Handles
methodType = methodType(void.class, Object.class, String.class);
mh = lookup().findStatic(RT.class, "lol", methodType);
mh.invokeWithArguments(1L, "hello");
Method Handles
mh2 = mh.insertArguments(0, 1L);
mh2.invokeWithArguments("hello");
currying!
Method Handles
mh.invokeWithArguments(1L, "lol");
what sorcery is this?
Method Handles
public boolean test(Object x){
// test something on x
};
public Object doIt(Object x){};
public Object orElse(Object x){};
Method Handles
mhTest = // test method;
mhTarget = // doIt;
mhFallback = // orElse;
MethodHandles.guardWithTest(mhTest, mhTarget, mhFallback)
bytecode - standard invoke
INVOKEVIRTUAL #39, #42
#39 is method name, #42 is the signature with types
bytecode - invokedynamic
INVOKEDYNAMIC name, #42, BSM, BSM_SIG
signature (our #42)
public void lol(Object o, String s) {
(Object,String)V
bootstrap method
(our BSM)
public static CallSite bsm(...) {
}
CallSite
...static CallSite bsm(String name) {
if("magic".equals(name)){
mh = //lookup the magic
return new ConstantCallSite(mh);
}
return null;
}
we're teaching
the JVM
on how to link stuff
the JVM is
amazing
at doing the dirty job for me
what JRuby uses
- constants
- ivars
- ffi
- basic math
who cares?
I hate Ruby!
<insert bburke's pic here>
possible uses
- faster-than-reflection invoking
- bytecode based FSMs
- JIT-able EL?
- inlinable AOP/Interceptors
- Java 8 Lambdas
rule of thumb
the best code optimization is: don't