La majorité des informations techniques sur l'architecture et l'approche du système GHC se trouve dans leur wiki. Je vais créer des liens vers les éléments clés, ainsi que vers des documents connexes que les gens ne connaissent peut-être pas.
Quelles optimisations typiques sont appliquées ?
Le document clé à ce sujet est : Un optimiseur basé sur la transformation pour Haskell , SL Peyton Jones et A Santos, 1998, qui décrit le modèle utilisé par GHC pour appliquer des transformations préservant les types (refactorings) d'un langage de base de type Haskell pour améliorer le temps et l'utilisation de la mémoire. Ce processus est appelé "simplification".
Les opérations typiques d'un compilateur Haskell sont les suivantes :
- Inlining ;
- Réduction du bêta ;
- Élimination des codes morts ;
- Transformation des conditions : cas d'espèce, élimination des cas.
- Unboxing ;
- Retour du produit construit ;
- Transformation totale de la paresse ;
- Spécialisation ;
- Expansion d'Eta ;
- Levage de lambda ;
- Analyse de la rigueur.
Et parfois :
- La transformation de l'argument statique ;
- Construction/foldr ou fusion de flux ;
- Élimination des sous-expressions communes ;
- Spécialisation du constructeur.
Le document susmentionné est le point de départ essentiel pour comprendre la plupart de ces optimisations. Certaines des optimisations les plus simples sont données dans le livre précédent, Mise en œuvre des langages fonctionnels Simon Peyton Jones et David Lester.
Quel est l'ordre d'exécution lorsqu'il y a plusieurs candidats à évaluer ?
En supposant que vous êtes sur un uni-processeur, alors la réponse est "un ordre que le compilateur choisit statiquement en se basant sur l'heuristique et le modèle de demande du programme". Si vous utilisez l'évaluation spéculative par le biais de sparks, alors "un certain modèle d'exécution non déterministe, hors de l'ordre".
En général, pour savoir quel est l'ordre d'exécution, il faut regarder le noyau, avec, par exemple, l'élément ghc-core outil. Un site introduction à Core se trouve dans le chapitre de RWH sur les optimisations.
Comment les thunks sont-ils représentés ?
Les thunks sont représentés comme des données allouées au tas avec un pointeur de code.
Véase la disposition des objets du tas . Plus précisément, voir comment les thunks sont représentés .
Comment sont utilisés la pile et le tas ?
Tel que déterminé par la conception de la G-machine sans étiquette et sans spin. plus précisément, avec de nombreuses modifications depuis la publication de cet article. En gros, le modèle d'exécution :
- Les objets (encadrés) sont alloués sur le tas global ;
- cada l'objet thread a une pile qui consiste en des cadres ayant la même disposition que les objets du tas ;
- lorsque vous faites un appel de fonction, vous poussez les valeurs sur la pile et sautez à la fonction ;
- si le code doit allouer, par exemple, un constructeur, ces données sont placées sur le tas.
Pour comprendre en profondeur le modèle d'utilisation de la pile, voir "Pousser/Entrer versus Eval/Appliquer" .
Qu'est-ce qu'un CAF ?
Une "forme applicative constante". Par exemple, une constante de haut niveau dans votre programme, allouée pour toute la durée de l'exécution de votre programme. Puisqu'elles sont allouées de manière statique, elles doivent être traités spécialement par le ramasseur de déchets .
Références et lectures complémentaires :