disclaimer
hardcore stuff
lingua franca
Java?
Car car = new Car();
JavaScript?
var x = new Car();
stack-based
Virtual Machine
isn't this cool?
2.days.ago
2
> 2.class
=> Fixnum
> 2.methods[1..10]
=> [:even?, :magnitude, :&, :[], :div, :<<, :modulo, :times, :==, :/]
let's do this in java
public class Fixnum {
public Fixnum +(Fixnum f) {
return new Fixnum(
this.intValue()+f.intValue()
);
}
}
fixing
the java class
public class Fixnum {
public Fixnum op_add(Fixnum f) {
return new Fixnum(
this.intValue()+f.intValue()
);
}
}
Java
Y U NO OPERATOR OVERLOADING
Java (language) is
limited
(and that's ok)
it's all about
invocation
bytecodes!!!
invokevirtual #3, #8
bytecode is hard
let's go shopping!
this java code
Car car = new Car();
car.honk();
jitescript
// new instance
newobj(p(Car.class));
dup();
jitescript
// calls the default constructor
invokespecial(p(Car.class),
"<init>", sig(void.class));
// calls the "honk" method
invokevirtual(p(Car.class),
"honk", sig(void.class));
summary
invokestatic |
for static methods |
invokevirtual |
for instance methods |
invokespecial |
for super() and constructors |
invokeinterface |
for calling against an interface |
requires
ALL THE TYPES
during compilation
What about some
JavaScript?
JavaScript
var car = new Car();
car.honk();
let's do this in Java
OHWAIT
from ECMA 262 specification, Topic 4.3.3
An object is a collection of properties and has a single prototype object.
let's follow the spec
public class JSObject {
// yuck!
private Map<String, Map<String, Object>> properties = ...;
private Object prototype;
}
The Car Object
JSObject obj = new JSObject();
obj.getProperties().put("honk",
new HashMap<String, Object>(){{
put("call", SomeClass.class);
}});
invoking honk()
// cast to Class!
Class honk = (Class) obj.getProperties().get("honk").get("call");
honk.getDeclaredMethod("call").invoke(obj);
JVM
the bytecode for this is huge
L0
LINENUMBER 24 L0
ALOAD 0
GETFIELD me/qmx/javace/indydemo/JSObjectTest.obj : Lme/qmx/javace/indydemo/JSObject;
INVOKEVIRTUAL me/qmx/javace/indydemo/JSObject.getProperties ()Ljava/util/Map;
LDC "honk"
INVOKEINTERFACE java/util/Map.get (Ljava/lang/Object;)Ljava/lang/Object;
CHECKCAST java/util/Map
LDC "call"
INVOKEINTERFACE java/util/Map.get (Ljava/lang/Object;)Ljava/lang/Object;
CHECKCAST java/lang/Class
ASTORE 1
L1
LINENUMBER 25 L1
ALOAD 1
LDC "honk"
ICONST_0
ANEWARRAY java/lang/Class
INVOKEVIRTUAL java/lang/Class.getDeclaredMethod (Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
ACONST_NULL
ICONST_0
ANEWARRAY java/lang/Object
INVOKEVIRTUAL java/lang/reflect/Method.invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
POP
L2
LINENUMBER 26 L2
RETURN
what if we could
help the JVM?
what if we could
avoid slow reflection?
what if we could
teach the JVM the **fast** path?
what if we could
// put a car object on the stack
invokedynamic("dyn:call:honk", sig(Object.class, Object.class));
avoiding reflection
int (*foo)(int)
MethodHandles
aka method pointers
MethodHandles
MethodHandle honk = MethodHandles
.lookup()
.findVirtual(Car.class, "honk",
MethodType.methodType(void.class));
honk.invoke(new Car());
reflection is slow because of
security checks
at each call
MethodHandles do all
security checks
during creation
and they are immutable too :)
polymorphic signatures
handle.invoke(1,2.0,3L,"lol");
the place where the caller calls the callee is called a
Call Site
(inception?)
a Call Site
public static void main(...) {
new Car().honk();
}
to help the JVM, we need to
create the CallSites
back to the invokedynamic instruction
// put a car object on the stack
invokedynamic("dyn:call:honk", sig(Object.class, Object.class), ?, ?);
we need a
bootstrap method
bootstrap method (BSM)
public class MyBootstrapper {
public static CallSite(caller, name, methodType) {
if (name.equals("dyn:call:honk")) {
// lookup a Method Handle
}
}
}
back to the JS code, invokedynamic version
JS
- invokedynamic("dyn:call:honk", signature, bootstrap, bootstrap_signature)
- bootstrap method
- MethodHandles that maps straight to the desired object
- CallSite
monomorphic CallSite
Object[] objects = {1L, 2L, 3L};
for(Object o : objects {
System.out.println(o);
}
polymorphic CallSite
Object[] objects = {1L, 2.0, 3f};
for(Object o : objects {
System.out.println(o);
}
megamorphic CallSite
Runnable[] objects = {.....};
for(Runnable o : objects {
o.run();
}