:: Enseignements :: ESIPE :: E5INFO :: 2020-2021 :: Machine Virtuelle (et bazar autour ...) ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Lab 3b - JVM Interpreter / Object Optimization |
Exercice 1 - get field/set field/method call
We have not finished the implementation of the JVM interpreter, all the object related syntax are not supported.
The aim of this exercise is to implement them.
Here is the code of the bootstrap methods (we will optimize them in the exercise 2).
...
private static final MethodHandle GET_MH, LOOKUP_MH;
static {
var lookup = MethodHandles.lookup();
try {
LOOKUP = lookup.findVirtual(JSObject.class, "lookup", methodType(Object.class, String.class));
REGISTER = lookup.findVirtual(JSObject.class, "register", methodType(void.class, String.class, Object.class));
...
GET_MH = lookup.findVirtual(JSObject.class, "getMethodHandle", methodType(MethodHandle.class));
METH_LOOKUP_MH = lookup.findStatic(RT.class, "lookupMethodHandle", methodType(MethodHandle.class, JSObject.class, String.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
...
public static CallSite bsm_get(Lookup lookup, String name, MethodType type, String fieldName) {
return new ConstantCallSite(insertArguments(LOOKUP, 1, fieldName).asType(type));
}
public static CallSite bsm_set(Lookup lookup, String name, MethodType type, String fieldName) {
return new ConstantCallSite(insertArguments(REGISTER, 1, fieldName).asType(type));
}
@SuppressWarnings("unused") // used by a method handle
private static MethodHandle lookupMethodHandle(JSObject receiver, String fieldName) {
var function = (JSObject)receiver.lookup(fieldName);
return function.getMethodHandle();
}
public static CallSite bsm_methodcall(Lookup lookup, String name, MethodType type) {
var combiner = MethodHandles.insertArguments(METH_LOOKUP_MH, 1, name).asType(methodType(MethodHandle.class, Object.class));
var target = MethodHandles.foldArguments(invoker(type), combiner);
return new ConstantCallSite(target);
}
...
-
Explain what bsm_get does ?
why asType is called ?
-
What the method MethodHandles.foldArguments does ?
Explain how bsm_methodcall works ?
-
We propose this code for rewriting a New AST node:
.when(New.class, (_new, env) -> {
mv.visitInsn(ACONST_NULL);
mv.visitMethodInsn(INVOKESTATIC, JSOBJECT, "newObject", "(L" + JSOBJECT + ";)L" + JSOBJECT + ';', false);
_new.initMap().forEach((key, init) -> {
mv.visitInsn(DUP);
mv.visitLdcInsn(key);
visitor.visit(init, env);
mv.visitMethodInsn(INVOKEVIRTUAL, JSOBJECT, "register", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
});
})
What this code does ?
Explain mv.visitInsn(ACONST_NULL); ?
Why DUP is needed here ?
Verify that tests marked Q13 and Q14 pass.
-
Implement the visit for the AST node FieldAccess
and verify that tests marked Q15 pass.
-
Implement the visit for the AST node FieldAssignment
and verify that tests marked Q16 pass.
-
Implement the visit for the AST node MethodCall
and verify that tests marked Q17 pass.
Exercice 2 - optimizing field access using speculative optimizations
While JavaScript allows to dynamically add fields to any objects,
in practice it's rare to find such occurence after the object creation,
so it makes sense to optimize as if the object have the same constant set of fields.
If the set of fields of objects is mostly constant it makes sense to try to optimize
using an inlining cache.
The idea is to associate one unique object (the layout) for each set of fields so
if two objects have the same set the fields, then they share the same layout object.
(this is what the class ArrayMap does).
So the algorithm is the following, first check the layout,
if it's the same layout as the last time, then the index of the field is a constant for all the object
with that layout.
The skeleton of an inlining cache for field access
public static CallSite bsm_get(Lookup lookup, String name, MethodType type, String fieldName) {
//return new ConstantCallSite(insertArguments(LOOKUP, 1, fieldName).asType(type));
return new InliningFieldCache(type, fieldName);
}
private static class InliningFieldCache extends MutableCallSite {
private static final MethodHandle SLOW_PATH, LAYOUT_CHECK, FAST_ACCESS;
static {
var lookup = MethodHandles.lookup();
try {
...
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
private final String fieldName;
public InliningFieldCache(MethodType type, String fieldName) {
super(type);
this.fieldName = fieldName;
setTarget(SLOW_PATH.bindTo(this));
}
@SuppressWarnings("unused") // called by a MH
private static boolean layoutCheck(ArrayMap.Layout layout, Object o) {
return layout == ((JSObject)o).getLayout();
}
@SuppressWarnings("unused") // called by a MH
private Object slowPath(Object receiver) {
var jsObject = (JSObject)receiver;
// classical access to the value
var value = jsObject.lookup(fieldName);
// fast access
//var layout = jsObject.getLayout();
//var slot = layout.slot(fieldName); // may be -1 !
//var value = jsObject.fastAccess(slot);
//TODO
return value;
}
}
-
Add the guardWithTest to finish the implementation of the inlining cache.
Verify that the tests marked Q15 and Q16 still work.
-
Add a depth check so the inlining cache is only bi-morphic.
© Université de Marne-la-Vallée