8
votes

Il et arguments

IL a quelques opcodes pour fonctionner avec des arguments, tels que ldarg.0 , ldarg.1 et ainsi de suite.

Je sais que ces arguments sont poussés sur la pile avant qu'un appel opcode est exécuté, dans certains cas, ldarg.0 est utilisé pour obtenir une référence à Ce (par exemple des membres)

Ma question est la suivante: où sont stockés ces arguments lorsqu'un appel est initié? Est une copie de la pile de l'appelant accessible à partir de l'appel exécuté?

Où puis-je trouver plus d'informations sur ce sujet?

mise à jour

Je sais que la machine virtuelle est abstraite et que le compilateur JIT s'occupe de ces problèmes, mais imaginons si l'IL a été interprété, comme si elle est sur Micro Framework


0 commentaires

3 Réponses :


8
votes

ECMA-335 est probablement un bon point de départ pour Ceci.

Par exemple, la section I.12.4.1 a ceci:

Les instructions émises par le générateur de code CIL contiennent des informations suffisantes pour différentes implémentations de la CLI pour utiliser différentes conventions d'appel natif. Tous les appels de méthode initialisent les zones d'état de la méthode (voir §.12.3.2) comme suit:

  1. La matrice d'arguments entrants est définie par l'appelant sur les valeurs souhaitées.
  2. Le tableau de variables locales a toujours NULL pour les types d'objets et les champs dans des types de valeur qui contiennent des objets. De plus, si le Le drapeau localinit est défini dans l'en-tête de la méthode, puis les variables locales tableau est initialisé à 0 pour tous les types entier et à 0,0 pour tous types de points flottants. Les types de valeur ne sont pas initialisés par la CLI, mais Le code vérifié fournira un appel à une initialiseur dans le cadre de la Code du point d'entrée de la méthode.
  3. La pile d'évaluation est vide.

    et I.12.3.2 a:

    Une partie de chaque état de la méthode est une matrice qui contient des variables locales et un tableau qui contient des arguments. Comme la pile d'évaluation, chaque élément de ces tableaux peut contenir tout type de données unique ou une instance de type de valeur. Les deux tableaux commencent à 0 (c'est-à-dire que le premier argument ou la variable locale est numéroté 0). L'adresse d'une variable locale peut être calculée à l'aide de l'instruction LDLOCA et de l'adresse d'un argument à l'aide de l'instruction LDARGA.

    associé à chaque méthode est la métadonnée qui spécifie:

    • si les variables locales et la mémoire de pool de mémoire seront initialisées lorsque la méthode est entrée.
    • Le type de chaque argument et la longueur du tableau d'arguments (mais voir ci-dessous pour les listes d'arguments variables).
    • Le type de chaque variable locale et la longueur du tableau de variables locales.

      Le CLI inserve le rembourrage selon le cas pour l'architecture cible. C'est-à-dire que sur certaines architectures de 64 bits, toutes les variables locales peuvent être alignées de 64 bits, tandis que sur d'autres, ils peuvent être alignés de 8, 16 ou 32 bits. Le générateur CIL ne doit faire aucune hypothèse sur les compensations de variables locales dans le tableau. En fait, la CLI est libre de réorganiser les éléments du tableau de variables locales et différentes implémentations pourraient choisir de les commander de différentes manières.

      puis dans la partition III, la description de Callvirt (tout comme exemple) a:

      Callvirt apparaît l'objet et les arguments de la pile d'évaluation avant d'appeler la méthode. Si la méthode a une valeur de retour, elle est poussée sur la pile lors de la fin de la méthode. Sur le côté de la calle, le paramètre Obj est accessible en argument 0, arg1 comme argument 1, etc.

      Maintenant c'est tout dans un niveau spécification. La mise en œuvre peut bien décider de simplement rendre l'appel à la fonction hériter des éléments TOP N de la pile de la méthode actuelle, ce qui signifie que les arguments sont déjà au bon endroit.


0 commentaires

9
votes

MSIL fonctionne avec une spécification d'une machine virtuelle . Le modèle mental des arguments passés à une méthode est d'être présente dans un tableau. Lorsque Ldarg choisit un élément de ce réseau pour accéder à l'argument de la méthode et la pousse à la pile d'évaluation. OPCODES.LDARG_0 est une version abrégée de l'instruction OPCODES.LDARG plus générale, elle enregistre deux octets par un élément de cueillette toujours 0. Même idée pour OPCODES.LDARG_1 pour la 2e argument. Très fréquent bien sûr, LDARG ne devient "coûteux" que lorsque la méthode comporte plus de 4 arguments. L'accent mis sur les citations doubles, ce n'est pas le genre de dépenses que vous vous inquiétez.

Le stockage réel d'arguments à l'exécution est très différent. Cela dépend de la gigue que vous utilisez, différentes architectures utilisent différentes façons de passer des arguments. En général, les premiers arguments sont passés par des registres de la CPU, le reste de la pile de la CPU. Les processeurs comme X64 ou le bras ont beaucoup de registres, alors passez plus d'arguments à l'aide d'un registre que x86. Régi par les règles du __clrcall Convention d'appel pour cette architecture.


4 commentaires

Bonjour Hans, s'il vous plaît voir ma mise à jour, je suis pleinement conscient de cela que l'IL est en réalité jit'ed et que la machine virtuelle est un simple résumé.


Je n'ai pas étudié l'interprète MF, ce n'est pas si intéressant. Msil a été fait pour être jeté. Il suffit de regarder vous-même, MF est open source. Vous le trouverez [ici] (netmf.codeplex.com)


La raison pour laquelle je demande cela, c'est parce que je rédigeais un interprète (voici Github.com/animaonline / ILtools ), j'ai déjà vu ces sources, merci


@HANSPASTANT: Le modèle mental des arguments transmis à une méthode est présente dans un tableau. Où Ldarg choisit un élément de ce réseau pour accéder à l'argument de la méthode et la pousse sur la pile d'évaluation Il aide à visualiser mais également à visualiser le modèle mental ailleurs :-) Ce que je veux dire ici est - il avant que la méthode appelait habituellement LDLOC ou LDC etc. que j'ai lu comme appuyer sur l'article d'argument à la pile d'évaluation. Donc, si la callee au début de la méthode dispose de LDARG, cela signifie que la même valeur d'argumentation est à nouveau poussée à la pile d'évaluation?



9
votes

L'IL (maintenant connu sous le nom de CIL, une langue intermédiaire commune, pas MSIL EM>) décrit les opérations sur une machine d'empilement imaginaire. Le compilateur JIT prend les instructions Il et le compose dans le code de la machine.

Lorsque vous appelez une méthode, le compilateur JIT doit adhérer à une convention d'appel em>. Cette convention spécifie la manière dont les arguments sont transmis à la méthode appelée, comment la valeur de retour est transmise à l'appelant et qui est responsable de l'élimination des arguments de la pile (l'appelant ou la callee). Dans cet exemple, j'utilise le CDECL Convention d'appel, mais les compilateurs JIT utilisent d'autres conventions.

approche générale h3>

Les détails exacts dépendent de la mise en œuvre, mais l'approche générale utilisée par les compilateurs .NET et mono JIT pour la compilation de CIL au code de la machine est la suivante: P>

  1. "Simulez" une pile et utilisez-la pour transformer toutes les opérations de pile en opérations sur registres virtuels em> (variables). Il y a un nombre infini théorique de registres virtuels. LI>
  2. Tournez toutes les instructions IL dans les instructions de la machine équivalentes. LI>
  3. Attribuez chaque enregistrement virtuel à un registre de la machine em>. Il n'y a qu'un nombre limité de registres de machines disponibles. Par exemple, l'architecture X86 32 bits n'a que 8 registres de machine. Li> ol>

    Bien sûr, il y a beaucoup d'optimisation entre ces étapes. P>

    Exemple h3>

    prenons un exemple pour expliquer ces étapes: p>

    mov eax, [addr_of_arg1]     // Move argument 1 in EAX
    mov ecx, [addr_of_arg3]     // Move argument 3 in ECX
    add eax, ecx                // Add ECX to EAX
    
    push eax                    // Push EAX on the real stack
    call [addr_of_MyMethod]     // Call the method
    add esp, 4
    
    mov ecx, eax                // Move the return value into ECX
    mov eax, ecx                // Move ECX into the return value register EAX
    ret                         // Return
    


2 commentaires

Merci pour une réponse étendue, mais je sais déjà tout cela, la question était plus théorique et plus abstraite plutôt que pratique.


@animaonline alors vous vraiment devez reformuler votre question. Vous dites que vous savez comment cela fonctionne en théorie (pile d'évaluation) et dans la pratique (mon message). Alors que voulez-vous savoir?