Moin.
»» Wie genau ein solcher 'Rahmen' aussieht ist abhängig von der calling convention der entsprechenden Programmiersprache.
Also bei Assembly anders als bei C anders als bei Fortran anders als bei Lisp.
Der Begriff Stackframe im engeren Sinne ergibt eigentlich nur für kompilierte Sprachen Sinn, da diese ihre Argumente und lokalen Variablen auf dem Hardware-Stack ablegen. Bei interpretierten Sprachen kann man den Begriff in Analogie verwenden, da es auch dort in der Regel einen call stack gibt. Die Funktions-Argumente liegen meist aber nicht auf dem Hardware-Stack (das Argument-Objekt in JavaScript sollte auf dem Heap zu finden sein).
Die calling convention beschreibt, wie ein Funktionsaufruf auf Assembler-Ebene durchgeführt wird (wo liegen die Argumente, wo die Rücksprungadresse, wer ist verantworlich für die Freigabe des Speichers für Argumente und lokale Variable, ...). Compiler können auch mehrere Konventionen für eine Sprache unterstützen. In C beispielsweise sind für x86-Architekturen die Konventionen cdecl (der Standard), stdcall (Windows API, nur für Funktionen mit fester Argumentzahl möglich) und fastcall (die ersten beiden Argumente liegen in Registern und nicht auf dem Stack) verbreitet.
[...] da bin ich mir selbst nicht so ganz sicher. C resultiert doch in Assembly, oder? Nicht aber Java, PHP, Lisp, Fortran.
C und Fortran werden vom Compiler direkt in Maschinencode übersetzt, der Zwischenschritt über Assembly wird in der Regel nicht genommen. Soweit ich weiß disassembliert beispielsweise der Aufruf gcc -S
den generierten Maschinencode.
PHP und Lisp werden in der Regel interpretiert, wobei es wie bereits beschrieben bei letzterer Sprache auch die Möglichkeit zur Kompilierung gibt.
Bei Java ist das komplizierter: Der Java-Compiler erzeugt Bytecode, d.h. Maschinencode für eine 'virtuelle' Maschine und nicht den x86 Prozessor. Erst beim Aufruf des Java-Programms wird der Bytecode in x86 Maschinencode übersetzt, der dann sofort ausgeführt wird. Der Vorteil gegenüber rein interpretierten Sprachen ist hier, dass die Übersetzung des Bytecodes in Maschinencode viel schneller durchgeführt werden kann. Der Vorteil gegenüber einer direkten Kompilierung in Maschinencode ist, dass der Bytecode unabhängig von der Rechnerarchitektur ist, d.h. die selben .class-Dateien können auf jeder Rechnerarchitektur verwendet verden, für die eine JVM verfügbar ist. Das Kompilieren zur Laufzeit erlaubt der VM Optimierungen, die ein klassischer Compiler nicht durchführen kann, da er weniger 'Wissen' über den Programmablauf besitzt.
Wenn aber immer wieder interpretiert wird, nur um die do-schleife weiterzuspulen, dann dauerts natürlich ewig. Das wäre ja, wie wenn der Fortran/C-Compiler für jeden Schleifendurchlauf neu komplieren würde (;-).
Genau das macht ein klassischer Interpreter aber, wobei allerdings in der Regel der Syntaxbaum nur einmalig generiert wird und dieser dann durchlaufen wird. Wird hingegen maschinencode erzeugt, ist der Interpreter zum Compiler geworden.
Christoph