:: Enseignements :: Master :: M2 :: 2015-2016 :: Machine Virtuelle (et bazar autour ...) ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Lab 3 - JVM Interpreter |
We now want to implement an interpreter based on the JVM.
A source code to boot this lab is available:
vm2016-lab3.zip
Here is a video of Charles Nutter, one of the creators of JRuby that
explains how the Java bytecode works.
Java Bytecode for Dummies
by Charles Nutter
Exercice 1 - JVM interpreter
The aim of this exercise is to write a simple interpreter/compiler that
will generate a Java Class with one static method for each function of
minijs.
One goal is to make the interpreter lazy and to only compile a method when
needed (i.e. at the first execution) so the interpreter will work mostly
like a JIT.
Once a function is translated to bytecode, the interpreter will transfer
the execution to the JVM
-
What is the purpose of the classes Rewriter,
FunctionClassLoader, Dictionary and RT ?
How the method Rewriter.createFunction works in details ?
Why the enum StackResult exists ? How to use it ?
-
Modify the Rewriter in order to execute the following code
"hello"
Verify that a POP is generated to remove "hello" from
the stack.
Note: you can use the instruction
LDC
to load a constant on stack.
-
Why we can't reuse LDC to load an integer literal ?
Use invokedynamic with the bootstrap method bsm_const
defined in RT to load an integer literal in the same way that
undefined is loaded.
Test with the following code that everything works !
3
-
Implement in the Rewriter the function call and add a special
case in bsm_funcall of RT to be able to call
"print" by creating a private static method in RT that
prints the value.
And then verify that the following code works
print("hello");
print(3);
Note: don't forget to drop the JSObject corresponding to the
qualifier in Rt.bsm_funcall.
-
What the following code should print ?
print(print)
In the Rewriter, change the lambda corresponding to
LocalVarAccess to do a lookup on the global object.
Note: you should have to implement bsm_lookup in RT
too !
Note 2: to get the JSObject "global", take the class of the caller
(lookupClass), get the classloader, cast it to a
FunctionClassLoader and then get the global object.
-
Generalize the code of bsm_funcall to be able to code any
JSObject which is a function creating by a method handle on
JSObject.invoke.
Note: the receiver of a function call is undefined, so the
first argument of JSObject.invoke should be always
undefined. You can use MethodHandles.insertArguments
for that.
Note 2: given that JSObject.invoke last parameter is an array
(a varargs), you should use MethodHandle.asCollector to
transform the method handle.
-
What this code prints, is it what we want ?
print(print(3))
-
Implement the support of local variable in order to execute the
following code:
var a = 3;
print(a);
-
We want to be able to execute the following code:
print(a);
var a = 2;
What method should be changed for that ?
Change this method to be able to execute the code below.
-
We now want to be able to create and execute a function.
function foo(x) {
return x + 1;
}
print(foo(2));
Implement in the Rewriter the code that calls
invokedynamic with the fun AST node (in order to do
that, because invokedynamic is not able to encode live object
but only constant, use the Dictionary object as usual) and then use the
bootstrap method bsm_fun to create a JSObject corresponding to
the function by calling the Rewriter and to show the JSObject
as a constant.
Note: remember that we want the interpreter to be lazy and create the
JObject corresponding to a function only the first time the function is
called.
Note 2: if the function has a name, the function should be registered in
the global object (see RT.bsm_register).
-
We now want to implement the if.
function f(x) {
if (x < 3) {
return 0;
} else {
return x;
}
}
print(f(2));
print(f(7));
Implement the lambda in the visitor corresponding to the if in
the Rewriter.
Note: in byte, the instruction ifeq want a boolean on stack so
we need a way to convert any Object to a boolean (see the class
Boolean), that's what the bootstrap method bsm_truth
does.
-
Verify that recursive calls work by executing the sample
samples/fibo.js.
function fibo(n) {
if (n < 2) {
return 1
} else {
return fibo(n - 1) + fibo(n - 2)
}
}
print(fibo(7))
-
Add the support of the object creation and test with the following code:
var o = {
x: 1,
y: 2
}
Note: here we know that the result is a JSObject, so creating the
JSObject and populating it can be done by using classical call
instruction like invokestatic and invokevirtual.
Note 2: don't forget the JSObject prototype.
-
Verify that the following code works:
var a = 1;
var o = {
x: a,
y: a + 1
}
-
Add the code to extract a field value from an object.
var john = { name: "John" };
print(john.name);
-
And then add the code to change the value of a field of an object.
var john = { name: "John" };
john.name = "Jane";
print(john.name);
-
Verify that if the field doesn't exist, the field is created.
var object = { };
object.foo = "bar";
print(object);
© Université de Marne-la-Vallée