JRuby on Steroids

why invokedynamic is a game changer

JUDCon 2012:Boston

whoami

@qmx

dynjs
JRuby

Ruby

<3

Y U NO Java?

JVM

stack-based

Virtual Machine

1+2 = ?

(+ 1 2)

ZOMG, lisp???

le stack

PUSH 1
  • 1
PUSH 2
  • 1
  • 2
ADD
  • 3

le stack - bytecode

iconst_1
  • 1
iconst_2
  • 1
  • 2
iadd
  • 3

iadd?

integer add

^^^^------

statically typed

1 + 2

is 1 an integer?

NO

					> 1.class
=> Fixnum
					

OO

taken to the next level

1+2

						1.+(2)
					

1+2

						1.send(:+, 2)
					

writing this in Java

						
IRubyObject +(IRubyObject o){}
						
					

syntax error

Java

Y U NO OPERATOR OVERLOADING

we <3 Java

but

Java (language) is

limited

(and that's ok)

writing this in Java

						
IRubyObject op_plus(IRubyObject o){}
						
					

IRubyObject?

everything is an object

Java

Virtual Machine

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?

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

					

what's happening here?

steps

  1. gets the object
  2. hash lookup
  3. context lookup
  4. actual invocation
  5. profit?

what if...?

we could teach

the JVM

on how to reach the DynamicMethod instance we want?

what if...?

we could give

the JVM

more hints about the code it runs?

mlvm

leonardo

invokedynamic

(and friends)

method handles?

bootstrap method?

WTF?

invokedynamic 101

Method Handles

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?

polymorphic signatures

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

bytecode - standard invoke

						INVOKEVIRTUAL #39, #42
					

#39 is method name, #42 is the signature with types

bytecode - invokedynamic

						INVOKEDYNAMIC name, #42, BSM, BSM_SIG
					

whoa

signature (our #42)

						public void lol(Object o, String s) {
					

(Object,String)V

bootstrap method

(our BSM)

						public static CallSite bsm(...) {
}
					

CallSite?

CallSite

						...static CallSite bsm(String name) {
  if("magic".equals(name)){
   mh = //lookup the magic
   return new ConstantCallSite(mh);
 }
 return null;
}
					

demo

we're teaching

the JVM

on how to link stuff

the JVM is

amazing

at doing the dirty job for me

what about

JRuby?

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

closing

we <3

Java

we <3<3<3

the JVM

rule of thumb

the best code optimization is: don't

don't

thanks!

?

thanks!