2015-01-21 2 views
6

In einem sehr interessanten post aus dem Jahr 2001 erklärt Allen Wirfs-Brock, wie Blockverschlüsse implementiert werden können, ohne den (nativen) Stack zu vereinheitlichen.Warum ist eine bestimmte Blockabschlussoptimierung gut und gültig?

Aus den vielen Ideen, die er herausstellt, gibt es eine, die ich nicht ganz verstehe und ich dachte, es wäre eine gute Idee, sie hier zu stellen. Er sagt:

Jede Variable, die während der Lebensdauer eines Blocks niemals zugewiesen werden kann (z. B. Argumente umschließender Methoden und Blöcke), muss nicht in der Umgebung platziert werden, wenn stattdessen eine Kopie der Variablen in den Abschluss platziert wird wenn sie erstellt wird

es gibt zwei Dinge, die ich nicht sicher bin ich gut genug, um zu verstehen:

  1. Warum in die Umgebung mit zwei Kopien des nur-Lese-Variable ist schneller als bewegt, um die Variable zu haben? Liegt es daran, dass der umschließende Kontext schneller auf die (ursprüngliche) Variable im Stack zugreifen würde?
  2. Wie können wir sicherstellen, dass die beiden Variablen synchronisiert bleiben?

In Frage 1 muss es einen anderen Grund geben. Ansonsten sehe ich den Gewinn nicht (im Vergleich zu den Kosten für die Implementierung der Optimierung).

Für Frage 2 nehmen Sie ein Nicht-Argument, das in der Methode und nicht im Block zugewiesen ist. Warum würde der im Stapel gespeicherte OOP während der Lebensdauer des Blocks unverändert bleiben?

Ich glaube, ich kenne die Antwort auf Q2: Weil die Ausführung des Blocks nicht mit der Ausführung der Methode verflochten werden kann, d. H. Während der Block lebt, wird der umschließende Kontext nicht ausgeführt. Aber gibt es keine Möglichkeit, den Stack vorübergehend zu modifizieren, während der Block lebt?

+1

Interessanterweise klagte bera nur über Schließung blogged, es scheint, dass Sie den gleichen Fokus teilen https://clementbera.wordpress.com/2015/01/21/context-and-blockschloss-implementation/ –

+0

Danke für den Link. Es ist eine sehr klare Darstellung. (Es gibt einen Tippfehler in der Auswahl, sollte aber ZooKeeper >> ** free ** AllAnimals gelesen haben ;-) –

Antwort

3

Dank dem Kommentar von @ aka.nice fand ich die Antworten auf die beiden Fragen in Clement Beras Beitrag, dessen Lektüre sowohl angenehm als auch klärend ist.

Für Q1 sagen wir zuerst, dass die Bemerkung von Allen bedeutet, dass die Kopie der schreibgeschützten Variablen in den Stapel des Blocks platziert werden kann, als wäre es ein lokales Temporär des Blocks. Der Vorteil, dies zu tun, tritt nur auf, wenn alle Variablen, die außerhalb des Blocks definiert sind und in ihm verwendet werden, niemals in den Block geschrieben werden. Unter diesen Umständen wäre es nicht notwendig, das Umgebungsarray zu erstellen und einen Prolog oder Epilog auszugeben, um sich darum zu kümmern.

Der Maschinencode, der einen Stapel Variable zugreift entspricht dem man die Umgebung ein den Zugriff erforderlich, da die ersten, die Lage [ebp + offset] mit Adresse würde, während die zweite [edi + offest] verwenden würde, sobald edi wurde an die Umgebung Array Punkt eingestellt (tempVector in Clements Notation). Es gibt also keinen Gewinn, wenn einige, aber nicht alle Umgebungsvariablen schreibgeschützt sind.

Die zweite Frage wird auch in Clements hervorragendem Blog beantwortet. Ja, es gibt eine andere Möglichkeit, die Synchronität zwischen der ursprünglichen Variablen und ihrer Kopie im Stack des Blocks zu brechen: der Debugger (wie aka.nice uns gesagt hätte!) Wenn der Programmierer die Variable im umschließenden Kontext ändert, wird der Debugger benötigt um die Aktion zu erkennen und die Kopie zu aktualisieren. Gleiches, wenn der Programmierer die im Stapel des Blocks gespeicherte Kopie modifiziert.

Ich bin froh, dass ich mich entschieden habe, die Frage hier zu stellen. Die Hilfe, die ich von aka erhielt.Schön und Clement Bera, und die Kommentare, die einige Leute mir per Email schickten, halfen mir sehr dabei, mein Verständnis zu erweitern.

Eine letzte Bemerkung. Wirfs-Brock behauptet, dass die Vermeidung der Verdinglichung von Methodenkontexten zwingend erforderlich ist. Ich neige dazu, zuzustimmen. Viele wichtige Operationen an diesen Datenstrukturen können jedoch besser implementiert werden, wenn die Verdinglichung dem Leichtbaumuster folgt. Genauer gesagt können Sie beim Debuggen diese Kontexte mit "Viewern" modellieren, die auf den nativen Stack verweisen, und zwei Indizes verwenden, um den Teil zu begrenzen, der der zu analysierenden Aktivierung entspricht. Dies ist sowohl effizient als auch sauber und die Kombination beider Techniken führt zu den besten der Welt, weil Sie Geschwindigkeit und Ausdruckskraft auf einmal haben können. Smalltalk ist erstaunlich.

Verwandte Themen