Revenant au début, Java-Kisama s'est moqué de Hello World-

Kisama s'est moqué de Hello World

Lors du démarrage d'un langage de programmation, il est courant d'imprimer "Hello World". Surtout quand je dois l'utiliser pour les affaires, j'écrirai Hello World à la vitesse de gokiburi dash et j'essaierai de passer à l'étape suivante.

Mais ai-je compris comment fonctionnait ce Hello World? Cette fois, je voudrais revenir au début et revoir Hello World dans la mesure où je ne peux pas être dérouté par le Dr Retsu, "Kisama a ridiculisé Hello World."

Gokiburi comme un tableau de bord Hello World

environnement

Windows 10 java version "1.8.0_202" Java(TM) SE Runtime Environment (build 1.8.0_202-b08) Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

Créer-exécuter Helloworld

Créez et exécutez Hello World comme d'habitude. Tout d'abord, écrivez le code java dans un éditeur de texte.

HelloWorld.java


public class HelloWorld {
	public static void main(String[] args) {
		System.out.println("Hello World");
	}
}

Exécutez la commande javac avec le fichier java créé comme entrée pour créer un fichier de classe. Cette fois, ajoutez l'option "-g: none" pour empêcher la génération d'informations de débogage.

javac -g:none HelloWorld.java

Exécutez le "HelloWorld.class" créé avec la commande java.

>java HelloWorld
Hello World

"Hello World" est sorti. Contrairement aux fichiers exécutables créés avec c ou c ++, le HelloWorld.class créé fonctionne de la même manière sous Windows, Mac et Linux tant qu'il contient Java. Non, Java est pratique.

**la fin! !! Fermé! !! c'est tout! !! Tout le monde s'est dissous! !! ** **

Il fut un temps où je pensais comme ça

C'était la fin. Oui, je n'ai pas eu l'occasion de penser à ce qu'est cette HelloWorld.class. Cette fois, c'est un gros problème, alors vérifions le contenu du fichier binaire créé.

Le contenu de HelloWorld.class est constitué des binaires suivants.

image.png

Pour lire ce fichier binaire, vous devez lire la spécification de la machine virtuelle Java®. https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

Spécifications JVM utilisées cette fois

Je décrirai brièvement les spécifications de la JVM utilisée cette fois, mais si vous voulez analyser rapidement le binaire du fichier de classe, veuillez [Ignorer](analyse binaire de #helloworldclass).

class La structure du fichier est la suivante.

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

u1 représente 1 octet, u2 représente 2 octets et u4 représente 4 octets de données. D'autres sont des structures, donc je vous expliquerai à chaque fois.

magic est un nombre magique qui identifie le format de fichier de classe et est "0xCAFEBABE". L'origine de ce nombre magique est décrite dans CAFE BABE: Java's Magic Word, veuillez donc le lire. Je l'utilise à une date et il est dessiné.

minor_version et major_version sont les numéros de version mineure et majeure de ce fichier de classe. Les numéros de version majeure et mineure déterminent la version du format de fichier de classe.

constant_pool [] et constant_pool_count sont la table et le nombre de structures qui représentent les constantes de chaîne, les noms de classe et d'interface, les noms de champ et d'autres constantes. La plage valide pour l'index de constant_pool est de 1 à constant_pool_count-1.

access_flags est une combinaison des indicateurs suivants.

Nom du drapeau valeur Interprétation
ACC_PUBLIC 0x0001 public est déclaré. Il est accessible depuis l'extérieur du package.
ACC_FINAL 0x0010 final est déclaré. Les sous-classes ne sont pas autorisées.
ACC_SUPER 0x0020 Traite les méthodes de superclasse spécialement lorsqu'elles sont appelées par l'instruction invokespecial.
ACC_INTERFACE 0x0200 C'est une interface, pas une classe.
ACC_ABSTRACT 0x0400 Il a été déclaré abstrait. N'instanciez pas.
ACC_SYNTHETIC 0x1000 Indique qu'il a été généré par le compilateur. * Par exemple, un fichier de classe créé lorsqu'une classe est créée dans une classe(ex. Hello$Test.class)A été donné à
ACC_ANNOTATION 0x2000 Déclaré comme une annotation.
ACC_ENUM 0x4000 Déclaré comme type enum.

this_class doit être une valeur d'index valide dans constant_pool []. Les données référencées dans l'index doivent être une structure CONSTANT_Class_info qui contient les informations pour la classe spécifiée dans le fichier.

super_class doit être 0 ou une valeur d'index valide dans constant_pool []. Les données référencées dans l'index doivent être une structure CONSTANT_Class_info qui représente la superclasse directe de la classe définie dans ce fichier de classe.

interfaces_count et interfaces [] sont un tableau d'index dans la structure CONSTANT_Class_info qui représente les interfaces de la classe définie dans ce fichier de classe. S'il n'y a pas d'interfaces, interfaces_count sera égal à 0 et les interfaces [] n'existeront pas.

field_count, fields [] représentent les champs de la classe définie dans ce fichier de classe [structure de champ](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html C'est un tableau de # jvms-4.5). S'il n'y a pas de champs, fields_count sera égal à 0 et les champs [] n'existeront pas.

methods_count et methods [] sont un tableau de [structures de méthode](#method structures) qui représentent les méthodes de la classe définie dans ce fichier de classe. S'il n'y a pas de champs, methods_count sera égal à 0 et les méthodes [] n'existeront pas.

attributes_count et attributes [] sont un tableau de [structures d'attributs](# structures d'attributs) qui représentent les informations d'attribut pour les classes définies dans ce fichier de classe.

constant_pool Cette structure est une balise de 1 octet qui détermine à quoi ressemblera la structure.

Constant Type Value
CONSTANT_Class 7
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_String 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
CONSTANT_MethodHandle 15
CONSTANT_MethodType 16
CONSTANT_InvokeDynamic 18

Nous expliquerons ce que nous utiliserons cette fois-ci, veuillez donc vous référer à ce qui suit pour les autres structures. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4-140

CONSTANT_Class Utilisé pour représenter une classe ou une interface.

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

7 représentant CONSTANT_Class est stocké dans la balise. La valeur de l'élément name_index sera l'index de la [structure CONSTANT_Utf8_info](# constant_utf8) dans la table constant_pool.

CONSTANT_Fieldref

CONSTANT_Fieldref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

La balise contient 9 qui représente la valeur CONSTANT_Fieldref_info. La valeur de class_index est l'index de la structure CONSTANT_Class_info dans la table constant_pool. La valeur de l'élément name_and_type_index est l'index de la structure CONSTANT_NameAndType_info (#constant_nameandtype) dans la table constant_pool.

CONSTANT_Methodref

CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

La balise contient 10 qui représente la valeur CONSTANT_Methodref. La valeur de class_index est l'index de la structure CONSTANT_Class_info dans la table constant_pool. La valeur de l'élément name_and_type_index est l'index de la structure CONSTANT_NameAndType_info (#constant_nameandtype) dans la table constant_pool.

CONSTANT_String

CONSTANT_String_info {
    u1 tag;
    u2 string_index;
}

La balise contient 8 qui représente la valeur CONSTANT_String. La valeur de string_index est l'index de la [structure CONSTANT_Utf8_info](# constant_utf8) dans la table constant_pool.

CONSTANT_NameAndType Utilisé pour représenter un champ ou une méthode. Cependant, il n'indique pas le type de classe ou d'interface auquel il appartient.

CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}

La balise contient 12 qui représente la valeur CONSTANT_NameAndType. La valeur du champ name_index doit être un index valide de la [structure CONSTANT_Utf8_info](# constant_utf8) dans constant_pool.

CONSTANT_Utf8

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

La balise contient 1 qui représente la valeur CONSTANT_Utf8. length représente le nombre d'octets dans le tableau d'octets (pas la longueur de la chaîne) Le tableau d'octets contient les octets de la chaîne. De plus, le caractère terminal n'est pas inclus. Voir ci-dessous pour plus d'informations sur cette chaîne. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.7

structure de la méthode

method_info { 
    u2 access_flags; 
    u2 name_index; 
    u2 descriptor_index; 
    u2 attributes_count; 
    attribute_info attributes [attributes_count]; 
}

La valeur de l'élément access_flags est une combinaison d'autorisations sur cette méthode et les indicateurs utilisés pour indiquer les propriétés de cette méthode.

Nom du drapeau valeur La description
ACC_PUBLIC 0x0001 Public déclaré. Il est accessible depuis l'extérieur du package.
ACC_PRIVATE 0x0002 Déclaré privé. Uniquement accessible dans la classe de définition.
ACC_PROTECTED 0x0004 Déclaré protégé. Vous pouvez y accéder dans une sous-classe.
ACC_STATIC 0x0008 Déclaré statique.
ACC_FINAL 0x0010 Déclaré définitif. Il ne doit pas être écrasé.
ACC_SYNCHRONIZED 0x0020 Déclaré synchronisé.
ACC_BRIDGE 0x0040 Utilisé pour indiquer la méthode de pont générée par le compilateur pour le langage de programmation Java.Java Generics - Bridge method?Prière de se référer à.
ACC_VARARGS 0x0080 Déclaré avec un nombre variable d'arguments.
ACC_NATIVE 0x0100 Déclaré natif. Il est implémenté dans des langages autres que Java.
ACC_ABSTRACT 0x0400 Résumé déclaré. Aucune implémentation n'est fournie.
ACC_STRICT 0x0800 Déclaré strictfp.
ACC_SYNTHETIC 0x1000 Indique qu'il n'apparaît pas dans le code source généré par le compilateur.

La valeur de name_index est l'index de la [structure CONSTANT_Utf8_info](# constant_utf8) dans la table constant_pool. Contient le nom de la méthode ou ou .

La valeur de descriptor_index est l'index de la [structure CONSTANT_Utf8_info](# constant_utf8) dans la table constant_pool. Contient le descripteur de méthode (https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3).

attributes_count et attributes [] sont un tableau de [structures d'attributs](# structures d'attributs) qui représentent les informations d'attribut pour les classes définies dans ce fichier de classe.

structure d'attribut

La forme de cette structure change en fonction de l'attribut. Le format commun est le suivant.

attribute_info { 
    u2 attribute_name_index; 
    u4 attribute_length; 
    u1 info [attribute_length]; 
}

La valeur de attribute_name_index est l'index de la [structure CONSTANT_Utf8_info](# constant_utf8) dans la table constant_pool. attribute_length représente la longueur des informations suivantes en octets. Les informations sont différentes pour chaque attribut.

attribut Location
SourceFile ClassFile
InnerClasses ClassFile
EnclosingMethod ClassFile
SourceDebugExtension ClassFile
BootstrapMethods ClassFile
ConstantValue field_info
Code method_info
Exceptions method_info
RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations method_info
AnnotationDefault method_info
MethodParameters method_info
Synthetic ClassFile, field_info, method_info
Deprecated ClassFile, field_info, method_info
Signature ClassFile, field_info, method_info
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations ClassFile, field_info, method_info
LineNumberTable Code
LocalVariableTable Code
LocalVariableTypeTable Code
StackMapTable Code
RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations ClassFile, field_info, method_info, Code

Voir ci-dessous pour les éléments non couverts ici. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

Attribut de code

Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1 code[code_length];
    u2 exception_table_length;
    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

attribut_name_index et attribute_length sont décrits dans un format courant. Le caractère spécifié par attribut_name_index doit être "Code".

La valeur de l'élément max_stack est la profondeur maximale de la pile d'opérateurs de cette méthode. Ce sera.

La valeur de l'élément max_locals correspond aux variables locales (https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6.1) affectées lors de l'appel de cette méthode. ).

La valeur de l'élément code_length est le numéro de code [].

Le tableau de code affiche les octets réels du code de la machine virtuelle Java qui implémente la méthode. Ce code est décrit ci-dessous. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5

exception_table_length stocke le nombre d'entrées pour exception_table.

exception_table représente les informations d'exception. Le contenu de chaque élément de exception_table est le suivant. -Start_pc, end_pc: indique la valeur d'index du tableau de codes pour lequel le gestionnaire d'exceptions est activé. En code java, c'est la plage entourée par try ward. -L'élément de handler_pc est la valeur d'index du tableau de code démarré par le gestionnaire d'exceptions. En code java, c'est la plage entourée par la zone de capture. -Catch_type est 0 ou un index valide de la table constant_pool, et cet index est la structure CONSTANT_Class_info qui représente la classe d'exception.

attributes_count et attributes [] sont un tableau de [structures d'attributs](# structures d'attributs) qui représentent les informations d'attribut pour les classes définies dans ce fichier de classe.

Analyse binaire HelloWorld.class

Sélection et configuration de l'éditeur binaire

Le frère du langage machine sera capable de lire les nombres hexadécimaux en utilisant n'importe quel éditeur binaire, mais honnêtement, il est difficile de lire les nombres hexadécimaux à l'ère de Reiwa, alors considérez un éditeur binaire qui semble être aussi facile à lire que possible. J'ai essayé de.

Cette fois, nous utiliserons BZ Editor. Les raisons d'adopter BZ Editor sont les suivantes. ・ Peut être utilisé sur Windows (récemment, il semble qu'il puisse être utilisé sur MacOS s'il est construit) ・ La structure peut être affichée. ・ Hino peut utiliser la vraie langue -Comme la source est ouverte au public, elle peut être étendue si vous en avez envie.  https://github.com/devil-tamachan/binaryeditorbz

Si vous souhaitez envisager d'autres éditeurs binaires, consultez Wikipedia pour un tableau de comparaison des éditeurs binaires. https://en.wikipedia.org/wiki/Comparison_of_hex_editors Parmi eux, HxD semblait être facile à utiliser.

Paramètres de l'éditeur BZ

Définition de la structure

Vous pouvez définir la structure dans Bz.def, qui se trouve dans le même dossier que le fichier exécutable de BZ Editor. Notez que seules des structures de taille fixe peuvent être spécifiées, donc l'analyse ne peut pas être effectuée parfaitement.

Bz.def


struct ClassFile_1 {
       BYTE magic[4];
       short minor_version;
       short majoir_version;
       short constant_pool_count;
} class;
struct ClassFile_2 {
       BYTE access_flags[2];
       short this_class;
       short super_class;
       short interfaces_count;
} class;

struct CONSTANT_Class {
       BYTE tag;
       short index;
} class;

struct CONSTANT_Methodref_info {
       BYTE tag;
       short class_index;
       short name_and_type_index;
} class;

struct CONSTANT_Fieldref {
       BYTE tag;
       short class_index;
       short name_and_type_index;
} class;

struct CONSTANT_NameAndType_info {
       BYTE tag;
       short name_index;
       short descriptor_index;
} class;

struct CONSTANT_String_info {
       BYTE tag;
       short string_index;
} class;


struct CONSTANT_Utf8 {
       BYTE tag;
       short length;
} class;

struct Code_attribute {
       short attribute_name_index;
       int attribute_length;
       short max_stack;
       short max_locals;
       int code_length;
} class;

Ce BZ.def peut être écrit comme le langage C. Voir TYPESTR [NUM_MEMBERS] dans le code ci-dessous pour les types que vous pouvez utiliser. https://github.com/devil-tamachan/binaryeditorbz/blob/master/Bz/BZFormVw.cpp

Après avoir démarré BZEditor, cochez «Affichage»> «Affichage de la structure» pour afficher la fenêtre enfant pour l'affichage de la structure. image.png

En double-cliquant sur une adresse, les informations de structure à partir de cette adresse s'affichent. image.png

Changer l'ordre des octets

Sélectionnez Motorola lors de l'analyse du fichier de classe. image.png

Analyse des fichiers de classe avec BZ Editor

Analysons ClassFile depuis le début.

Du début à constant_pool_count

image.png

"0x CAFE BABE" s'affiche pour la magie. la version mineure est 0 major_version est 52. constant_pool_count sera 26, et l'octet suivant sera l'entrée pour constant_pool.

Analyse de constant_pool []

constant_pool[1] image.png Puisque le premier octet est 0x0A = 10, l'entrée pour ce constant_pool sera CONSTANT_Methodref. class_index vaut 6 et name_and_type_index vaut 12. Après avoir examiné tous les constants_pools, vérifiez ce que ces index indiquent réellement.

constant_pool[2] image.png Puisque le premier octet est 0x09, l'entrée pour ce constant_pool sera CONSTANT_Fieldref. class_index vaut 13 et name_and_type_index vaut 14.

constant_pool[3] image.png

Comme le premier octet est 0x08, l'entrée pour constant_pool sera CONSTANT_String. L'indice sera de 15.

constant_pool[4] image.png

Puisque le premier octet est 0x0A = 10, l'entrée pour ce constant_pool sera CONSTANT_Methodref. class_index vaut 16 et name_and_type_index vaut 17.

constant_pool[5] image.png

Étant donné que le premier octet est 0x07, l'entrée pour ce pool_ constant sera CONSTANT_Class. L'indice sera de 18.

constant_pool[6] image.png

Étant donné que le premier octet est 0x07, l'entrée pour ce pool_ constant sera CONSTANT_Class. L'indice sera de 19.

constant_pool[7] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 6 et les 6 octets suivants stockent les caractères "\ <init >".

constant_pool[8] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 3 et le caractère "() V" est stocké dans les 3 octets suivants.

constant_pool[9] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 4 et les 4 octets suivants stockent le caractère "Code".

constant_pool[10] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 4, et les 4 octets après cela stockent le caractère "main".

constant_pool[11] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 22, et les 22 octets après cela stockent le caractère "([Ljava / lang / String;) V".

constant_pool[12] image.png

Étant donné que le premier octet est 0x0C = 12, l'entrée pour ce pool_ constant sera la structure CONSTANT_NameAndType_info. name_index vaut 7 et descriptor_index vaut 8.

constant_pool[13] image.png

Étant donné que le premier octet est 0x07, l'entrée pour ce pool_ constant sera CONSTANT_Class. L'indice sera de 20.

constant_pool[14] image.png

Étant donné que le premier octet est 0x0C = 12, l'entrée pour ce pool_ constant sera la structure CONSTANT_NameAndType_info. name_index sera 21 et descriptor_index sera 22.

constant_pool[15] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 11 et les 11 octets suivants stockent les caractères "Hello World".

constant_pool[16] image.png

Étant donné que le premier octet est 0x07, l'entrée pour ce pool_ constant sera CONSTANT_Class. L'indice sera 23.

constant_pool[17] image.png

Étant donné que le premier octet est 0x0C = 12, l'entrée pour ce pool_ constant sera la structure CONSTANT_NameAndType_info. name_index vaut 24 et descriptor_index vaut 25.

constant_pool[18] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 10 et les 10 octets suivants stockent les caractères "Hello World".

constant_pool[19] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 16 et les 16 octets suivants stockent les caractères "java / lang / Object".

constant_pool[20] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 16 et les 16 octets suivants stockent les caractères "java / lang / System".

constant_pool[21] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 3 et le caractère «out» est stocké dans les 3 octets suivants.

constant_pool[22] image.png Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 21 et les 21 octets qui suivent stockent les caractères "Ljava / io / PrintStream;".

constant_pool[23] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 19 et les 19 octets suivants stockent les caractères «java / io / PrintStream».

constant_pool[24] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 7 et les 7 octets après cela stockent le caractère "println".

constant_pool[25] image.png

Étant donné que le premier octet est 0x01, l'entrée pour ce pool_constants sera [CONSTANT_Utf8](# constant_utf8). La longueur est de 21, et les 21 octets après cela stockent le caractère "(Ljava / lang / String;) V".

Résumé de constant_pool de HelloWorld.class

Le constant_pool peut être résumé comme suit.

No Structure Contenu
1 CONSTANT_Methodref class_l'indiceest6:HelloWorld、name_and_type_l'indiceest12::V()
2 CONSTANT_Fieldref class_l'indice est 13:java/lang/System、name_and_type_l'indice est 14: out:Ljava/io/PrintStream;
3 CONSTANT_String l'indice est 15:「Hello World」
4 CONSTANT_Methodref class_l'indiceest16:java/io/PrintStream、name_and_type_l'indiceest17:println:(Ljava/lang/String;)V
5 CONSTANT_Class l'indice est 18:「HelloWorld」
6 CONSTANT_Class l'indice est 19:「java/lang/Object」
7 CONSTANT_Utf8 「<init>Est la chaîne de caractères
8 CONSTANT_Utf8 「()La chaîne "V"
9 CONSTANT_Utf8 La chaîne "Code"
10 CONSTANT_Utf8 La chaîne "main"
11 CONSTANT_Utf8 「([Ljava/lang/String;)La chaîne "V"
12 CONSTANT_NameAndType_info name_l'indiceest7:「<init>」,descriptor_l'indiceest8:「()V」。MethodDescriptorsVoir
13 CONSTANT_Class l'indice est 20;「java/lang/System」
14 CONSTANT_NameAndType_info name_l'indiceest21:「out」,descriptor_l'indiceest22:「Ljava/io/PrintStream;」FieldDescriptorsVoir
15 CONSTANT_Utf8 La chaîne "Hello World"
16 CONSTANT_Class l'indice est 23:「java/io/PrintStream」
17 CONSTANT_NameAndType_info name_l'indiceest24:「println」,descriptor_l'indiceest25:「(Ljava/lang/String;)V」MethodDescriptorsVoir
18 CONSTANT_Utf8 La chaîne "Hello World"
19 CONSTANT_Utf8 「java/lang/La chaîne "Object"
20 CONSTANT_Utf8 「java/lang/La chaîne "System"
21 CONSTANT_Utf8 La chaîne "out"
22 CONSTANT_Utf8 「Ljava/io/PrintStream;Est la chaîne de caractères
23 CONSTANT_Utf8 「java/io/La chaîne "Print Stream"
24 CONSTANT_Utf8 La chaîne "println"
25 CONSTANT_Utf8 「(Ljava/lang/String;)La chaîne "V"

Des access_flags aux interfaces []

image.png

-Access_flags est 0x0021. Autrement dit, ACC_SUPER (0x20) et ACC_PUBLIC (0x01).

-Comme this_class est constant_pool [5], c'est une classe HelloWorld.

-Puisque super_class est constant_pool [6], c'est une classe java / lang / Object.

-Interfaces_count vaut 0, et il n'y a pas d'interfaces ultérieures [].

jusqu'à champs compte ~ champs []

image.png

Puisque fields_count vaut 0, il n'y a aucun fichier à suivre.

methods_count~methods[] image.png

Puisque methods_count vaut 0x0002, il y a 2 cas, suivis de la structure method_info.

method_info[0] image.png

-Access_flags est 0x0001. Autrement dit, ACC_PUBLIC (0x01).

-Name_index sera "\ <init >" de constant_pool [7]. Il s'agit d'un constructeur implicite créé lors de la compilation Java.

-L'index de description sera "() V" de constant_pool [8].

-Attributes_count est égal à 1 et il existe une structure d'attributs.

method_info[0].attributes[0] image.png

Puisque l'attribut_name_index est le "Code" de constant_pool [9], cette structure est la [structure Code_attribute](structure #code_attribute).

attribute_length sera de 17 octets et déterminera la taille de cette structure.

max_stack vaut 1 et max_locals vaut 1.

Le code_length est 5, ce qui signifie que le prochain "0 x 2A B7 00 01 B1" est un code d'octet. 0x2a devient aload_0. Cette instruction place ceci sur la pile d'opérandes.

0xb7 devient invokesplecial. Cette instruction appelle la méthode avec les 2 octets suivants comme index de constant_pool. Dans ce cas, il s'agit de "0x00 01", donc constant_pool [1], "java / lang / Object." ": () V" sera appelé.

0xb1 devient return.

Exception_table_length et attributes_count ont la valeur 0.

method_info[1] image.png

-Access_flags est 0x0009. Autrement dit, ACC_PUBLIC (0x01) et ACC_STATIC (0x08).

-Name_index sera "principal" de constant_pool [10].

-L'index de description sera "([Ljava / lang / String;) V" de constant_pool [11].

-Attributes_count est égal à 1 et il existe une structure d'attributs.

method_info[1].attributes[0] image.png

Puisque l'attribut_name_index est le "Code" de constant_pool [9], cette structure est la [structure Code_attribute](structure #code_attribute).

attribute_length sera de 21 octets et déterminera la taille de cette structure.

max_stack vaut 2 et max_locals vaut 1.

Le code_length est 9, ce qui signifie que le prochain "0 x B2 00 02 12 03 B6 00 04 B1" est un code d'octet.

0xb2 est getstatic. Cette instruction obtient le champ de la classe statique avec les 2 octets suivants comme index de constant_pool. Dans ce cas, il s'agit de "0x00 02", alors sortez "out: Ljava / io / PrintStream" de la classe "java / lang / System", qui est constant_pool [2]. Le résultat obtenu est chargé sur la pile d'opérandes.

0x12 est ldc. Cette instruction utilise l'octet suivant comme index de constant_pool et charge son contenu dans la pile d'opérandes. Dans ce cas, il s'agit de "0x03", donc la chaîne de caractères "Hello World" de constant_pool [3] est chargée sur la pile d'opérandes.

0xb6 est invokevirtual. Cette instruction utilise les 2 octets suivants comme index pour constant_pool pour exécuter sa méthode. Dans ce cas, c'est "0x00 04", donc exécutez println: (Ljava / lang / String;) V de la classe java / io / PrintStream, qui est constant_pool [4].

0xb1 devient return.

Exception_table_length et attributes_count ont la valeur 0.

ClassFile attributes_count, attributes []

image.png

Puisque attributes_count vaut 0, il n'y a pas de données d'attributs.

Résumé de l'analyse des fichiers de classe

De cette façon, vous pouvez analyser les fichiers de classe avec les spécifications JVM et l'éditeur binaire. ** Cependant, vous pouvez analyser avec la commande javap sans utiliser un éditeur binaire aussi gênant. ** **

>javap -v HelloWorld
Classfile /C:/XXXXXXX/HelloWorld.class
  Last modified 2019/06/09; size 340 bytes
  MD5 checksum 3ee6d0a4b44197baaeb0cec79a0b73d3
public class HelloWorld
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#12         // java/lang/Object."<init>":()V
   #2 = Fieldref           #13.#14        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #15            // Hello World
   #4 = Methodref          #16.#17        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #18            // HelloWorld
   #6 = Class              #19            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               main
  #11 = Utf8               ([Ljava/lang/String;)V
  #12 = NameAndType        #7:#8          // "<init>":()V
  #13 = Class              #20            // java/lang/System
  #14 = NameAndType        #21:#22        // out:Ljava/io/PrintStream;
  #15 = Utf8               Hello World
  #16 = Class              #23            // java/io/PrintStream
  #17 = NameAndType        #24:#25        // println:(Ljava/lang/String;)V
  #18 = Utf8               HelloWorld
  #19 = Utf8               java/lang/Object
  #20 = Utf8               java/lang/System
  #21 = Utf8               out
  #22 = Utf8               Ljava/io/PrintStream;
  #23 = Utf8               java/io/PrintStream
  #24 = Utf8               println
  #25 = Utf8               (Ljava/lang/String;)V
{
  public HelloWorld();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello World
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
}

C'est plus facile que de lire un binaire. Eh bien, cela a approfondi ma compréhension de Hello World. Je suis heureux.

(Enquête) Le faites-vous toujours?

Explorons un peu plus en détail le fonctionnement de HelloWorld.class.

Interrupteur et compilateur

On dit souvent que Java peut être compilé plusieurs fois. Qu'est-ce que cela signifie? Ceci a été décrit par Tobias Hartmann [Java HotSpot VM](https://www.ethz.ch/content/dam/ethz/special-interest/infk/inst-cs/lst-dam/documents/Education/ Classes / Spring2018 / 210_Compiler_Design / Slides / 2018-Compiler-Design-Guest-Talk.pdf).

image.png

Le bytecode créé comme indiqué ci-dessus peut être exécuté soit en code machine compilé avec C1 ou C2, soit dans un interpréteur. De plus, en Java8, ce qui fonctionnait sur l'interpréteur peut changer pour celui compilé sur C1 à partir du milieu, ou il peut être compilé étape par étape en tant qu'interpréteur → C1 → C2.

** Je veux dire, je n'avais aucune idée du fonctionnement de Hello World ... **

S'il a été compilé

Existe-t-il un moyen de savoir si le code d'octet exécuté a été exécuté dans l'interpréteur ou dans le code machine compilé? Vous pouvez le savoir en utilisant "-XX: + PrintCompilation" lors de l'exécution de java.

>java  -XX:+PrintCompilation HelloWorld
     73    1       3       java.lang.String::hashCode (55 bytes)
     74    2       3       java.lang.String::equals (81 bytes)
     75    4     n 0       java.lang.System::arraycopy (native)   (static)
     76    3       4       java.lang.String::charAt (29 bytes)
     76    5       3       java.lang.Object::<init> (1 bytes)
     78    6       4       sun.misc.ASCIICaseInsensitiveComparator::toLower (16 bytes)
     78    7       4       sun.misc.ASCIICaseInsensitiveComparator::isUpper (18 bytes)
     79    8       4       java.lang.String::length (6 bytes)
     79    9       3       java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
     80   10       3       java.lang.Character::toLowerCase (9 bytes)
     80   11       3       java.lang.CharacterData::of (120 bytes)
     81   15       1       java.lang.Object::<init> (1 bytes)
     81    5       3       java.lang.Object::<init> (1 bytes)   made not entrant
     81   12       3       java.lang.CharacterDataLatin1::toLowerCase (39 bytes)
     82   13       3       java.lang.CharacterDataLatin1::getProperties (11 bytes)
     82   17       3       java.io.WinNTFileSystem::isSlash (18 bytes)
     84   16       3       java.lang.AbstractStringBuilder::append (29 bytes)
     84   18  s    3       java.lang.StringBuffer::append (13 bytes)
     85   14       3       java.lang.Math::min (11 bytes)
     86   19       3       java.lang.StringBuilder::append (8 bytes)
     88   20       3       java.lang.String::getChars (62 bytes)
     90   22       3       java.lang.String::indexOf (70 bytes)
     91   21       3       java.util.Arrays::copyOfRange (63 bytes)
     92   23       3       java.lang.System::getSecurityManager (4 bytes)
Hello World

Vous pouvez voir quelle méthode a été compilée et exécutée à l'aide de PrintCompilation. Les détails de cette sortie peuvent être trouvés dans Stack Overflow, mais je vais jeter un œil au code source d'Open SDK. ..

Le code source Java 8 peut être obtenu à partir de ce qui suit. https://download.java.net/openjdk/jdk8u40/ri/openjdk-8u40-src-b25-10_feb_2015.zip

Jetons un coup d'œil au code ci-dessous, qui est pensé pour créer le contenu qui est généré lorsque la compilation d'impression est ajoutée dans ce code.

openjdk\hotspot\src\share\vm\compiler\compileBroker.cpp


// ------------------------------------------------------------------
// CompileTask::print_compilation_impl
void CompileTask::print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
                                         bool is_osr_method, int osr_bci, bool is_blocking,
                                         const char* msg, bool short_form) {
  if (!short_form) {
    st->print("%7d ", (int) st->time_stamp().milliseconds());  // print timestamp
  }
  st->print("%4d ", compile_id);    // print compilation number

  // For unloaded methods the transition to zombie occurs after the
  // method is cleared so it's impossible to report accurate
  // information for that case.
  bool is_synchronized = false;
  bool has_exception_handler = false;
  bool is_native = false;
  if (method != NULL) {
    is_synchronized       = method->is_synchronized();
    has_exception_handler = method->has_exception_handler();
    is_native             = method->is_native();
  }
  // method attributes
  const char compile_type   = is_osr_method                   ? '%' : ' ';
  const char sync_char      = is_synchronized                 ? 's' : ' ';
  const char exception_char = has_exception_handler           ? '!' : ' ';
  const char blocking_char  = is_blocking                     ? 'b' : ' ';
  const char native_char    = is_native                       ? 'n' : ' ';

  // print method attributes
  st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char);

  if (TieredCompilation) {
    if (comp_level != -1)  st->print("%d ", comp_level);
    else                   st->print("- ");
  }
  st->print("     ");  // more indent

  if (method == NULL) {
    st->print("(method)");
  } else {
    method->print_short_name(st);
    if (is_osr_method) {
      st->print(" @ %d", osr_bci);
    }
    if (method->is_native())
      st->print(" (native)");
    else
      st->print(" (%d bytes)", method->code_size());
  }

  if (msg != NULL) {
    st->print("   %s", msg);
  }
  if (!short_form) {
    st->cr();
  }
}

Le tampon de type est affiché dans la première colonne.

La deuxième colonne est compilation_id et method_attributes. cocmpilation_id est un nombre à 4 chiffres. method_attributes est une combinaison d'indicateurs et s'affiche comme suit.

lettre conditions
% Pour la méthode OCR.Dans le cas de InvalidOSREntryBci lorsque MethodCompilation de type enum est défini et qu'il existe InvocationEntryBci et InvalidOSREntryBci.
s En cas de synchronisé
! exception_Si vous avez un gestionnaire
b En cas de blocage
n Pour le code natif

La troisième colonne indique le niveau de compilation lorsque la compilation par niveaux est activée. Cette compilation hiérarchisée peut être contrôlée avec les options -XX: -Tiered Compilation ou + XX: -Tiered Compilation, mais pour Java 8, la valeur par défaut est ON. Le niveau de compilation est le suivant.

level Contenu
0 interpreter
1 C1 with full optimization (no profiling)
2 C1 with limited profiling
3 C1 with full profiling
4 C2

En d'autres termes, le même C1 est divisé en trois étapes.

Le nom de la méthode est affiché dans la 4e colonne.

Regardons maintenant la sortie du premier -XX: + PrintCompilation. Il n'inclut pas le principal de la classe HelloWorld, vous pouvez donc voir que le code est en cours d'exécution dans l'interpréteur.

Même s'il est compilé en code machine, ne pouvez-vous pas voir son contenu?

Le code machine créé en compilant avec C1 et C2 n'est pas sorti dans un fichier, il n'existe qu'en mémoire. Plusieurs étapes sont nécessaires pour le confirmer.

Tout d'abord, obtenez hsdis-amd64.dll qui autorise l'assembleur inversé. Pour Windows, vous pouvez le télécharger depuis: https://sourceforge.net/projects/fcml/files/

Après avoir téléchargé la DLL, passez-la par le chemin.

Exécutez ensuite la commande suivante.

java -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+PrintAssembly -XX:+LogCompilation  HelloWorld

Un fichier journal est créé dans le répertoire courant et vous pouvez voir quel type de code machine vous avez créé.

Exemple de sortie


Decoding compiled method 0x0000000002d00750:
Code:
RIP: 0x2d008a0 Code size: 0x000001f0
[Entry Point]
[Constants]
  # {method} {0x00000000192f4fc0} &apos;hashCode&apos; &apos;()I&apos; in &apos;java/lang/String&apos;
  #           [sp+0x40]  (sp of caller)
  0x0000000002d008a0: mov     r10d,dword ptr [rdx+8h]
  0x0000000002d008a4: shl     r10,3h
  0x0000000002d008a8: cmp     r10,rax
  0x0000000002d008ab: jne     2c35f60h          ;   {runtime_call}
  0x0000000002d008b1: nop     word ptr [rax+rax+0h]
  0x0000000002d008bc: nop
[Verified Entry Point]
  0x0000000002d008c0: mov     dword ptr [rsp+0ffffffffffffa000h],eax
  0x0000000002d008c7: push    rbp
  0x0000000002d008c8: sub     rsp,30h
  0x0000000002d008cc: mov     rax,193e7ac8h
  0x0000000002d008d6: mov     esi,dword ptr [rax+8h]
  0x0000000002d008d9: add     esi,8h
  0x0000000002d008dc: mov     dword ptr [rax+8h],esi
//Abréviation

Il y a beaucoup de fichiers journaux et c'est difficile à voir ...

Le fichier journal qui produit le code machine contient une grande quantité d'informations et il sera difficile de trouver les informations souhaitées. Dans ce cas, vous souhaiterez peut-être naviguer sur JitWatch. https://github.com/AdoptOpenJDK/jitwatch/

image.png

image.png

Veuillez consulter ce qui suit pour une utilisation détaillée.

** Regardez la compilation JIT sur JIT Watch! ** ** https://www.sakatakoichi.com/entry/2014/12/04/202747

Comment l'interprète interprète-t-il le bytecode?

A présent, nous savons que HelloWorld :: main s'exécute sur l'interpréteur. Ensuite, où et comment les commandes suivantes telles que getstatic to return sont-elles traitées?

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello World
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
}

L'équipe de recherche, qui cherchait le code source de l'OpenSDK pour résoudre ce mystère, a finalement trouvé la partie pertinente. J'ai trouvé que des instructions telles que getstatic et ldc sont interprétées et exécutées par runWithChecks () / run () dans bytecodeInterpreter.cpp.

hotspot\src\share\vm\interpreter\bytecodeInterpreter.cpp


/*
 * BytecodeInterpreter::run(interpreterState istate)
 * BytecodeInterpreter::runWithChecks(interpreterState istate)
 *
 * The real deal. This is where byte codes actually get interpreted.
 * Basically it's a big while loop that iterates until we return from
 * the method passed in.
 *
 * The runWithChecks is used if JVMTI is enabled.
 *
 */
#if defined(VM_JVMTI)
void
BytecodeInterpreter::runWithChecks(interpreterState istate) {
#else
void
BytecodeInterpreter::run(interpreterState istate) {
#endif
  //Abréviation
#ifndef USELABELS
  while (1)
#endif
  {
#ifndef PREFETCH_OPCCODE
      opcode = *pc;
#endif
      // Seems like this happens twice per opcode. At worst this is only
      // need at entry to the loop.
      // DEBUGGER_SINGLE_STEP_NOTIFY();
      /* Using this labels avoids double breakpoints when quickening and
       * when returing from transition frames.
       */
  opcode_switch:
      assert(istate == orig, "Corrupted istate");
      /* QQQ Hmm this has knowledge of direction, ought to be a stack method */
      assert(topOfStack >= istate->stack_limit(), "Stack overrun");
      assert(topOfStack < istate->stack_base(), "Stack underrun");

#ifdef USELABELS
      DISPATCH(opcode);
#else
      switch (opcode)
#endif
      {
      CASE(_nop):
          UPDATE_PC_AND_CONTINUE(1);
      //Abréviation
      }
    }
  }
}

Cette boucle en while jusqu'à ce que tous les codes d'octet de la méthode soient exécutés, et est branchée et exécutée dans la section CASE selon le code d'instruction. Par exemple, getstatic a l'implémentation suivante.

getstatic


      CASE(_getfield):
      CASE(_getstatic):
        {
          u2 index;
          ConstantPoolCacheEntry* cache;
          //Remarque: emplacement actuel du bytecode pc+Obtenez 1 à 2 octets de données et stockez-les dans l'index
          index = Bytes::get_native_u2(pc+1);

          // QQQ Need to make this as inlined as possible. Probably need to
          // split all the bytecode cases out so c++ compiler has a chance
          // for constant prop to fold everything possible away.
          //Remarque: constatnt_Spécifiez l'index de la table et prenez une valeur.
          cache = cp->entry_at(index);
          if (!cache->is_resolved((Bytecodes::Code)opcode)) {
            CALL_VM(InterpreterRuntime::resolve_get_put(THREAD, (Bytecodes::Code)opcode),
                    handle_exception);
            cache = cp->entry_at(index);
          }

#ifdef VM_JVMTI
          if (_jvmti_interp_events) {
            int *count_addr;
            oop obj;
            // Check to see if a field modification watch has been set
            // before we take the time to call into the VM.
            count_addr = (int *)JvmtiExport::get_field_access_count_addr();
            if ( *count_addr > 0 ) {
              if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) {
                obj = (oop)NULL;
              } else {
                obj = (oop) STACK_OBJECT(-1);
                VERIFY_OOP(obj);
              }
              CALL_VM(InterpreterRuntime::post_field_access(THREAD,
                                          obj,
                                          cache),
                                          handle_exception);
            }
          }
#endif /* VM_JVMTI */

          oop obj;
          if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) {
            //Remarque: constante_table[2]Obtenez les informations de classe et mettez-les dans obj
            Klass* k = cache->f1_as_klass();
            obj = k->java_mirror();
            MORE_STACK(1);  // Assume single slot push
          } else {
            obj = (oop) STACK_OBJECT(-1);
            CHECK_NULL(obj);
          }

          //
          // Now store the result on the stack
          //
          TosState tos_type = cache->flag_state();
          //Remarque: constante_table[2]Obtenir des informations sur le champ du champ_Mettre en offset
          int field_offset = cache->f2_as_index();
          if (cache->is_volatile()) {
            if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
              OrderAccess::fence();
            }
            if (tos_type == atos) {
              VERIFY_OOP(obj->obj_field_acquire(field_offset));
              SET_STACK_OBJECT(obj->obj_field_acquire(field_offset), -1);
            } else if (tos_type == itos) {
              SET_STACK_INT(obj->int_field_acquire(field_offset), -1);
            } else if (tos_type == ltos) {
              SET_STACK_LONG(obj->long_field_acquire(field_offset), 0);
              MORE_STACK(1);
            } else if (tos_type == btos) {
              SET_STACK_INT(obj->byte_field_acquire(field_offset), -1);
            } else if (tos_type == ctos) {
              SET_STACK_INT(obj->char_field_acquire(field_offset), -1);
            } else if (tos_type == stos) {
              SET_STACK_INT(obj->short_field_acquire(field_offset), -1);
            } else if (tos_type == ftos) {
              SET_STACK_FLOAT(obj->float_field_acquire(field_offset), -1);
            } else {
              SET_STACK_DOUBLE(obj->double_field_acquire(field_offset), 0);
              MORE_STACK(1);
            }
          } else {
            if (tos_type == atos) {
              //Remarque: constante_table[2]Obtient le champ de la classe de et stocke le résultat sous forme d'objet sur la pile.
              VERIFY_OOP(obj->obj_field(field_offset));
              SET_STACK_OBJECT(obj->obj_field(field_offset), -1);
            } else if (tos_type == itos) {
              SET_STACK_INT(obj->int_field(field_offset), -1);
            } else if (tos_type == ltos) {
              SET_STACK_LONG(obj->long_field(field_offset), 0);
              MORE_STACK(1);
            } else if (tos_type == btos) {
              SET_STACK_INT(obj->byte_field(field_offset), -1);
            } else if (tos_type == ctos) {
              SET_STACK_INT(obj->char_field(field_offset), -1);
            } else if (tos_type == stos) {
              SET_STACK_INT(obj->short_field(field_offset), -1);
            } else if (tos_type == ftos) {
              SET_STACK_FLOAT(obj->float_field(field_offset), -1);
            } else {
              SET_STACK_DOUBLE(obj->double_field(field_offset), 0);
              MORE_STACK(1);
            }
          }
          //Exécutez l'instruction 3 octets avant getstatic.
          UPDATE_PC_AND_CONTINUE(3);
         }
// Have to do this dispatch this way in C++ because otherwise gcc complains about crossing an
// initialization (which is is the initialization of the table pointer...)
#define DISPATCH(opcode) goto *(void*)dispatch_table[opcode]
//Abréviation
#define UPDATE_PC_AND_CONTINUE(opsize) {                        \
        pc += opsize; opcode = *pc;                             \
        DO_UPDATE_INSTRUCTION_COUNT(opcode);                    \
        DEBUGGER_SINGLE_STEP_NOTIFY();                          \
        DISPATCH(opcode);                                       \
    }

DISPACH est exécuté lorsque l'instruction suivante est exécutée. Il s'agit d'une instruction goto, qui exécute l'instruction suivante en passant à l'étiquette d'instruction.

Comme vous pouvez le voir, si vous regardez l'interrupteur à partir de ce code comme point de départ, vous pouvez avoir une idée du type de traitement qu'il effectue. ~~ À ce stade, il fait plus de 30 000 caractères, il est donc difficile de rassembler toutes les informations analysées ~~

Résumé

Cette fois, je suis retourné au début et j'ai vu comment fonctionne Hello World.

Je dis: «Voir c'est croire, voir c'est croire», mais je suis désolé, j'ai léché Hello World. C'était très ennuyeux.

référence:

Demystifying the JVM: Interpretation, JIT and AOT Compilation https://metebalci.com/blog/demystifying-the-jvm-interpretation-jit-and-aot-compilation/#disqus_thread

DEMYSTIFYING THE JVM: JVM VARIANTS, CPPINTERPRETER AND TEMPLATEINTERPRETER https://metebalci.com/blog/demystifying-the-jvm-jvm-variants-cppinterpreter-and-templateinterpreter/#disqus_thread

** Enquête sur la compilation Java JIT avec JIT Watch ** https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-MA15-Architect-newland.pdf

** Regardez la compilation JIT sur JIT Watch! ** ** https://www.sakatakoichi.com/entry/2014/12/04/202747

** J'ai essayé de sortir [Java] en utilisant uniquement un éditeur binaire ** https://tech.recruit-mp.co.jp/etc/java_class_hello_world/

Recommended Posts

Revenant au début, Java-Kisama s'est moqué de Hello World-
Revenir au début, démarrer avec Java ② Instructions de contrôle, instructions de boucle
Défi d'expliquer Hello World de Java en se référant aux spécifications du langage
Bonjour tout le monde!
Introduction à Ratpack (3) - Explication détaillée de Hello World
Afficher "Hello World" dans le navigateur à l'aide de Java
Afficher "Hello World" dans le navigateur à l'aide de Java
Essayez d'afficher Hello World avec Spring + Gradle
Facile à afficher Hello World avec Rails + Docker
Lire "Hello world"
Java Hello World
[Introduction] Affichez Android Studio Hello World sur l'émulateur
Kotlin peut faire passer le monde de l'application au Web