L’assembleur du Web

(Merci à Nicolas B. Pierron et Goofy pour les relectures)

asm.js est un projet de recherche de Mozilla qui vise à améliorer les performances de JavaScript en n’utilisant qu’un sous-ensemble du langage, plus facile à optimiser.

Il se compose de plusieurs sous-projets :

  • la spécification du langage ;
  • OdinMonkey, un module de l’interpréteur JavaScript SpiderMonkey, qui prend en charge le code asm.js ;
  • des travaux sur emscripten pour que le code généré soit conforme à la spécification asm.js ;

Asm.js

La spécification ne conserve qu’un sous-ensemble strict d’EcmaScript, respectant certaines règles. Ce n’est donc pas, à la différence de CoffeeScript ou TypeScript par exemple, un nouveau langage. Le code asm.js est du JavaScript valide qui peut s’exécuter dans tous les navigateurs récents.

Parmi les exemples d’optimisation, asm.js s’assure que les variables ne changent pas de type. Le code inclut des indications sur le type des variables, afin que l’interpréteur n’ait pas à le deviner. Le langage permet également une meilleure utilisation de la mémoire, limitant les ralentissements causés par le garbage collector (le code asm.js utilise des tableaux typés (typed arrays) comme pile pour certaines opérations).

Pour indiquer à l’interpréteur JS que le code respecte la spécification et peut être optimisé, il suffit d’ajouter une nouvelle directive "use asm" de syntaxe similaire au "use strict". Si l’interpréteur ne reconnait pas cette directive, il l’ignorera et interprètera le code normalement. Sinon, il validera que le code respecte bien la norme, et si oui, l’exécutera de façon optimisée.

OdinMonkey

OdinMonkey va bientôt être intégré au tronc de SpiderMonkey. Les performances semblent intéressantes, puisque du code C++ compilé via Emscripten puis interprété par OdinMonkey ne s’exécute que deux fois plus lentement que lorsqu’il est compilé avec gcc. Ce sont des performances similaires à celles de langages utilisant une machine virtuelle, comme Java ou C#.

Emscripten

Emscripten est un compilateur qui traduit en JavaScript du bytecode LLVM obtenu à partir de source en C ou C++. Il permet donc de porter des programmes écrits en C ou C++ pour les exécuter dans un interpréteur JavaScript. À titre d’exemple, un portage de la bibliothèque de composants graphiques multi-plateformes Qt est en cours, qui permet d’exécuter des applications « natives » écrites pour Qt dans un navigateur, la balise canvas étant utilisée pour l’affichage. Pour tester les possibilités d’asm.js en matière de jeux, un portage du jeu de tir en vue subjective Cube 2: Sauerbraten a été entrepris.

D’autres expériences visent à porter les interpréteurs de divers langages. Repl.it propose d’exécuter directement dans le navigateur, après conversion en JavaScript, des programmes écrits en Ruby, Python, Lua, Scheme

L’assembleur du Web

Plus que les implications en terme de performance, l’intérêt d’asm.js est qu’il permet de faire un pas de plus vers le Web comme plate-forme applicative, dont les navigateurs seront le système d’exploitation. D’ici quelques années, il sera possible de faire fonctionner n’importe quel code, quel que soit le langage dans lequel il a été écrit, dans un navigateur.

Bien sûr, il faut raison garder. Il n’y a pas grand-chose de neuf sous le soleil. Le portage d’applications natives vers le navigateur est une vieille lune. Java promettait cela il y a 15 ans, avec le succès que l’on sait. GWT permet depuis des années de compiler d’autres langages en JS, et je n’ai pas l’impression qu’il soit très utilisé hors de Google. Je ne crois guère que des applications entières seront portées directement en JS. Mais je pense que cela va accroitre la perméabilité entre les environnements frontend et backend. Avec SpiderMonkey et node, du code JS écrit pour le navigateur pouvait s’exécuter sur le serveur. Bientôt, toute bibliothèque “serveur” pourra s’exécuter dans le navigateur. On pourra ainsi réellement partager du code, l’écrire dans son langage de prédilection et l’exécuter selon le contexte dans le navigateur ou sur un serveur.

Quelques liens

Reconstruire une toile

Karl nous incitait récemment à renforcer le caractère hypermédia de nos publications sur le Web en utilisant notamment l’attribut rel qui permet de qualifier un lien.

David disait hier à peu près qu’un souci avec nos carnets est que le mécanisme actuel de commentaires sous les billets transforme ce qui devrait être une énorme fourmilière parsemée de couloirs en maisons individuelles isolées..

Actuellement, je vois essentiellement l’attribut rel utilisé pour gérer la pagination à l’intérieur des carnets. Indiquer aux robots (moteurs de recherche ou fonctionnalité d’aide à la navigation dans le navigateur) les premiers et derniers billets, le précédent et le suivant. Mais ce ne sont pas forcément les liens les plus pertinents sur une page. Lorsque je lis le billet de David, m’intéresse davantage le contexte que la liste des autres publications sur d’autres sujets dans son carnet. Un robot devrait pouvoir détecter à qui répond ce billet, quelles sont les autres réponses, et les billets qui eux-même y répondent (feu nos trackbacks). Il suffirait que l’auteur ajoute manuellement ces références à son article. On pourrait ainsi extraire une carte affichant le billet dans son contexte, une visualisation de la conversation.

Malheureusement, je n’ai pas trouvé de valeur de rel signifiant « répond à », « complète » ou « a suscité cette réaction ». De telles relations existent dans certains vocabulaires (par exemple references et isReferencedBy en Dublin Core) mais cela nécessite probablement d’utiliser RDFa Lite ou les micro-données HTML5, donc une chaîne de publication plus lourde. À moins que… Le Dublin Core a proposé d’utiliser son vocabulaire dans des rel (ce que je fais d’ailleurs ici-bas), mais ça ne semble pas normalisée. La syntaxe serait <a rel="dct:references">…</a> (pour autant que la proposition concerne aussi les balises A et non uniquement les LINK).

Mais puisque la discussion sur le sujet des commentaires reprend, pourquoi ne pas réfléchir à pousser à la normalisation de la proposition du DC, ou à proposer de nouvelles valeurs pour rel ?

Note personnelle : ce carnet est actuellement rédigé en Markdown et converti en HTML avec Maruku. Maruku implémente une extension de Markdown qui permet d’ajouter des attributs aux éléments :

This is [a link][ref]{:#myid rel=abc rev=abc}

Je pourrais donc rajouter les attributs rel directement dans mon Markdown. Mais malheureusement je crois que Maruku est le seul interpréteur Markdown à implémenter cette extension, cela lierait donc mes billets à un logiciel (et les enfermerait dans un format non standard).

L'écrivaillon qui rêvait de cathédrales

Je me demande si j’aime la direction dans laquelle va le Web.

Je me suis récemment amusé à une de mes vieilles marottes, ajouter de la sémantique sur ce site. L’occasion de constater une fois de plus l’état navrant du Web Sémantique :

  • il y a actuellement deux spécifications qui font pratiquement la même chose, RDFa Lite et les micro-données HTML5. Aucune ne semble prendre le dessus, il faut donc si on veut être exhaustif ajouter au code les attributs des deux (et des micro-formats pour faire bonne mesure). C’est peu lisible (cf la bouillie du code source de cette page)) et encore moins maintenable ;
  • bien peu d’outils existent, comme le souligne Karl, pour ne serait-ce que valider le code. Ne parlons même pas de consommer ces méta-données ;

Bien sûr, en cherchant et tâtonnant un peu, on y arrive, mais c’est laborieux, et il faut vraiment comme moi préférer affûter ses outils que s’en servir pour se donner la peine d’ajouter ces informations sémantiques.

On est en 2013, et le Web Sémantique reste toujours un rêve de chercheurs et un joujou pour geeks snobinards. Pratiquement rien n’a changé depuis que j’ai commencé à m’y intéresser il y huit ans. Quelle différence avec le chemin parcouru par le Web Applicatif. Jadis, deux visions du Web se sont affrontées. XHTML 2 vs HTML5. Le Web des données contre le Web des applications. Ceux qui voulaient que la toile SOIT une gigantesque base de toutes les connaissances que l’on pourrait interroger contre ceux qui voulaient l’utiliser comme fondation pour FAIRE. Être et faire, toujours. Le résultat est connu depuis longtemps, les pragmatiques l’ont emporté.

J’ai toujours eu le cul entre deux chaises. Je préfère savoir plutôt que faire, suis persuadé que le savoir est la condition sine qua non de l’action. Pratique excuse à mon immobilisme. Les promesses du Web des données me faisaient donc rêver. Construire une cathédrale dédiée au savoir. Mais je m’intéresse aussi à la liberté, et à tout ce qui nous donne les moyens concrets d’être plus libre, plus autonome. Et le Web des applications constitue de ce point de vue une formidable opportunité. Internet et le Web sont une des plate-formes les plus ouvertes qui soit. Les outils bâtis au-dessus embarquent par défaut cette ouverture dans leur ADN (ça n’est bien sûr pas une garantie, les contre-exemples sont légions, mais l’ouverture est une possibilité native). J’ai donc soutenu avec enthousiasme la croissance de ce Web, et l’arrivée de FirefoxOS est une étape très importante dans l’histoire du Web Applicatif, une chance de prouver que le pari original était le bon, que le Web est une plate-forme applicative sérieuse. Mais une étape c’est aussi l’occasion de faire une pause et de regarder dans le rétroviseur. Et de constater que cette évolution s’est aussi faite au détriment de mon cher Web Sémantique.

Le constat de cet échec à se concrétiser des promesses du Web Sémantique donne un goût un peu amer à la victoire en cours du Web Applicatif. Samedi prochain, je tâcherai de passer à l’App Day parisien. Mais, hormis fêter FirefoxOS, je me demande ce que j’y ferai. Après tout, je ne suis pas un menuisier numérique, juste un petit écrivaillon qui rêve de cathédrales.

Affûter ses outils

Lu dans CQFD, cet extrait :

(…) la formule du groupe Sex Pistols « Don’t know what I want, but I know how to get it » (…) résume parfaitement la posture de l’humanité moderne qui, à défaut de savoir ce qu’elle veut, se consacre sans répit à la multiplication et au perfectionnement des moyens dont elle dispose (en ce sens, les scientifiques et les ingénieurs seraient des punks nihilistes).(…)

Cette citation devrait je crois être inscrite au fronton des salles où nous faisons nos réunions TupperVim. Je n’ai aucune idée de ce que je veux. Mais j’affute sans cesse ma pratique de mes outils.

Ça m’a rappelé ce brouillon commencé il y a quelques mois et que j’avais oublié de mettre en ligne. Oubli réparé :

Je prends peu à peu conscience que Notepad est un bien meilleur éditeur de texte que Vim.

Qu’est-ce qu’un éditeur de texte ? Un outil pour écrire de la poésie, en prose ou en code, peu importe. Il doit donc non seulement aider à écrire, mais aussi protéger contre tout ce qui éloigne de l’écriture. Notepad n’a aucune fonctionnalité, aucune option. On ne peut rien y faire d’autre qu’écrire. Vim au contraire est un rêve pour qui comme moi cherche à retarder au maximum le moment fatidique où il faut se lancer. J’ouvre un fichier vierge, et avant même d’avoir commencé à taper je me dis que mon éditeur serait bien plus efficient avec tel nouveau raccourci clavier, ou si je modifiais légèrement la coloration syntaxique, rajoutais une information capitale à la barre de statut… Voilà, j’ai trouvé une excuse pour retarder le moment de me lancer.

Mais pourquoi chercher des excuses pour ne pas me livrer à ce que je prétends depuis toujours être mon activité favorite ? Probablement parce que, comme l’a si bien formulé Desproges, il vaut mieux se taire et passer pour un con plutôt que de parler et ne laisser aucun doute à ce sujet.. Pour rester dans cette seconde de suspension juste avant de se jeter à l’eau. Lorsque le pianiste lève les mains au dessus du clavier et une dernière fois se concentre, lorsque le peintre prend son pinceau et réfléchit avant de poser la première touche. Un instant d’incertitude. Le concert, le tableau seront-t-ils beaux ? Tout est ouvert, possible. À la première fausse note, au premier gribouillis, le doute vole et la sinistre réalité s’impose.

Me mettre à écrire, c’est avouer au monde mon manque de talent pour la programmation. C’est fournir des preuves. Mettre enfin un terme à l’arnaque que j’entretiens depuis si longtemps. Je m’accroche donc à tous les prétextes possibles. J’apprends une nouvelle techno. Ou peaufine mon environnement de travail pour que lorsqu’enfin je me lancerai rien ne vienne entraver le flot. Foutaises, je sais bien que je ne me lancerai jamais.

Je dis souvent que je souhaite que mon .vimrc soit gravé sur ma pierre tombale. Ce n’est qu’une demi-boutade. De mes dépôts sur Github, c’est le plus actif. Et cela restera sans doute ma principale œuvre. Toute sa vie, il a affûté sa plume. Il ne s’en sera jamais servie.

Vim est un excellent éditeur. Mais pour les procrastineurs chroniques comme moi, Notepad serait probablement un bien meilleur outil, qui m’obligerait à trouver d’autres excuses. Ou à m’essayer à l’écriture.

post-scriptum : c’est en m’interrogeant sur d’autres outils, les organisations, que je me suis fait cette réflexion. Une organisation, que ce soit Mozilla, un syndicat, une association, une orga politique, etc, n’est qu’un outil au service d’une cause. Pourtant, beaucoup de gens consacrent l’essentiel de leur énergie à l’édification de l’organisation, bien plus qu’à la promotion de la cause elle-même. Et je me demande si ça ne serait pas par crainte de se mettre au boulot. À creuser.

VimTip : complétion JavaScript

Lorsque je code en JavaScript avec node.js ou le couple PhantomJs / CasperJS, l’auto-complétion native de Vim pour JS me laisse un peu sur ma faim. Plusieurs moyens de l’améliorer sont évidemment possibles :

  • utiliser doctorjs / jsctags pour créer des fichiers de mots clés (tags). Malheureusement, mes essais avec jsctags ont rarement été concluants. Je n’arrive par exemple pas à extraire les mots-clés de CasperJS ;

  • utiliser des extensions spécifiques comme :

    • jscomplete-vim qui prétend ajouter un meilleur support de la syntaxe native du langage ;
    • vim-node-jscomplete qui permet entre autre la complétion sur les modules de l’API native de Node (l’API est générée dynamiquement à partir de la documentation en ligne).

Aucune de ces méthodes ne me satisfaisant vraiment, j’ai décidé d’en tester une autre, via la complétion de mots-clés. Vim dispose en effet de plusieurs types de complétion. La plus « intelligente » est théoriquement l’Omni Completion, activée par Ctrl-X Ctrl-O. Elle est spécifique à chaque type de fichier et utilise des fonctions censées interpréter le langage. D’autres complétions utilisent des listes de mots clés, extraits d’un fichier spécifique (Ctrl-X Ctrl-] pour le fichier tags, Ctrl-X Ctrl-K pour un dictionnaire, Ctrl-X Ctrl-T pour un thesaurus, ne me demandez pas la différence entre ces derniers), ou du fichier courant (Ctrl-X Ctrl-N), voire de celui-ci et des fichiers qu’il inclut -Ctrl-X Ctrl-I). C’est sur cette dernière que je me suis penché.

Pour déterminer la liste les fichiers inclus à analyser, Vim utilise plusieurs variables définies dans la configuration :

  • include : une expression régulière pour extraire d’un fichier les noms des fichiers inclus. La valeur par défaut est adaptée au C et au C++, pour les require des modules CommonJs j’utilise set include=require(.\\zs[^'\"]*\\ze (dans une expression rationnelles Vim, \zs et \ze permettent de délimiter à l’intérieur du motif la portion à retourner) ;
  • includeexpr : une fonction qui permet de transformer le résultat de l’expression régulière précédente en nom de fichier. Par exemple, en Java, pour transformer les . dans les noms de classes en /. Souvent avec Node.js, on utilise require('toto'), toto étant le nom du dossier contenant le module. À l’intérieur de ce dossier, un fichier index.js inclut les fichiers nécessaires, alors que n’existe nul toto.js. includeexpr permet de gérer ces cas en essayant d’ajouter /index.js au chemin du fichier requis ;
  • suffixesadd : une liste de suffixes à ajouter aux noms précédents si les fichiers n’existent pas. Dans notre cas : set suffixesadd=.js ;
  • path est une liste de dossiers où Vim cherchera les fichiers. La chaîne vide correspond au dossier courant, . à celui contenant le fichier, et ** permet de désigner des sous-arborescences complètes. Pour rechercher dans les dossiers node_modules, j’utilise donc set path+=./node_modules/**,node_modules/**.

Au final, voici les quelques lignes de mon .vimrc :

  function! JsIncludeExpr(file)
    if (filereadable(a:file)) 
      return a:file
    else
      let l:file2=substitute(substitute(a:file,'\\.js$','','g'),'$','/index.js','g')
      return l:file2
    endif
  endfunction
  function s:setJSOptions()
    set omnifunc=javascriptcomplete#CompleteJS
    set path+=./node_modules/**,node_modules/**
    set include=require(.\\zs[^'\"]*\\ze
    set includeexpr=JsIncludeExpr(v:fname)
    set suffixesadd=.js
  endfunction
  autocmd FileType javascript call s:setJSOptions()

Ce code nécessite encore des améliorations, mais en l’état il commence à être utilisable. Pour le mettre au point, il est utile de connaître la commande checkpath! qui affiche l’ensemble des fichiers à inclure détectés par Vim (checkpath sans point d’exclamation n’affiche que les fichiers non trouvés).

Fork me on GitHub