Learn · concepts

Qu'est-ce que le bytecode JVM ? Explication des fichiers de classes Java

Le bytecode de la JVM est l'ensemble d'instructions compact que l'environnement d'exécution Java utilise. Découvrez comment fonctionnent les fichiers .class, pourquoi les mods réécrivent le bytecode et où ASM s'inscrit dans le processus.

TRtrolPublished 5 min read

Qu'est-ce que le bytecode de la JVM ?

Le bytecode de la JVM est l'ensemble d'instructions que la Machine Virtuelle Java exécute. Lorsque vous compilez du code source Java, le compilateur ne produit pas de code machine pour votre CPU. Il produit du bytecode, un format compact et portable stocké dans les fichiers .class. La JVM lit ces instructions au moment de l'exécution et les transforme en code natif au fur et à mesure.

Cette approche en plusieurs couches—du code source au bytecode puis au code machine—est ce qui rend Java portable. Le même fichier .class s'exécute sur Windows, macOS, Linux ou tout autre système doté d'une JVM compatible, car la JVM est la couche qui sait comment exécuter les instructions sur la machine locale. Écrivez une fois, exécutez partout.

Comment le code source devient du bytecode

Un fichier .java est un texte qu'une personne écrit. Un fichier .class est la sortie compilée que la JVM exécute. Le compilateur lit votre code source, le vérifie et écrit un fichier .class par classe, chacun contenant des instructions bytecode ainsi qu'un pool de constantes, des tables de méthodes et d'autres métadonnées.

Le bytecode n'est lié à aucun processeur en particulier. Le même fichier .class s'exécute sur Windows, macOS, Linux ou tout système doté d'un environnement d'exécution Java, car la JVM est la couche qui sait comment exécuter les instructions sur la machine locale. Cette portabilité est l'objectif principal de ce format.

À quoi ressemblent les instructions

Le bytecode est un ensemble d’instructions basé sur une pile. La plupart des opérations poussent des valeurs sur une pile d’opérandes, les retire et poussent un résultat. Il n’y a pas d’allocation de registres à prendre en compte ; le modèle est délibérément simple afin que la JVM puisse le vérifier et l’exécuter rapidement.

Quelques exemples d’opcodes donnent une idée :

OpcodeCe qu’il fait
iloadPousse une variable locale int sur la pile
iaddRetire deux ints, pousse leur somme
invokevirtualAppelle une méthode d’instance
getfieldLit un champ d’instance
returnRetourne d’une méthode

On lit ou on écrit rarement ces codes à la main. Des outils les génèrent et les consomment, c’est là qu’intervient une bibliothèque comme ASM.

Pourquoi le bytecode est important pour les mods

Le bytecode est important car il permet de modifier le comportement sans le code source original. Un mod Minecraft a presque jamais le code source du jeu. Ce qu’il a, c’est le jeu compilé sur le disque. Pour ajouter ou modifier une fonctionnalité, un mod lit le bytecode existant, le réécrit et renvoie le résultat à la JVM lorsque les classes sont chargées.

C’est ainsi que les frameworks de patching insèrent des hooks dans les méthodes qu’ils ne possèdent pas. Ils trouvent le bon endroit dans une méthode compilée et y insèrent un appel au code du mod. Travailler au niveau du bytecode signifie qu’un mod peut s’attacher au jeu même sans jamais voir une ligne du code Java original.

En pratique, c'est ainsi que Terminus et d'autres clients basés sur Fabric modifient Minecraft. Au lieu de posséder le code source de Minecraft, ils travaillent avec les fichiers .class compilés et réécrivent le bytecode pour ajouter des fonctionnalités telles que des modules, des écrans de paramètres et un rendu personnalisé.

Où ASM s'inscrit

ASM est une bibliothèque Java pour lire, écrire et transformer le bytecode. Elle analyse un fichier .class en événements ou en un arbre, permet de modifier les instructions et émet un fichier .class valide. Elle est petite, rapide et fonctionne au plus près du format brut, c'est pourquoi les outils de modding de plus haut niveau s'appuient dessus plutôt que d'analyser eux-mêmes les fichiers de classe.

La plupart des moddeurs n'appellent jamais ASM directement. Ils utilisent une couche de plus haut niveau qui masque les opcodes et expose une manière plus conviviale de dire « exécute mon code au début de cette méthode ». En dessous, cette couche modifie le bytecode, souvent via ASM.

Décompiler le bytecode en code source

Des décompilateurs comme Fernflower et CFR prennent des fichiers .class compilés et reconstruisent du code Java lisible à partir du bytecode. Le processus n'est pas parfait : certains noms et commentaires sont perdus, certaines constructions sont plus difficiles à récupérer que d'autres, et le code obscurci devient illisible. Mais pour le code ordinaire et non obscurci, les décompilateurs produisent généralement une sortie suffisamment proche de l'original pour comprendre et travailler avec.

Ceci est utile pour apprendre le fonctionnement du jeu, mais cela ne remplace pas la possession du code source réel. Le code décompilé est toujours une logique compilée sans commentaires, et les noms de variables reconstitués peuvent être trompeurs. C'est un outil de lecture, pas un outil d'écriture.

FAQ