Zurück zum Anfang verspottete Java-Kisama Hello World-

Kisama verspottete Hello World

Beim Starten einer Programmiersprache wird häufig "Hello World" gedruckt. Besonders wenn ich es geschäftlich nutzen muss, werde ich Hello World mit der Geschwindigkeit von Gokiburi Dash schreiben und versuchen, zur nächsten Stufe überzugehen.

Aber habe ich verstanden, wie diese Hallo Welt funktioniert? Dieses Mal möchte ich zum Anfang zurückkehren und Hello World so weit überprüfen, dass ich von Dr. Retsu nicht verwirrt werden kann: "Kisama hat Hello World verspottet."

Gokiburi Dash-ähnliche Hallo Welt

Umgebung

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)

Erstellen und Ausführen von Helloworld

Erstellen und führen Sie Hello World wie gewohnt aus. Schreiben Sie zuerst den Java-Code in einen Texteditor.

HelloWorld.java


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

Führen Sie den Befehl javac mit der erstellten Java-Datei als Eingabe aus, um eine Klassendatei zu erstellen. Fügen Sie diesmal die Option "-g: none" hinzu, um die Generierung von Debug-Informationen zu verhindern.

javac -g:none HelloWorld.java

Führen Sie die erstellte "HelloWorld.class" mit dem Befehl java aus.

>java HelloWorld
Hello World

"Hello World" wurde ausgegeben. Im Gegensatz zu ausführbaren Dateien, die mit c oder c ++ erstellt wurden, funktioniert die erstellte HelloWorld.class unter Windows, Mac und Linux genauso, solange sie Java enthält. Nein, Java ist praktisch.

**das Ende! !! Geschlossen! !! das ist alles! !! Alle haben sich aufgelöst! !! ** **.

Es gab eine Zeit, in der ich so dachte

Das war das Ende davon. Ja, ich hatte keine Gelegenheit darüber nachzudenken, was diese HelloWorld.class ist. Diesmal ist es eine große Sache, also überprüfen wir den Inhalt der erstellten Binärdatei.

Der Inhalt von HelloWorld.class sind die folgenden Binärdateien.

image.png

Um diese Binärdatei zu lesen, müssen Sie die Java® Virtual Machine Specification lesen. https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

Diesmal verwendete JVM-Spezifikationen

Ich werde kurz die Spezifikationen der diesmal verwendeten JVM beschreiben, aber wenn Sie die Binärdatei der Klassendatei schnell analysieren möchten, klicken Sie bitte auf [Überspringen](Binäranalyse von #helloworldclass).

class Die Struktur der Datei ist wie folgt.

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 steht für 1 Byte, u2 für 2 Byte und u4 für 4 Datenbytes. Andere sind Strukturen, deshalb werde ich jedes Mal erklären.

magic ist eine magische Zahl, die das Klassendateiformat identifiziert und "0xCAFEBABE" lautet. Der Ursprung dieser magischen Zahl ist in CAFE BABE: Javas magisches Wort beschrieben. Lesen Sie sie daher bitte. Ich benutze es an einem Datum und es wird gezeichnet.

minor_version und major_version sind die Minor- und Major-Versionsnummern dieser Klassendatei. Die Haupt- und Nebenversionsnummern bestimmen die Version des Klassendateiformats.

Constant_pool [] und Constant_pool_count sind die Tabelle und die Anzahl der Strukturen, die Zeichenfolgenkonstanten, Klassen- und Schnittstellennamen, Feldnamen und andere Konstanten darstellen. Der gültige Bereich für den Index zu Konstante_Pool ist 1 bis Konstante_Pool_Count-1.

access_flags ist eine Kombination der folgenden Flags.

Flaggenname Wert Interpretation
ACC_PUBLIC 0x0001 public wird deklariert. Es kann von außerhalb des Pakets zugegriffen werden.
ACC_FINAL 0x0010 final wird erklärt. Unterklassen sind nicht erlaubt.
ACC_SUPER 0x0020 Behandelt Methoden der Superklasse speziell, wenn sie von der aufrufspezifischen Anweisung aufgerufen werden.
ACC_INTERFACE 0x0200 Es ist eine Schnittstelle, keine Klasse.
ACC_ABSTRACT 0x0400 Es wurde als abstrakt deklariert. Nicht instanziieren.
ACC_SYNTHETIC 0x1000 Gibt an, dass es vom Compiler generiert wurde. * Zum Beispiel eine Klassendatei, die erstellt wird, wenn eine Klasse in einer Klasse erstellt wird(ex. Hello$Test.class)Wurde gegeben
ACC_ANNOTATION 0x2000 Als Anmerkung deklariert.
ACC_ENUM 0x4000 Als Aufzählungstyp deklariert.

Diese_Klasse muss ein gültiger Indexwert in Konstante_Pool [] sein. Die Daten, auf die im Index verwiesen wird, müssen eine Struktur CONSTANT_Class_info sein, die die Informationen für die in der Datei angegebene Klasse enthält.

super_class muss 0 oder ein gültiger Indexwert in constant_pool [] sein. Die Daten, auf die im Index verwiesen wird, müssen eine Struktur CONSTANT_Class_info sein, die die direkte Oberklasse der in dieser Klassendatei definierten Klasse darstellt.

interfaces_count und interfaces [] sind ein Array von Indizes in der Struktur CONSTANT_Class_info, die die Schnittstellen der in dieser Klassendatei definierten Klasse darstellt. Wenn keine Schnittstellen vorhanden sind, ist interfaces_count 0 und interfaces [] nicht vorhanden.

fields_count, fields [] repräsentieren die Felder der in dieser Klassendatei definierten Klasse Feldstruktur Es ist ein Array von # jvms-4.5). Wenn keine Felder vorhanden sind, ist fields_count 0 und fields [] ist nicht vorhanden.

Methods_count und Methods [] sind ein Array von [Methodenstrukturen](# Methodenstrukturen), die die Methoden der in dieser Klassendatei definierten Klasse darstellen. Wenn keine Felder vorhanden sind, ist Methods_count 0 und Methods [] ist nicht vorhanden.

Attribute_Count und Attribute [] sind ein Array von [Attributstrukturen](# Attributstrukturen), die Attributinformationen für die in dieser Klassendatei definierten Klassen darstellen.

constant_pool Diese Struktur ist ein 1-Byte-Tag, das bestimmt, wie die Struktur aussehen wird.

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

Wir werden erklären, was wir dieses Mal verwenden werden. Weitere Strukturen finden Sie im Folgenden. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4-140

CONSTANT_Class Wird verwendet, um eine Klasse oder Schnittstelle darzustellen.

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

7, die CONSTANT_Class darstellt, wird im Tag gespeichert. Der Wert des Elements name_index ist der Index für die Struktur [CONSTANT_Utf8_info](# constant_utf8) in der Tabelle const_pool.

CONSTANT_Fieldref

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

Das Tag enthält 9, die den Wert CONSTANT_Fieldref_info darstellt. Der Wert von class_index ist der Index für die CONSTANT_Class_info-Struktur in der Tabelle const_pool. Der Wert des Elements name_and_type_index ist der Index für die Struktur CONSTANT_NameAndType_info (#constant_nameandtype) in der Tabelle constant_pool.

CONSTANT_Methodref

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

Das Tag enthält 10, die den Wert CONSTANT_Methodref darstellen. Der Wert von class_index ist der Index für die CONSTANT_Class_info-Struktur in der Tabelle const_pool. Der Wert des Elements name_and_type_index ist der Index für die Struktur CONSTANT_NameAndType_info (#constant_nameandtype) in der Tabelle constant_pool.

CONSTANT_String

CONSTANT_String_info {
    u1 tag;
    u2 string_index;
}

Das Tag enthält 8, die den Wert CONSTANT_String darstellt. Der Wert von string_index ist der Index für die Struktur [CONSTANT_Utf8_info](# constant_utf8) in der Tabelle const_pool.

CONSTANT_NameAndType Wird verwendet, um ein Feld oder eine Methode darzustellen. Es gibt jedoch nicht den Typ der Klasse oder Schnittstelle an, zu der es gehört.

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

Das Tag enthält 12, die den Wert CONSTANT_NameAndType darstellen. Der Wert des Felds name_index muss ein gültiger Index für die Struktur [CONSTANT_Utf8_info](# constant_utf8) im Konstantenpool sein.

CONSTANT_Utf8

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

Das Tag enthält 1, die den Wert CONSTANT_Utf8 darstellt. Länge gibt die Anzahl der Bytes im Bytes-Array an (nicht die Länge der Zeichenfolge). Das Byte-Array enthält die Bytes der Zeichenfolge. Auch das Terminalzeichen ist nicht enthalten. Weitere Informationen zu dieser Zeichenfolge finden Sie weiter unten. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.7

Methodenstruktur

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

Der Wert des Elements access_flags ist eine Kombination aus Berechtigungen für diese Methode und den Flags, mit denen die Eigenschaften dieser Methode angegeben werden.

Flaggenname Wert Erläuterung
ACC_PUBLIC 0x0001 Für öffentlich erklärt. Es kann von außerhalb des Pakets zugegriffen werden.
ACC_PRIVATE 0x0002 Für privat erklärt. Nur innerhalb der Definitionsklasse zugänglich.
ACC_PROTECTED 0x0004 Für geschützt erklärt. Sie können innerhalb einer Unterklasse darauf zugreifen.
ACC_STATIC 0x0008 Als statisch deklariert.
ACC_FINAL 0x0010 Für endgültig erklärt. Es darf nicht überschrieben werden.
ACC_SYNCHRONIZED 0x0020 Als synchronisiert deklariert.
ACC_BRIDGE 0x0040 Wird verwendet, um die vom Compiler für die Programmiersprache Java generierte Bridge-Methode anzugeben.Java Generics - Bridge method?Bitte beziehen Sie sich auf.
ACC_VARARGS 0x0080 Mit einer variablen Anzahl von Argumenten deklariert.
ACC_NATIVE 0x0100 Als einheimisch deklariert. Es ist in anderen Sprachen als Java implementiert.
ACC_ABSTRACT 0x0400 Deklariert abstrakt. Es ist keine Implementierung vorgesehen.
ACC_STRICT 0x0800 Erklärt strictfp.
ACC_SYNTHETIC 0x1000 Gibt an, dass es nicht im vom Compiler generierten Quellcode angezeigt wird.

Der Wert von name_index ist der Index für die Struktur [CONSTANT_Utf8_info](# constant_utf8) in der Tabelle const_pool. Enthält den Methodennamen oder oder .

Der Wert von Descriptor_Index ist der Index für die Struktur [CONSTANT_Utf8_info](# Konstante_Autf8) in der Tabelle Constant_Pool. Enthält den Methodendeskriptor (https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3).

Attribute_Count und Attribute [] sind ein Array von [Attributstrukturen](# Attributstrukturen), die Attributinformationen für die in dieser Klassendatei definierten Klassen darstellen.

Attributstruktur

Die Form dieser Struktur ändert sich je nach Attribut. Das übliche Format ist wie folgt.

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

Der Wert von attribute_name_index ist der Index für die [CONSTANT_Utf8_info-Struktur](# constant_utf8) in der Tabelle constable_pool. attribute_length gibt die Länge nachfolgender Informationen in Bytes an. info ist für jedes Attribut unterschiedlich.

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

Siehe unten für Artikel, die hier nicht behandelt werden. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

Code-Attribut

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];
}

attribute_name_index und attribute_length werden in einem gemeinsamen Format beschrieben. Das durch attribute_name_index angegebene Zeichen muss "Code" sein.

Der Wert des Elements max_stack ist die maximale Tiefe des Operator-Stacks dieser Methode. Es wird sein.

Der Wert des Elements max_locals sind die lokalen Variablen (https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6.1), die beim Aufruf dieser Methode zugewiesen wurden. ).

Der Wert des Elements code_length ist die Nummer des Codes [].

Das Code-Array zeigt die tatsächlichen Bytes des Java Virtual Machine-Codes an, der die Methode implementiert. Dieser Code wird unten beschrieben. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5

exception_table_length speichert die Anzahl der Einträge für exception_table.

exception_table repräsentiert Ausnahmeinformationen. Der Inhalt jedes Elements von exception_table lautet wie folgt. -Start_pc, end_pc: Gibt den Indexwert des Code-Arrays an, für das der Ausnahmebehandler aktiviert ist. Im Java-Code ist dies der Bereich, der von Try Ward umgeben ist. -Das Element handler_pc ist der Indexwert des vom Ausnahmehandler gestarteten Codearrays. Im Java-Code ist dies der Bereich, der vom Fangbereich umgeben ist. -Catch_type ist 0 oder ein gültiger Index für die Tabelle constant_pool, und dieser Index ist die CONSTANT_Class_info-Struktur, die die Ausnahmeklasse darstellt.

Attribute_Count und Attribute [] sind ein Array von [Attributstrukturen](# Attributstrukturen), die Attributinformationen für die in dieser Klassendatei definierten Klassen darstellen.

HelloWorld.class Binäranalyse

Auswahl und Konfiguration des Binäreditors

Der maschinensprachliche Bruder kann Hexadezimalzahlen mit jedem Binäreditor lesen, aber ehrlich gesagt ist es im Zeitalter von Reiwa schwierig, Hexadezimalzahlen zu lesen. Betrachten Sie daher einen Binäreditor, der so einfach wie möglich zu lesen scheint. Ich versuchte zu.

Dieses Mal werden wir den BZ-Editor verwenden. Die Gründe für die Einführung von BZ Editor sind folgende. ・ Kann unter Windows verwendet werden (In letzter Zeit scheint es, dass es unter MacOS verwendet werden kann, wenn es erstellt wurde) ・ Struktur kann angezeigt werden. ・ Sie können Hinos Worte verwenden

Wenn Sie andere binäre Editoren in Betracht ziehen möchten, finden Sie in Wikipedia eine Vergleichstabelle mit binären Editoren. https://en.wikipedia.org/wiki/Comparison_of_hex_editors Unter ihnen schien HxD einfach zu bedienen zu sein.

BZ Editor Einstellungen

Strukturdefinition

Sie können die Struktur in Bz.def definieren, das sich im selben Ordner wie die ausführbare Datei des BZ-Editors befindet. Beachten Sie, dass nur Strukturen mit fester Größe angegeben werden können, sodass die Analyse nicht perfekt durchgeführt werden kann.

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;

Diese BZ.def kann wie die Sprache C geschrieben werden. Unter TYPESTR [NUM_MEMBERS] im folgenden Code finden Sie die Typen, die Sie verwenden können. https://github.com/devil-tamachan/binaryeditorbz/blob/master/Bz/BZFormVw.cpp

Aktivieren Sie nach dem Starten von BZEditor "Ansicht"> "Strukturanzeige", um das untergeordnete Fenster für die Strukturanzeige anzuzeigen. image.png

Durch Doppelklicken auf eine Adresse werden die Strukturinformationen ab dieser Adresse angezeigt. image.png

Ändern Sie die Reihenfolge der Bytes

Wählen Sie Motorola aus, wenn Sie die Klassendatei analysieren. image.png

Analysieren von Klassendateien mit dem BZ-Editor

Lassen Sie uns ClassFile von Anfang an analysieren.

Von Anfang an zu constant_pool_count

image.png

"0x CAFE BABE" wird für Magie angezeigt. Nebenversion ist 0 major_version ist 52. Konstante_Pool_Count ist 26 und das nächste Byte ist der Eintrag für Konstante_Pool.

Analyse von constant_pool []

constant_pool[1] image.png Da das erste Byte 0x0A = 10 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Methodref. class_index ist 6 und name_and_type_index ist 12. Überprüfen Sie nach dem Betrachten aller constant_pools, was diese Indizes tatsächlich anzeigen.

constant_pool[2] image.png Da das erste Byte 0x09 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Fieldref. class_index ist 13 und name_and_type_index ist 14.

constant_pool[3] image.png

Da das erste Byte 0x08 ist, lautet der Eintrag für constant_pool CONSTANT_String. Der Index wird 15 sein.

constant_pool[4] image.png

Da das erste Byte 0x0A = 10 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Methodref. class_index ist 16 und name_and_type_index ist 17.

constant_pool[5] image.png

Da das erste Byte 0x07 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Class. Der Index wird 18 sein.

constant_pool[6] image.png

Da das erste Byte 0x07 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Class. Der Index wird 19 sein.

constant_pool[7] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 6 und die 6 Bytes danach speichern die Zeichen "\ <init >".

constant_pool[8] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 3 und das Zeichen "() V" wird in den folgenden 3 Bytes gespeichert.

constant_pool[9] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 4 und die 4 Bytes danach speichern das Zeichen "Code".

constant_pool[10] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 4, und die 4 Bytes danach speichern das Zeichen "main".

constant_pool[11] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 22 und die 22 Bytes danach speichern das Zeichen "([Ljava / lang / String;) V".

constant_pool[12] image.png

Da das erste Byte 0x0C = 12 ist, ist der Eintrag für diesen Konstantenpool die CONSTANT_NameAndType_info-Struktur. name_index ist 7 und deskriptor_index ist 8.

constant_pool[13] image.png

Da das erste Byte 0x07 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Class. Der Index wird 20 sein.

constant_pool[14] image.png

Da das erste Byte 0x0C = 12 ist, ist der Eintrag für diesen Konstantenpool die CONSTANT_NameAndType_info-Struktur. name_index ist 21 und deskriptor_index ist 22.

constant_pool[15] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 11 und die 11 Bytes danach speichern die Zeichen "Hello World".

constant_pool[16] image.png

Da das erste Byte 0x07 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Class. Der Index wird 23 sein.

constant_pool[17] image.png

Da das erste Byte 0x0C = 12 ist, ist der Eintrag für diesen Konstantenpool die CONSTANT_NameAndType_info-Struktur. Name_Index ist 24 und Deskriptor_Index ist 25.

constant_pool[18] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 10 und die 10 Bytes danach speichern die Zeichen "Hello World".

constant_pool[19] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 16 und die folgenden 16 Bytes speichern die Zeichen "java / lang / Object".

constant_pool[20] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 16 und die folgenden 16 Bytes speichern die Zeichen "java / lang / System".

constant_pool[21] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 3 und das Zeichen "out" wird in den folgenden 3 Bytes gespeichert.

constant_pool[22] image.png Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 21 und die folgenden 21 Bytes speichern die Zeichen "Ljava / io / PrintStream;".

constant_pool[23] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 19 und die folgenden 19 Bytes speichern die Zeichen "java / io / PrintStream".

constant_pool[24] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 7, und die 7 Bytes danach speichern das Zeichen "println".

constant_pool[25] image.png

Da das erste Byte 0x01 ist, lautet der Eintrag für diesen Konstantenpool [CONSTANT_Utf8](# Konstante_Autf8). Die Länge beträgt 21 und die 21 Bytes danach speichern das Zeichen "(Ljava / lang / String;) V".

Zusammenfassung von constant_pool von HelloWorld.class

Der constante_pool kann wie folgt zusammengefasst werden.

No Struktur Inhalt
1 CONSTANT_Methodref class_Indexist6:HelloWorld、name_and_type_Indexist12::V()
2 CONSTANT_Fieldref class_Index ist 13:java/lang/System、name_and_type_Index ist 14: out:Ljava/io/PrintStream;
3 CONSTANT_String Index ist 15:「Hello World」
4 CONSTANT_Methodref class_Indexist16:java/io/PrintStream、name_and_type_Indexist17:println:(Ljava/lang/String;)V
5 CONSTANT_Class Index ist 18:「HelloWorld」
6 CONSTANT_Class Index ist 19:「java/lang/Object」
7 CONSTANT_Utf8 「<init>Ist die Zeichenkette
8 CONSTANT_Utf8 「()Die Zeichenfolge "V"
9 CONSTANT_Utf8 Die Zeichenfolge "Code"
10 CONSTANT_Utf8 Die Zeichenfolge "main"
11 CONSTANT_Utf8 「([Ljava/lang/String;)Die Zeichenfolge "V"
12 CONSTANT_NameAndType_info name_Indexist7:「<init>」,descriptor_Indexist8:「()V」。MethodDescriptorsSehen
13 CONSTANT_Class Index ist 20;「java/lang/System」
14 CONSTANT_NameAndType_info name_Indexist21:「out」,descriptor_Indexist22:「Ljava/io/PrintStream;」FieldDescriptorsSehen
15 CONSTANT_Utf8 Die Zeichenfolge "Hello World"
16 CONSTANT_Class Index ist 23:「java/io/PrintStream」
17 CONSTANT_NameAndType_info name_Indexist24:「println」,descriptor_Indexist25:「(Ljava/lang/String;)V」MethodDescriptorsSehen
18 CONSTANT_Utf8 Die Zeichenfolge "Hello World"
19 CONSTANT_Utf8 「java/lang/Die Zeichenfolge "Objekt"
20 CONSTANT_Utf8 「java/lang/Die Zeichenfolge "System"
21 CONSTANT_Utf8 Die Zeichenfolge "out"
22 CONSTANT_Utf8 「Ljava/io/PrintStream;Ist die Zeichenkette
23 CONSTANT_Utf8 「java/io/Die Zeichenfolge "Print Stream"
24 CONSTANT_Utf8 Die Zeichenfolge "println"
25 CONSTANT_Utf8 「(Ljava/lang/String;)Die Zeichenfolge "V"

Von access_flags zu Schnittstellen []

image.png

-Access_flags ist 0x0021. Das heißt, ACC_SUPER (0x20) und ACC_PUBLIC (0x01).

-Diese_Klasse ist eine HelloWorld-Klasse, da es sich um constant_pool handelt [5].

-Interfaces_count ist 0 und es gibt keine nachfolgenden Schnittstellen [].

bis zu Felder zählen ~ Felder []

image.png

Da fields_count 0 ist, müssen keine Dateien folgen.

methods_count~methods[] image.png

Da method_count 0x0002 ist, gibt es zwei Fälle, gefolgt von der method_info-Struktur.

method_info[0] image.png

-Access_flags ist 0x0001. Das heißt, ACC_PUBLIC (0x01).

-Name_index ist "\ <init >" von constant_pool [7]. Dies ist ein impliziter Konstruktor, der während der Java-Kompilierung erstellt wurde.

-Der description_index ist "() V" von constant_pool [8].

-Attributes_count ist 1 und es gibt eine Attributstruktur.

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

Da attribute_name_index der "Code" von constant_pool [9] ist, ist diese Struktur die [Code_attribute-Struktur](# code_attribute-Struktur).

attribute_length beträgt 17 Byte und bestimmt die Größe dieser Struktur.

max_stack ist 1 und max_locals ist 1.

Die Codelänge ist 5, was bedeutet, dass die nächste "0 x 2A B7 00 01 B1" ein Bytecode ist. 0x2a wird zu aload_0. Diese Anweisung legt dies auf den Operandenstapel.

0xb7 wird zu invokesplecial. Diese Anweisung ruft die Methode mit den folgenden 2 Bytes als Index von constant_pool auf. In diesem Fall ist es "0x00 01", also wird constant_pool [1], "java / lang / Object", "": () V "aufgerufen.

0xb1 wird zu return.

Sowohl exception_table_length als auch attribute_count sind 0.

method_info[1] image.png

-Access_flags ist 0x0009. Das heißt, ACC_PUBLIC (0x01) und ACC_STATIC (0x08).

-Name_index ist "main" von constant_pool [10].

-Der description_index ist "([Ljava / lang / String;) V" von constant_pool [11].

-Attributes_count ist 1 und es gibt eine Attributstruktur.

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

Da attribute_name_index der "Code" von constant_pool [9] ist, ist diese Struktur die [Code_attribute-Struktur](# code_attribute-Struktur).

attribute_length beträgt 21 Byte und bestimmt die Größe dieser Struktur.

max_stack ist 2 und max_locals ist 1.

Die Codelänge ist 9, was bedeutet, dass die nächste "0 x B2 00 02 12 03 B6 00 04 B1" ein Bytecode ist.

0xb2 ist getstatic. Diese Anweisung ruft das Feld aus der statischen Klasse mit den folgenden 2 Bytes als Index von constant_pool ab. In diesem Fall ist es "0x00 02", also holen Sie "out: Ljava / io / PrintStream" der Klasse "java / lang / System", die constant_pool [2] ist. Das erhaltene Ergebnis wird auf den Operandenstapel geladen.

0x12 ist ldc. Diese Anweisung verwendet das folgende 1 Byte als Index von constant_pool und lädt seinen Inhalt in den Operandenstapel. In diesem Fall ist es "0x03", daher wird die Zeichenfolge "Hello World" von constant_pool [3] auf den Operandenstapel geladen.

0xb6 ist invokevirtual. Diese Anweisung verwendet die folgenden 2 Bytes als Index für constant_pool, um ihre Methode auszuführen. In diesem Fall ist es "0x00 04". Führen Sie also println: (Ljava / lang / String;) V der Klasse java / io / PrintStream aus, die constant_pool [4] ist.

0xb1 wird zu return.

Sowohl exception_table_length als auch attribute_count sind 0.

ClassFile Attribute_Count, Attribute []

image.png

Da attribute_count 0 ist, gibt es keine Attributdaten.

Zusammenfassung der Klassendateianalyse

Auf diese Weise können Sie Klassendateien mit den JVM-Spezifikationen und dem Binäreditor analysieren. ** Sie können jedoch mit dem Befehl javap analysieren, ohne einen so problematischen Binäreditor zu verwenden. ** **.

>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
}

Es ist einfacher als eine Binärdatei zu lesen. Nun, das hat mein Verständnis von Hello World vertieft. Ich bin glücklich.

(Untersuchung) Tun Sie es immer noch?

Lassen Sie uns etwas tiefer in die Funktionsweise dieser HelloWorld.class eintauchen.

Interruptor und Compiler

Es wird oft gesagt, dass Java mehrfach kompiliert werden kann. Was bedeutet das? Dies wurde von Tobias Hartmann The Java HotSpot VM beschrieben. Klassen / Spring2018 / 210_Compiler_Design / Slides / 2018-Compiler-Design-Guest-Talk.pdf).

image.png

Der wie oben gezeigt erstellte Bytecode kann entweder in mit C1 oder C2 kompiliertem Maschinencode oder in einem Interpreter ausgeführt werden. In Java8 kann sich das, was auf dem Interpreter ausgeführt wurde, zu dem ändern, das von Mitte auf C1 kompiliert wurde, oder es kann Schritt für Schritt als Interpreter → C1 → C2 kompiliert werden.

** Ich meine, ich hatte keine Ahnung, wie Hello World funktioniert ... **

Ob es kompiliert wurde

Gibt es eine Möglichkeit festzustellen, ob der ausgeführte Bytecode im Interpreter oder im kompilierten Maschinencode ausgeführt wurde? Sie können dies herausfinden, indem Sie "-XX: + PrintCompilation" verwenden, wenn Sie Java ausführen.

>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

Mit PrintCompilation können Sie sehen, welche Methode kompiliert und ausgeführt wurde. Details zu dieser Ausgabe finden Sie unter Stapelüberlauf. Da es sich jedoch um eine große Sache handelt, werde ich mir den Quellcode des Open SDK ansehen. ..

Der Java 8-Quellcode kann wie folgt bezogen werden. https://download.java.net/openjdk/jdk8u40/ri/openjdk-8u40-src-b25-10_feb_2015.zip

Werfen wir einen Blick auf den folgenden Code, mit dem der Inhalt erstellt werden soll, der ausgegeben wird, wenn in diesem Code eine Druckkompilierung hinzugefügt wird.

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();
  }
}

Der Typstempel wird in der ersten Spalte ausgegeben.

Die zweite Spalte lautet compilation_id und method_attributes. cocmpilation_id ist eine 4-stellige Zahl. method_attributes ist eine Kombination von Flags und wird wie folgt angezeigt.

Brief Bedingungen
% Für die OCR-Methode.Im Fall von InvalidOSREntryBci, wenn MethodCompilation vom Aufzählungstyp definiert ist und InvocationEntryBci und InvalidOSREntryBci vorhanden sind.
s Im Falle einer Synchronisation
! exception_Wenn Sie einen Handler haben
b Im Falle einer Blockierung
n Für nativen Code

Die dritte Spalte zeigt die Kompilierungsstufe, wenn die gestufte Kompilierung aktiviert ist. Diese abgestufte Kompilierung kann mit den Optionen -XX: -Tiered Compilation oder + XX: -Tiered Compilation gesteuert werden. Für Java 8 ist die Standardeinstellung jedoch ON. Die Kompilierungsstufe ist wie folgt.

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

Mit anderen Worten, dasselbe C1 ist in drei Stufen unterteilt.

Der Methodenname wird in der 4. Spalte ausgegeben.

Schauen wir uns nun die Ausgabe der ersten -XX: + PrintCompilation an. Der Hauptteil der HelloWorld-Klasse ist nicht enthalten, sodass Sie sehen können, dass der dortige Code im Interpreter ausgeführt wird.

Können Sie den Inhalt nicht sehen, auch wenn er in Maschinencode kompiliert wurde?

Durch Kompilieren mit C1 und C2 erstellter Maschinencode wird nicht in eine Datei ausgegeben, sondern existiert nur im Speicher. Es sind mehrere Schritte erforderlich, um dies zu bestätigen.

Holen Sie sich zuerst hsdis-amd64.dll, das Reverse Assembler ermöglicht. Für Windows können Sie es herunterladen von: https://sourceforge.net/projects/fcml/files/

Führen Sie die DLL nach dem Herunterladen durch den Pfad.

Führen Sie dann den folgenden Befehl aus.

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

Im aktuellen Verzeichnis wird eine Protokolldatei erstellt, und Sie können sehen, welche Art von Maschinencode Sie erstellt haben.

Ausgabebeispiel


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
//Abkürzung

Es gibt viele Protokolldateien und es ist schwer zu sehen ...

Die Protokolldatei, die den Maschinencode ausgibt, enthält eine große Menge an Informationen, und es ist schwierig, die gewünschten Informationen zu finden. In diesem Fall möchten Sie möglicherweise in JitWatch surfen. https://github.com/AdoptOpenJDK/jitwatch/

image.png

image.png

Weitere Informationen zur Verwendung finden Sie im Folgenden.

** JIT-Zusammenstellung auf JIT Watch ansehen! ** **. https://www.sakatakoichi.com/entry/2014/12/04/202747

Wie interpretiert der Interpreter den Bytecode?

Inzwischen wissen wir, dass HelloWorld :: main auf dem Interpreter ausgeführt wird. Wo und wie werden dann die folgenden Befehle wie getstatic zur Rückgabe verarbeitet?

  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
}

Das Forschungsteam, das den Quellcode des OpenSDK suchte, um dieses Rätsel zu lösen, fand schließlich den relevanten Teil. Ich fand heraus, dass Anweisungen wie getstatic und ldc von runWithChecks () / run () in bytecodeInterpreter.cpp interpretiert und ausgeführt werden.

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
  //Abkürzung
#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);
      //Abkürzung
      }
    }
  }
}

Dies wird so lange wiederholt, bis alle Bytecodes in der Methode ausgeführt sind, und wird im CASE-Abschnitt gemäß dem Befehlscode verzweigt und ausgeführt. Zum Beispiel hat getstatic die folgende Implementierung.

getstatic


      CASE(_getfield):
      CASE(_getstatic):
        {
          u2 index;
          ConstantPoolCacheEntry* cache;
          //Hinweis: Aktueller Bytecode-Speicherort PC+Holen Sie sich 1-2 Byte Daten und speichern Sie diese im 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.
          //Hinweis: constatnt_Geben Sie den Index aus der Tabelle an und nehmen Sie einen Wert an.
          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) {
            //Hinweis: konstant_table[2]Holen Sie sich die Klasseninformationen von und setzen Sie sie in 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();
          //Hinweis: konstant_table[2]Feldinformationen des Feldes abrufen_Versatz einlegen
          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) {
              //Hinweis: konstant_table[2]Ruft das Feld der Klasse von ab und speichert das Ergebnis als Objekt auf dem Stapel.
              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);
            }
          }
          //Führen Sie den Befehl 3 Byte vor getstatic aus.
          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]
//Abkürzung
#define UPDATE_PC_AND_CONTINUE(opsize) {                        \
        pc += opsize; opcode = *pc;                             \
        DO_UPDATE_INSTRUCTION_COUNT(opcode);                    \
        DEBUGGER_SINGLE_STEP_NOTIFY();                          \
        DISPATCH(opcode);                                       \
    }

DISPACH wird ausgeführt, wenn der nächste Befehl ausgeführt wird. Dies ist eine goto-Anweisung, die die nächste Anweisung ausführt, indem sie zur Anweisungsbezeichnung springt.

Wie Sie sehen können, können Sie, wenn Sie den Unterbrecher aus diesem Code als Ausgangspunkt betrachten, eine Vorstellung davon bekommen, welche Art von Verarbeitung er ausführt. ~~ Zu diesem Zeitpunkt sind es über 30.000 Zeichen, daher ist es schwierig, alle analysierten Informationen zusammenzufügen ~~

Zusammenfassung

Dieses Mal ging ich zurück zum Anfang und sah, wie Hello World funktioniert.

Ich sage: "Sehen ist Glauben, Sehen ist Glauben", aber es tut mir leid, ich habe Hello World geleckt. Es war sehr nervig.

Referenz:

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

** Übersicht über die Java JIT-Kompilierung mit JIT Watch ** https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-MA15-Architect-newland.pdf

** JIT-Zusammenstellung auf JIT Watch ansehen! ** ** ** https://www.sakatakoichi.com/entry/2014/12/04/202747

** Ich habe versucht, [Java] nur mit einem Binäreditor auszugeben ** https://tech.recruit-mp.co.jp/etc/java_class_hello_world/

Recommended Posts

Zurück zum Anfang verspottete Java-Kisama Hello World-
Zurück zum Anfang, Erste Schritte mit Java ② Steueranweisungen, Schleifenanweisungen
Fordern Sie heraus, Javas Hello World unter Bezugnahme auf die Sprachspezifikationen zu erklären
Hallo Welt! Im Bootstrap Loader Bereich
Einführung in Ratpack (3) - Hallo Welt, detaillierte Erklärung
Zeigen Sie "Hello World" im Browser mit Java an
Zeigen Sie "Hello World" im Browser mit Java an
Versuchen Sie, Hallo Welt mit Frühling + Gradle anzuzeigen
Mit Rails + Docker einfach Hallo Welt anzuzeigen
Lesen Sie "Hallo Welt"
Java Hallo Welt
[Einführung] Zeigen Sie Android Studio Hello World auf dem Emulator an
Kotlin kann die Welt von der App ins Web bringen