4 Stimmen

Wo finde ich in Squeak den Code für den Algorithmus zur Nachrichtenverarbeitung?

Wenn man in Squeak eine Nachricht an ein Objekt sendet, sieht der Algorithmus für den Aufruf zur Laufzeit etwa so aus

  1. curr <- die Klasse des Empfängers
  2. Wiederholen, solange curr nicht gleich null ist
    1. Suche nach dem Selektor in den Methoden der Klasse; wenn er dort vorhanden ist, rufe ihn auf und gebe
    2. curr <- die Superklasse von curr
  3. Rufen Sie an. doesNotUnderstand: auf self

Ein sehr ähnlicher Algorithmus wird nun für die respondsTo: Methode, und in der Tat kann man dies durch eine Inspektion der respondsTo: Der Code. Was ich suche, ist die Stelle, an der der Code für den oben genannten Algorithmus für den Aufruf verwendet wird .

Ich weiß perform: macht etwas Ähnliches, aber ich glaube, es wird nicht für reguläre Methodenaufrufe verwendet, sondern nur als reflexionsähnlicher Methodenaufrufmechanismus (z.B. wenn der Methodenname dem Programmierer bis zur Laufzeit nicht bekannt ist).

Wenn der obige Code auch als primitive Richtlinie versteckt ist, wo würde ich den primitiven Aufruf finden? Wenn dies nicht der Fall ist, wo finde ich dann den Code selbst?

2voto

Frank Shearar Punkte 16759

Wahrscheinlich sollten Sie sich Folgendes ansehen VMMaker . Die Klasse Interpreter ist derjenige, der die Bytecodes einer CompiledMethod ausführt und die Nachrichten an Ihre Objekte sendet.

Wenn Sie sich zum Beispiel die Bytecodes für Object>>respondsTo: ansehen, werden Sie sehen

17 <70> self
18 <C7> send: class
19 <10> pushTemp: 0
20 <E0> send: canUnderstand:
21 <7C> returnTop

Der Interpreter liest einen Bytecode ein, sucht diesen Bytecode in seiner BytecodeTabelle (initialisiert in Interpreter class>>initialiseBytecodeTable) und führt die entsprechende Methode aus. Also <70> (#pushReceiverByteCode) schiebt self auf den internen Stack des Interpreters. Dann läuft (#bytecodePrimClass) auf "finde die Klasse von self" hinaus. <10> (#pushTemporaryVariableBytecode) schiebt das Argument zu #respondsTo: auf den Stack. Der interessante Teil passiert mit (#sendLiteralSelectorBytecode), der aufruft self normalSend . #normalSend ermittelt seinerseits die Klasse des Empfängers ( self class in diesem Fall), und ruft dann self commonSend der die gewünschte Methode findet und sie dann ausführt.

Ich bin ein VM-Neuling; das oben Gesagte ist vielleicht nicht der absolut beste Ort, um den Algorithmus in Aktion usw. zu sehen (oder sogar die beste Erklärung), aber ich hoffe, es ist ein guter Ausgangspunkt.

Der Algorithmus, den die VM zum Senden einer Nachricht verwendet, entspricht dem, was Sie in Ihrer Frage beschrieben haben. Die eigentliche Implementierung dieses Algorithmus ist definiert in Interpreter>>commonSend . Der Suchalgorithmus ist in Interpreter>>lookupMethodInClass: und der Ausführungsalgorithmus ist in Interpreter>>internalExecuteNewMethod .

Ersteres funktioniert ähnlich wie von Ihnen beschrieben:

  1. Posten auflisten
  2. Versuchen Sie, die Methode in dieser Klasse zu finden.
  3. Wenn nicht gefunden, suchen Sie in der Superklasse.
  4. Wenn dies rekursiv fehlschlägt, versuchen Sie #doesNotUnderstand zu finden:
  5. Wenn #doesNotUnderstand: nirgendwo in der Klassenhierarchie existiert, wird ein Fehler ausgegeben.

Letzteres funktioniert folgendermaßen:

  1. Wenn es sich um ein Primitiv handelt, führen Sie das Primitiv aus.
  2. Ist dies nicht der Fall, aktivieren Sie die neue Methode (erstellen Sie einen neuen Aktivierungssatz).
  3. (Prüfen Sie auf Unterbrechungen.)

1voto

Oak Punkte 25262

Wenn man weiter gräbt, findet man die ContextPart Klasse ist ein Interpreter, der Bytecode ausführen kann. Gemäß ihrer Dokumentation:

[seine für diese Frage relevanten Methoden] genau parallel zum Betrieb der Smalltalk-Maschine selbst .

Wenn wir prüfen, wie er Bytecode interpretiert,

  1. Seine interpret Methode ruft ihre interpretNextInstructionFor: für jede Anweisung.
  2. interpretNextInstructionFor: ruft auf. send:super:numArgs: wenn ein Sendebefehl auftaucht.
  3. send:super:numArgs: ruft auf. send:to:with:super: (vorausgesetzt, es handelt sich nicht um eine primitive Nachricht).
  4. send:to:with:super: utilise Behavior 's lookupSelector: um den richtigen Selektor für die Verwendung zu finden.
  5. Behavior 's lookupSelector: ist derjenige, der für die Schleife der Oberklasse in dem in der Frage genannten Algorithmus verantwortlich ist.

Dies ist also no die eigentliche Implementierung, nach der ich gesucht habe (und daher ist dies nicht wirklich eine Antwort), aber ich vermute, dass es helfen kann, die Nuancen des genauen Algorithmus zu verstehen.

1voto

blabla999 Punkte 3082

Um Franks Antwort zu verstehen, benötigen Sie einige Hintergrundinformationen:

der Compiler erzeugt einen "Sende-Bytecode", der später vom Bytecode-Interpreter der VM ausgeführt wird (oder jitted, aber die Semantik ist dieselbe). Sie würden also nicht erwarten, die Implementierung in einer Klasse zu finden, sondern in der VM.

Die meisten anderen VMs sind in C, Assembler oder was auch immer geschrieben...

Wie auch immer: die Squeak-VM ist in Smalltalk geschrieben und wird von einem "Subset-of-Smalltalk-to-C-Compiler" nach C kompiliert (so genanntes "Slang", weil es nicht die volle Smalltalk-Semantik abdeckt).

Da diese VM in Smalltalk geschrieben ist, kann sie natürlich von Squeak aus entwickelt, debuggt und getestet werden (indem man den Slang-Interpreter auf dem Image aus dem Image heraus startet). Aus diesem Grund finden Sie die Implementierung im Interpreter, wie von Frank beschrieben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X