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."
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 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! !! ** **.
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.
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
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
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
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.
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_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.
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.
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.
Durch Doppelklicken auf eine Adresse werden die Strukturinformationen ab dieser Adresse angezeigt.
Wählen Sie Motorola aus, wenn Sie die Klassendatei analysieren.
Lassen Sie uns ClassFile von Anfang an analysieren.
"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.
constant_pool[1] 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] 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]
Da das erste Byte 0x08 ist, lautet der Eintrag für constant_pool CONSTANT_String. Der Index wird 15 sein.
constant_pool[4]
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]
Da das erste Byte 0x07 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Class. Der Index wird 18 sein.
constant_pool[6]
Da das erste Byte 0x07 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Class. Der Index wird 19 sein.
constant_pool[7]
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]
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]
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]
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]
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]
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]
Da das erste Byte 0x07 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Class. Der Index wird 20 sein.
constant_pool[14]
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]
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]
Da das erste Byte 0x07 ist, lautet der Eintrag für diesen Konstantenpool CONSTANT_Class. Der Index wird 23 sein.
constant_pool[17]
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]
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]
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]
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]
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] 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]
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]
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]
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".
Der constante_pool kann wie folgt zusammengefasst werden.
No | Struktur | Inhalt |
---|---|---|
1 | CONSTANT_Methodref | class_Indexist6:HelloWorld、name_and_type_Indexist12: |
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" |
-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 [].
Da fields_count 0 ist, müssen keine Dateien folgen.
methods_count~methods[]
Da method_count 0x0002 ist, gibt es zwei Fälle, gefolgt von der method_info-Struktur.
method_info[0]
-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]
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", "
0xb1 wird zu return.
Sowohl exception_table_length als auch attribute_count sind 0.
method_info[1]
-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]
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.
Da attribute_count 0 ist, gibt es keine Attributdaten.
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.
Lassen Sie uns etwas tiefer in die Funktionsweise dieser HelloWorld.class eintauchen.
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).
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 ... **
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.
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} 'hashCode' '()I' in 'java/lang/String'
# [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
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/
Weitere Informationen zur Verwendung finden Sie im Folgenden.
** JIT-Zusammenstellung auf JIT Watch ansehen! ** **. https://www.sakatakoichi.com/entry/2014/12/04/202747
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 ~~
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.
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]
Recommended Posts