Vorteile der Stack-basierten Architektur der JVM-Anweisung

8

Warum wurde die Java Virtual Machine ohne Register entworfen, um Zwischendatenwerte zu speichern? Stattdessen funktioniert alles auf Stack. Gibt es einen bestimmten Vorteil einer Stack-basierten Architektur anstelle einer Registrierung?

    
gpuguy 09.05.2012, 11:28
quelle

3 Antworten

5

Java wurde entwickelt, um von Grund auf tragbar zu sein. Aber wie können Sie Ihren Bytecode portabel halten, wenn es von bestimmten Registern auf der Plattform abhängt, auf der Sie ihn ausführen? Vor allem, wenn man bedenkt, dass ursprünglich beabsichtigt war, (auch) auf Set-Top-Boxen zu laufen, die eine ganz andere Prozessorarchitektur als Mainstream-PCs haben.

Es ist nur Runtime, dass die JVM tatsächlich die verfügbaren Register und andere Hardware-spezifische Sachen kennt. Dann kann (und wird) der JIT-Compiler für diese gegebenenfalls optimieren.

    
Péter Török 09.05.2012, 11:30
quelle
7

Ich muss den vorherigen Antworten respektvoll widersprechen.

Die Annahme der Existenz eines Ausdrucksstacks ist nicht besser als die Existenz von Registern. Typischerweise können Registermaschinen Stapelopcodes nicht direkt ausführen, und Stapelmaschinen können Registeropcodes nicht direkt ausführen. Sie müssen kartiert werden.

EJP sagt "Wenn der Host-Rechner einen Stack hat, wie alle anderen, gibt es nichts zu tun " . Dies ist eine falsche Aussage. Der Vorschlag, dass alle Maschinen Stacks haben, die Berechnungen ausführen können, zeigt Verwirrung darüber, was eine Stack-Maschine wirklich ist.

  1. Eine stack-basierte Maschine hat einen Befehlssatz mit impliziten Operanden auf der Oberseite eines "Ausdrucksstacks". Kein allgemeiner Stapel. Ein Stapel für allgemeine Zwecke wird von einer Stapelmaschine nicht erstellt. Sie können Werte speichern / wiederherstellen. Alle Plattformen haben das. Aber sie können keine Berechnungen ausführen.
  2. Eine registerbasierte Maschine führt typische Opcodes mit Operanden aus, die explizit virtuell sind Register, die im Befehlsstrom codiert sind. Diese VMs verfügen weiterhin über allgemeine Stapel und Opcodes zum Speichern und Wiederherstellen von Registern. Sie können Stapelverarbeitungsoperationen nicht auf einen Datenstapel abbilden. Die Operanden des Kernbefehlssatzes sind Register, Speicheradressen oder Unmittelbare (codiert innerhalb des Opcodes).

Es gibt also mehr als "nichts zu tun", um Opcodes von einer Maschinenarchitektur zu einer anderen zu mappen. Sofern Sie sich nicht auf einem Chip mit nativer Java-Opcode-Beschleunigung befinden, sollten Sie das nicht besser annehmen.

Ich behaupte nicht, dass eine Stapelmaschine eine gute Wahl für die Portabilität ist. Ich sage, dass es etwas zu tun gibt, um Befehle von Stapel zu Register oder von Register zu Stack abzubilden. Beides ist möglich.

Aber viel ist akademisch. In practice , im Jahr 2014, ist die vorherrschende Plattform registriert. Selbst stapelbasierte "Prozessoren" sind oft weiche Chips, die oben auf einem Registerchip implementiert sind. Sehen Sie sich die Java Card 3 Spezifikation an und schauen Sie sich die Implementierungen an und finden Sie heraus, welche Prozessoren tatsächlich verwendet werden. Ich überlasse das als Übung.

Wenn wir nicht eine VM für eine ganz bestimmte Plattform entwerfen (wie wir zum Beispiel eine JVM entworfen haben, die immer nur auf einem GreenSpaces-Prozessor läuft, was ich nicht sehe), nehme ich den Kontext an ist allgemeine Anwendung, eingebettete Anwendungen, Set-Top-Box, Firmware-Controller, Spielzeug, sogar Smartcards. Für alle diese, sehe ich 8-32-Bit-Prozessoren wie ARM, entweder verwendet oder verfügbar. Die Mainstream-JVM ist in C geschrieben. C ermöglicht es, einen Interpreter entweder mit virtuellen Stapel- oder virtuellen Register-Opcodes zu entwerfen. In den 90er Jahren gab es viele Diskussionen über Stack-basierte Java-Prozessoren, die JVM-Opcodes direkt unterstützen. Im Jahr 2014 sehen wir diese Implementierungen auf registerbasierter Hardware oder als ergänzende Anweisungen wie Jazelle (Java-Beschleunigung) auf dem ARM926EJ-S, wo es auch Register und Unterstützung für den ARM-Befehlssatz gibt.

Für allgemeine Anwendung werden Stack-basierte VMs in der Praxis sicherlich nicht auf Stacks abgebildet. Diese Maschinen verwenden alle Register-basierte primäre Anweisungen; und die Stapeloperationen dienen zum Speichern und Wiederherstellen von Registern oder Aufrufstapeln, ohne Berechnungen, Logik oder Verzweigungen durchzuführen. Die Stapel-VMs JIT zum nativen Befehlssatz der Maschine, unabhängig davon, ob es sich um einen Stapel- oder Registerbefehlssatz handelt. Seit 1980 wurde praktisch jede neue Prozessorarchitektur registriert, nach Hennessy And Patterson - "Computer Architecture A Quantitative Approach" . Das bedeutet Register-Register-, Register-Speicher- oder Register-Sofort-Befehlssätze. Sie können nicht 2 Werte auf dem Stapel auf einem Computer hinzufügen, der kein stapelbasiertes Add enthält. Auf x86 könnten Ihre stack-basierten Opcodes für eine ADD-Operation übersetzt werden von:

%Vor%

zum nativen Registercode:

%Vor%

Zweitens kann ein JIT unabhängig davon, ob der Opcode-Datenstrom ein Stack oder ein Register ist, diesen in nativen Code kompilieren. Die Wahl des VM-Modells ist also einfach ein Softwaremodell. Registermaschinen sind genauso virtuell. Sie codieren keine nativen Registerinformationen, die Register in den Opcodes sind virtuelle Symbole.

Als Java entwickelt wurde, ging es nun um kleine Opcodes und die Kompatibilität mit 8-Bit-Prozessoren. Stack-basierte Opcodes sind kleiner als Register-Opcodes. Es ergab also einen Sinn. Ich bin mir sicher, dass ich irgendwo gelesen habe, dass dies einer der Hauptgründe dafür war, dass James Gosling diesen für Oak (ursprünglicher Name für Java) wählte, abgesehen von der Einfachheit. Ich habe nur keine Hand. Insofern stimme ich Péter Török zu.

  • Es gibt beobachtbare Vorteile beim Stack-Opcode. Die Codestreams sind oft kleiner / dichter. In Bezug auf JVM und CLR können beobachtete Stack-basierte Bytecodes 15-20% kleiner sein als bei anderen Maschinen. Stack-Bytecodes können leicht in & lt; = 8 Bits codiert werden. (Forth-Maschinen können so wenig wie 20 oder so Opcodes haben). Der Opstream ist einfacher zu codieren / zu decodieren. Versuchen Sie, einen Assembler oder Disassembler für Java und dann für x86 zu schreiben.
  • Es gibt sichtbare Vorteile bei der Registrierung von Opcode. Weniger Opcodes zur Codierung eines Ausdrucks = bessere IPC = weniger High-Level-Verzweigung im Interpreter. Es kann auch praktisch jedem modernen Prozessor eine kleine Anzahl von Registern (8 bis 16) zuordnen. Die Verwendung von Registern erzielt einen viel höheren Durchsatz aufgrund einer besseren Cache-Lokalität der Referenz. Im Gegensatz dazu benötigen Stapelmaschinen viel Speicherbandbreite.

In VMs verwenden die Register-Bytecodes häufig einen großen virtuellen Registersatz, der größere Bytecodes erfordert. Auf der meisten realen Hardware werden Register typischerweise mit ungefähr 3 Bits (Intel × 86) bis 5 Bits (Sparc) codiert, so dass die Dichte von VM zu VM oder CPU zu CPU oder VM zu CPU variieren kann. Dalvik verwendet 4 bis 16 Bits, um Register darzustellen, während Parrot 8 Bits pro Register für alle Opcodes verwendete (mindestens das v2-Bytecodeformat, das ich verwendete). Dalvik erreicht eine bessere durchschnittliche Dichte. Basierend auf meiner Erfahrung mit dem Erstellen von ihnen, ist es schwierig, ein Allzweck-Register-Maschine innerhalb von 8-Bit-Bytecode zu bauen, es sei denn, Sie halten sich streng an Grundelemente und verwenden eine kleine Registerdatei. Dies mag nicht intuitiv erscheinen, aber typischerweise hat ein einzelner Opcode tatsächlich mehrere Kodierungen mit unterschiedlichen Registertypen.

Ein letzter Punkt: Viele der Soft-Core-Optimierungen gehen möglicherweise aus dem Fenster, wenn der JIT ins Bild kommt.

Die primäre Ausnahme, die ich mit dem Argument anstellen kann, dass Stack-Maschinen besser der Hardware zugeordnet sind, besteht darin, dass sie ignoriert, wo die JVM läuft und / oder wohin die Technologie geht. Außerhalb von Chuck Moore kenne ich niemanden, der Stack-basierte Prozessoren entwickelt (IGNITE und GreenSpaces GA144), und die meisten Neuentwicklungen sind Registermaschinen. Die Argumente für Stack-Maschinen sind überwiegend akademischer Natur. Für jedes 8-Bit-Stack-Prozessor-Argument kann ich Ihnen mehrere Registermaschinen (Hitachi H8 mit Registern, ARM926 mit Registern, Intel 8051) mit einem C-Compiler zeigen. Sie schreiben eher in Forth auf einem reinen Stack-Prozessor als in Java. Für eine neue Plattform ist es sinnvoller, mit einem billigen ARM-Prozessor zu arbeiten, wo es C-Compiler, volle JVM usw. gibt. Diese laufen Register-Befehlssätze ab.

Also, wenn das wahr ist? Ist es wichtig? Meiner Meinung nach ist meine Meinung "nicht so sehr wie die Leute denken". Denken Sie daran, Bytecode ist nur eine Zwischenrepräsentation. Der rein interpretierte Kern einer Maschine ist oft ein Sprungbrett, eine Brücke, ein ausfallsicherer Standardkern. Das endgültige Ziel ist die eventuelle Version 2 mit einem JITter zur nativen Leistung. Der Standpunkt von vielen, die es ein- oder zweimal gemacht haben, ist, dass es sinnvoll ist, den Kern so einfach wie möglich zu halten und zum JIT weiterzugehen, wo 90% der Optimierung dort investiert werden. Jeglicher verschwendete Aufwand, den angepassten Kern abzustimmen, könnte als vorzeitige Optimierung angesehen werden. Wenn Sie andererseits keinen JITter planen oder JIT aufgrund von Speicherbeschränkungen nicht praktikabel ist, optimieren Sie den virtuellen Kern oder implementieren Sie die VM auf einem Chip.

    
codenheim 19.06.2014 07:42
quelle
2
___ qstntxt ___

Warum wurde die Java Virtual Machine ohne Register entworfen, um Zwischendatenwerte zu speichern? Stattdessen funktioniert alles auf Stack. Gibt es einen bestimmten Vorteil einer Stack-basierten Architektur anstelle einer Registrierung?

    
___ qstnhdr ___ Vorteile der Stack-basierten Architektur der JVM-Anweisung ___ tag123java ___ Java (nicht zu verwechseln mit JavaScript oder JScript oder JS) ist eine universelle objektorientierte Programmiersprache, die für die Verwendung in Verbindung mit der Java Virtual Machine (JVM) entwickelt wurde. "Java-Plattform" ist der Name für ein Computersystem, auf dem Tools zum Entwickeln und Ausführen von Java-Programmen installiert sind. Verwenden Sie dieses Tag für Fragen, die sich auf die Java-Programmiersprache oder Java-Plattform-Tools beziehen. ___ answer10515179 ___

Java wurde entwickelt, um von Grund auf tragbar zu sein. Aber wie können Sie Ihren Bytecode portabel halten, wenn es von bestimmten Registern auf der Plattform abhängt, auf der Sie ihn ausführen? Vor allem, wenn man bedenkt, dass ursprünglich beabsichtigt war, (auch) auf Set-Top-Boxen zu laufen, die eine ganz andere Prozessorarchitektur als Mainstream-PCs haben.

Es ist nur Runtime, dass die JVM tatsächlich die verfügbaren Register und andere Hardware-spezifische Sachen kennt. Dann kann (und wird) der JIT-Compiler für diese gegebenenfalls optimieren.

    
___ antwort13113724 ___

Beim Entwerfen einer virtuellen Maschine ist es viel einfacher, einen Stapel als einen Satz von virtuellen Registern zu setzen. Wenn der Host-Rechner wie alle einen Stack hat, gibt es nichts zu tun, und wenn er Register hat, können Sie sie immer noch für andere Dinge verwenden: Provisorien usw. Wenn andererseits der Host-Rechner keine Register hat , nur ein Stapel, und Sie entwerfen Ihre VM um Register herum, haben Sie ein großes Implementierungsproblem in Ihren Händen, wie Sie den nativen Stapel verwenden müssen, auf Weisen, die seine Verwendung als der virtuelle Stapel stören werden.

    
___ answer24301283 ___

Ich muss den vorherigen Antworten respektvoll widersprechen.

Die Annahme der Existenz eines Ausdrucksstacks ist nicht besser als die Existenz von Registern. Typischerweise können Registermaschinen Stapelopcodes nicht direkt ausführen, und Stapelmaschinen können Registeropcodes nicht direkt ausführen. Sie müssen kartiert werden.

EJP sagt "Wenn der Host-Rechner einen Stack hat, wie alle anderen, gibt es nichts zu tun " . Dies ist eine falsche Aussage. Der Vorschlag, dass alle Maschinen Stacks haben, die Berechnungen ausführen können, zeigt Verwirrung darüber, was eine Stack-Maschine wirklich ist.

  1. Eine stack-basierte Maschine hat einen Befehlssatz mit impliziten Operanden auf der Oberseite eines "Ausdrucksstacks". Kein allgemeiner Stapel. Ein Stapel für allgemeine Zwecke wird von einer Stapelmaschine nicht erstellt. Sie können Werte speichern / wiederherstellen. Alle Plattformen haben das. Aber sie können keine Berechnungen ausführen.
  2. Eine registerbasierte Maschine führt typische Opcodes mit Operanden aus, die explizit virtuell sind Register, die im Befehlsstrom codiert sind. Diese VMs verfügen weiterhin über allgemeine Stapel und Opcodes zum Speichern und Wiederherstellen von Registern. Sie können Stapelverarbeitungsoperationen nicht auf einen Datenstapel abbilden. Die Operanden des Kernbefehlssatzes sind Register, Speicheradressen oder Unmittelbare (codiert innerhalb des Opcodes).

Es gibt also mehr als "nichts zu tun", um Opcodes von einer Maschinenarchitektur zu einer anderen zu mappen. Sofern Sie sich nicht auf einem Chip mit nativer Java-Opcode-Beschleunigung befinden, sollten Sie das nicht besser annehmen.

Ich behaupte nicht, dass eine Stapelmaschine eine gute Wahl für die Portabilität ist. Ich sage, dass es etwas zu tun gibt, um Befehle von Stapel zu Register oder von Register zu Stack abzubilden. Beides ist möglich.

Aber viel ist akademisch. In practice , im Jahr 2014, ist die vorherrschende Plattform registriert. Selbst stapelbasierte "Prozessoren" sind oft weiche Chips, die oben auf einem Registerchip implementiert sind. Sehen Sie sich die Java Card 3 Spezifikation an und schauen Sie sich die Implementierungen an und finden Sie heraus, welche Prozessoren tatsächlich verwendet werden. Ich überlasse das als Übung.

Wenn wir nicht eine VM für eine ganz bestimmte Plattform entwerfen (wie wir zum Beispiel eine JVM entworfen haben, die immer nur auf einem GreenSpaces-Prozessor läuft, was ich nicht sehe), nehme ich den Kontext an ist allgemeine Anwendung, eingebettete Anwendungen, Set-Top-Box, Firmware-Controller, Spielzeug, sogar Smartcards. Für alle diese, sehe ich 8-32-Bit-Prozessoren wie ARM, entweder verwendet oder verfügbar. Die Mainstream-JVM ist in C geschrieben. C ermöglicht es, einen Interpreter entweder mit virtuellen Stapel- oder virtuellen Register-Opcodes zu entwerfen. In den 90er Jahren gab es viele Diskussionen über Stack-basierte Java-Prozessoren, die JVM-Opcodes direkt unterstützen. Im Jahr 2014 sehen wir diese Implementierungen auf registerbasierter Hardware oder als ergänzende Anweisungen wie Jazelle (Java-Beschleunigung) auf dem ARM926EJ-S, wo es auch Register und Unterstützung für den ARM-Befehlssatz gibt.

Für allgemeine Anwendung werden Stack-basierte VMs in der Praxis sicherlich nicht auf Stacks abgebildet. Diese Maschinen verwenden alle Register-basierte primäre Anweisungen; und die Stapeloperationen dienen zum Speichern und Wiederherstellen von Registern oder Aufrufstapeln, ohne Berechnungen, Logik oder Verzweigungen durchzuführen. Die Stapel-VMs JIT zum nativen Befehlssatz der Maschine, unabhängig davon, ob es sich um einen Stapel- oder Registerbefehlssatz handelt. Seit 1980 wurde praktisch jede neue Prozessorarchitektur registriert, nach Hennessy And Patterson - "Computer Architecture A Quantitative Approach" . Das bedeutet Register-Register-, Register-Speicher- oder Register-Sofort-Befehlssätze. Sie können nicht 2 Werte auf dem Stapel auf einem Computer hinzufügen, der kein stapelbasiertes Add enthält. Auf x86 könnten Ihre stack-basierten Opcodes für eine ADD-Operation übersetzt werden von:

%Vor%

zum nativen Registercode:

%Vor%

Zweitens kann ein JIT unabhängig davon, ob der Opcode-Datenstrom ein Stack oder ein Register ist, diesen in nativen Code kompilieren. Die Wahl des VM-Modells ist also einfach ein Softwaremodell. Registermaschinen sind genauso virtuell. Sie codieren keine nativen Registerinformationen, die Register in den Opcodes sind virtuelle Symbole.

Als Java entwickelt wurde, ging es nun um kleine Opcodes und die Kompatibilität mit 8-Bit-Prozessoren. Stack-basierte Opcodes sind kleiner als Register-Opcodes. Es ergab also einen Sinn. Ich bin mir sicher, dass ich irgendwo gelesen habe, dass dies einer der Hauptgründe dafür war, dass James Gosling diesen für Oak (ursprünglicher Name für Java) wählte, abgesehen von der Einfachheit. Ich habe nur keine Hand. Insofern stimme ich Péter Török zu.

  • Es gibt beobachtbare Vorteile beim Stack-Opcode. Die Codestreams sind oft kleiner / dichter. In Bezug auf JVM und CLR können beobachtete Stack-basierte Bytecodes 15-20% kleiner sein als bei anderen Maschinen. Stack-Bytecodes können leicht in & lt; = 8 Bits codiert werden. (Forth-Maschinen können so wenig wie 20 oder so Opcodes haben). Der Opstream ist einfacher zu codieren / zu decodieren. Versuchen Sie, einen Assembler oder Disassembler für Java und dann für x86 zu schreiben.
  • Es gibt sichtbare Vorteile bei der Registrierung von Opcode. Weniger Opcodes zur Codierung eines Ausdrucks = bessere IPC = weniger High-Level-Verzweigung im Interpreter. Es kann auch praktisch jedem modernen Prozessor eine kleine Anzahl von Registern (8 bis 16) zuordnen. Die Verwendung von Registern erzielt einen viel höheren Durchsatz aufgrund einer besseren Cache-Lokalität der Referenz. Im Gegensatz dazu benötigen Stapelmaschinen viel Speicherbandbreite.

In VMs verwenden die Register-Bytecodes häufig einen großen virtuellen Registersatz, der größere Bytecodes erfordert. Auf der meisten realen Hardware werden Register typischerweise mit ungefähr 3 Bits (Intel × 86) bis 5 Bits (Sparc) codiert, so dass die Dichte von VM zu VM oder CPU zu CPU oder VM zu CPU variieren kann. Dalvik verwendet 4 bis 16 Bits, um Register darzustellen, während Parrot 8 Bits pro Register für alle Opcodes verwendete (mindestens das v2-Bytecodeformat, das ich verwendete). Dalvik erreicht eine bessere durchschnittliche Dichte. Basierend auf meiner Erfahrung mit dem Erstellen von ihnen, ist es schwierig, ein Allzweck-Register-Maschine innerhalb von 8-Bit-Bytecode zu bauen, es sei denn, Sie halten sich streng an Grundelemente und verwenden eine kleine Registerdatei. Dies mag nicht intuitiv erscheinen, aber typischerweise hat ein einzelner Opcode tatsächlich mehrere Kodierungen mit unterschiedlichen Registertypen.

Ein letzter Punkt: Viele der Soft-Core-Optimierungen gehen möglicherweise aus dem Fenster, wenn der JIT ins Bild kommt.

Die primäre Ausnahme, die ich mit dem Argument anstellen kann, dass Stack-Maschinen besser der Hardware zugeordnet sind, besteht darin, dass sie ignoriert, wo die JVM läuft und / oder wohin die Technologie geht. Außerhalb von Chuck Moore kenne ich niemanden, der Stack-basierte Prozessoren entwickelt (IGNITE und GreenSpaces GA144), und die meisten Neuentwicklungen sind Registermaschinen. Die Argumente für Stack-Maschinen sind überwiegend akademischer Natur. Für jedes 8-Bit-Stack-Prozessor-Argument kann ich Ihnen mehrere Registermaschinen (Hitachi H8 mit Registern, ARM926 mit Registern, Intel 8051) mit einem C-Compiler zeigen. Sie schreiben eher in Forth auf einem reinen Stack-Prozessor als in Java. Für eine neue Plattform ist es sinnvoller, mit einem billigen ARM-Prozessor zu arbeiten, wo es C-Compiler, volle JVM usw. gibt. Diese laufen Register-Befehlssätze ab.

Also, wenn das wahr ist? Ist es wichtig? Meiner Meinung nach ist meine Meinung "nicht so sehr wie die Leute denken". Denken Sie daran, Bytecode ist nur eine Zwischenrepräsentation. Der rein interpretierte Kern einer Maschine ist oft ein Sprungbrett, eine Brücke, ein ausfallsicherer Standardkern. Das endgültige Ziel ist die eventuelle Version 2 mit einem JITter zur nativen Leistung. Der Standpunkt von vielen, die es ein- oder zweimal gemacht haben, ist, dass es sinnvoll ist, den Kern so einfach wie möglich zu halten und zum JIT weiterzugehen, wo 90% der Optimierung dort investiert werden. Jeglicher verschwendete Aufwand, den angepassten Kern abzustimmen, könnte als vorzeitige Optimierung angesehen werden. Wenn Sie andererseits keinen JITter planen oder JIT aufgrund von Speicherbeschränkungen nicht praktikabel ist, optimieren Sie den virtuellen Kern oder implementieren Sie die VM auf einem Chip.

    
___
EJP 28.10.2012 22:37
quelle

Tags und Links