mardi, avril 09, 2013

L'approche radicaliste de l'architecture des applications Web : l'assembleur

Un grand quotidien du soir s'alarmait dans ses colonnes, pourtant rarement ouvertes à la technique, du blocage des cookies tiers par défaut de la nouvelle version du navigateur Web de Mozilla, Firefox 22. Les zélateurs de la publicité ciblée font assaut de promptitude pour faire entendre leur voix. Après Google, fossoyeur de la presse écrite, Apple pourfendeur de la gratuité peccamineuse offerte par nos startups nationales dans le mobile, Mozilla, éradicateur de nos publicitaires culturellement exceptionnels ? Faut-il donc laisser le Web aux mains de quelques architectes programmeurs dont le radicalisme se fait entendre avec une certaine insistance ces derniers temps ?

 

Pour cantonner la réflexion au plan technique, quelques initiatives notables visent aujourd'hui à une redéfinition, à vrai dire plutôt une définition, de l'API du Web. Qu'est-ce à dire  ?

 

Il est utile de rappeler que le Web n'a pas été initialement créé par des programmeurs pour des programmeurs. Aussi surprenant que cela puisse paraître aux yeux de la Génération Y, la « récupération » du Web par les entreprises comme territoire d'expansion est une opération de grande ampleur mais somme toute récente. Cette guerre de prédation primitive qui ne dit pas son nom est à l'origine de certaines des tensions aujourd'hui sensibles dans l'analyse du développement du Net : neutralité, sécurité, accès et contrôle sociétal, données et statistiques, propriété et Open Source, sont tous des sujets qui ont largement débordé des marches de l'empire des directions informatiques d'entreprise pour envahir la discussion globale du Web.

 

Dans un billet récent (#), John Resig, le démiurge du toolkit Javascript JQuery, succès fulgurant chez les développeurs d'applications Web, tresse des louanges que cette auréole JQuery revêt d'une qualité semi-divine à asm.js (#). C'est un projet de la fondation Mozilla visant à une spécification d'un langage assembleur pour les applications Web à partir du langage script Javascript, la lingua franca actuelle des programmeurs Web.

 

Faut-il rappeler à nos jeunes lecteurs que l'assembleur est un séducteur faustien qui apparaît dans la splendeur de la beauté du Diable. Il compense l'expression aride de ses phonèmes gutturaux par une performance d'exécution inégalée : sa proximité concupiscente des instructions machines du hardware emporte ainsi toutes les préventions linguistiques. Prenons, par exemple, ce court fragment de code source assembleur :

 

020252,000178: 35,2000                                          SETLOC   CSI/CDH
020253,000179: 35,2000                                          BANK
020254,000180: 35,2000  E4,1770                                 EBANK=   SUBEXIT
020255,000181: 35,2000                                          COUNT    35/P3474
020256,000182:
020257,000183: 35,2000           04627        P34               TC       AVFLAGA
020258,000184: 35,2001           02003                          TC       P34/P74A
020259,000185: 35,2002           04642        P74               TC       AVFLAGP
020260,000186: 35,2003           04647        P34/P74A          TC       P20FLGON                              #  SET UPDATFLG, TRACKFLG

Même aux âmes les plus rébarbatives cet extrait insufflera une poésie musicale ineffable, et c'est miraculeusement ce même code qui mit en 1969 deux hommes sur la lune (#). Que l'invention géniale du stored program de Von Neumann retrouve à l'ère du Web toute sa portée conceptuelle est une joie toute pascalienne !

 

Car, comme l'indique Resig, un nouveau clan — un Clang pourrait-on dire — d'applications Javascript s'apprête à déferler sur le Web, signant le grand retour du Compilateur. On connaissait le retour en grâce, modeste néanmoins jusqu'à présent, du compilateur dans les navigateurs Web. Ces compilateurs Just In Time (JIT), comme IonMonkey (#) de Mozilla, utilisent les techniques éprouvées de l'indien Sioux en flairant des traces d'exécution des langages dynamiques laissées dans leurs interpréteurs (#) pour optimiser l'exécution ultérieure. Cette compilation JIT n'est pas propre au Web ; elle s'applique tout autant à Javascript qu'à d'autres langages populaires comme Python et qu'à des langages intermédiaires pour machines virtuelles comme CIL chez Microsoft ou le bytecode Java lui-même. Mais dans le cas présent, nous parlons bien du retour de Compilateur Khan, de l'idée pure et essentielle de recompiler des applications classiques et historiques, laborieusement écrites en C et C++ par les vétérans aux catogans grisonnants, vers Javascript, ramenant de facto le navigateur au rang d'environnement runtime.

 

Pour réussir ce retour en force, ces applications C/C++ traversent une nouvelle chaîne de compilation et de génération de code dont les développements, ces dernièes années, ont réussi à laisser quelque peu dans l'ombre le précurseur irrédentiste GNU. Les compilateurs paramétrables LLVM (#), habillés de frontaux comme CLang (#), qui nous avaient déjà esbaudis dans cette chronique (#), produisent un bytecode générique ouvert, que l'extraordinaire Emscripten (#) peut à son tour compiler en Javascript — et faire tourner ainsi sur le client dans le navigateur Web comme sur le serveur avec, par exemple, node.js (#), lui aussi initiateur d'un véritable écosystème Javascript pour le cloud. Dans le cas d'émerveillement évangélisé par Resig, la compilation produit un sous-ensemble de Javascript, appelé asm.js et présenté comme « l'assembleur » des applications Web.

 

Par conception, asm.js est de fonctionnalité limitée, un compromis accepté en échange d'une exécution ultra-rapide. La proximité d'asm.js avec les instructions machines permet en effet — et c'est l'idée directrice de Mozilla — au compilateur JIT Javascript embarqué dans le navigateur de reconnaître du code asm.js et de le passer, pratiquement sans transformation supplémentaire, à l'assembleur machine correspondant.

 

Bien sûr, les poètes d'entre nous ne trouveront peut-être pas dans asm.js :

 

function Vb(d) {
  d = d | 0;
  var e = 0, f = 0, h = 0, j = 0, k = 0, l = 0, m = 0, n = 0,
    o = 0, p = 0, q = 0, r = 0, s = 0;
  e = i;
  i = i + 12 | 0;
  f = e | 0;
  h = d + 12 | 0;
  j = c[h >> 2] | 0;
  if ((j | 0) > 0) {
    c[h >> 2] = 0;
    k = 0
  } else {
    k = j
  }
  j = d + 24 | 0;
  if ((c[j >> 2] | 0) > 0) {
    c[j >> 2] = 0
  }
  l = d + 28 | 0;
  c[l >> 2] = 0;
  c[l + 4 >> 2] = 0;
  l = (c[1384465] | 0) + 3 | 0;
  do {
    if (l >>> 0 < 26) {
      if ((4980736 >>> (l >>> 0) & 1 | 0) == 0) {
      break
    }

le même impair si soluble dans l'air qu'exhale un authentique assembleur S/370 transpirant le cambouis et l'huile de vidange :

 

//IEFBR14  JOB CLASS=A,MSGCLASS=A,RESTART=ASMF
//*--------------------------------------------------------------------
//IEHPROGM EXEC PGM=IEHPROGM
//SYSPRINT  DD SYSOUT=*
//MVS3380   DD UNIT=3380,VOL=SER=MVS809,DISP=SHR
//SYSIN     DD *
 SCRATCH DSNAME=JMM.S370ASM.LOAD,VOL=3380=MVS809
 UNCATLG DSNAME=JMM.S370ASM.LOAD
//*--------------------------------------------------------------------
//ALLOC    EXEC PGM=IEFBR14
//LOAD      DD DSN=JMM.S370ASM.LOAD,
//             UNIT=3380,VOL=SER=MVS809,
//             SPACE=(CYL,(20,0,15)),
//             DCB=(RECFM=U,BLKSIZE=32760),
//             DISP=(,CATLG)
//*--------------------------------------------------------------------
//ASMF     EXEC PGM=IFOX00,REGION=2048K
//SYSLIB    DD DSN=SYS1.AMODGEN,DISP=SHR
//          DD DSN=SYS1.AMACLIB,DISP=SHR
//SYSUT1    DD DISP=(NEW,DELETE),SPACE=(1700,(900,100)),UNIT=SYSDA
//SYSUT2    DD DISP=(NEW,DELETE),SPACE=(1700,(600,100)),UNIT=SYSDA
//SYSUT3    DD DISP=(NEW,DELETE),SPACE=(1700,(600,100)),UNIT=SYSDA
//SYSPRINT  DD SYSOUT=*
//SYSPUNCH  DD DSN=&&OBJ,UNIT=SYSDA,SPACE=(CYL,1),DISP=(,PASS)
//SYSIN     DD *
IEFBR14  CSECT ,
         SLR   15,15
         BR    14
         END   ,
//*-------------------------------------------------------------------
//LKED     EXEC PGM=IEWL,
//             COND=(5,LT,ASMF),
//             PARM='LIST,MAP,XREF,LET,NCAL,RENT'
//SYSPRINT  DD SYSOUT=*
//SYSLMOD   DD DSN=JMM.S370ASM.LOAD,DISP=SHR
//* SLIB    DD DSN=SYS1.LINKLIB,DISP=SHR
//SYSUT1    DD UNIT=SYSDA,SPACE=(TRK,(5,5))
//SYSLIN    DD DSN=&&OBJ,DISP=(OLD,DELETE)
//          DD *
 NAME IEFBR14(R)
//*-------------------------------------------------------------------
//IEFBR14  EXEC PGM=IEFBR14
//STEPLIB   DD DSN=JMM.S370ASM.LOAD,DISP=SHR

mais impossible de mettre en doute l'efficacité du code engendré. Au point que l'éditeur de jeux Epic a réussi le tour de force de porter son moteur de jeux Unreal Engine 3 vers asm.js (#) et à faire tourner les jeux les plus consommateurs de ressources dans le navigateur Firefox et sous WebGL, un rendering pas particulièrement connu pour sa vélocité !

 

Tout ceci ne va pourtant pas sans chagriner quelques gardiens du temple de la Compilation éclairée (#). Pointant en particulier le fait que les compilateurs Javascript modernes sont déjà des fusées à plusieurs étages d'optimisation, comme Crankshaft dans V8 (#) chez Google, l'idée de réduire Javascript à un sous-ensemble n'est-elle pas contradictoire avec celle, devenue presque courante aujourd'hui, de créer plutôt des surensembles de Javascript, bénéficiant de l'empilement d'optimisations de ces compilateurs JIT. (Que l'on pense par exemple à TypeScript (#), CoffeeScript (#), voire à Dart (#), Script# (#) et autre espèces du bestiaire (#) scriptural.)

 

Mais bien plus, arguent ces Quirites contemporains, asm.js ne fait que porter le masque de Javascript. Il ne serait qu'un bytecode vulgum pecus paradant sur les voies impériales et menant ultimement à la confusion des genres. À cacher un bytecode dans un langage de haut niveau, ne court-on pas à la « pollution » du langage de haut niveau de features pertinents pour le seul bytecode de plus bas niveau ? Ce mariage morganatique est-il donc si fâcheux ?

 

Le débat sur l'approche radicaliste de l'architecture Web ne fait que s'ouvrir.

 

ShareThis