• [^] # Re: Surprise

    Posté par (site web personnel) . En réponse au journal Lisaac: sorti de la 0.39beta. Évalué à 3.

    ca n'empeche pas que ce sont des approches tres differentes
    la seule et unique différence, c'est que le compilateur JIT travail "en live" quand le compilateur classique (AOT) travail en amont. Mais le travail effectué est absoluement identique !
    D'ailleur la commande AOT de mono qui permet d'obtenir un binaire exécutable n'est rien d'autre que l'appel vers le moteur JIT en lui disant que tout doit être compilé là maintenant tout de suite.

    Ce que tu appels un "énorme" bout de code pour transformer en code natif, tu le retrouves pareil dans GCC comme l'a très bien expliqué beafg.
    GCC est basé sur un frontend et un backend avec au milieu un langage intermédiaire qui est tout comme un bytecode : une représentation qui fait abstraction des spécificités de la machine cible, le backend se chargeant de traduire dans le code machine cible.
    Il n'y a donc fondamentalement pas de différence entre GCC et le compilateur C#+compilateur mono.

    Je sais tres bien que mettre du code interprete en cache n'est pas du jit, mais s'il ya cache, c'est qu'il ya une forme de compilation, non?
    Un interpréteur ne met rien en cache, il interprête !
    Un interpréteur c'est ça :
    while(true)
    var instruction = analyse_instruction_suivante(input)
    switch(instruction.type)
    case "add" : locale[instruction.res] = intruction.left + instruction.right
    case "mul" : locale[instrction.res] = instruction.left * instruction.right
    etc.

    Bref, une boucle infini qui analyse chaque instruction et exécute l'action correspondante, il n'est pas possible de mettre de code en cache, tout ce que tu peux mettre en cache c'est l'analyse. Tu seras toujours obligé de te taper en "live" le switch, bref le code qui s'exécute c'est celui de l'interpréteur.

    Tout l'inverse d'un compilateur, qui lui joue plutôt comme ca :
    foreach(instr in extractInstructions(source))
    switch(instruction.type)
    case "add" : exe.append(tranlateAddToX86(instr));
    case "mul" : exe.append(translateMulToX86(instr));

    Un compilateur JIT ne fait ni plus ni moins la même chose, sauf qu'au lieu d'écrire le résultat dans un binaire, il l'écrit dans un cache et l'exécute.

    L'interpréteur a un seul intérêt : il est extrêment simple et ne nécessite pas de connaître le langage machine sur lequel il tourne (forcement il n'en produit pas), il suffit juste que l'interpréteur soit lui même écrit dans un langage portable pour que le langage interprété le soit également.
    Le compilateur en revanche, cherche à éviter à tout prix la phase d'interprétation coûteuse (le switch voir l'analyse) en effectuant une traduction en code machine. C'est beaucoup plus complexe, et c'est ce que font .NET et GCC.

    Les frontieres sont extremements floues dans ce domaine
    Elles sont floues dans ta tête :) Ce sont 2 techniques totalement différentes sans rapport, si ce n'est leur but.

    mais tu ne m'enleveras pas de l'idee est que chaque langage vient avec une philosophie
    certes.

    Et cette philosophie inclue la chaine de compilation, interprete, bytecode ou natif pur.
    Pour moi non :
    Python a d'abort été un langage interprété, puis est apparu un moteur JIT.
    JavaScript a subit la même destinée. Java également.
    .NET marche avec un compilateur AOT ou un compilateur JIT mais peut aussi être interprété.
    Tu peux coller GCC en sortie de mono. Tu peux coller mono en sortie de GCC.
    Pour moi la phylosophie d'un langage c'est d'autres caractéristiques : typage fort, dynamique, syntaxe, prototype, objet,etc.
    Après ses caractéristiques peut le rendre plus ou moins facilement compilable, c'est un fait.

    Et ca inclue aussi le runtime de base du langage, et le fait de savoir si on peut faire confiance a une couche en dessous, qui va verifier que tu ne dereference pas un pointeur null, que t'as acces a tel api d'ecriture sur le disque qui va verifier tes droits et tout ce genre de connerie, couche qui s'appelle une VM, verifie la signature du code, que la version de la lib est la bonne etc.
    Là encore, tu confonds plusieurs choses : runtime et VM.
    Une VM, ce n'est ni plus ni moins qu'un ensemble d'instruction "virtuelles", un processeur virtuel. C'est la représentation intermédiaire pour le frontend GCC, c'est le C89 pour Lisaac, c'est le bytecode pour le compilateur Java, etc.
    Le runtime, c'est l'ensemble des services/code nécessaires à l'exécution pour rendre concrêtement la sémantique du langage pour lequel il est prévu.
    Le C a un runtime minimaliste, le C++ en a déjà plus élaboré (pour les exceptions ainsi que pour la vérification de type, optionnel), Java en a un beaucoup plus gros parcqu'il offre de nombreux services.

    Tu peux très bien compiler du code C# en code natif qui embarque le runtime (c'est ce que propose mono pour développer sur iPhone grâce à l'AOT), comme le fait le compilateur C++ qui est linké avec le runtime C++. C'est strictement identique, les étapes sont les mêmes, le service "validation" de l'AppleStore n'y voit que du feu : c'est du code natif et rien n'est généré dynamiquement.

    De meme pour les "libs" d'aop qui fonctionnent en manipulant en temps reel le bytecode
    Ce sont des libs, pas le langage. Les libs n'ont qu'à pas faire trop de supposition sur le code qui s'exécute. Le contrat, c'est la VM, rien n'indique que le bytecode est disponible sous la forme de donnée à l'exécution.

    Lisaac qui est designe pour etre execute de facon native.
    On est d'accord, Lisaac peut être conçu pour être utilisé d'une certaine façon. En l'occurrence Lisaac a été conçu pour être compilé en targetant la VM C89 de GCC.
    Idem pour JSCript.NET, il a été conçu philosophiquement pour targeter la VM CLI de .NET en reprenant la syntaxe ECMAJavascript.
    GCC comme .NET propose la compilation en code natif, c'est strictement identique, à la différence que .NET propose la souplesse de le faire en amont (comme GCC) ou en live.