-
HINTERGRUND
DER ERFINDUNG
-
Die
vorliegende Erfindung betrifft Implementierungen eines Ausführungsstapels.
Insbesondere betrifft die Erfindung das Implementieren eines Ausführungsstapels
zur Verwendung mit Funktionen, die in mehreren Programmiersprachen
geschrieben sein können
wie beispielsweise einem Ausführungsstapel für eine Java-Virtual-Machine.
-
Die
Java-Programmiersprache ist eine objektorientierte Hoch-Programmiersprache,
die von Sun Microsystems aus Palo Alto, Kalifornien, entwickelt
worden ist und ist dazu entworfen, portabel genug zu sein, um von
einem weiten Bereich von Computern ausgeführt zu werden, die von kleinen
Personalcomputern bis zu Supercomputern reichen. Computerprogramme,
die in Java (oder anderen Sprachen) geschrieben sind, können in
Virtual-Machine-Anweisungen kompiliert werden für eine Ausführung durch eine Java-Virtual-Machine.
Im Allgemeinen ist die Java-Virtual-Machine ein Interpreter, der Virtual-Machine-Anweisungen
dekodiert und ausführt.
-
Die
Virtual-Machine-Anweisungen für
die Java-Virtual-Machine sind Byte-Codes, was bedeutet, dass sie
eines oder mehrere Bytes einschließen. Die Byte-Codes sind in
einem speziellen Dateiformat, der "Klassen-Datei" (Fachbegriff: Class File), die Byte-Codes
für Verfahren
einer Klasse einschließen. Zusätzlich zu
den Byte-Codes für
Verfahren einer Klasse schließen
die Klassen-Dateien eine Symboltabelle ein sowie andere Zusatzinformationen.
-
Ein
als Java-Byte-Codes in einer oder mehreren Klassen-Dateien umgesetztes
Computerprogramm ist plattformunabhängig. Das Computerprogramm
kann unmodifiziert auf vielen Computern ausgeführt werden, die imstande sind,
eine Implementierung der Java-Virtual-Machine ablaufen zu lassen. Die
Java-Virtual-Machine
ist ein Software-Emulator eines "generischen" Computers, was ein
Hauptfaktor dabei ist, es Computerprogrammen für Java-Virtual-Machines zu
ermöglichen,
plattformunabhängig
zu sein.
-
Die
Java-Virtual-Machine wird allgemein als ein Software-Interpreter implementiert.
Konventionelle Interpreter dekodieren die Virtual-Machine-Anweisungen
eines interpretierten Programms einer Anweisung auf einmal während des
Ausführens
und führen
sie aus. Compiler dekodieren demgegenüber Quellencode bzw. Source-Code
in eigene Maschinenanweisungen bzw. Native-Maschinen-Anweisungen
vor dem Ausführen,
so dass das Dekodieren nicht während
des Ausführens
ausgeführt
werden kann. Weil konventionelle Interpreter jede Anweisung jedes
Mal, wenn die Anweisung auftritt, dekodieren bevor sie ausgeführt wird,
wird ein Ausführen
von interpretierten Programmen üblicherweise
viel langsamer sein als das von kompilierten Programmen, weil die
Native-Maschinen-Anweisungen der kompilierten Programme auf der
Native-Machine oder dem Computersystem ohne das Erfordernis des
Dekodierens ausgeführt
werden können.
-
Die
Java-Virtual-Machine wird typischerweise in einer Programmiersprache
geschrieben, die von der Java-Programmiersprache
abweicht (z.B. der C++-Programmiersprache).
Demnach kann das Ausführen
eines Java-Programms
das Ausführen von
Funktionen einbeziehen, die in mehreren Programmiersprachen geschrieben
sind. Zudem kann der Byte-Code selbst Funktionen aufrufen (z.B.
Systemfunktionen oder Eingabe/Ausgabe), die nicht in der Java-Programmiersprache
geschrieben sind. Es ist demnach für ein Java-Programm, das ausgeführt wird, üblich, das
Ausführen
von Funktionen zu verursachen, die in mehreren Programmiersprachen
geschrieben sind. Es wird wünschenswert
sein, einen Ausführungsstapel
(Executing Stack) zu haben, der Funktionen, die in mehreren Programmiersprachen geschrieben sind,
speichern kann. Zudem würde
es vorteilhaft sein, Ausnahmen bzw. Exceptions, die durch diese
Funktionen verbreitet werden, zuzulassen mit dem Umwandeln der Ausnahme
in das geeignete Format, falls erforderlich. Die Java-Virtual-Machine ermöglicht es
Java-Programmen, dynamisch native Verfahren zu laden und auszuführen, wobei ein
natives Verfahren (Native Method) in einer anderen Sprache als der
Java-Programmiersprache implementiert ist. Native Verfahren erfordern
häufig
Ressourcen zum Ausführen,
so dass Ressourcen jedes Mal zugewiesen (Allocate) und freigegeben
(Deallocate) werden wenn ein natives Verfahren aufgerufen wird.
Jedoch kann Ressourcen-Zuweisung und -Freigabe sehr zeitaufwändig sein
und die kontinuierliche Zuweisung und Freigabe von Ressourcen kann
zu einer signifikanten Verschlechterung der Effizienz des interpretierten
Programms führen.
Daher würde
es wünschenswert
sein, effizientere Techniken der Ressourcen-Zuordnung und -Freigabe bzw. Deallocation bereitzustellen.
-
Chen-Hsueh
et al, "Java Bytecode
to Native Code Translation: The Cavveine Prototype and Preliminary
Results" Proceedings
of the 29th Annual IEEE/ACM International
Symposium on Microachritecture (MICRO-29), Paris, Frankreich, IEEE
Computer Society Press, Los Alamitos, cA, US, 2.–4. Dezember 1996, Seiten 90–97, ISBN:
0-8186-76413-8, beschreibt einen optimierten Native-Code-Übersetzer
zum Ausführen
von Java-Bytecode-Programmen.
Dieses Papier bezieht sich darauf, wie Programmsourcecode wie z.B.
Java-Bytecode analysiert und übersetzt
wird in Native-Code, so dass wenn das Programm ausgeführt wird,
es effizienter läuft
als wenn es als pure Java-Bytecodes interpretiert worden wäre. Die
offenbarten Übersetzerverfahren schließen die
Verwendung von Ausführungsstapeln (z.B.
Abbildungsstapel (mapping stacks) zum virtuellen Registrieren von
Dateien und Analysestapeln (analysing stacks)) als Teil des Optimierungsprozesses
ein. Jedoch beschreibt dieses Papier keine Technik in Bezug auf
Ausführungsstapel,
die Daten für Funktionen
enthalten, die in unterschiedlichen Programmiersprachen geschrieben
sind. Auch richtetet es sich nicht auf das Zulassen von Ausnahmen,
die zu verbreiten sind um Teile von Stapeln, die Daten für solche
Funktionen enthalten.
-
US-A-5530870
beschreibt ein Verfahren zum effizienten Übertragen von Steuerung zwischen Funktionen.
Ein Standard CALL und RETURN-Statement in einer Funktion wird ersetzt
durch ein PASS-CONTROL-Statement. Dies ermöglicht es einer ersten Funktion,
wirksam zu enden wenn sie eine zweite Funktion aufruft statt auf
die zweite Funktion zu warten, um zu enden, bevor die Steuerung
zurückgegeben
wird zu der ersten Funktion, die dann endet. Das Verfahren wird
durch Speichern der Lokal- und Temporär-Variablen bewirkt, die einer
aufgerufenen Funktion in dem Rahmen der Funktion zugewiesen sind,
die sie aufruft. Die Funktionen werden in derselben Programmiersprache
geschrieben. Ferner werden keine Techniken erwähnt, die das verlaufen von Ausnahmen
um Teile eines Ausführungsstapels
ermöglichen
in Entsprechung zu Funktionen, die in unterschiedlichen Programmiersprachen
geschrieben sind.
-
Demgemäss gibt
es einen Bedarf nach Techniken zum Implementieren eines Ausführungsstapels,
der imstande ist, Funktionsaktivierungen für Funktionen zu halten, die
in unterschiedlichen Programmiersprachen implementiert sind, und
insbesondere zu ermöglichen,
dass Ausnahmen durch diese Funktionen und die entsprechenden Aktivierungen
fortgepflanzt werden. Zusätzlich
gibt es einen Bedarf zum Bereitstellen von Interpretern, die effizienter
sind in der Art, in der Ressourcen zugeordnet und freigegeben werden,
so dass die Ausführungsgeschwindigkeit
zunehmen kann.
-
Demgemäss stellt
in einem Aspekt die vorliegende Erfindung ein Verfahren zum Implementieren eines
Ausführungsstapels
bereit, der Rahmen für
in einer Vielzahl von Programmiersprachen geschriebene Funktionen
speichert, wobei das Verfahren umfasst: Speichern eines ersten Rahmens
des Ausführungsstapels
für eine
erste Funktion, wobei die erste Funktion in einer ersten Programmiersprache
geschrieben ist; und ansprechend auf die erste Funktion, Aufrufen
einer zweiten, in einer zweiten Programmiersprache geschriebenen
Funktion, Speichern eines Datenblocks auf dem Ausführungsstapel
vor dem Speichern eines zweiten Rahmens für die zweite Funktion auf dem
Ausführungsstapel,
wobei der Datenblock mindestens einen Zeiger (Pointer) zu einem
vorhergehenden Rahmen für
eine vorhergehende Funktion einschließt, die in der zweiten Programmiersprache
geschrieben ist, welcher vor dem ersten Rahmen auf dem Ausführungsstapel
gespeichert worden war.
-
Im
Allgemeinen stellen Ausführungsformen der
vorliegenden Erfindung innovative Systeme und Verfahren bereit zum
Implementieren eines Ausführungsstapels,
der Rahmen für
in mehreren Programmiersprachen geschriebene Funktionen speichert. Rahmen
für in
mehreren Programmiersprachen geschriebene Anweisungen werden auf
demselben Ausführungsstapel
unter Verwendung eines Eingabe- bzw. Entry-Rahmens (oder Datenblocks) gespeichert,
der Zeiger bzw. Pointer zu einem vorangehenden Rahmen auf dem Ausführungsstapel
speichert für
eine Funktion, die in derselben Programmiersprache gespeichert ist.
Der Entry-Rahmen
ermöglicht es,
dass der Ausführungsstapel "um" Rahmen für Funktionen,
die in anderen Programmiersprachen geschrieben sind herum durchlaufen
wird und dass Ausnahmen durch den Ausführungsstapel fortgepflanzt
werden können
für das
Handhaben durch den geeigneten Ausnahmen-Handhaber (Exception Handler),
selbst wenn die Funktionen in unterschiedlichen Programmiersprachen
geschrieben sind und das Format der Ausnahmen unterschiedlich ist.
Zudem können
Ressourcen auf das Eingeben einer Funktion, die in einer Programmiersprache
(z.B. der Java-Programmiersprache) geschrieben ist, zugewiesen werden,
so dass die Ressourcen für
irgendwelche nachfolgenden Funktionen (z.B. native) in anderen Programmiersprachen
verfügbar
sind. Die Ressourcen können
dann dereinst, wenn die aufrufende Funktion beendet wird, freigegeben
werden bzw. deallocated, hierdurch die Effizienz der Ressourcen-Zuordnung
und Freigabe verbessernd.
-
Einige
Ausführungsform
der Erfindung werden nachstehend beschrieben.
-
Mindestens
ein Zeiger kann ein Stapelzeiger sein und ein Rahmenzeiger. Darauffolgend,
wenn eine dritte, in der ersten Programmiersprache geschriebene
Funktion aufgerufen wird, wird der Datenblock auf dem Ausführungsstapel
vor einem dritten Rahmen für
die dritte Funktion gespeichert. Der Datenblock speichert mindestens
einen Zeiger zu dem ersten Rahmen auf dem Ausführungsstapel, der im Lokalspeicher
gespeichert worden ist, so dass der Datenblock einen Weg um den
zweiten Rahmen auf dem Ausführungsstapel
bereitstellt. In bevorzugten Ausführungsformen ist die erste
Programmiersprache die Java-Programmiersprache.
-
Andere
Merkmale und Vorteile der Erfindung werden auf die Betrachtung der
folgenden detaillierten Beschreibung im Zusammenhang mit den beiliegenden
Zeichnungen leicht ersichtlich.
-
KURZBESCHREIBUNG
DER ZEICHNUNGEN
-
Es
zeigt:
-
1 ein
Beispiel eines Computersystems, das zum Ausführen der Software einer Ausführungsform
der Erfindung verwendet werden kann;
-
2 ein
Systemblockdiagramm des Computersystems der 1;
-
3 wie
ein Java-Quellencodeprogramm ausgeführt wird;
-
4 die
Komponenten einer Implementierung eines Java-Laufzeitsystems bzw. Java-Runtime-Systems;
-
5 Rahmen
für Funktionen,
die auf einem Ausführungsstapel
gespeichert sind;
-
6 einen
Prozess der Implementierung eines Ausführungsstapels auf hohem Level,
der Rahmen für
Funktionen, die in mehreren Programmiersprachen geschrieben sind,
speichert;
-
7 einen
Ausführungsstapel,
der Rahmen für
in der Java-Programmiersprache und einer anderen Programmiersprache
geschriebene Funktionen speichert;
-
8 einen
Prozess zum Eintreten von externem Code in Java-Code;
-
9 einen
Prozess zum Eintreten in Java-Code von Extern-Code;
-
10 einen
Prozess des Verlassens von Java-Code nach Extern-Code;
-
11 einen
Prozess des Verlassens von Extern-Code nach Java-Code;
-
12 einen
Ausführungsstapel
mit einer Ausnahmeschirmung bzw. einem Exception-Schield zwischen
einem C++-Rahmen
und einem Java-Rahmen, und einer Ausnahmenschirmungsaufhebung bzw.
einem Exception-Unshield
zwischen dem Java-Rahmen und einem anderen C++-Rahmen;
-
13A und 13B einen
Prozess einer Ausnahme, die Extern-Code nach Java-Code verlässt;
-
14A und 14B einen
Prozess einer Ausnahme, die Java-Code nach Extern-Code verlässt;
-
15 Informationen,
die in dem Thread-Lokalspeicher gespeichert werden können, um
einen Ausführungsstapel
zu implementieren, der Rahmen für
in mehreren Programmiersprachen geschriebene Funktionen implementiert.
-
DETAILLIERTE
BESCHREIBUNG DER BEVORZUGTEN AUSFÜHRUNGSFORMEN
-
Definitionen
-
- Funktion – eine
Software-Routine (auch Subroutine, Prozedur, Member-Funktion und
Verfahren (Method) genannt).
- Rahmen (oder Aktivierungsrahmen, Aktivierungsaufzeichnung) – eine Aufzeichnung,
die auf einem Ausführungsstapel
gespeichert wird für
eine Funktion zum Speichern von Information für das Ausführen der Funktion, wobei solche
Funktion Zustandsvariablen, Lokalvariablen und einen Operanden-Stapel
einschließen
kann.
- Ausführungsstapel – Ein Stapel,
der während
des Ausführens
des Programms zum Speichern von Rahmen für Funktionen in ihrer sequentiellen
Aufrufreihenfolge verwendet wird. Wenn eine Funktion ("Callee") aufgerufen wird
(Call), wird ein Rahmen für die
Funktion durch einen Pusch-Vorgang in den Ausführungsstapel geschoben. Darauffolgend,
wenn die Funktion endet, wird dieser Rahmen durch eine Popp-Off-Funktion
aus dem Stapel genommen und die Funktion "Caller" für
den Rahmen im Ausführungsstapel
oben nimmt wieder das Ausführen
auf.
- Operanden-Stapel – Ein
Stapel, der zum Speichern von Operanden zur Verwendung durch Maschinenanweisungen
während
des Ausführens
verwendet wird.
- Extern-Code – Computercode,
der in einer Programmiersprache geschrieben ist, die von einer spezifischen
Programmiersprache (z.B. der Java-Programmiersprache) abweicht.
Beispielsweise kann die Java-Virtual-Machine in C++-Programmiersprache
geschrieben werden und die Java-Virtual-Machine könnte als
externer Code angesehen werden in Bezug auf den Java-Code eines
Programms, das interpretiert wird. Extern-Code schließt Native-Verfahren ein.
Native-Verfahren-Funktionen,
die in einer Programmiersprache geschrieben sind, die von der Java-Programmiersprache
abweicht. Native-Verfahren können
durch ein Java-Programm aufgerufen werden, das sie veranlasst, dynamisch
geladen und ausgeführt
zu werden. Zusätzlich
können
Native-Verfahren Funktionen aufrufen, die in der Java-Programmiersprache
geschrieben sind.
-
Übersicht
-
In
der folgenden Beschreibung wird die vorliegende Erfindung unter
Bezugnahme auf eine bevorzugte Ausführungsform beschrieben, die
einen Ausführungsstapel
für eine
Java-Virtual-Machine
implementiert, der ein Java-Programm (z.B. Bytecodes) ausführt. Speziell
werden Beispiele beschrieben, in denen die Java-Virtual-Machine
in der C++-Programmiersprache
geschrieben ist. Jedoch ist die Erfindung nicht auf irgendwelche
spezielle Sprache, Computerarchitektur oder spezifische Implementierung beschränkt. Daher
dient die folgende Beschreibung der Ausführungsformen nur zum Zwecke
der Erläuterung
und nicht zur Einschränkung.
-
1 zeigt
ein Beispiel eines Computersystems, das zum Ausführen der Software einer Ausführungsform
der Erfindung verwendet werden kann. 1 zeigt
ein Computersystem 1, das eine Anzeige 3, einen
Bildschirm 5, ein Gehäuse 7,
eine Tastatur 9 und eine Maus 11 einschließt. Die
Maus 11 kann einen oder mehrere Tasten haben zum Interagieren
mit einer graphischen Benutzerschnittstelle. Das Gehäuse 7 nimmt
ein CD-ROM-Laufwerk auf, einen Systemspeicher und ein Festplattenlaufwerk
(siehe 2), das verwendet werden kann zum Speichern und
Wiederbeschaffen von Softwareprogrammen, in denen Computercode enthalten
ist, der die Erfindung implementiert, Daten zur Verwendung mit der
Erfindung und Ähnliches.
Obwohl die CD-ROM 15 als ein beispielhaftes Computer-lesbares
Speichermedium gezeigt ist, können
auch andere Computer-lesbare Speichermedien einschließlich Floppydisk,
Band, Flash-Speicher, Systemspeicher und Festplatte verwendet werden.
Zudem kann ein in einer Trägerwelle realisiertes
Datensignal (z.B. in einem Netz einschließlich dem Internet) das Computer-lesbare Speichermedium
sein.
-
2 zeigt
ein Systemblockdiagramm des Computersystems 1, das zum
Ausführen
der Software einer Ausführungsform
der Erfindung verwendet wird. Wie in 1 schließt das Computersystem 1 einen
Monitor 3 und eine Tastatur 9 und Maus 11 ein. Das
Computersystem 1 schließt ferner Subsysteme oder Untersysteme
ein wie einen Zentralprozessor 51, einen Systemspeicher 53,
eine Festplatte 55 (z.B. ein Festplattenlaufwerk), einen
entfernbaren Speicher 57 (z.B. ein CD-ROM-Laufwerk), einen
Anzeigeadapter 59, eine Audiokarte 61, Lautsprecher 63 und
eine Netzschnittstelle 65. Andere Computersysteme, die
geeignet sind zur Verwendung mit der Erfindung, können zusätzliche
oder weniger Subsysteme einschließen. Beispielsweise könnte ein
anderes Computersystem mehr als einen Prozessor 51 einschließen (z.B.
ein Mehrprozessorsystem), oder einen Cash- bzw. einen schnellen
Zwischenspeicher.
-
Die
Systembus-Architektur des Computersystems 1 ist durch Pfeile 67 dargestellt.
Jedoch sind diese Pfeile nur erläuternd
in Bezug auf irgendein Zwischenverbindungsschema, das zum Verknüpfen der
Subsysteme dient. Beispielsweise könnte ein Lokalbus verwendet
werden zum Verbinden des Zentralprozessors mit dem Systemspeicher
und dem Anzeigeadapter. Das in 2 gezeigte
Computersystem 1 ist allerdings nur ein Beispiel eines
Computersystems, das geeignet ist zur Verwendung mit der Erfindung.
Andere Computer-Architekturen mit unterschiedlichen Konfigurationen
der Subsysteme können
ebenfalls verwendet werden.
-
Typischerweise
werden in Java-Programmiersprache geschriebene Computerprogramme
in Bytecodes oder Java-Virtual-Machine- Anweisungen kompiliert, die dann durch
eine Java-Virtual-Machine ausgeführt werden.
Die Bytecodes werden in Klassen-Dateien
(Class Files) gespeichert, die in die Java-Virtual-Machine eingegeben
werden für
die Interpretation. 3 zeigt eine Verarbeitung eines
einfachen Stücks
von Java-Source-Code
während
des Ausführens
durch einen Interpreter, die Java-Virtual-Machine.
-
Java-Source-Code 101 schließt das klassische "Hello World"-Programm ein, das in Java geschrieben
ist. Der Source-Code wird dann in einen Bytecode-Compiler 103 eingegeben,
der den Source-Code in Bytecodes kompiliert. Die Bytecodes sind Virtual-Machine-Anweisungen,
da sie durch einen Software-emulierten
Computer ausgeführt
werden. Typischerweise sind Virtual-Machine-Anweisungen generisch
(d.h., nicht für
irgendeinen speziellen Mikroprozessor oder eine Computer-Architektur ausersehen),
aber dies ist nicht erforderlich. Der Bytecode-Compiler gibt eine
Java-Klassendatei 105 aus, die die Bytecodes für das Java-Programm
enthält.
-
Die
Java-Klassendatei wird in eine Java-Virtual-Machine 107 eingegeben.
Die Java-Virtual-Machine schließt
einen Interpreter ein, der die Bytecodes in der Java-Klassendatei
ausführt.
Die Java-Virtual-Machine kann als ein Interpreter betrachtet werden,
aber wird gewöhnlich
als eine Virtual-Machine
betrachtet, da sie einen Mikroprozessor oder eine Computer-Architektur
in Software emuliert (z.B. einen Mikroprozessor oder eine Computer-Architektur, die
nicht in Hardware existieren).
-
4 zeigt
die Komponenten einer Implementierung eines Java-Laufzeitsystems
bzw. Java-Runtime-Systems. Die Implementierungen der Java-Virtual-Machine
sind als Java-Runtime-Systeme
bekannt. Ein Java-Runtime-System 201 kann eine Eingabe
von Java-Klassendateien 203 empfangen, eingebaute Standard-Java-Klassen 205 und Native-Verfahren 207,
um ein Java-Programm auszuführen.
Die eingebauten Standard-Java-Klassen (standard built-in Java classes)
können Klassen
für Objekte
sein wie Threads, Strings und Ähnliches.
Die Native-Verfahren können
in von Java abweichenden Programmiersprachen geschrieben sein. Die
Native-Verfahren werden typischerweise in dynamischen Verknüpfungs-Bibliotheken (DLLs
bzw. dynamic link libraries) gespeichert oder in geteilten Bibliotheken.
-
Das
Java-Runtime-System kann auch eine Schnittstelle mit einem Betriebssystem 209 bilden. Beispielsweise
können
Ein-/Ausgabe-Funktionen einschließlich dem
Bereitstellen des Java-Runtime-Systems mit Schnittstellen zu Java-Klassendateien 203,
Standard-built-in-Java-Klassen 205 und Native-Verfahren 207 durch
das Betriebssystem gehandhabt werden.
-
Ein
dynamischer Klassenlader und Verifizierer 311 lädt Java-Klassendateien 203 und
Standard-built-in-Java-Klassen 205 über das Betriebssystem 209 in
einen Speicher 213. Zusätzlich
kann der dynamische Klassenlader und Verifizierer die Korrektheit
der Bytecodes in den Java-Klassendateien verifizieren und irgendwelche
erfassten Fehler melden.
-
Ein
Native-Verfahren-Linker bzw. Verknüpfer 215 verknüpft Native-Verfahren 207 über das
Betriebssystem 209 in das Java-Runtime-System und speichert die Native-Verfahren
in Speicher 213. Wie dargestellt, kann der Speicher 213 einen
Klassen- und Verfahrensbereich
für die
Java-Klassen und einen Native-Verfahrensbereich
für Native-Verfahren einschließen. Der
Klassen- und Verfahrensbereich im Speicher 213 kann in
einem "Garbage Collected Heap" gespeichert sein.
Wenn neue Objekte erstellt werden, werden sie in dem "Garbage Collected
Heap" gespeichert.
Das Java-Runtime-System und nicht die Anwendung ist zuständig für das Neubeanspruchen
von Speicher in dem "Garbage
Collected Heap",
wenn Raum nicht länger
verwendet wird.
-
Im
Herzen des Java-Runtime-Systems, das in 4 gezeigt
ist, ist eine Ausführungs-Engine 217. Die
Ausführungs-Engine führt die
Anweisungen aus, die im Speicher 213 gespeichert sind,
und kann in Software, Hardware oder einer Kombination davon implementiert
sein. Die Ausführungs-Engine
unterstützt
objektorientierte Anwendungen und konzeptionell gibt es mehrere
Ausführungs-Engines,
die nebeneinander ablaufen, einen für jeden Java-Thread. Die Ausführungs-Engine
kann auch Support-Code 221 verwenden. Der Support-Code
kann funktional in Bezug auf Ausnahmen, Threads, Sicherheit und Ähnliches
bereitgestellt werden.
-
Wenn
ein Java-Programm ausgeführt
wird, werden Funktionen innerhalb jedes Thread aufeinanderfolgend
aufgerufen (call). Für
jeden Thread gibt es einen Ausführungs-Stapel,
der Rahmen für
jede der Funktionen speichert, die nicht vollständig ausgeführt sind. Ein Rahmen speichert
Information für
das Ausführen
der Funktion, solche Information kann Zustandsvariablen, Lokalvariablen
und einen Operandenstapel einschließen. Wenn eine Funktion aufgerufen
wird, wird ein Rahmen der Funktion unter Anwendung eines Push-Vorgangs
auf den Ausführungsstapel
geschoben. Wenn die Funktion endet, wird der Rahmen der Funktion
durch Popp-Off von dem Ausführungsstapel
genommen. Demgemäss
ist nur die Funktion in Entsprechung zu dem obersten Rahmen des
Ausführungsstapels
aktiv, die Funktionen, die Rahmen unterhalb des obersten vom Ausführungsstapel
entsprechen, haben ihre Ausführung ausgesetzt
bis die Funktion, die sie aufgerufen haben, zurückkehrt (d.h., endet).
-
5 zeigt
Rahmen für
Funktionen, die auf einem Ausführungsstapel
gespeichert sind. ein Ausführungsstapel 301 mit
einem Rahmen 303 oben auf dem Ausführungsstapel und Rahmen 305 und 307 jeweils
unterhalb des Rahmens 303, ist gezeigt. Ein Stapelzeiger
(Stack Pointer) SP zeigt auf die Spitze des Ausführungsstapels während ein
Rahmenzeiger (Frame Pointer) FP auf einen Rahmenzeiger im Rahmen
an der Spitze des Ausführungsstapels 301 zeigt.
-
Jeder
Rahmen wird als Zustandsvariablen, Lokalvariablen und einen Operandenstapel
für die dem
Rahmen entsprechende Funktion einschließend dargestellt. Zudem sollte
der letzte Punkt in dem Rahmen in einem Rahmenzeiger gespeichert
werden, der auf den Rahmenzeiger in dem Rahmen unterhalb des derzeitigen
Rahmens auf dem Ausführungsstapel
zeigt, wie durch Pfeile 309 und 311 gezeigt.
-
Wenn
eine Funktion eine andere Funktion aufruft, schiebt das System zuerst
die Rücksprungadresse
für die
derzeitige Funktion auf den Ausführungsstapel 301 und
schiebt dann einen neuen Rahmen für die zuletzt aufgerufene Funktion.
Auf diese Weise ist das System, wenn die neue Funktion zurückkehrt,
imstande, den Rahmen an der Spitze des Ausführungsstapels abzuwerfen (Pop)
und dann die Rücksprungadresse
des Ausführungsstapels
abzuwerfen und den Programmzähler
gleich dieser Rücksprungadresse
zu setzen, so dass das Ausführen
der aufrufenden Funktion fortgesetzt werden kann. Demgemäss ist das
der Grund, dass die Rahmen 305 und 307 Rücksprungadressen
einschließen
und der aktive Rahmen 303 keine Rücksprungadresse einschließt. Wenn
jedoch die Funktion in Entsprechung zu dem Rahmen 303 eine
andere Funktion aufruft, würde
die Rücksprungadresse
auf den Ausführungsstapel 301 geschoben
bevor der Rahmen für
die neue Funktion auf den Ausführungsstapel
geschoben wird.
-
Die
Rahmenzeiger ermöglichen
es dem System, den Rahmen exakt auf dem Ausführungsstapel zu durchlaufen.
Beispielsweise skizzieren Stapelzeiger SP und Rahmenzeiger FP den
Rahmen an der Spitze des Ausführungsstapels.
Zudem spezifiziert der Rahmenzeiger im Rahmen 303 den nächsten Rahmen
auf dem Ausführungsstapel.
Die Adresse gerade unter dem Rahmenzeiger in dem Riemen 303 ist
der Beginn des nächsten
Rahmens auf dem Ausführungsstapel
und die Inhalte des Rahmenzeigers auf dem Riemen 303 spezifizieren
den letzten Unterpunkt im nächsten
Rahmen des Ausführungsstapels, welches
der Rahmen 305 ist. In ähnlicher
Weise spezifiziert der Rahmenzeiger FP im Rahmen 305 den Ort
des nächsten
Rahmens auf dem Ausführungsstapel.
-
Daher
ermöglicht
die Kette der Rahmenzeiger es dem System, die Rahmen auf dem Ausführungsstapel
zu durchlaufen (z.B., wenn die Rahmen aus dem Ausführungsstapel
abgeworfen (popped off) werden.
-
Obwohl 5 eine
Implementierung eines Ausführungsstapels
zeigt, ist die Erfindung nicht auf die gezeigte Implementierung
beschränkt.
Beispielsweise ist der Ausführungsstapel
als ein nach oben im Speicher anwachsender gezeigt, jedoch sollte
klar sein, dass der Stapel auch im Speicher nach unten anwachsen
kann. Zudem kann die in jedem Rahmen gespeicherte Information abhängig von
der Implementierung variieren.
-
Gemischter
Ausführungsstapel
-
Der
in 5 gezeigte Ausführungsstapel kann gut arbeiten
für Funktionen,
die in derselben Programmiersprache geschrieben sind. Wenn jedoch
die Funktionen in mehreren Programmiersprachen geschrieben sind,
ist die Organisation des in 5 gezeigten
Ausführungsstapels
nicht zufriedenstellend aus einer Anzahl von Gründen. Beispielsweise kann das
Format eines Rahmens in einer anderen Programmiersprache substantiell
unterschiedlich sein. Daher kann es gegebenenfalls nicht möglich sein,
eine Kette von Rahmenzeigern zu erstellen durch Rahmen für Funktionen,
die in mehreren Programmiersprachen geschrieben sind. Gegebenenfalls
können
auch die exakte Größe oder
die Inhalte von Rahmen für
Funktionen, die in anderen Programmiersprachen geschrieben sind,
nicht bekannt sein.
-
Um
das Problem klarer zu demonstrieren, kann es hilfreich sein, ein
Beispiel unter Verwendung des in 5 gezeigten
Ausführungsstapels
zu beschreiben. Für
einen Moment angenommen, dass die Rahmen 305 und 307 für Funktionen
dienen, die in einer abweichenden Programmiersprache geschrieben
sind als die Funktion des Rahmens 303. Wenn die Funktion
für den
Rahmen 303 ausgeführt wird,
können
Inhalte oder Größe der Rahmen 305 und 307 gegebenenfalls
nicht bekannt sein. Demnach kann es auch noch nicht bekannt sein,
selbst wenn der Rahmenzeiger des Rahmens 303 auf einen vorangehenden
Rahmen im Ausführungsstapel
für eine
Funktion gesetzt wäre,
die in derselben Programmiersprache wie der Rahmen 303 geschrieben wäre (nicht
dargestellt), wo der Rahmen auf dem Ausführungsstapel beginnt. Demgemäss machen diese
Probleme es schwierig, einen Ausführungsstapel, der Rahmen für Funktionen
speichert, die in mehreren Programmiersprachen geschrieben sind, zu
implementieren. Die vorliegende Erfindung stellt Implementierungen
für Ausführungsstapel
bereit, die Rahmen für
Funktionen speichern, die in mehreren Programmiersprachen geschrieben
sind und stellt auch andere Vorteile bereit einschließlich verbesserter
Ressourcenzuordnung und Ausnahmenbehandlung.
-
6 zeigt
einen Prozess auf einem hohen Level des Speicherns von Rahmen auf
einem Ausführungsstapel
für Funktionen,
die in mehreren Programmiersprachen geschrieben sind. Der in 6 gezeigte
Prozess ist auf einem hohen Level und wird in nachfolgenden Figuren
und der folgenden Beschreibung detaillierter beschrieben. Bei einem Schritt 401 speichert
das System einen ersten Rahmen auf dem Ausführungsstapel für eine erste
in einer Programmiersprache geschriebene Funktion.
-
Wenn
die erste Funktion eine zweite Funktion aufruft, die in einer anderen
Programmiersprache geschrieben ist, speichert das System im Lokalspeicher
einen Zeiger oder Zeiger zu dem ersten Rahmen auf dem Ausführungsstapel
bei einem Schritt 403. In bevorzugten Ausführungsformen
ist die Programmiersprache der ersten Funktion die Java-Programmiersprache.
Jeder Java-Thread hat einen Thread-Lokalspeicher zugeordnet, so dass in
diesen bevorzugten Ausführungsformen
der Lokalspeicher der Thread-Lokalspeicher für den Thread ist, der die ersten
und zweiten Funktionen ausführt.
Zudem sind der Stapelzeiger und der Rahmenzeiger des ersten Rahmens
in dem Thread-Lokalspeicher gespeichert.
-
Bei
einem Schritt 405 speichert das System einen zweiten Rahmen
auf dem Ausführungsstapel für die zweite
Funktion, die in einer anderen Programmiersprache geschrieben ist.
Als ein Beispiel kann die andere Programmiersprache die C++-Programmiersprache,
Pascal, FORTRAN, Assembly oder Ähnliches
sein.
-
Wenn
die zweite Funktion eine dritte Funktion aufruft, die in der Programmiersprache
der ersten Funktion geschrieben ist, speichert das System einen
Datenblock (oder Entry-Rahmen) auf dem Ausführungsstapel, der den oder
die Zeiger zu dem ersten Rahmen auf dem Ausführungsstapel einschließt, bei
einem Schritt 407. Der oder die Zeiger, der/die im Lokalspeicher
bei Schritt 403 gespeichert wurde/n, wird/werden in den
Datenblock kopiert, der oberhalb des zweiten Rahmens für die zweite
Funktion auf den Ausführungsstapel
geschoben wird (Push). Der Datenblock stellt einen Mechanismus zum
Durchlaufen des Ausführungsstapels
um herum oder durch den zweiten Rahmen auf dem Ausführungsstapel
bereit. Obwohl der in 6 gezeigte Prozess nur eine
einzelne zweite Funktion in einer anderen Programmiersprache geschrieben
zeigt, sollte verstanden werden, dass es viele Funktionen geben
kann, die in einer anderen Programmiersprache geschrieben sind, die
einander aufrufen bevor die dritte Funktion aufgerufen wird.
-
Bei
einem Schritt 409 speichert das System einen dritten Rahmen
auf dem Ausführungsstapel
für die
dritte Funktion, die in der Programmiersprache der ersten Funktion
geschrieben ist. Demgemäß speichert
der Ausführungsstapel
nun Rahmen für Funktionen,
die in mehreren Programmiersprachen geschrieben sind und schließt Mechanismen
ein zum Durchlaufen des Ausführungsstapels
durch die Rahmen. Um den in 6 gezeigten
Prozess weiter zu erläutern,
wird auf einen Ausführungsstapel,
der Rahmen für
Funktionen, die in der Java-Programmiersprache geschrieben sind
und in einer anderen Programmiersprache geschrieben sind, unter
Bezugnahme auf 7 beschrieben.
-
Wie
in 7 gezeigt, speichert ein Steuerrahmen 451 Rahmen
für in
der Java-Programmiersprache geschriebene Funktionen und Extern-Rahmen
für in
Programmiersprachen, die nicht die Java-Programmiersprache sind
(z.B., C++-Programmiersprache) geschriebene Funktionen. Ein Java-Rahmen 453 wird
an der Spitze des Ausführungsstapels
gespeichert und ein Java-Rahmen 455 wird unten auf dem
Ausführungsstapel
gespeichert. Zur Einfachheit werde die Details der Rahmen nicht
dargestellt, jedoch, in bevorzugten Ausführungsformen sind die Details
der Rahmen wie in 5 gezeigt.
-
Ein
Entry-Rahmen 457 ist auf dem Ausführungsstapel gezeigt, der unter
anderem einen LAST_JAVA_SP und einen LAST_JAVA_FP speichert, welches
Pointer auf einen vorangehenden Java-Rahmen 459 auf dem Ausführungsstapel
sind. Ein Extern-Rahmen 461 ist auf dem Ausführungsstapel
zwischen dem Entry-Rahmen 457 und dem Java-Rahmen 459 gezeigt.
Der oder die Extern-Rahmen
kann/können
für Funktionen
vorgesehen sein, die in einer anderen Sprache geschrieben sein können als
der Java-Programmiersprache.
Wie dargestellt, ist der Entry-Rahmen ein Datenblock, der mindestens
einen Zeiger um den Extern-Rahmen einschließt.
-
In
der Zeitlinie des Ausführens
des Programms, das den in 7 gezeigten
Ausführungsstapel
erzeugt hat, wird die dem Java-Rahmen 459 entsprechende
Funktion zuerst ausgeführt.
Die dem Java-Rahmen 459 entsprechende Funktion ruft eine Funktion
auf, die in einer anderen Programmiersprache geschrieben ist. Bevor
der Extern-Rahmen für diese
Funktion auf den Ausführungsstapel
geschoben wird, speichert das System mindestens einen Zeiger zu
dem Java-Rahmen 459 im Lokalspeicher.
-
Darauffolgend
ruft die dem Extern-Rahmen 461 entsprechende Funktion eine
Java-Funktion auf. Ansprechend auf das Aufrufen der Java-Funktion schiebt
das System Entry-Rahmen 457 auf den Ausführungsstapel
und speichert darin mindestens einen Zeiger auf den Java-Rahmen 459,
der im Lokalspeicher gespeichert worden ist, welcher in diesem Fall der
LAST_JAVA_SP und der LAST_JAVA_FP sind. Die Funktion in Entsprechung
zu dem Java-Rahmen 455 ruft
dann eine Java-Funktion in Entsprechung zu dem Java-Rahmen 453 auf.
-
Um
die vorliegende Erfindung klarer zu verstehen, gibt es vier verschiedene
Aktionen, die unter Bezugnahme auf den Ausführungsstapel der 7 beschrieben
werden. Wie gezeigt, kann das System von Java-Code in Extern-Code
eintreten, was bedeutet, dass eine Java-Funktion eine Extern-Funktion aufgerufen
hat, die in einer andere Programmiersprache geschrieben ist. Zudem
kann das System von Extern-Code in Java-Code eintreten. Indem die
zu dem Java-Rahmen 455 entsprechende Java-Funktion zurückkehrt,
verlässt
das System den Java-Code zum Extern-Code und indem die dem Extern-Rahmen 461 entsprechende
Extern-Funktion zurückkehrt,
verlässt
das System Extern-Code zu Java-Code. Im Folgenden wird jeder dieser
vier Prozesse detaillierter beschrieben.
-
Wir
beginnen mit einer eine externe Funktion aufrufenden Java-Funktion. 8 zeigt
einen Prozess des Eintretens in Extern-Code von Java-Code. Bei einem
Schritt 501 speichert das System den derzeitigen Stapelzeiger
SP und Rahmenzeiger FP als die LAST_JAVA_SP und LAST_JAVA_FP in
dem Thread-Lokalspeicher.
An diesem Punkt sollte daran erinnert werden, dass eine Java-Funktion
eine Extern-Funktion aufgerufen hat. Der Stapelzeiger und der Rahmenzeiger,
die in dem Thread-Lokalspeicher gespeichert
sind, werden nachfolgend verwendet zum Durchlaufen um die Extern-Rahmen
unter Verwendung eines Datenblocks oder Entry-Rahmens, der diese
Zeiger speichert. Obwohl bevorzugten Ausführungsformen sowohl den Stapelzeiger
als auch dem Rahmenzeiger im Thread-Lokalspeicher speichern, kann
die Erfindung auch beim Speichern anderer oder weniger Zeiger in
anderen Speicherorten in vorteilhafter Weise verwendet werden.
-
Das
System ruft dann bei einem Schritt 503 den Extern-Code
auf. An diesem Punkt wird das System einen Extern-Rahmen für die Extern-Funktion auf
den Ausführungsstapel
schieben. Bevor der Extern-Code aufgerufen wird, schiebt das System
die Rücksprungadresse
für die
Java-Funktion auf den Ausführungsstapel
vor dem Schieben des Extern-Rahmens an die Spitze des Ausführungsstapels.
Wenn einmal im Extern-Code, kann die Extern-Funktion eine Java-Funktion
aufrufen oder eine andere Extern-Funktion aufrufen, die eine Java-Funktion
aufruft.
-
Oben
ist eine eine Extern-Funktion aufrufende Java-Funktion beschrieben
worden. Nun wird das Aufrufen einer Java-Funktion von einer Extern-Funktion
beschrieben.
-
9 zeigt
einen Prozess des Eintretens in Java-Code von Extern-Code. typischerweise
wird die Rücksprungadresse
von Extern-Funktion auf den Ausführungsstapel
geschoben bevor die Java-Funktion aufgerufen wird. Bei einem Schritt 551 schiebt das
System einen Entry-Rahmen oder Datenblock auf den Ausführungsstapel.
Die LAST_JAVA_SP und LAST_JAVA_FP, die im Thread-Lokalspeicher gespeichert
sind, werden dann bei einem Schritt 553 in den Entry-Rahmen
kopiert. Die LAST_JAVA_SP- und LAST_JAVA_FP-Zeiger
zeigen auf einen vorangehenden Java-Rahmen auf dem Ausführungsstapel. Fachleuten sollte
ersichtlich sein, dass die hier gezeigten und beschriebenen Prozessschritte
zum Erläutern
der Erfindung bereitgestellt werden und nicht genommen werden sollten,
um zu implizieren, dass irgendeine spezielle Reihenfolge der Schritte
zwingend notwendig ist. Beispielsweise kann eine Ausführungsform
der Erfindung zuerst einen Zeiger in dem Entry-Rahmen speichern,
bevor er auf den Ausführungsstapel
geschoben wird und eine solche Ausführungsform würde sicherlich
in den Schutzbereich der hier beschriebenen Erfindung fallen.
-
Bei
einem Schritt 555 löscht
das System die in dem Thread-Lokalspeicher
gespeicherten LAST_JAVA_SP und LAST_JAVA_FP. Diese Zeiger im Thread-Lokalspeicher
können
gegebenenfalls durch Setzen ihrer Werte gleich Null gelöscht werden oder
durch irgendeine andere, Fachleuten bekannte Weise. In bevorzugten
Ausführungsformen
werden die Zeiger auf Null gesetzt, so dass die Zeiger geprüft werden
können,
um zu bestimmen, ob Java-Code oder Extern-Code derzeit auf dem System
läuft (z.B. Nichtnull
= extern und Null = Java).
-
In
konventionellen Systemen werden Ressourcen für Native-Verfahren typischerweise zugeordnet,
wenn die Native-Verfahren
aufgerufen werden. Ein andermal wird eine Java-Funktion mehrere Native-Verfahren auf
rufen, so dass die konventionelle Ressourcen-Zuordnung zu mehreren
Zuordnungen (Allocation) und Freigaben (Deallocation) der Ressourcen
führt.
Mit Ausführungsformen
der Erfindung werden Ressourcen für Native-Verfahren zugewiesen,
wenn in eine Java-Funktion eingetreten wird, so dass diese Ressourcen
allen Native-Verfahren verfügbar sind,
die die Java-Funktion aufrufen kann. Zusätzlich können Ressourcen gegebenenfalls
für Native-Verfahren einmal
zugeordnet werden, wenn in die Java-Funktion eingetreten wird und
sie können einmal
freigegeben werden, wenn die Java-Funktion zurückführt, hierdurch die Effizienz
der Ressourcen-Zuordnung/Freigabe erhöhend.
-
Bei
einem Schritt 557 ordnet das System Ressourcen für Native-Verfahren
zu und speichert die Ressourcen in dem Thread-Lokalspeicher. Das System
ruft dann den Java-Code bei einem Schritt 559 auf.
-
Wenn
eine Java-Funktion, die durch eine Extern-Funktion aufgerufen worden
ist, zurückkehrt, wird
die Ausführung
mit der Extern-Funktion, die die Java-Funktion aufgerufen hat, fortgesetzt. 10 zeigt
einen Prozess des Verlassens von Java-Code zum Extern-Code. Bei
einem Schritt 601 speichert das System die LAST_JAVA_SP
und LAST_JAVA_FP erneut in den Thread-Lokalspeicher. Das System
kopiert die in dem Entry-Rahmen
gespeicherten Zeiger zurück
zu dem Thread-Lokalspeicher.
Sollte die Extern-Funktion einst wieder eine Java-Funktion aufrufen,
werden demgemäß die Zeiger wieder
in dem Thread-Lokalspeicher zum Einrichten eines Entry-Rahmens verfügbar sein.
-
Das
System gibt Ressourcen für
Native-Verfahren bei einem Schritt 603 frei. In bevorzugten
Ausführungsformen
werden die Ressourcen in dem Thread-Lokalspeicher gespeichert, nachdem
sie zugeordnet sind. Bei einem Schritt 605 kehrt das System
zurück
zu Extern-Code, der typisch durch eine Rücksprungadresse auf dem Ausführungsstapel
zugewiesen ist.
-
Sobald
die Extern-Funktion, die durch eine Java-Funktion aufgerufen worden
ist, zurückkehrt, wird
die Ausführung
der Java-Funktion, die die Extern-Funktion aufgerufen hat, wieder
aufgenommen. 11 zeigt einen Prozess des Verlassens
von Extern-Code zu Java-Code. Bei einem Schritt 621 löscht das
System die LAST_JAVA_SP und LAST_JAVA_FP im Thread-Lokalspeicher. In
bevorzugten Ausführungsformen
werden die in dem Thread-Lokalspeicher gespeicherten Stapelzeiger und
Rahmenzeiger festgelegt auf einen Null-Wert, wenn das System eine
Java-Funktion ausführt,
und festgelegt auf einen Nichtnull-Wert, wenn das System einen Extern-Code
ausführt.
Die Stapel- und Rahmenzeiger sind Nichtnull-Werte, wenn Extern-Code
ausgeführt
wird, da die Zeiger auf einen vorangehenden Java-Rahmen auf dem
Ausführungsstapel
zeigen.
-
Das
System kehrt zurück
zu Java-Code bei einem Schritt 653. Das System kehrt zurück zu Java-Code
durch Einstellen des Programmzählers
auf die Rücksprungadresse,
die als die Extern-Funktion aufgerufen worden ist, auf den Ausführungsstapel geschoben
worden ist.
-
Das
Voranstehende hat gezeigt, wie Ausführungsformen der vorliegenden
Erfindung eine Implementierung eines Ausführungsstapels bereitstellen, der
Rahmen für
Funktionen, die in mehreren Programmiersprachen geschrieben sind,
speichert. Obwohl die Beschreibung auf Funktionen für die Java-Programmiersprache
fokussiert war, ist die vorliegende Erfindung nicht auf irgendeine
spezifische Programmiersprache beschränkt. Die Erfindung kann in
vorteilhafter Weise auf Systeme angewendet werden, die Programme
unter Verwendung von Funktionen ausführen, die in mehreren Programmiersprachen
geschrieben sind. Dadurch, dass es dem System ermöglicht wird,
den Ausführungsstapel
zu durchlaufen und Ressourcen effizienter zuzuordnen, können Programme
effizienter ausgeführt
werden.
-
Ausnahmen buw. Exceptions
-
Ausnahmen
sind Signale, die angeben, dass irgendetwas vom Normalen Abweichendes
aufgetreten ist. Beispielsweise kann eine Ausnahme angeben, dass
das System ein Problem nicht ausreichenden Speichers erfahren hat
oder dass das Ende "end-of-file" einer Datei erreicht
worden ist. Einige Ausnahmen geben nicht abdeckbare Situationen
an (z.B. wenn zu wenig Speicher verfügbar ist) und einige Ausnahmen
geben abdeckbare Situationen an (z.B. "end-of-file").
-
Wenn
eine Ausnahme erzeugt wird, sucht ein Java-Runtime-System typischerweise
nach einem Ausnahme-Handhaber (Exception-Handler) für dies Ausnahme.
Die Suche beginnt innerhalb der Funktion, in der sich die Ausnahme
ergeben hat und pflanzt sich dann durch die Funktionen auf dem Ausführungsstapel
fort. Wenn ein Ausnahme-Handhaber gefunden wird, nimmt (Catch) der
Ausnahme-Handhaber die Ausnahme und ergreift die angemessenen Schritte,
die das Weitergeben (Throwing) einer anderen Ausnahme einschließen können.
-
Als
ein Beispiel werden wir eine Ausführungsform beschreiben, bei
der die Java-Virtual-Machine in der C++-Programmiersprache geschrieben ist.
Demgemäß wird der
Ausführungsstapel C++-Rahmen
und Java-Rahmen einschließen.
Mit Ausführungsformen
der Erfindung können
Ausnahmen durch die unterschiedlichen Rahmen des Ausführungsstapels
fortgepflanzt werden. Obwohl eine spezielle Ausführungsform beschrieben worden
ist, um die Erfindung zu erläutern,
ist die Erfindung nicht auf irgendeine spezielle Sprache oder Konfiguration beschränkt. 12 zeigt
einen Ausführungsstapel, der
sowohl C++- als auch Java-Rahmen einschließt. Ein C++-Rahmen 703 befindet
sich an der Spitze des Ausführungsstapels.
Die dem C++-Rahmen 703 entsprechende C++-Funktion wurde
durch eine einem Java-Rahmen 705 entsprechende Java-Funktion aufgerufen.
Wie zuvor beschrieben, wird ein Entry-Rahmen 707 in dem
Ausführungsstapel
gespeichert, um es dem System zu ermöglichen, C++-Rahmen 709 und 711 zu
einem Java-Rahmen 713 zu durchlaufen.
-
Konzeptionell
gibt es eine Schirmung (shield) 715 zwischen C++-Rahmen 703 und
Java-Rahmen 705. Shield 715 fängt C++-Ausnahmen ein (Catch), die nicht in
C++-Rahmen 703 gehandhabt werden und gibt die Ausnahme
zu dem Java-Rahmen 705 weiter. Es kann erforderlich sein,
die C++-Ausnahme zu einer Java-Ausnahme
zu transformieren bevor die Ausnahme weitergeleitet wird. Wie dargestellt,
kann auch ein Schirm 716 (shield) zwischen C++-Rahmen 711 und
Java-Rahmen 713 vorgesehen sein.
-
Ein
Aufheben der Schirmung bzw. Unschield 717 ist zwischen
dem Java-Rahmen 705 (und dem Entry-Rahmen 707)
und dem C++-Rahmen 709.
Unshield 717 führt
die Java-Ausnahmen, die nicht innerhalb des Java-Rahmens 705 gehandhabt
werden, weiter und führtt
sie weiter zu einem C++-Rahmen 709. Der Ausführungsstapel,
der in 12 gezeigt ist, ist nun kurz
beschrieben worden, so dass es vorteilhaft sein kann, einen Prozess
einer Ausnahme zu beschreiben, die Extern-Code zu Java-Code verlässt.
-
13A und 13B zeigen
einen Prozess einer Extern-Code zu Java-Code verlassenden Ausnahme.
Bei einem Schritt 801 ist eine C++-Ausnahme weitergegeben
worden (thrown). Die C++-Ausnahme
kann durch einen geeigneten Ausnahme-Handhaber eingefangen (Catch)
und gehandhabt werden, wie im Stand der Technik bekannt ist. Wenn die
C++-Ausnahme durch einen Ausnahme-Handhaber bei einem Schritt 803 gehandhabt
wird, setzt das System das Ausführen,
wie es auf den Ausnahme-Handhaber
gerichtet ist, fort.
-
Schritt 805 und
die nachfolgenden Schritte 807, 809, 811, 813, 815 und 817 entsprechen
Shield 715 der 12. Bei
einem Schritt 805 fängt
das System alle Ausnahmen ein, die nicht innerhalb des C++-Rahmens
gehandhabt werden. Das System bestimmt dann, ob die aufgerufene
Ausnahme eine Java-Ausnahme ist bei einem Schritt 807.
Mit anderen Worten, das System bestimmt, ob die C++-Ausnahme in
eine Java-Ausnahme übersetzt
werden kann. Wenn die C++-Ausnahme nicht umgewandelt werden kann
in eine Java-Ausnahme, kann das System eine Bug-Fehlermeldung bei einem Schritt 809 ausgeben
und das Ausführen
anhalten.
-
Wenn
die C++-Ausnahme eine Java-Ausnahme ist, entfernt das System den
C++-Rahmen von der Spitze des Ausführungsstapels bei einem Schritt 811.
Der C++-Rahmen entspricht der C++-Funktion, die abgearbeitet worden war,
als die Ausnahme weitergegeben (thrown) worden ist. Das System speichert
die Ausnahme und eine Rücksprungadresse
in dem Thread-Lokalspeicher
bei einem Schritt 813. Die gespeicherte Rücksprungadresse
kann verwendet werden zum Erzeugen einer Java-Ausnahme.
-
Bei
einem Schritt 815 setzt das System die Rücksprungadresse
auf dem Ausführungsstapel
mit einer Adresse zu einem Ausnahmeweiterleiter zusammen. Der Ausnahmeweiterleiter
ist ein Extern-Code einer Virtual-Machine-Funktion (in bevorzugten
Ausführungsformen
in C++-Funktionen oder Assembly geschrieben), die auf das Erzeugen
einer Java-Ausnahme und das Springen zu dem Ausnahme-Handhaber für den nächsten Java-Rahmen des Ausführungsstapels
hin an.
-
Bei
einem Schritt 817 kehrt das System zurück zu Extern-Code. Nun ist
die Rücksprungadresse für den Java-Rahmen 705 bei
Schritt 815 eingesetzt worden, um Bezug zu nehmen auf den
Ausnahmeweiterleiter, das System wird als Nächstes Ausnahmeweiterleiterfunktion
ausführen,
die in 13B gezeigt ist. 13B zeigt eine Ausführungsform des Ausnahmeweiterleiters.
Bei einem Schritt 851 richtet das System eine Java-Ausnahme
ein. Eine Java-Ausnahme schließt
sowohl ein Ausnahmeobjekt als auch einen Programmzähler (oder "ausgebender PC" bzw. "issuing PC") ein, wo die Ausnahme
weitergegeben (thrown) worden ist. Der Programmzähler kann leicht aus der in
dem Thread-Lokalspeicher gespeicherten Rücksprungadresse für ein einfaches Subtrahieren
von Eins von der Rücksprungadresse erzeugt
werden. Obwohl die beschriebene Ausführungsform die Rücksprungadresse
speichert, sollte leicht ersichtlich sein, dass der ausgebende PC
auch in dem Thread-Lokalspeicher gespeichert werden könnte.
-
Die
im Thread-Lokalspeicher gespeicherte Rücksprungadresse verwendend,
erhält
der Ausnahmeweiterleiter die Ausnahme-Handhaberroutine für das durch die Rücksprungadresse
spezifizierte Verfahren. Nachdem der geeignete Ausnahme-Handhaber identifiziert
ist, wird bei einem Schritt 855 ein Sprung zu der Ausnahme-Handhaber
ausgeführt. Demgemäss ist gezeigt
worden, wie eine C++-Ausnahme übersetzt
und gehandhabt werden kann als eine Java-Ausnahme. Das Folgende
wird eine Ausnahme beschreiben, die Java-Code zu externem Code hin
verlässt.
-
14A und 14B zeigen
einen Prozess einer Ausnahme, die Java-Code verlässt zu Extern-Code hin. Bei
einem Schritt 901 ist eine Java-Ausnahme weitergegeben
(thrown) worden. Das System bestimmt, ob die Ausnahme in dem Java-Rahmen
gehandhabt werden sollte bei einem Schritt 903. Wenn die
Ausnahme durch einen Ausnahme-Handhaber für diesen Rahmen behandelt werden
sollte, springt das System zu diesem Ausnahme-Handhaber bei einem
Schritt 905.
-
Wenn
die Java-Ausnahme nicht von dem Ausnahme-Handhaber für diesen
Java-Rahmen behandelt werden sollte, entfernt das System den Java-Rahmen
von dem Ausführungsstapel
bei einem Schritt 907. Das System findet dann den Ausnahme-Handhaber
für die
in dem CPU-Register gespeicherte Rücksprungadresse bei einem Schritt 909.
Bei einem Schritt 911 springt das System zu dem Ausnahme-Handhaber.
Der Ausnahme-Handhaber wird der Ausnahme-Handhaber für den Entry-Rahmen sein.
-
14B zeigt einen Prozess für den Ausnahme-Handhaber des
Entry-Rahmens. Bei einem Schritt 951 sichert der Ausnahme-Handhaber die Ausnahme
im Thread-Lokalspeicher. Der Ausnahme-Handhaber beendet die Ausführung und
setzt sie fort nach dem Aufruf in C++ bei Schritt 953.
Wenn das Ausführen
beginnt nach dem Aufruf in C++, bestimmt das Aufheben der Schirmung
bzw. Unshield, das als Unshield 717 in 12 gezeigt
ist, ob eine Ausnahme anhängig
ist bei einem Schritt 955. Es kann bestimmt werden, dass
eine Ausnahme anhängig
ist durch Prüfen
lokaler Speicher, um zu sehen, ob eine Ausnahme anhängig ist.
Beispielsweise kann bestimmt werden, ob eine Ausnahme im Thread-Lokalspeicher
gespeichert ist. Wenn eine Ausnahme anhängig ist, kann eine C++-Ausnahme
weitergegeben (thrown) werden bei einem Schritt 957 durch
weitergeben (throw) der in dem Thread-Lokalspeicher gespeicherten
Ausnahme. Demgemäss
ist eine Java-Ausnahme umgewandelt worden und neu weitergegeben
(thrown) worden als eine C++-Ausnahme.
-
Die
oben beschriebenen Ausführungsformen haben
gezeigt, dass Information in dem Thread-Lokalspeicher gespeichert
werden kann, um einen Ausführungs-Stack
zu implementieren, der Rahmen für Funktionen,
die in mehreren Programmiersprachen geschrieben sind, speichert. 15 zeigt
die Information, die in dem Thread-Lokalspeicher gespeichert werden
kann. Die Information ist oben unter Bezugnahme auf die anderen
Figuren beschrieben worden; jedoch kann es vorteilhaft sein, die
Information neu zu betrachten, die gegebenenfalls darin gespeichert werden
kann. Ein LAST_JAVA_SP 1001 und LAST_JAVA_FP 1003 sind
Zeiger zu einem vorangehenden Java-Rahmen auf dem Ausführungsstapel. Diese Zeiger
ermöglichen
es dem Ausführungsstapel,
um oder durch Rahmen auf dem Ausführungsstapel durchlaufen zu
werden, die in anderen Programmiersprachen geschrieben worden sind.
-
Ressourcenen 1005 werden
zugewiesen, wenn das System von einer Funktion, die in einer anderen
Programmiersprache geschrieben worden ist, in eine Java-Funktion
eintritt. Die Ressourcen können
dann durch irgendwelche Native-Verfahren verwendet werden, die durch
die Java-Funktion oder irgendwelche Java-Funktionen aufgerufen worden sind.
-
Eine
Ausnahme 1007 und eine Rücksprungadresse 1009 werden
gespeichert, um es der Ausnahme zu ermöglichen, von einer in einer
anderen Programmiersprache (z.B. der C++-Programmiersprache) geschriebenen Funktion
weiterzuleiten zu einer Java-Funktion und umgekehrt. Andere Informationen
können
auch in dem Thread-Lokalspeicher gespeichert werden.
-
Abschluss
-
Während das
Obige eine vollständige
Beschreibung bevorzugten Ausführungsformen
der Erfindung ist, können
Alternativen, Modifikationen und Äquivalente verwendet werden.
Es sollte klar sein, dass die Erfindung in gleicher Weise anwendbar
ist durch Vornehmen geeigneter Modifikationen an den oben beschriebenen
Ausführungsformen.
Beispielsweise sind beschriebene Ausführungsformen in Referenz gewesen
zu einem gemischten Ausführungsstapel
einschließlich
Java-Rahmen, aber die Prinzipien der vorliegenden Erfindung können leicht
angewendet werden auf andere Systeme und Sprachen. Daher sollte
die obige Beschreibung nicht als den Schutzbereich der Erfindung
einschränkend
betrachtet werden, der durch die Maßnahmen und Schranken der beiliegenden
Ansprüche
gemeinsam mit deren vollem Schutzumfang der Äquivalente definiert ist.