327 votes

Quel est le but d’une pile ? Pourquoi avons-nous besoin ? (MSIL)

Donc, je suis en train d'apprendre le langage MSIL dès maintenant à apprendre à déboguer mon C# .NET applications.

Je me suis toujours demandé: quel est le but de la pile?

Juste pour mettre ma question dans le contexte:
Pourquoi est-il un transfert à partir de la mémoire de la pile ou de la "chargement?" D'autre part, pourquoi il y a un transfert de la pile de la mémoire ou de "stockage"? Pourquoi ne pas les avoir tous mis dans la mémoire?

  • Est-ce parce que c'est plus rapide?
  • Est-ce parce que c'est de la RAM?
  • Pour plus d'efficacité?

J'essaie de saisir ce pour m'aider à comprendre CIL codes beaucoup plus profondément.

448voto

Eric Lippert Points 300275

Mise à JOUR: j'ai bien aimé cette question tellement j'en ai fait le sujet de mon blog, le 18 novembre 2011. Merci pour la grande question!

Je me suis toujours demandé: quel est le but de la pile?

Je suppose que vous voulez dire la pile d'évaluation de la MSIL langue, et non pas le par-de la pile lors de l'exécution.

Pourquoi est-il un transfert à partir de la mémoire de la pile ou de la "chargement?" D'autre part, pourquoi il y a un transfert de la pile de la mémoire ou de "stockage"? Pourquoi ne pas les avoir tous mis dans la mémoire?

MSIL est une "machine virtuelle" de la langue. Compilateurs comme le compilateur C# générer CIL, puis lors de l'exécution d'un autre compilateur appelé le JIT (Just In Time) compilateur transforme le IL en code machine qui peut s'exécuter.

Alors d'abord, nous allons répondre à la question "pourquoi avez-MSIL à tous?" Pourquoi ne pas simplement avoir le compilateur C# écrire du code machine?

Parce qu'il est moins cher de faire de cette façon. Supposons que nous n'avons pas le faire de cette façon; supposons que chaque langue possède sa propre machine générateur de code. Vous avez vingt langues différentes: le C#, JScript .NET, Visual Basic, IronPython, F#... Et supposons que vous ayez dix différents processeurs. Combien de générateurs de code avez-vous écrire? 20 x 10 = 200 générateurs de code. C'est beaucoup de travail. Maintenant, supposons que vous souhaitez ajouter à un nouveau processeur. Vous devez écrire le générateur de code pour vingt fois, une pour chaque langue.

En outre, il est travail difficile et dangereux. Écriture efficace des générateurs de code pour les frites que vous n'êtes pas un expert, c'est un dur métier! Compilateur concepteurs sont des experts sur l'analyse sémantique de leur langue, et non pas sur l'efficacité de l'allocation des registres de nouveaux jeux de puces.

Maintenant, supposons que nous ne le CIL. Combien de CIL générateurs avez-vous écrire? Un par langue. Combien de compilateurs JIT avez-vous écrire? Un par processeur. Total: 20 + 10 = 30 générateurs de code. En outre, le langue-à-CIL generator est facile à écrire car CIL est un langage simple, et le CIL-de-machine-générateur de code est également facile à écrire car CIL est un langage simple. Nous débarrasser de toutes les subtilités du langage C# et VB et autres joyeusetés et "bas" tout en un langage simple qui est facile à écrire un jitter pour.

Avoir un langage intermédiaire abaisse le coût de production d'un nouveau compilateur de langage de façon spectaculaire. Il réduit également le coût de l'appui de une nouvelle puce de façon spectaculaire. Vous souhaitez soutenir une nouvelle puce, vous trouverez certains des experts sur cette puce et demandez-leur d'écrire un CIL de la gigue et vous avez terminé; vous, alors en charge toutes les langues sur votre carte à puce.

OK, nous avons donc établi pourquoi nous avons MSIL; car le fait d'avoir un langage intermédiaire permet de réduire les coûts. Pourquoi, alors, est la langue d'une pile "machine"?

Parce que la pile machines sont conceptuellement très simple pour le compilateur de langage écrivains à traiter. Les piles sont simples, faciles à comprendre mécanisme pour décrire les calculs. Pile machines sont aussi conceptuellement très facile pour le compilateur JIT écrivains à traiter. À l'aide d'une pile est une simplification de l'abstraction, et, par conséquent, encore une fois, il contribue à réduire nos coûts.

Vous demandez: "pourquoi une pile?" Pourquoi ne pas tout faire directement à partir de la mémoire? Eh bien, nous allons y réfléchir. Supposons que vous souhaitez générer du code CIL pour:

int x = A() + B() + C() + 10;

Supposons que nous avons la convention que "ajouter", "appel", "magasin", et ainsi de suite toujours prendre leurs arguments en dehors de la pile et de mettre leur résultat (si il y en a un) sur la pile. Pour générer du code CIL pour cette C# que nous venons de dire quelque chose comme:

load the address of x // The stack now contains address of x
call A()              // The stack contains address of x and result of A()
call B()              // Address of x, result of A(), result of B()
add                   // Address of x, result of A() + B()
call C()              // Address of x, result of A() + B(), result of C()
add                   // Address of x, result of A() + B() + C()
load 10               // Address of x, result of A() + B() + C(), 10
add                   // Address of x, result of A() + B() + C() + 10
store in address      // The result is now stored in x, and the stack is empty.

Supposons maintenant que nous l'avons fait sans une pile. Nous allons le faire à votre façon, où chaque opcode prend les adresses de ses opérandes et l'adresse à laquelle il stocke ses résultats:

Allocate temporary store T1 for result of A()
Call A() with the address of T1
Allocate temporary store T2 for result of B()
Call B() with the address of T2
Allocate temporary store T3 for the result of the first addition
Add contents of T1 to T2, then store the result into the address of T3
Allocate temporary store T4 for the result of C()
Call C() with the address of T4
Allocate temporary store T5 for result of the second addition
...

Vous voyez comment ça se passe? Notre code devient énorme parce que nous avons explicitement attribuer la totalité de l'entreposage temporaire qui serait normalement par convention, il suffit d'aller sur la pile. Pire, nos opérateurs eux-mêmes sont tous énormes, car ils sont maintenant tous de prendre comme argument l'adresse qu'ils vont écrire leur résultat, et l'adresse de chaque opérande. Une "ajouter" de l'enseignement qui sait qu'il va prendre deux choses en dehors de la pile et de mettre une chose sur peut être un seul octet. Un complément d'instruction qui prend deux opérandes adresses et un résultat d'adresses va être énorme.

Nous utilisons en fonction de pile opcodes parce que les piles de résoudre le problème commun. À savoir: je veux allouer du stockage temporaire, l'utiliser très rapidement et ensuite se débarrasser de lui rapidement quand je suis fait. En faisant l'hypothèse que nous avons une cheminée à notre disposition, nous pouvons faire les opcodes très petite et le code très laconique.

Mise à JOUR: Quelques réflexions supplémentaires

D'ailleurs, cette idée d'une baisse drastique des coûts par (1) spécifiant une machine virtuelle, (2) l'écriture de compilateurs qui cible la VM de la langue, et (3) la rédaction des implémentations de la machine virtuelle sur une variété de matériel, n'est pas une idée nouvelle. Il n'est pas né avec MSIL, LLVM, le bytecode Java, ou toutes autres infrastructures modernes. La première mise en œuvre de cette stratégie, je suis conscient de est le code postal de la machine à partir de 1966.

La première que j'ai personnellement entendu parler de ce concept a été quand j'ai appris comment l'Infocom réalisateurs réussi à obtenir Zork cours d'exécution sur beaucoup de machines différentes, si bien. Ils ont spécifié une machine virtuelle appelée la Z-machine, puis mis à la Z-machine émulateurs pour tout le matériel qu'ils voulaient exécuter leurs jeux sur. Cela a eu l'ajout d'énormes bénéfices qu'ils pourraient mettre en œuvre une gestion de mémoire virtuelle sur les primitives 8-bits des systèmes; un jeu qui pourrait être plus grand que ne le fit dans la mémoire, car ils pourraient tout page le code à partir du disque quand ils en ont besoin et de les jeter quand ils avaient besoin de charger le nouveau code.

86voto

Hans Passant Points 475940

Gardez à l'esprit que lorsque l'on parle de MSIL ensuite vous parlez des instructions pour une virtual machine. La machine virtuelle utilisée .NET est une pile en fonction de la machine virtuelle. Par opposition à un registre VM, le Dalvik VM utilisée dans les systèmes d'exploitation Android en est un exemple.

La pile dans la VM est virtuel, c'est à l'interprète ou le juste-à-temps compilateur pour traduire la VM instructions dans le code qui s'exécute sur le processeur. Qui, dans le cas d' .NET est presque toujours une gigue, la MSIL jeu d'instructions a été conçu pour être jitted de l'aller. Contrairement à Java bytecode par exemple, il comporte des instructions pour les opérations sur des types de données spécifiques. Ce qui le rend optimisé pour être interprété. Un MSIL interprète existe réellement, il est utilisé dans le .NET Micro Framework. Qui s'exécute sur des processeurs avec des ressources très limitées, ne peut pas se permettre d'acheter de la mémoire vive nécessaire pour stocker le code machine.

La machine réelle, code de modèle est mixte, ayant à la fois une pile et les registres. Le gros travail de l'équipe de code optimizer est de trouver des moyens pour stocker des variables qui se trouvent sur la pile dans les registres, ainsi, d'améliorer considérablement la vitesse d'exécution. Un Dalvik gigue a le problème inverse.

La machine de la pile est par ailleurs un très de base installation de stockage qui a été autour du processeur, des dessins pour un temps très long. Il a un très bon localité de référence, une caractéristique très importante sur les processeurs modernes qui percent à travers les données beaucoup plus rapide que la RAM peut le fournir, et prend en charge la récursivité. Le langage de conception est fortement influencée par le fait d'avoir une pile, visible à l'appui pour les variables locales et la portée limitée pour le corps de la méthode. Un problème important avec la pile est celle que ce site est nommé pour.

8voto

skyman Points 437

Pour ajouter un peu plus à la pile en question. Le concept de pile dérive de CPU design, où le code de l'ordinateur dans l'unité arithmétique et logique (ALU) opère sur des opérandes qui sont situés sur la pile. Par exemple, une multiplication opération peut prendre les deux opérandes de la pile, multiples et placer le résultat sur la pile. Langage Machine a généralement deux fonctions de base pour ajouter et supprimer des opérandes de la pile; PUSH et POP. Dans de nombreux processeurs dsp (processeur de signal numérique) et de contrôleurs de machines (telles que le contrôle d'une machine à laver) la pile est situé sur la puce elle-même. Cela donne un accès plus rapide à l'ALU et consolide les fonctionnalités dans une seule puce.

5voto

Azodious Points 8187

Si le concept de pile/tas n’est pas respectée et les données sont chargées à l’emplacement de la mémoire vive ou les données sont stockées à partir d’emplacements mémoire aléatoire... ça va être très structurées et non managé.

Ces concepts sont utilisés pour stocker des données dans une structure prédéfinie pour améliorer les performances, l’utilisation de la mémoire... et par conséquent appelés des structures de données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X