2010-07-26 26 views
4

Lors de l'envoi d'un message à un objet dans Squeak, l'algorithme d'appel d'exécution est quelque chose commeDans Squeak, où trouver le code de l'algorithme de gestion des messages?

  1. Curr < - la classe de récepteur
  2. Répéter tout Curr est non nul
    1. Rechercher le sélecteur dans les méthodes de cette classe; si elle est là, l'invoquer et de retour
    2. curr < - superclasse de curr
  3. Appel doesNotUnderstand: sur self

Maintenant, un algorithme très similaire est utilisé pour la méthode respondsTo:, et en effet, il peut être vu en inspectant le code de respondsTo:. Ce que j'essaie de trouver est l'emplacement du code pour l'algorithme ci-dessus utilisé pour l'invocation. Je sais que perform: fait quelque chose de similaire mais je crois qu'il n'est pas utilisé pour l'invocation de méthode régulière mais seulement comme mécanisme d'appel de méthode de réflexion (par exemple quand le nom de la méthode n'est pas connu du programmeur avant l'exécution).

Si le code ci-dessus est également masqué comme directive primitive, où trouver l'appel primitif? Si ce n'est pas le cas, où trouverais-je le code lui-même?

Répondre

2

Vous voudrez probablement regarder VMMaker. Sa classe Interpreter est le type qui exécute les bytecodes d'un CompiledMethod, et enverra réellement les messages à vos objets.

Par exemple, si vous regardez le bytecode pour objet >> respondsTo: vous verrez

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

L'interprète se lit dans un bytecode, lève les yeux qui bytecode dans son BytecodeTable (initialisées en classe interprète> > initialiseBytecodeTable) et exécute la méthode appropriée. Donc < 70> (#pushReceiverByteCode) pousse le self sur la pile interne de l'interpréteur. Alors (#bytecodePrimClass) se résume à "trouver la classe de soi". < 10> (#pushTemporaryVariableBytecode) pousse l'argument à #respondsTo: sur la pile. La partie intéressante se passe avec (#sendLiteralSelectorBytecode), qui appelle self normalSend. #normalSend détermine à son tour la classe du récepteur (self class dans ce cas), puis appelle self commonSend, qui trouve la méthode réelle que nous cherchons à exécuter, puis l'exécute.

Je suis un débutant VM; Ce qui précède peut ne pas être le meilleur endroit pour voir l'algorithme en action, etc. (ou même la meilleure explication) mais j'espère que c'est un bon point de départ.

L'algorithme utilisé par la machine virtuelle pour envoyer un message est tel que vous l'avez indiqué dans votre question. L'implémentation réelle de cet algorithme est définie dans Interpreter>>commonSend. L'algorithme de recherche est en Interpreter>>lookupMethodInClass: et l'algorithme d'exécution est en Interpreter>>internalExecuteNewMethod.

Les anciens travaux beaucoup que vous décrivez:

  1. Liste
  2. article
  3. Essayez de trouver la méthode dans cette classe.
  4. Si non trouvé, regardez dans la superclasse.
  5. Si cela échoue récursivement, essayez de trouver #doesNotUnderstand:
  6. Si #doesNotUnderstand: n'existe pas dans la hiérarchie des classes, lancez une erreur.

Ce dernier fonctionne comme ceci:

  1. Si c'est une primitive, exécutez la primitive.
  2. Si ce n'est pas le cas, activez la nouvelle méthode (créez un nouvel enregistrement d'activation).
  3. (Vérifiez les interruptions.)
+0

RE "compilation" - J'ai modifié la question pour clarifier ce que je voulais dire. – Oak

+0

Je vais ajuster ma réponse en conséquence. –

1

Creuser un peu plus, la classe ContextPart est un interprète capable d'exécuter bytecode. Selon sa documentation:

[ses méthodes pertinentes à cette question] exactement parallèle le fonctionnement de la machine elle-même Smalltalk.

Si nous vérifions comment il interprète bytecode,

  1. Sa méthode interpret appelle son interpretNextInstructionFor: pour chaque instruction.
  2. interpretNextInstructionFor: appelle send:super:numArgs: lorsqu'une instruction d'envoi est rencontrée.
  3. send:super:numArgs: appels send:to:with:super: (en supposant que ce n'est pas un message primitif).
  4. send:to:with:super: utilise BehaviorlookupSelector: pour localiser le bon sélecteur à utiliser.
  5. BehaviorlookupSelector: est le responsable de la boucle de la superclasse dans l'algorithme apparaissant dans la question.

C'est donc pas la mise en œuvre réelle que je cherchais (et donc ce n'est pas vraiment une réponse), mais je suppose que cela peut aider à comprendre les nuances de l'algorithme précis.

1

Pour comprendre la réponse Franks, vous avez besoin d'une information de fond:

le compilateur génère un « envoyer bytecode », qui est ensuite exécuté par l'interpréteur de bytecode de la machine virtuelle (ou jitted, mais la sémantique est le même). Ainsi, vous ne vous attendez pas à trouver l'implémentation dans une classe, mais dans la machine virtuelle.

La plupart des autres VM sont écrites en C, Assembler ou quoi d'autre ...Cependant, la machine virtuelle squeak est écrite en Smalltalk et compilée en C par un "sous-ensemble de Smalltalk-à-C-Compiler" (appelé "Slang", car elle ne couvre pas la sémantique complète de Smalltalk). . Étant écrit en Smalltalk, cette VM peut bien sûr être développée, débuggée et testée depuis Squeak (en exécutant l'interpréteur Slang sur l'image depuis l'image). C'est pourquoi vous pouvez trouver l'implémentation dans Interpreter tel que décrit par Frank.