:: Enseignements :: Master :: M2 :: 2012-2013 :: Machine Virtuelle (et bazard autour ...) ::
[LOGO]

Bytecode Java & invokedynamic


Le but de ce TD est créer un nouveau runtime pour le langage Small en utilisant l'interpretur de la machine virtuelle Java.
L'archive au format ZIP contenant une base de code (les classes de l'AST, le rewriter et l'Engine) est disponible ici

Exercice 1 - Java Engine

  1. En utilisant l'exemple ci-dessous, indiquer quelles sont les méthodes qui sont appelées et ce que chaque méthode fait.
                def main():
                  2   
              
    Et implanter la méthode qui manque pour que le code s'exécute.
  2. Modifier la classe FunctionWriter pour pouvoir exécuter le script ci-dessous
     
               def main():
                 print(2)
             
  3. A quoi sert la classe RegisterAllocator ?
  4. Modifier la classe FunctionWriter pour pouvoir exécuter le script ci-dessous
     
               def main():
                 a = 2
                 print(a)
             
  5. Implanter l'appel de fonction.

Exercice 2 - Operation unaire, binaire, conversion booléene et if

Avant d'implanter toutes les opérations unaires et binaires qui nécessite de tester si le type est valide avant d'effectuer l'opération, nou allons dans un premier temps implanter le 'if' et les tests '==' et '!='

  1. Implanter les opérations binaire '==' et '!=' sachant que celles-ci marche sur tout les types.
               def main():
                 print(2 == 3)
             
  2. Implanter le test 'if', pour que le code suivant fonctionne
               def main():
                 a = 2 == 3?( 42 | 53)
                 print(a)
             
    Comme les opération de saut conditionelle en bytecode travaille sur des booléens (en fait les int 0 et 1), il faut en plus du test, générer une conversion de Object vers boolean sous forme d'un appel de fonction (bsm_as_boolean).
  3. Vérifier que le code suivant fonctionne
               def main():
                 a = 2 == 3?( 42 |)
                 print(a)
             
  4. Rappeler comment marche la méthode guardWithTest de la classe java.lang.invoke.MethodHandles.
  5. Ecrire le code permettant exécuter l'opération unaire '-' en expliquant au préalable pourquoi le type de retour doit être Object.
                def main():
                  print(-3)
              
  6. Faire en sorte que le '+' unaire n'exécute pas de code.
  7. Implanter la négation booléenne (le '!').
              def main():
                a = true
                print(!a)
             
  8. Ajouter le code permettant de gérer les opéartions binaires sur les entiers '+', '-', '*', '/' et '%' ainsi que les tests sur les entiers '<', '<=' '>' et '>='.

Exercice 3 - Allocateur de registre

L'allocateur de registre utilisé précédemment est très basique, on se propose d'écrire un allocateur un petit peu plus performant.
Actuellement, l'allocateur initialise l'ensemble des variables locales à "undefined" avant d'exécuter le code de la fonction, ce n'est pas nécessaire car soit la variable est initialisée peu après soit si elle n'est pas initilisée, le générateur de code peut alors remplacer l'accés à la variable par l'instruction permettant de charger undefined.

  1. Changer le visteur de la classe RegisterAllocator ainsi que le générateur de code FunctionRewriter pour implanter ce nouvel algorithme.