Frage

Ich werde eine virtuelle Maschine in x86 implementieren und ich frage mich, welche Art von Design beste Ergebnisse ergeben würde. Was soll ich darauf konzentrieren, den Saft zerquetschen aus? Ich werde die gesamte virtuelle Maschine in x86-Assembler zu implementieren.

Ich habe nicht viele Anweisungen und ich kann ihre Form wählen. Die Anweisungen Projekt direkt in smalltalk Syntax in Blöcken. Ich gebe den Befehl Design I dacht:

^ ...       # return
^null     # return nothing
object    # address to object
... selector: ... # message pass (in this case arity:1 selector: #selector:)
var := ... # set
var # get

Die Art von VM ich dachten an:

mov eax, [esi]
add esi, 2
mov ecx, eax
and eax, 0xff
and ecx, 0xff00 # *256
shr ecx, 5          # *8
jmp [ecx*4 + operations]
align 8:
    operations:
dd retnull
dd ret
# so on...
    retnull:          # jumps here at retnul
# ... retnull action
    ret:
# ... ret action
#etc.

Sie fragen nicht starten, warum ich noch Implementierung eine andere virtuelle Maschine benötigen. Interpretierenden Routinen sind nicht auf Lager Material, das Sie nur abholen, wann immer Sie sie benötigen. Die meisten virtuellen Maschinen Sie sind an anderer Stelle vorschlagen, auf Portabilität mit den Kosten der Leistung gewichtet. Mein Ziel ist nicht die Portabilität, mein Ziel ist die Leistung.

Der Grund dieser Interpreter überhaupt, weil smalltalk Blöcke benötigt wird, nicht am Ende die gleiche Art und Weise interpretiert gotten:

A := B subclass: [
    def a:x [^ x*x]
    clmet b [...]
    def c [...]
    def d [...]
]

[ 2 < x ] whileTrue: [...]

(i isNeat) ifTrue: [...] ifFalse: [...]

List fromBlock: [
    "carrots"
    "apples"
    "oranges" toUpper
]

Ich brauche der wirkliche Nutzen aus den interpretierenden Routinen kommt, dass die Wahl des Kontextes ist, wo in das Programm lesen Natürlich sollten gut Compiler nur die meiste Zeit wie die offensichtlichen Fälle zusammenstellen. ‚IfTrue: ifFalse‘ oder ‚whileTrue:‘ oder die Liste Beispiel. Die Notwendigkeit für Dolmetscher nicht nur verschwinden, weil man immer einen Fall treffen kann, wo man nicht sicher sein kann, der Block die Behandlung bekommt man erwartet.

War es hilfreich?

Lösung

Ich sehe es einige Verwirrung über Portabilität ist hier, also ich fühle mich verpflichtet, Fragen einige zu klären. Das sind meine bescheidenen Meinungen so Sie sind natürlich frei, gegen sie zu widersprechen.

Ich nehme an, Sie kam accross http://www.complang.tuwien.ac .at / her / Einfädeln / , wenn Sie ernsthaft eine VM betrachten zu schreiben, damit ich nicht auf die beschriebenen Techniken wohnen.

Bereits erwähnt, hat eine VM-Targeting einige Vorteile wie reduzierte Codegröße, reduziert Compiler Komplexität (oft schnellere Kompilierung übersetzt), Portabilität (beachten Sie, dass der Punkt einer VM Tragbarkeit des ist die Sprache , so dass es nicht egal, ob die VM selbst nicht tragbar ist).

Unter Berücksichtigung dynamischer Natur Ihres Beispiel VM eine JIT-Compiler ähneln mehr als andere populäreren. So altough S.Lott den Punkt in diesem Fall verpasst, seine Erwähnung von Forth ist sehr an Ort und Stelle. Wenn ich eine VM für eine sehr dynamische Sprache zu entwerfen, würde ich Interpretation in zwei Phasen trennen;

  1. Eine Erzeugerstufe, die einen AST-Stream auf Nachfrage berät und verwandelt sie in eine sinnvollere Form (zum Beispiel einen Block nehmen, zu entscheiden, ob sie sofort oder ausgeführt werden sollte irgendwo für eine spätere Ausführung gespeichert) möglicherweise die Einführung neue Arten von Token. Im Wesentlichen erholen Sie kontextsensitive Informationen, die hier in Parsen verloren kann.

  2. Ein Verbraucher Phase des erzeugten Stroms aus 1 Abrufen und führt es blind wie jede andere Maschine. Wenn Sie es machen Forth möchten, können Sie einfach einen gespeicherten Strom schieben und mit ihm statt Springen Befehlszeiger um durchgeführt werden.

Wie Sie sagen, nur imitiert, wie die verdammte Prozessor Arbeit in einer anderen Art und Weise keine Dynamik nicht erreichen (oder jede andere Funktion Pfifferling wert, wie Sicherheit), die Sie benötigen. Andernfalls würden Sie einen Compiler schreiben.

Natürlich können Sie hinzufügen beliebig Comlex Optimierungen in der Stufe 1.

Andere Tipps

Wenn Sie etwas wirklich schnell wollen, versuchen Sie es mit LLVM . Es kann für die meisten Prozessoren von einem hohen Niveau Programmbeschreibung nativen Code erzeugen. Sie können entweder mit dem eigenen Assemblersprache gehen oder die llvm Struktur zu erzeugen, um die Montagephase überspringen, je nachdem, was Sie finden am bequemsten.

Ich bin mir nicht sicher, ob es das Beste für Ihr Problem, aber es ist auf jeden Fall, was ich verwendet, wenn ich kritische Ausführung von Code einig Performance tun würde, die nicht mit dem Rest des Programms kompiliert werden kann.

Der Punkt eines Dolmetschers ist Portabilität, die meiste Zeit. Der schnellste Ansatz, den ich denken kann, ist auf x86-Code im Speicher direkt, wie JIT-Compiler, aber dann, natürlich, Sie keinen Dolmetscher mehr zu erzeugen. Sie haben einen Compiler.

Allerdings bin ich mir nicht sicher, ob der Dolmetscher in Assembler Schreiben Sie die beste Leistung geben (es sei denn, Sie ein Assembler-Guru und Ihr Projekt sind in ihrem Umfang sehr begrenzt). eine übergeordnete Sprache verwenden, können Sie für, sagen wir, Symbol Lookup konzentrieren sich auf bessere Algorithmen helfen und Allokationsstrategien registrieren.

Sie können Ihre Dispatch-Routine mit einem unverschlüsselte Befehlssatz beschleunigen:

mov eax, [esi]
add esi, 4
add eax, pOpcodeTable
jmp eax

, die einen Overhead <4 Zyklen für jeden Versand auf CPUs> haben sollte Pentium 4.

Als Ergänzung aus Performance-Gründen ist es besser, ESI (IP) in jeder primitiven Routine zu erhöhen, weil die Chancen hoch sind, dass die Inkrementierung mit anderen Anweisungen kombiniert werden:

mov eax, [esi]
add eax, pOpcodeTable
jmp eax

~ 1-2 Takte Überkopf.

Ich habe zu fragen, warum mit einem Fokus auf der Leistung eine virtuelle Maschine erstellen? Warum nicht nur x86-Code direkt schreiben? Nichts kann möglicherweise schneller sein.

Wenn Sie eine wollen sehr schnell interpretierte Sprache, Blick auf Forth . Ihr Design ist sehr ordentlich und sehr einfach zu kopieren.

Wenn Sie nicht JIT mögen und Ihr Ziel ist nicht die Portabilität. Ich denke, dass Sie Interesse bekommen können in Google NativeClient Projekt. Sie tun Statiker, Sandboxing und andere. Sie ermöglichen es dem Host-RAW-x86-Befehle auszuführen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top