• [^] # Supprimer la VFT

    Posté par (site web personnel) . En réponse à la dépêche 23 mars: Conférence au LORIA sur Lisaac, un nouveau langage. Évalué à 4.

    On se place dans un contexte où l'on compile l'ensemble du code disponible. Le compilateur peut analyser l'ensemble de celui-ci et donc transformer ce code objet en un code procédural, c'est ce que fait Lisaac.
    Tu peux aussi, avec le compilateur compiler des "macro-objets", c'est à dire que tu as un code procédural (un fichier C avec plein de fonctions dedans et un .h associé), et tu utiliseras (c'est le cas d'IsaacOS) de la liaison dynamique pour communiquer entre objet.
    (Bien qu'on ai imaginé Benoit et moi un mécanisme tordu de table dichotomique à trou qui se rempliraient une fois les objets installés en mémoire...)

    Prenons un exemple.
    Soit une classe/prototype IMAGE et ses descendants BMP et JPG. Soit une méthode affiche_toi() définie comme virtuelle dans IMAGE, mais contenant du code dans BMP et IMG.
    Soit image une variable de type BMP ou JPG.

    1/Dans le monde à classe (Eiffel, donc), on effectue une analyse syntaxique (ou une analyse de flot) du code pour créer des procédure contextualisant le polymorphisme.
    C'est à dire que le compilateur SmartEiffel va produire en C
    BMP_affiche_toi()
    JPG_affiche_toi()

    et il colle un test du genre si besoin :
    if (image->type == BMP) {
    affiche_toi_BMP();
    } else { // C'est du JPEG
    affiche_toi_JPEG();
    };

    Tandis qu'avec une VFT, image est un pointeur sur la structure :
    (là imagine que C++ produise du C)

    struct Image_jpg
    {
    //données
    void *affiche_toi();
    };

    et

    struct Image_bmp
    {
    //données
    void *affiche_toi();
    };


    donc si la variable (l'instance dans le monde objet) image est de type BMP, on a
    Image_bmp *image;
    Et un appel de la fonction se fait
    image->affiche_toi();

    La compilation de l'Eiffel est pas trop problématique car c'est un langage à classe, donc ta variable image est soit de type BMP ou soit de type JPG. Il suffit de lire le code et d'appeler la bonne fonction.

    Seulement ni C++ qui fait de la VFT, ni Eiffel qui fait du procédural ne produise que la fonction qui va être utilisée.
    Même si tu as un code du genre

    private BMP image;
    image.set_image(mon_bitmap); //on lui balance le tableau d'octets
    image.affiche_toi();

    C++ va te pondre les deux structures décrites plus haut et va te faire un appel dans la VFT.
    Eiffel, il me semble (je ne suis pas sûr) va faire de même, mais en procédural lui, donc sans vider le cache code du processeur, ce qui coute très cher et en pouvant faire des inlines, etc....

    2/Dans le monde à prototype, le problème est beaucoup plus ardu parce tu as l'héritage dynamique.
    Donc là tu renverse ton arbre d'héritage.
    Tu vas avoir IMAGE qui va hériter, soit de JPG ou soit de BMP
    Tu auras dans le code :

    - name := IMAGE;
    Section INHERIT
    - parent choix : BOOLEAN : OBJECT <-
    (
    + result : OBJECT;
    choix.if {result := JPG;}
    else
    {result := BMP;};
    result
    );

    Il suffit que tu en enchaine qq uns comme ça et ça explose vite...
    Donc là on est obligé de faire de l'analyse de flot : il faut recencer le code vivant, autrement dit, calculer quels sont les possibilités que tu vas utiliser pour virer les autres.

    Le compilateur recence donc le code vivant, spécialise les appels (s'ils se rend compte que tu n'utilise jamais BMP.affiche_toi; il ne la compile pas) et inline au besoin.

    Mais je le répète, ce n'est possible que si le compilateur dispose de l'ensemble du code sous la main.
    Sinon, tu es obligé de faire de la VFT ou de la table dichotomique à trou, c'est à dire à du code asm auto-écrit, et là ça part un peu en live.

    Les contrats c'est pareil, ils sont compilés, backpropagés, etc...

    Pour finir, je cite Benoit, dans un mail qu'il m'a écrit il y a un an et demi pour m'expliquer ça (et dont je me suis largement inspiré) :
    "
    Le pb est que C++ n' est pas capable d'analyser suffisemment son code pour
    savoir si il y a un ou plusieurs type possible pour un site d'appel.
    Consequence: Tous les appels sur les objets sont realise' par la technique
    decrite en 4)[ie. la VFT]. Alors que, dans la pratique, il n' est pas rare que le type
    soit unique et que donc, l'appel peut etre direct (statique).
    Dans un langage comme C++, tout n' est pas objet, donc 2+2 n' est pas
    un appel du type 2.plus(2) (le message "plus" sur l' objet 2) donc sa technique
    reste lente mais viable. En Lisaac, 2+2 est un appel sur objet, si nous
    utilisions la technique de C++, les perfs serait tout bonnement catastrophique!
    Ici, le compilo detecte sans mal qu'il n'y a qu'un seul type dynamique
    possible, l'appel est direct et statique sur la methode "plus" de NUMERIC.
    Cette methode sera ensuite inline', et nous retomberons sur un 2+2 aussi
    efficace que C.
    Meme dans le cas de site reellement polymorphique (plusieurs type dynamique
    possible), il est preferable de realiser des branchements avec des appels
    statique.
    Exemple:
    if (image->type == BMP) {
    affiche_toi_BMP();
    } else { // C'est du JPEG
    affiche_toi_JPEG();
    };
    Les appels statiques ainsi produit peuvent ensuite etre inline', specialise',
    ... Et les caches du processeurs ne sont pas vide' (meme dans le cas de
    multiple branchement, le pipeline execute les differentes branches en meme
    temps et choisi les effets de bord de la bonne branche apres evaluation
    de la conditionnelle).

    Donc, la ou C++ realise un appel indirect (considere' comme liaison dynamique),
    le compilo Lisaac produit ou un appel statique (84%) ou plusieurs branches
    avec des appels statiques (16%).
    Ce score est passe' a 91% en produisant des methodes plus specialise' selon
    le contexte courant d'appel. Nous produisons plusieurs exemplaires d'une
    methode. Chaque exemplaire etant specialise' a un contexte d'appel et donc
    plus rapide (moins de types dynamiques possible dans ce contexte d'appel plus
    precis)."

    « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker